diff --git a/BACKGROUND b/BACKGROUND deleted file mode 100644 index c15c665e..00000000 --- a/BACKGROUND +++ /dev/null @@ -1,70 +0,0 @@ -This package consists of many parts. This document offers a small tour -around the most important pieces. Not all aspects are discussed -exhaustively, but it should be enough to give you the feeling you -understand what you are seeing happen. - -When you want to communicate with a piece of hardware, you need a kernel -driver (well, that is not quite true, but it is in most cases the only -way to do it safely). In the past, this meant you had to patch the kernel -and recompile it. These days, you can use kernel modules. We support both -approaches. - -We have chooses for a very modular (no pun intended) setup. There are a -few general-purpose base kernel modules, which you always need. In -addition, there is one kernel module for each piece of hardware - whether -this is an I2C bus adapter, an SMBus adapter or a sensors chip. - -The kernel modules communicate their information through both the /proc -and sysctl interfaces (Linux 2.4) or the /sys interface (Linux 2.6). To -keep things uncomplicated, the sensor chips always advert their -measurements 'as is'. This means that the values they report are not -immediately relevant to you - they must first be scaled and translated -to correspond to the real world. - -It is also possible to communicate directly with chips on an I2C bus -or SMBus. This is done through /dev files. This is useful if you -quickly want to test how a certain chip behaves, without having to -write a kernel driver. - -Note that all other parts of this package function in so-called user-space. -This is important, because bugs in kernel-space might crash your -computer or do other bad things. And kernel memory can not be swapped out! - -Applications could (and can) directly read the sensor values through the -/proc, sysctl or /sys interfaces. This is harder than it sounds; because -no two chips are the same, the information they communicate may also -be very unlike. This would mean that every application would have to know -about every type of chip. But there is a better solution. - -libsensors is a (shared or static) library of access functions. It -knows about every type of chip supported by the kernel modules (or it -should, if it is up-to-date). It offers a simple-to-use interface for -applications to access the sensor chip readings, to set new limits, -and all other commonly needed things. From the application's point of -view, there is no need to know very much about a specific sensors chip. -Having some inside information can still be useful, but it is possible to -write a generic fall-back function that takes care of newer, unknown -chips, and to display all really important information. - -libsensors takes care of one other thing. The kernel modules report -so-called 'as is' values. They have to be scaled or translated to be -relevant in the real world. libsensors reads a configuration file -(usually /etc/sensors.conf) which specifies how this translation should -be done (with some other things). Again, the application does not have -to know about it. And because the configuration file is reread each time -a new application is started, you can change configuration values without -having to recompile anything. - -This package does not contain a nice graphical monitor. See -http://www.lm-sensors.org/wiki/UsefulLinks for pointers to such programs. -It does contain an example console program that reports all current sensors -values. This program is called 'sensors'. You can use it as a reference -implementation for more intricate programs. - -There are many, many kernel modules in this package, and there are lots -of different sensor chips supported. Sometimes, it can be hard to -determine what chips and adapters you have, and which modules correspond -to them. Fortunately, there is a user-space application 'sensors-detect' -that should tell you exactly what is available, and what you need to -do. This perl script uses the /dev interface, and you may use it as an -example how you can do this. diff --git a/BUGS b/BUGS deleted file mode 100644 index b584ba98..00000000 --- a/BUGS +++ /dev/null @@ -1,87 +0,0 @@ -Except for many unimplemented things (listed in the TODO file), there may be -true bugs too. If you experience any problems not listed here, do not hesitate -to mail us (see http://www.lm-sensors.org/wiki/FeedbackAndSupport). -But read this file and doc/FAQ first, please! - -============================================================================ -These are current problems with specific programs and drivers. -In general, please don't send us mail telling us you have the -same problem!! Do send us mail if you have a fix!! - - -================================ -Asus boards - as99127f support (w83781d driver) - -Several problems. Asus will not release a datasheet. -Support was developed - and tweaked - with experimentation and user feedback. -These will not be fixed unless we get a datasheet. -If you have problems, please lobby Asus to release a datasheet. -Unfortunately, several others have done so, without success. -Please do not send mail to us asking for better as99127f support. -We have done the best we can without a datasheet. -The changes we do make to please some people generally makes -things worse for people with other types of motherboard. -Please do not send mail to the author or the sensors group asking for -a datasheet or ideas on how to convince Asus. -See doc/chips/w83781d for more information. - -================================ -i2c/smbus lockup (i2c-piix4 and i2c-ali15x3 drivers) - -Sometimes the i2c bus will get hung and the driver can't un-hang it. -If this is caused by a hung sensor chip (mtp008 and w83781d chips may -be culprits), only a reboot or even power cycle will clear it -(if the SDRAM eeproms are on the hung i2c bus, the machine probably won't -boot until the power is cycled). -If there are bugs in the i2c bus drivers, or improvements we can make to -error recovery, we don't know what they are. - -On the ASUS P5A motherboard, there are several reports that -the SMBus will hang and this can only be resolved by -powering off the computer. It appears to be worse when the board -gets hot, for example under heavy CPU load, or in the summer. -There may be electrical problems on this board. -On the P5A, the W83781D sensor chip is on both the ISA and -SMBus. Therefore the SMBus hangs can generally be avoided -by accessing the W83781D on the ISA bus only. - -================================ -IBM Thinkpad laptops and sensors-detect -See the file README.thinkpad - - -================================ -mtp008 support - -This chip does not always respond, as evidenced by 'XX' fields -in i2cdump. Results in non-detection by sensors-detect and/or -the mtp008 driver, or periodic bad readings. -Cause unknown - perhaps a bug in the chip, or the chip -not meeting the i2c specifications. - - -================================ -sis5595 (sis5595 and i2c-sis5595 drivers) - -These drivers latch on to many non-sis5595 chips which -do not support sensors, i2c bus, or both. -This is because SiS uses the same PCI ID for several different chips. -This will have to be fixed by us to recognize these other chips. - -Right now, the driver tries -writing the base addresses (using the force_addr=0x.... parameter to modprobe), -it does not work for some machines (dmesg message is "force address failed"). -Either some chips do not support sensors, or there is some undocumented -lock bit for the base address registers. - -Also, the temperature reading in sis5595 is usually wrong. -Different formulas are required for different versions of -the chip and different motherboards. - -================================ -bus drivers (all) - -Rmmod'ing a bus driver when the /proc directory for a chip -driver on that bus is in use may cause a kernel oops, because -the chip driver gets removed too. See ticket #331 for details. -Not likely to happen. No obvious way to fix. diff --git a/CHANGES b/CHANGES index 003e6708..85589153 100644 --- a/CHANGES +++ b/CHANGES @@ -1,1849 +1,207 @@ -lm_sensors CHANGES file +lm-sensors CHANGES file ----------------------- SVN-HEAD - File lm_sensors.lsm: Delete, don't advertise a legacy branch - File doc/developers/release_checklist: Skip mail to lsm - Program sensors-detect: Fix detection of older DS1621 - -2.10.8 (20081216) - File doc/chips/lm90: Update datasheet links (2.6 backport) - File doc/chips/pc87360: Drop dead links to datasheets (2.6 backport) - File i2c-dev.h: Drop I2C_FUNC_SMBUS_*I2C_BLOCK_2 defines - Library: Avoid namespace pollution - Add support for the IT8720F chip - Support separate prefixes lm89, max6658, max6659, max6681, - max6646, max6647 and max6649 - Add alternative feature name for f71882fg temperature alarms - Module i2c-i801: Remove verbose debugging messages (2.6 backport) - Properly report bus arbitration lost (2.6 backport) - Add support for PCH (Ibex Peak) (2.6 backport) - Module i2c-piix4: Minor cleanups (2.6 backport) - Module i2c-viapro: Add VX800/VX820 support (2.6 backport) - Module lm78: Prevent misdetection of Winbond chips - Module lm90: Don't spam the kernel log (2.6 backport) - Module max1619: Use inline functions instead of macros (2.6 backport) - Program decode-dimms.pl: Only export the ceil function from POSIX - Fix decoding of SDR SDRAM bytes 12-14 - Program pwmconfig: Fix MINSTOP and MINSTART test functions (#2340) - Change default for MINTEMP from 0 to 20 degrees C - Program sensord: Add it8720 support - Add lm89, max6658, max6659, max6681, max6646, max6647 - and max6649 support - Accept negative temperatures in RRD database - Don't bail out on transient errors (#2330) - Program sensors: Recognize it87 thermal sensor type 4 as thermistor - Add it8720 support - Add lm89, max6658, max6659, max6681, max6646, max6647 - and max6649 support - Program sensors-detect: Add VIA VT1212 support - Add SMSC EMC2700LPC support - Add ITE IT8720F support - Add Texas Instruments TMP411 support - Prevent misdetection of W83627DHG on I2C as LM78 - W83627DHG has no subclients - Add VIA VX800/VX820 support - Fix detection of Intel 5000 series FB-DIMM AMB - Fix detection of ADT7462 - Fix detection of SMSC LPC47M292 - Add SMSC LPC47M233 support - Fix SMBus detection of W83627EHF and W83627DHG - Add Intel Core I7 support - -2.10.7 (20080701) - Library: Don't choke on unrecognized devices, part 2 - Parse the configuration file in C locale (#2312) - Makefile: Fallback to simple depmod if System.map can't be found - Module asb100: Remove some dead code (2.6 backport) - Module i2c-amd756: Fix functionality flags (2.6 backport) - Module i2c-amd756-s4882: Fix an error path (2.6 backport) - Module i2c-i801: Drop broken I2C block read support - Add ICH10 support - Module i2c-piix4: Minor cleanups (2.6 backport) - Module i2c-sis5595: Minor cleanups (2.6 backport) - Module lm75: Fix an incorrect comment (2.6 backport) - Module lm90: Fix LM86 detection (#2335) - Module w83l785ts: Don't ask user to report failures (2.6 backport) - Program fancontrol: Don't use named pipes when we don't need them (#2319) - Program sensord: Add lm90, adm1032, lm99, lm86, max6657, adt7461 support - Fix adm1021, adm1023 support with 2.6 kernel (#2334) - Program sensors-detect: New device ID for the SMSC SCH5317 - Add SMSC SCH5127 detection - Add National Semiconductor LM64 detection - Add Asus F8000 detection - Add Intel ICH10 (bus) detection - Don't probe I2C addresses 0x40-0x47 - Fix the parsing of I2C addresses not to scan - Detect and skip 1-register-only I2C devices - Avoid SMBus word transactions where possible - Add Dallas DS1631 detection - Fix Andigilog aSC7621 support - Fix Analog Devices ADT7461 support - Add VIA C7 support - Fix Winbond W83L786NR/NG/R/G support (#2336) - -2.10.6 "Welcome Home Lina" (20080306) - Library: Fix fschrc and fschmd support - Fix sysfs presence detection - Don't choke on unrecognized devices, part 1 (#2087) - Fix lm93 vid2 access (#2295) - No in1 on w83783s - Support DOS-style configuration files again (#2284) - Makefile: Revert changeset 4738, fix bug #2187 differently - Module adm1026: Various cleanups - Module eeprom: Hide Sony Vaio serial numbers to regular users (2.6 backport) - Drop useless debugging log messages - Recognize VGN as a valid Sony Vaio name prefix (2.6 backport) - Module gl518sm: Fix fan speed reading (2.6 backport) - Module gl520sm: Fix fan speed reading (2.6 backport) - Module lm90: Use generic i2c reads during detection (2.6 backport) - Module w83627hf: Enable VBAT monitoring (#2282, 2.6 backport) - Program decode-dimms.pl: Fix DDR2 SDRAM module speed decoding - Update manufacturer IDs. - Program decode-vaio.pl: Private data might not be readable by non-root users - Print the asset tag - Fix the timestamp decoding - Program i2cdump: Fix I2C block mode error code - Program fancontrol: Detect improperly formatted FCTEMPS value (#2293) - Program pwmconfig: Better diagnostics in pwmdisable - Give the fans some time to spin up - Really hide errors on sysfs writes - Deal gracefully with read-only pwm_enable files - Warn about outputs found in automatic mode - Fix duplicate warning message when config file is broken - Program sensord: Add lm85 support - Program sensors: Hide spurious errors on missing f71872f voltage inputs - Hide spurious errors on missing adm1026 inputs - Fix W83783S prefix matching - Program sensors-detect: Add Texas Instruments TMP401 detection - Mention the f75375s driver - Add SMSC LPC47B367-NC detection (no sensors) - Reduce w83781d/lm78 I2C address probing range - Drop PCA9540 detection - Add Intel Celeron 4xx and Penryn (CPU on 45nm) - detection - Improve sysconfig and modprobe.d integration - Add SMSC SCH5514D-NS detection (no sensors) - Lower the confidence of MAX6650/MAX6651 - Add Fintek F71858DG detection - Add Fintek F81216D detection (no sensors) - Add SMSC SCH5027D detection - Do not access I/O ports on PPC - Move south bridge sensor detection to the right - section - Run chip_special_cases() earlier - Program unhide_ICH_SMBus: Add support for the 82801AA (ICH) - -2.10.5 (20071024) - File i2c-dev.h: Rename I2C_FUNC_SMBUS_HWPEC_CALC to I2C_FUNC_SMBUS_PEC - File sensors.conf.eg: Add a thmc50 section - File useful_addresses.html: Moved to the wiki - Library: Fix a memory leak on error - Speed up sensors_get_ignored() a bit - Fix thmc50 support for Linux 2.6 - Fix bmcsensors support for Linux 2.6 - Fix lm93 VID support for Linux 2.6 - Fix adm1024 support for Linux 2.6 - Fix maxilife support for Linux 2.6 - Fix magnitude of temperature offsets in Linux 2.6 - Fix adm1026 critical temperature limits for Linux 2.6 - Fix smsc47m192 temperature faults - Add sch311x support - Add support for adm1022 temp3 - Makefile: Fix kernel version detection (#2187) - Man page sensord.8: Update - Module fscher: Add missing read of control register (2.6 backport) - Module i2c-i801: Add Tolapai support (2.6 backport) - Module i2c-nforce2: Declare PEC as supported (2.6 backport) - Module i2c-piix4: Add ATI SB700 and SB800 support (2.6 backport) - Module lm93: Fix an array overrun (2.6 backport) - Program sensord: Fix f71805f fans - Synchronize the version with lm-sensors - Fix a memory leak when daemonizing - Fix memory leaks in command line parsing - Add w83793 support - Log the error code on failure - Add lm87 support - Program sensors: Fix two memory leaks on error - Add sch311x support - Hide error on missing dme1737 fan and pwm - Add thmc50/adm1022 support - Hide error on missing adm1021 die code - Handle gl518sm with no voltage input values - Program sensors-detect: Don't probe i2c-isa as a regular i2c bus - Add Winbond W83L786NR/NG/R/G detection - Add Winbond W83L771W/G detection - Add Intel Tolapai SMBus detection - Fix SMSC SCH311x detection - Add AMD K10 CPU sensor detection - Fix SMSC LPC47B357/M967 detection - Select the right driver for FSC chips - Program sensors-detect-stat.pl: Handle alternative chip lists - - -2.10.4 (20070716) - File doc/vid: Update the sysfs paths, update the chip lists - File i2c-dev.h: Support I2C block reads with specified length - File sensors.conf.eg: Add a dme1737 section - File lm_sensors.sysconfig: Delete, now generated by sensors-detect - Library: Clean up pwm symbol names translation - Add dme1737 support - Add applesmc support - Add abituguru3 support - Add f71882fg support - Add w83627ehf support (for Linux 2.4) - Add support for the w83627ehf VID function - Add support for the w83627ehf thermal sensor types - Add support for it87 fan4 and fan5 - Man page sensors.conf.5: Update the chip statement section - Module i2c-nforce2: Add nForce MCP61, MCP65 support (2.6 backport) - Module lm85: Fix setting the fan speed min limit to 0 - Add support for the EMC6D102 extra resolution bits - Module thmc50: Fix the i2c address range - Module w83627ehf: New (2.6 backport) - Programs i2cdump, i2cget, i2cset: Do not force the slave address by default - Program i2cdump: Use the new I2C block read function - Program isadump: Detect when address bit 7 is a busy flag - Fix Super-I/O exit sequence for Winbond/Fintek chips - Program fancontrol: Use let for arithmetic evaluation - No longer need awk and grep - Limit calls to external programs (Linux 2.6 only) - Check for configuration file validity - Support optional min and max PWM values - Better integration with init scripts - Use linear control instead of quadratic - Program pwmconfig: Use smaller steps for low PWM values - Support optional min and max PWM values - Program mkpatch: Include w83627ehf - Program rrd: Support non-i2c devices (hwmon class) - Add missing shell declarations - Update URI - Program sensors: Drop ddcmon and eeprom support - Add dme1737 support - Add applesmc support - Add max6680 support - Add abituguru3 support - Add f71882fg support - Fix alignment of alarm for one-limit temperatures - Add w83627ehf support (for Linux 2.4) - Add support for the w83627ehf VID function - Add support for the w83627ehf thermal sensor types - Add support for it87 fan4 and fan5 - Display the extra resolution bits of the emc6d102 - Program sensors-detect: Stop Super-I/O probe after first family success - Fix SMSC DME1737 detection - Add /usr/sbin to the PATH (#2199) - Add ATI SB700 detection - Add Maxim MAX6680/MAX6681 detection - Add IT8726F detection - Fix IPMI support for 2.6 kernels - Add detection for non-standard SMSC Super-I/Os - No longer depend on i2cdetect - Add SMSC SCH5317 detection - Drop detection of most non-sensors I2C chips - Fix ADM1022 detection - Add detection of many SMSC Super-I/O chips - Add Fintek F71806FG and F71862FG detection - - -2.10.3 (20070319) - Library: Do not skip i2c adapters with only a class device and no - physical device. This change is required to survive the - planned struct class_dev removal from future 2.6 kernels. - Add support for the SMSC LPC47M292 fans (prefix smsc47m2) - Recognize i2c-isa-based devices as such even after class_dev - is gone - Compile with -D_REENTRANT - Fix support of Linux 2.6's max6650 driver - Fix max1619 support - Man page i2cdetect.8: Scanning range can be restricted - Module bmcsensors: Fix debugging messages - Module i2c-ali1563: Improve the status messages (2.6 backport) - Fix device initialization (2.6 backport) - Module i2c-amd8111: Cleanups (2.6 backport) - Fix initialization race (2.6 backport) - Module i2c-nforce2: Drop unused reference to pci_dev (2.6 backport) - Module i2c-piix4: Add ATI SB600 support (2.6 backport) - Module i2c-viapro: Add CX700 support (2.6 backport) - Module smsc47m1: Add SMSC LPC47M292 support - Get rid of a useless semaphore (2.6 backport) - Programs i2cdetect, i2cdump, isadump: Flush output in real time - Program i2cdump: Cleaner output in SMBus block read mode - Program fancontrol.pl: Fix pwmN_enable access (#2190) - Program sensors: Add smsc47m2 support (fans) - Fix -A option (hide adapter name) on error - Program sensors-detect: Only probe relevant I2C addresses - Drop ARP-capable device detection - Add Maxim MAX6655/MAX6656 detection - (Olexiy Avramchenko) - Add Maxim MAX1668, MAX1805, MAX1989 detection - Add VIA CX700 detection - Drop legacy W83627HF ISA detection - Don't bufferize stdout during probes - Speed up the LM75 and LM77 detection - Clean up the EEPROM detection - Add Dallas DS75 detection - Add SMSC LPC47M292 detection - Add nVidia MCP61 and MCP65 detection - Fix ADM1028 detection - Add Nat. Semi. PC8347L Super-I/O detection - Add SMSC SCH5504 Super-I/O detection (no sensors) - Make the LM78 and W83781D detection safer - - -2.10.2 (20070115) - RPM: Obsolete, removed - File doc/fan-divisors: Update - File sensors_vid.h: Trim VID values to correct number of bits (2.6 backport) - Library: Add support for the pc87247 driver (fans only) - Probe for busses before chips - Drop support for algorithm names - Add support for coretemp driver - Major update/optimization of config-file scanner - Add config-file scanner regression tests - Add f71872f support - Add w83627dhg support (David Holl, #2157) - Get the i2c adapter names from classdev.name - Add adm1029 support (Corentin Labbe) - Man page i2cdetect.8: Describe the output convention - Man page sensors.1: Update (option -c) and clean up - Module bmcsensors: Fix several warnings - Fix fragile structure initialization - Module i2c-i801: Add ICH9 support - Module p4b_smbus: Add support for the ICH5 - Module f71805f: Fix the device address decoding (2.6 backport) - Module icspll: Delete. It was useless and dangerous. - Program decode-dimms.pl: Remove spaces at end of lines - Program eepromer: Fix loads of warnings - Program i2cdetect: Make the output clearer - Program py-smbus: New! Python i2c-dev bindings (prog/py-smbus) - Program unhide_ICH_SMBus: New! Unhides the ICH SMBus for 2.6 kernels - without need of recompilation. - Programs dump/*: More robust handling of user inputs - Programs pwmconfig, fancontrol: Handle write errors for bash 3.1 - Add support for non-i2c drivers - Program fancontrol.pl: Disable debugging by default - Add support for non-i2c drivers - More tolerant config file parsing - Program sensord: Add pc87247 support (fans only) - Add vt1211 support (#2150) - Add w83627dhg support (David Holl, #2157) - Add w83627ehf voltage support (Dave Platt) - Add k8temp support (Dave Platt) - Program sensors: Add pc87247 support (fans only) - Hide error on missing f71805f fan - Handle option -c more efficiently - Drop option -a (show algorithm names) - Add f71872f support - Add w83627dhg support (David Holl, #2157) - Add adm1029 support (Corentin Labbe) - Hide error on missing w83793 temp (Gong Jun) - Program sensors-detect: Add SMSC DME1737 detection - Add Fintek F71882FG and EPoX EP1308 detection - Add Intel Core thermal sensor detection - Preallocate memory for I2C_FUNCS ioctl (#2138) - Prevent misdetection of MAX6633/MAX6634/MAX6635 - Add Intel ICH9 detection - Add Maxim MAX6648/MAX6692 detection - Improve ADM1029 detection - Add Andigilog chips detection - Add Intel AMB FB-DIMM thermal sensor detection - Add ATI SB600 detection - - -2.10.1 (20060924) - File doc/developers/checklist renamed to dev/developers/release_checklist - with clarifications and updates for new SVN server. - File README.package: Delete. - File doc/busses/i2c-piix4: Update (2.6 backport) - File doc/developers/sysfs-interface: Update - File etc/sensors.conf.eg: Add an smsc47m192 section - Comment out all set statements - Add an it8716 section - Add a w83793 section - Adjust the vt1211 section to match the new driver - interface - Library: Fix device scan when no i2c support is present - Add support for W83627EHF voltage inputs and alarms - Add support for the smsc47m192 driver - Fix all memory leaks (yeah!) - Fix no sensors being reported as an error - Add support for the IT8716F and IT8718F chips - Add support for the W83793 chip (Yuan Mu) - Map the 2.6 adm1026's fan8 to fan0 - Missing sysfs busses and classes are not errors - Change vt1211 temp3-7 magnitude from 1 to 3 - Makefile: Don't grep autoconf.h on user-space targets - Fix depmod on non-running kernel version - Remove empty include directories on make user_uninstall - Module i2c-ali1535: Drop redundant semaphore (2.6 backport) - Module i2c-amd756-s4882: Improve static semaphore initialization - (2.6 backport) - Module i2c-i801: Disable PEC mode after every transaction (2.6 backport) - Add ICH8 support (2.6 backport) - Fix block transaction poll loops (2.6 backport) - Remove PCI function check (2.6 backport) - Cleanups (2.6 backport) - Module i2c-nforce2: Add nForce4 MCP51, MCP55 support (2.6 backport) - Module i2c-piix4: Add ServerWorks HT-1000 support (2.6 backport) - Add ATI IXP200, IXP300, IXP400 support (2.6 backport) - Drop the fix_hstcfg parameter (2.6 backport) - Module i2c-viapro: Fix compilation with kernels < 2.4.21 - Add VT8237A and VT8251 - Module lm83: Add LM82 support (2.6 backport) - Module vt1211: The VT1211 has no in6 - Rework the voltage and temperature conversions and the - temperature input order to match the Linux 2.6 driver - Module w83781d: Use real-time alarm registers when possible (2.6 backport) - Add specific alarm and beep defines for the W83791D - Module w83792d: Fix PWM range (2.6 backport) - Program decode-dimms.pl: Decode depending on the memory type - Decode the manufacturing date to an ISO8601 date - Add the memory size computation and provide brief - timing characteritics for SDRAM/DDR/DDR2 memory - Add memory size computation for Rambus memory - Various output cleanups and fixes - Program decode-edid.pl: Add /usr/sbin or /usr/local/sbin to $PATH if needed - Program decode-vaio.pl: Detect and skip false positives - Program i2cdetect: Add a mode to print adapter functionalities - Program i2cdump: Restore bank after bank switching - Add new mode W (read word on even register addresses) - Program mkpatch: Fix typo breaking f71805f - Turn warnings on (-w), and fix them - Print a usage message on missing command line parameters - Program pwmconfig: Use mktemp instead of tempfile - Program sensors: No error messages on missing w83792d fan4-7 (Yuan Mu) - Add smsc47m192 support - Add abituguru support (Hans de Goede) - Fix memory leak when printing an unknown chip - Add it8716 and it8718 support - Make each it87 fan and fan div optional - Print missing w83791d values - Add w83793 support (Yuan Mu) - The adt7463 may not have in4 (#2119) - Hide more vt1211 missing input errors - Clearer error messages when no sensors found - Program sensors-detect: Add ServerWorks HT-1000 SMBus detection - Add ATI IXP200/300/400 SMBus detection - Prevent warning on 64-bit PCI addresses - Add Fintek F75363SG, F75111R/RG/N, F75121R, - F75122R/RG, F75373S/SG, F75375S/SP, F75383S/M, - F75384S/M, F75387SG/RG and F81218D detection - Add Winbond W83793R/G and W83627DHG detection - Handle the W83791D driver difference between kernels - Add nForce4 MCP04, MCP51 and MCP55 detection - Add AMD Geode devices detection - Add ITE IT8716F and IT8718F detection - Add NatSemi/Winbond PC87427 detection - Get driver information for busy addresses from - sysfs (2.6 only) - Drop the ISA IT87xxF detection - Check i2c adapter functionalities before probing - Add Intel ICH8 SMBus detection - Add AMD K8 thermal sensors detection - Simplify detection of SiS5595, VIA686 and VT8231 - Add Analog Devices ADM1033, ADM1034, ADT7462, - ADT7466, ADT7470, ADT7473 and ADT7475 detection - Check for root user at startup - Attempt to be slightly more user-friendly - Add VT8237A and VT8251 - Remove detection of nVidia graphics adapters - Use sysfs for PCI device enumeration - Add generic PCI SMBus adapter detection - Add generic Super-I/O logical device detection - Add SMSC LPC47M172/182 detection - - -2.10.0 (20060214) - File doc/lm_sensors-FAQ.texi: Remove version 1 specifics part - File doc/busses/i2c-viapro: Update (2.6 backport) - File doc/chips/via686a: Update (2.6 backport) - File doc/chips/w83627hf: W83627THF VID clarification (2.6 backport) - File etc/sensors.conf.eg: Do not set vrm by default - File i2c-dev.h: Fix union i2c_smbus_data definition - Sync i2c_msg definition with i2c.h (Hideki Iwamoto) - Add missing parentheses around macros - Drop I2C_FUNC_SMBUS_EMUL - Drop I2C_FUNC_SMBUS_*_PEC - Drop I2C_SMBUS_*_PEC - File sensors_vid.h: Drop default VRM - Library: NOTE: libsensors(3) will no longer see eeprom (SPD) chips - This is intentional. Use decode-dimms.pl if you still - need your memory SPD data. - Library: Big update to use libsysfs. More TODO though. - Fix bus matching code for Linux 2.6 (Karsten Petersen) - Add f71805f, w83687thf support - Add platform drivers support - Fix sysctl warnings on x86_64 - Restore vt1211 temp1 - Makefile: Compile user-space programs with -Wundef - Module i2c-i801: Simplify the hardware PEC code - Always set PEC mode explicitly before each transaction - Module i2c-i810: Documentation update, PCI IDs cleanup - Module i2c-keywest: Remove bus probing code (2.6 backport) - Module i2c-nforce2: Remove dead code (2.6 backport) - Add the ID of the nForce4 MCP-04 (2.6 backport) - Module i2c-via: Remove dead code - Module i2c-viapro: Remove dead code - Support I2C block read (2.6 backport) - Code cleanups (2.6 backport) - Improve debug register dump (2.6 backport) - Modules i2c-ali1535, i2c-ali1563, i2c-ali15x3, i2c-amd756, i2c-amd8111, - i2c-i801, i2c-nforce2, i2c-piix4, i2c-sis5595, i2c-sis630, - i2c-sis645: Use pci_driver name to request I/O region; do - not initialize i2c_adapter name to "unset" (2.6 - backport) - Modules i2c-amd8111, i2c-i801, i2c-nforce2: Drop software PEC code - (2.6 backport) - Module adm9240: Cleanups (2.6 backport) - Module f71805f: New, supports the Fintek F71805F/FG Super-I/O - Module it87: Minor cleanups - Fix fan3_div setting bug (Anton V. Staaf) - Module lm90: Support the ADM1032-2 and ADT7461-2 (2.6 backport) - Separate the register read function - Add PEC support for the ADM1032 - Module via686a: Cleanups - Module w83627hf: Drop useless initialization step (2.6 backport) - Fix in4 for W83627THF and W83637HF (Yuan Mu) - Fix alarms (Yuan Mu) - Preserve fan min on fan div change (Yuan Mu) - Properly handle W83627THF without VID (Yuan Mu) - Fix in0 limit settings in "VRM9" mode (Yuan Mu) - Add W83687THF support - Module w83781d: Drop W83697HF support (Grant Coady) - Module w83792d: Bug fixes and code cleanups (Yuan Mu, 2.6 backport) - Fix fan control mode (PWM/DC) reporting - Fix fan div auto-adjust (Yuan Mu) - Fix the subclient handling - Module w83l785ts: Minor cleanup (2.6 backport) - Module vt1211: Restore temp1 - Modules vt1211, vt8231: Change default VRM to 9.1 - Program decode-dimms.pl: Add lookup tables for manufacturer names - Fix rounding error in PCxxxx speed computation - Improve text output - Improve speed under Linux 2.6 - Verify checksum before decoding anything - Improve manufacturing location decoding - Improve memory type detection - Improve part number decoding - Program i2cdump: Drop now useless #ifdef tests - Fix capability check for continuous byte mode - Program i2cget: New - Program i2cset: Add PEC support - Fix argc check - Programs i2cdetect, i2cdump, i2cset: Stop printing the algorithm name - Print the correct bus type if bus - functionality can be queried - Program isadump: Display the real addresses in flat mode - Program mkdev.sh: Silently skip already existing nodes - Program mkpatch: Include f71805f - Program sensord: Do not log algorithm names - Drop EEPROM support (Aurelien Jarno) - Add W83627EHF, F71805F/FG support - Fix PC87365/PC87366 alarms - Program sensors: Drop free_the_label - Fix compilation with uclibc (no iconv) - Add f71805f, w83687thf support - Program sensors-detect: Drop algorithm names - Do not rely on i2cdetect -l printing algo names - Simplify adapter name matching mechanism - New address for ADM1032, ADT7461 - Improve ADT7467, ADT7468 support - Fix MAX6659 reported driver - Add Fintek F71805F detection - Add Analog Devices ADT7476 detection - Add Intel 82845G detection - Add IT8201R/IT8203R/IT8206R/IT8266R detection - Fix udev detection in some corner case - Improve DS1621 detection - Always prefer ISA access over SMBus access - - -2.9.2 (20050906) - File doc/chips/*: Big update (2.6 backport) - Library: Drop ds1780-specific code (now use adm9240) - Fix memory leak in sensors_get_label() - Support /sys/class/hwmon (Linux 2.6.14+) - Limit stack usage in sensors_read_proc_chips() - Makefile: Detect 2.6+ kernels and check targets - Man page isaset.8: Fix typos - Module adm1031: Fix broken kfree() calls - Module i2c-ali1563: New (2.6 backport by Winbond) - Modules i2c-ipmb, i2c-ipmi: Support ipmi_request() additional argument - Modules it87, pc87360, sis5595, smsc47m1, vt1211, vt8231, - w83627hf.c: Tag find function __init - Module lm93: Fix memory leak - Module smsc47m1: Fix PWM enable polarity on read - Modules w83627hf, w83781d: Allow setting fan divisor to 128 - Program decode-dimms.pl: Support Linux 2.6 (Burkart Lingner) - Added DDR/DDR2 frequency reporting in convenient - form of DDRxxx PCyyyy - Program i2cdump: Properly handle short i2c block reads - Program fancontrol.pl: Fix compile errors - Program mkpatch: Include i2c-ali1563 - Include w83792d - Program pwmconfig: Fix unsafe temporary file use - Program rrd: Support 2.6 kernels - Program sensord: Add support for w83637hf - Support pc87360 (Henrik Brix Andersen) - Program sensors: Support the VAIO "VGN" prefix for eeprom - Program sensors-detect: Add SMSC LPC47M15x/LPC47M192 SMBus detection - Advertise the w83792d driver - Improve IT8705F and IT8712F detection - Merge LM82 and LM83 detection - Add W83687THF detection - - -2.9.1 (20050412) - File doc/busses/i2c-nforce2: Update - File doc/chips/it87: Update - File doc/chips/lm90: Update for adt7461 - File doc/chips/mic74: New - File etc/sensors.conf.eg: New sections for lm92 and w83792d - Library: Add support for 2.6 fscpos driver (Stefan Ott) - Fix sis5595 in4 (Aurelien Jarno) - Add support for 2.6 gl520sm driver (Maarten Deprez) - Add support for 2.6 bmcsensors driver (Yani Ioannou) - Add support for w83792d (Chunhao Huang/Winbond) - Add support for 2.6 adt7461 (James Chapman) - Add support for 2.6 lm92 - Add support for 2.6 vt1211 - Add preliminary support for 2.6 w83627ehf - Makefile: Support mips, sparc32 and sparc64 (Aurelien Jarno) - Use -fno-strict-aliasing on all architectures - Man pages pwmconfig, fancontrol: New (Aurelien Jarno) - Module bmcsensors: Fix compile error - Support IPMI V0.9 (Yani Ioannou/Vladislav Bogdanov) - Module ds1621: Fix detection (Aurelien Jarno) - Module eeprom: Discard SPD-centric checksum module parameter - Cleanup detection function (backport from Linux 2.6) - Module i2c-ali1535: Add delay loops for reliability (Ubel Walter) - Module i2c-i801: Temporarily disable broken I2C block read - Module i2c-ipmi: Fix bogus return in a middle of a function (Sergio - Gelato) - Module i2c-nforce2: Add nForce4 support (Hans-Frieder Vogt) - Module i2c-viapro: Prevent repeated resets - Module it87: Improve Super-I/O detection - Limit I2C address range - Support VID on the IT8712F - Module lm75: Only initialize CMP/INT bit - Module lm78: Fix bug with setting negative temperature limits - Module lm85: Properly differentiate between ADM1027 and ADT7463 - Add EMC6D102 support - Module lm90: Fix MAX6657, MAX6658 and MAX6659 detection - Add limited ADT7461 support - Module lm93: Fix IN10 (+5V) scaling - Module mic74: New - Module w83627hf: Support secondary Super-I/O address - Enable temp2 and temp3 if they are disabled - Module w83781d: Revert AS99127F temp2 and temp3 computation change - Skip final initialization step for AS99127F chips - Module w83792d: New (Chunhao Huang/Winbond) - Program ddcmon: New; user-space replacement for the ddcmon driver - Program eeprog: Fix missing first char in ascii mode (J. A. McMahan Jr.) - Program isadump: Handle Super-I/O keys - Program lm_sensors.init: Cleanups (Axel Thimm) - Program mkdev.sh: Add basic command-line interface - Program mkpatch: Add adm1031, fscher, lm63, lm93 and max1619 - Program pwmconfig: Secure the creation of temporary files (Aurelien Jarno) - Don't complain about read-only enable files (lm85) - Fix handling of alternate config file name - Program sensord: Fix erroneous error message (Aurelien Jarno) - Support sis5595 in4 (Aurelien Jarno) - Support w83627thf - Support the separate it8712 prefix (Aurelien Jarno) - Program sensors: Display sis5595 in4 (Aurelien Jarno) - No errors on missing pc87360 fans - Add gl520sm support (Maarten Deprez) - Improve vt1211 error/ignore handling (Michael Carland) - Support w83792d, w83627ehf - Program sensors-detect: Fix MAX6657, MAX6658 and MAX6659 detection - Improve IT8705F and IT8712F detection - Improve udev detection - Fix DS1621 detection - Add W83627EHF detection - Add ATI SMBus detection - Add VT1211 alias detection - Warn if chip modules not found - Add i2c-ipmi to list if bmcsensors is on it - Add PC87591 detection - Search for correct udev db file name - Add nForce3 250Gb and nForce4 detection - - -2.9.0 (20041228) - NOTE: Requires i2c-2.9.0 or newer! - File README.thinkpad: Update - File doc/chips/it87: Cleanups - File doc/chips/lm63: New - File etc/sensors.conf.eg: Set via686a voltage limits - File kernel/chips/Module.mk: Resync module list with mkpatch - File kernel/include/sensors_compat.h: Define __devexit_p if missing - (kernels 2.4.16 and older) - Modules (all bus drivers): Remove owner from i2c_adapter; restore inc_use - and dec_use removed in release 2.8.0 - Modules (all chip drivers): Remove owner from i2c_driver; pass - controlling_mod to i2c_register_entry() again - Module bmcsensors: Support function 1/x - Module i2c-amd756: Display the real bus name - Module i2c-amd756-s4882: New; SMBus multiplexing on the Tyan S4882 - Module i2c-i801: Support i2c block read (ICH5 and higher) - Add PEC support for ICH6 - Add support for ICH7 - Module i2c-ipmb: Remove from build since it doesn't work - Module i2c-nforce2: Support the nForce3 (Pro150 and 250Gb) - Module icspll: Fix compilation - Module lm63: New driver for the National Semiconductor LM63 - Module lm83: Use signed types for temperatures - Check limits on register writes - Module lm87: Round voltages properly - Retry on read errors (David Knierim) - Less agressive init (no reset) - Module lm90: Use signed types for temperatures - Check limits on register writes - Module lm93: Added module parameter for VID pin input thresholds. - Fix typo in dynamic VID alarms - Adds a couple log messages for failed transactions (David - Knierim) - Fix compilation breaking C99-ism (Axel Thimm) - Fix block read retries - Module pc87360: Support secondary Super-I/O address - Module smsc47m1: Add support for 47M15x and 47M192 (fans only) - Library: Add lm63 support - Add lpc47b397 support - Programs *.init: Rename lockfile to match file name - Programs i2cset, isaset: Written byte/word can be masked - Program decode-vaio.pl: Find eeproms on non-0 i2c bus too - Program mkpatch: Include i2c-amd756-s4882 - Program pwmconfig: Handle new (well, back to old) pwm files names for - Linux 2.6.10 and up - Program sensord: Do not scale load average (Aurelien Jarno) - Program sensors: Add lm63, lpc47b397 support - Support DDR2 memory module EEPROMs (Rudolf Marek) - Support only one location for the default configuration file - Display the default configuration file location in --help - Simplify the configuration file opening code - Program sensors-detect: Improve LM63 detection - Discard IBM Thinkpad detection code - Add PCA9556, LPC47B397, ICH7 detection - Fix W83792D detection, add W83791SD detection - - -2.8.8 (20041007) - File doc/donations: Update - File doc/lm_sensors-FAQ.texi: Add 4.6.1 - Update 4.7 - File doc/chips/gl518sm: Update "iterate" info - File doc/chips/it87: Discard outdated module parameters - File doc/chips/lm75: LM77 is not supported - File doc/chips/lm90: LM86, MAX6657 and MAX6658 are supported - File doc/chips/lm93: New - File doc/chips/w83l785ts: Improvements - File etc/sensors.conf.eg: Fix it87 lines order - Update lm87 section - File kernel/include/sensors_vid.h: Support VRM 10.0 - Library: Support 2.6 adm1025 - Preliminary support for 2.6 lm87 - Support 2.6 adm9240 - Allow an alternative sysfs file name for chip features (2.6) - Fix lm83 critical limits (2.6) - Add lm93 support - Prevent some procfs errors from being silently ignored - Makefiles: Implement user_uninstall (Rudolf Marek) - Spoof LOGNAME and HOSTNAME when making html man pages - Module adm1025: Refine detection - Update limit registers again (revert of 2.8.1) - Init high limits if they read 0 - Fix conversions - Module lm75: Refine detection - Module lm78: Fix init - Module lm83: Default to kind lm83 if forced. - Fix temperature macros. - Module lm90: Add LM86, MAX6657 and MAX6658 support - Module lm93: New - Module mtp008: Fix the setting of limits on temp2 - Module pca9540: Refine detection - Module pc87360: Change voltage/thermistor magnitude from 2 to 3 - Support VID - Fix fan_div file when fan count is less than 3 - Additional init and debug - Module smsc47m1: Fix pwm_enable being inverted - Module w83627hf: Add alternate VCORE/in0 calculation method - Remove reset of chip by driver on initialization - Module w83781d: Fix default VRM for w83791d - Module w83l785ts: Implement read error handling (backport from 2.6) - Programs i2cset, i2cdump, i2cdetect, isaset, isadump: - Wait for user input to continue (as opposed to 5 sec - delay), can be skipped with -y - Various cleanups and code refactoring - Update manual pages - Program fancontrol.init: New (Dean Takemori) - Program fancontrol.pl: Restore fans on many kinds of errors/interrupts - Program lm_sensors.init: Support 2.6 kernels and sensors in /usr/bin - (Giuseppe Della Bianca) - Program mkdev.sh: Detect devfs and refuse to run - Use mknod's mode instead of chmod - Program mkpatch: Include xeontemp and pc87360 - Program sensors: Rework adm1025 support - Display pc87365/pc87366 VID - Improve smsc47m1 support - Hide 2.6 adm1027 alarm_mask being missing - Print VRM version for all supported chips - Program sensors-detect: Support LM93, LM77, LM63 - Support PC8739x Super-I/O family (no sensors) - Fix PCA9540 support - Refine ADM1025/ADM1025A detection - Refine LM75 detection - Ignore missing /proc/modules (Andras Bali) - Script-wide Perl cleanups - Support udev - Support W83792D, LM96000 - - -2.8.7 (20040611) - File README.thinkpad: Update 24RF08 status - File doc/fan-divisors: More info on accuracy - File doc/lm_sensors-FAQ.texi: Update 4.27 - File doc/chips/adm1031: New - File doc/chips/max1619: New - File doc/chips/pc87360-fan: Renamed to pc87360 - File doc/chips/pc87360: Big update - File doc/chips/w83781d: Update AS99127F documentation - File etc/sensors.conf.eg: Add comments about BP6 voltages - Add comment on Asus A7V8X-X VCore - Misc fixes to lm80 section - Update via686a section - New lm99 section - Add section for LM85-like chips - Preliminary pc87366 section - Add comment on GL520SM application modes - Document beep_enable (Aurelien Jarno) - Preliminary max1619 section - Preliminary adm1030 and adm1031 sections - Library: Fix 2.6 VRM - Fix 2.6 hyst temp for 2.6 (lm75, lm78 and gl518sm) - Fully support the PC87360 family - Support the lm99 - Add version and date strings - Support 2.6 max1619 - Makefile: Do not run depmod on staged installs (Peter Breitenlohner) - Man page i2cdetect.8: document new command line flags - Man page i2cdump.8: More details on how i2cdump can write to a chip - Modules (all chip drivers): Rework memory allocation scheme. - Module adm1031: New (Alexandre d'Alton) - Module bmcsensors: Fix oops by creating thread for initialization - Modules dmi_scan, i2c-piix4: Move IBM detection into dmi_scan - Modules w83781d.c, smartbatt.c, lm75.c, gl520sm.c, gl518sm.c, ds1621.c, - asb100.c, lm92.c: Use swab16 - Modules eeprom, ddcmon: Unconditional prevention of 24RF08 corruption - Module gl520sm: Less agressive initialization process - Fix temp1 limits being unsettable in application - Ensure that temp2 and in4 are not used at the same time - Module i2c-i801: Support 6300ESB and ICH6 - Module i2c-piix4: Don't blacklist IBM with Serverworks chip - Module i2c-sis645: Add support for SiS655 - Module it87: Discard non-standard Super-I/O exit sequence (Bjorn Mork) - Module lm90: Support LM99 and LM89 - Module lm92: Support MAX6633, MAX6634, MAX6635 and LM76 - Get rid of useless i2c_probe call - Module max1619: New (Alexey Fisher) - Module p4b_smbus: Add support for mobile versions of the 82801 - (Axel Thimm) - Module pc87360-fan: Renamed to pc87360 - Module pc87360: Also support PC87365 and PC87366 - Add write support - Correctly set the chip name depending on the type - Add voltage and temperature support - Fix fan speed computation - Retrieve fans configuration from Super-I/O space - Export pwm_enable (read-only) - Honor pwm invert bits - Clear fan alarms after we read them - Do not read fan data when monitoring is disabled - Do not include SENSORS_INSMOD stuff - New module parameter: init - Fan clock dividers change automatically - Add thermistor dupport - Module smsc47m1: Lock on reads and writes - Various PWM fixes - Module thmc50: Fix address range - Module via686a: Fix voltage roundings - Simplify temperature conversions - Module w83781d: Drop PWM support for as99127f - Invert AS99127F beep bits in driver rather than user-space - Programs pwmconfig, fancontrol: Switch to new sysfs naming scheme - Program fancontrol: restore fans on TERM and KILL (Stephen Kitt) - Program fancontrol.pl: New - Program i2cdetect: Adapt probing method to address - Add -q and -r flags to force probing methods - Allow probing range selection - Program isadump: Major improvements - Program isaset: New - Program mkpatch: Patch dmi_scan.c in kernel instead of adding our own - module - Include i2c-nforce2 - Program sensord: New --rrd-no-average parameter - Synchronize time slots with rrd - Fix W83781D temp3 alarm (Aurelien Jarno) - Add ASB100 support (Andrew May) - Program sensors: Fully support the PC87360 family - Fix lm80 temperature alarms - Support the lm99 - Do not invert AS99127F beep bits anymore - Fix W83781D temp3 alarm (Aurelien Jarno) - Print library version string - Program sensors-detect: Rework Super I/O detection - Support SiS655/SiS96x - Support ADT7461 and ADT7467 - Better support for ADM1027, ADT7460 and ADT7463 - Explicitly support ADM1028 - Scan all logical devices of PC87365 and PC87366 - Detect LM92, LM76, MAX6633, MAX6634, MAX6635 - Detect eeproms with software write protect (not - enabled by default) - Support ALi 1563 (2.6 only) - Drop LTC1710 support - Use byte reads for probing on ranges 0x30-0x37 and - 0x50-0x5F - Improve LM89 and LM99 support - Support GeForce FX 5900 video cards - Fix devfs misdetection (Aurelien Jarno) - Detect 6300ESB, ICH6 - Fix double detection of ISA chips - Support MAX1619 - Support PC87373 Super-I/O - Fix unknown adapters appearing multiple times - Refine MAX6650/MAX6651 detection - - -2.8.6 (20040405) - File README.thinkpad: Update status - File doc/chips/pca9540: New - File doc/chips/pc87360-fan: New - File etc/sensors.conf.eg: Update pcf8591 default configuration - Library: Switch to new sysfs naming standard - Fix gcc 3.3 warnings (Philipp Thomas) - Support 2.6 ds1621 and pcf8591 - Change pcf8591 magnitudes - Support pc87360-fan - Makefile: Install shared library 755 - Man pages i2cdump.8, i2cset.8, isadump.8: New (Debian team) - Man pages i2cdetect.8, sensors-detect.8: New (Debian team) - Modules ds1621, pcf8591: Check for capabilities before using them - (Aurelien Jarno) - Modules pcf8574, pcf8591: Cleanups - Modules ddcmon, eeprom: Fix bogus init (Ralf Roesch) - Module adm1021: Better detection and initialization - Module pca9540: New driver for the Philips PCA9540 - Module pc87360-fan: New driver for the National Semiconductor PC87360, - PC87363 and PC87364 Super I/O chips - Module smsc47m1: Support the LPC47B27x - Programs i2cdetect, i2cdump, i2cset: Fix incorrect bus names if possible - Program i2cdetect: Skip special addresses by default - Program sensord: Prevent null pointer dereference (Tim Toohey) - Program sensors: Print the degree symbol in the terminal's current locale - (Aurelien Jarno) - Update pcf8591 print to support 2.6 driver - Support pc87360-fan - Program sensors-detect: Support Maxim MAX6900, ALi M5879, Philips PCA9540 - Improved SiS chips support - Add a white list of IBM systems - Drop support of undetectable adapters - Fix smart battery detection - Add smart battery charger and manager detection - Rework adm1021 and clones detection - The PC87360, PC87363 and PC87364 Super I/O chips - now have a (preliminary) driver - Rework Super I/O detection - Better support of devfs - Program sensors-detect-stat.pl: New - - -2.8.5 (20040305) - File doc/chips/SUMMARY: Update - File etc/sensors.conf.eg: Epox 8K3A tweaks. (Kronos) - Makefiles hotplug and rrd: Remove -o and -g arguments to install - Module bmcsensors: Increase max SDRs to 100 - Module fscher: Rename fanN_min to pwmN (Reinhard Nissl) - Module i2c-amd756: Don't register driver to avoid driver conflicts. - (Daniel Rune Jensen) - Module it87: Better temperature sensor types handling (Takeru Komoriya) - Fix reset=1 (Takeru Komoriya) - Module lm80: Code cleanups - Module vt1211: Fix bitmask in uch_config read and write; remove in6 and temp1 - Module vt8231: Fix bitmask in uch_config read and write; remove in6 and temp1 - Module w83627hf: Add w83637hf support - Fix exported name - Fix PWM in w83627thf - Preserve other bits when forcing temp2/3 to comparator mode - Module w83781d: Preserve other bits when forcing temp2/3 to comparator mode - Remove asb100 support - Modules asb100, fscher, lm90, max6650, w83l785ts, xeontemp: - Define driver ID if i2c-id.h doesn't have it yet. - Modules i2c-ali1535, i2c-hydra, i2c-i801, i2c-sis5595: - Backport oops fix from Linux 2.6. - Modules (all chips): Get rid of useless headers - Program decode-edid.pl: Add sysfs support - Program sensors: Add w83637hf support - Add support for Shuttle Ethernet EEPROMs - Drop 2.6 subclient detection - Program sensors-detect: Add heuristics to the LM80 detection function - Add support for W83L785R, improve W83L784R/AR - Add GeForce FX 5600 as supported by rivatv - More Super IO chips, better handling - Library: Update to match renames in fscher - Reverse temporary changes to w83l785ts mappings - Fix vt1211 and vt8231 uch_config not being writable - Add 2.6 lm80 support - Add w83637hf support - Remove in6 and temp1 from vt1211 and vt8231 - Add support for Shuttle Ethernet EEPROMs - Remove unused as99127f features - - -2.8.4 (20040207) - File doc/lm_sensors-FAQ.texi: Update 4.20. - File doc/chips/it87: Change hyst to low - File doc/chips/w83l785ts: New - File etc/sensors.conf.eg: Change it87 hyst to low - Fix w83697hf supposed to have temp3 - Limits initialization for adm1025/ne1619 - Handle fscher voltage conversions - Add Tyan Trinity S2495 KT400 setup (Eric - Schumann) - Fix fscher fan labels (Reinhard Nissl) - Library: Better 2.6 eeprom support - Change it87 hyst to low - Add 2.6 gl518sm, fscher support - Fix 2.6 negative voltages handling - Temporary fix to w83l785ts mappings - Module adm1025: Separate prefix for NE1619 - Module adm1026: Remove use of temporary ID - Define addresses as a range - Module bmcsensors: Fix reservations - Module fscher: Externalize voltage conversions - Module eeprom: Remove memtype - Module i2c-piix4: Fix resource release error - Various cleanups - Program decode-vaio.pl: Add sysfs support - Program mkpatch: Add max6650, lm83, lm90, asb100 and w83l785ts - Drop linux 2.2 support - Add w83627hf - Program sensors: Do not show algorithm by default - Cleanup temperature unit display code - Cleanup label spacing code - Fix output to UTF-8 terms (Marcel Sebek) - Simplify gl518sm print - Do not ignore errors in FSC chips prints - Fix w83l785ts print - Cleanup FSC chips prints - Program sensors-detect: Fix PATH issues - Correctly point to the fscher driver - - -2.8.3 (20040115) - File lm_sensors.spec: Update - Library: Add 2.6 eeprom, lm90 support - Fix 2.6 temp_hystX for 2.6.1-rc1 and later - Makefile: Update Alpha CMODFLAGS (Daniel Nilsson) - Makefiles: Remove -o and -g arguments to install; add DESTDIR where missing - Module i2c-amd756: Fix byte writes - Module i2c-tsunami: Cleanups (Daniel Nilsson) - Module it87: Fix sg_tlx writes; fix sensor type reporting; - add 8712 Super I/O detection; - remove initialization of temp_type and fan_ctl; - remove init and temp_type module parameters - Module lm90: Handle hysteresis differently - Module smartbatt: Fix detection, magnitudes, temp - Module w83781d: Fix negative voltages - Module w83l785ts: New - Program eeprog: Make 8 bit mode the default - Program fancontrol: Improvements, fixes, support 2.6 kernels - Program mkpatch: Add lm75.h - Program pwmconfig: Improvements, fixes, support 2.6 kernels - Program sensors: Add ASB100 support - Program sensors-detect: Add 8712 Super I/O detection; - add W83L785TS detection - - -2.8.2 (20031211) - IMPORTANT: Limit initialization removed from all chip drivers! - If you didn't run 'sensors -s' in the past you may need to now! - File sensors.conf.eg: Change lm75 scaling back to 1; - Add example for asb100 - Library: Fix bmcsensors scaling, increase number of sensors; - Add w83627thf support; Advance version to 3.0.0; - Add hermes, ADM1032, ASB100 support; - Add it87 sensor type support; - Add sysfs support for kernel 2.6; - Fix memory leaks - Makefiles: Install fancontrol, pwmconfig, decode-*.pl; - Fail if no kernel .config file exists; - Don't build module dependencies for user and user_install - Modules adm1021, adm1024, adm1025, adm9240, ds1621, gl518sm, gl520sm, - it87, lm75, lm78, lm80, lm83, lm87, lm90, mtp008, sis5595, - smsc47m1, thmc50, via686a, w83627hf, w83781d: - Remove initialization of limits by driver. - Modules it87, lm78, mtp008, sis5595, w83627hf: Fix IN_FROM_REG rounding - Modules (chip): Init cleanups - Module asb100: New - Module bmcsensors: Fix voltage scaling, voltage and fan limits - Modules ddcmon, eeprom: Add failure printks - Module fscher: New (Fujitsu-Siemens Hermes driver) - Module i2c-amd756: Fix AMD8111 support - Module i2c-amd8111: Fix byte writes - Module i2c-nforce2: Fix byte writes - Module i2c-piix4: Add support for CSB6; add fix_hstcfg option - Module i2c-sis630: Sync with 2.6.0-X driver version - Module i2c-viapro: Add support for Via 8237 - Module it87: Add pwm and "smart guardian" support; - add it87 sensor type support - Module lm75: Fix negative voltages - Module lm90: Add ADM1032 support - Module w83781d: Fix 791d and 627hf detection - Module w83627hf: Add VID support - Program dmidecode: Remove (sensors-detect doesn't need it anymore) - Program eeprog: New - Programs i2cdetect, i2cdump, i2cset: add -v (version) option; - support sysfs for i2c bus search - Program i2cdetect: Add -l option to list busses - Program i2cdump: Add 'c' mode for consective address reads - Program mkpatch: Cleanups - Program pwmconfig: Handle multiple fans controlled by a single pwm - Program sensord: Remove ddcmon support - Program sensors: Add ADM1032 support; add messages for sysfs - Program sensors-detect: Prefer Super I/O drivers; - Fix W83627HF and W83791D detection; detect CSB6; - Detect ADM1029, ADM1030, ADM1031; - Detect W83637HF, W83697UF; - Add it87 sensor type support; add sysfs support - Reduce lm80 misdetects; remove PCFxxxx "detection" - Detect VT8237 (KT600) - Use VPD instead of DMI+ACPI for Thinkpad detection - Suggest new asb100 driver instead of w83781d - - -2.8.1 (20031005) - NOTE: Requires i2c-2.8.1 or newer! - File sensors.conf.eg: Improved adm1025 section - Default temp labels for as99127f - Improved lm83 section - Better support for Asus A7V8X-X - File doc/chips/SUMMARY: Add SMSC manufacturer ID - File doc/chips/adm1025: Add decent documentation (almost new) - File doc/chips/lm83: Known motherboards list update, misc updates - Library: Change adm1025 names (hyst/over become low/high) - Swap adm1025 temp1 and temp2 to match the driver's order - Advance version to 2.0.1 - Update lm83 support - Add support for lm90, xeontemp, max6650 - Add separate messages for read and write errors - Add missing message for parse error - Makefile: Move LINUX_HEADERS from ALL_CPPFLAGS to MODCPPFLAGS - Modules (various): Fix includes for compilation on Alpha - Use the new i2c_delay function instead of the various - do_pause functions - Module i2c-ali15x3: Fix resource leak (Daniele Bellucci) - Module i2c-nforce2: Cleanups - Module i2c-i810: Use readl/writel for portable access to PCI memory - Module i2c-piix4: Force CPCI735 bug workaround (Tom Rini) - Module i2c-savage4: Use readl/writel for portable access to PCI memory - Module i2c-sis630: Fix detection - Add block data read/write support - Module i2c-sis645: Detection method change/bugfix - Module i2c-viapro: Prevent buffer overrun (Sergey Vlasov) - Module i2c-voodoo3: Use readl/writel for portable access to PCI memory - Module adm1025: Major driver update - Add support for Philips NE1619 - Simplify the driver a lot (unified voltages, unified - temperatures and much more) - Fix default voltage limits - Change default temperature limits - Swap remote and local temperatures to match the internal - registers order (make the code unification possible) - Export remote diode fault through alarms - Module ddcmon: Major update - Add half a dozen new features - Add checksum parameter (same as for the eeprom module) - Fix monitor limits - Module eeprom: Ignore Sony Vaio EEPROMs with a password set - Module lm78: Fix a fan_div/fan_min bug - Module lm83: Add t_crit and alarms support - Module lm90: New - Module max6650: New - Module saa1064: New - Module smsc47m1: Add support for 47M142 - Module w83627hf: Fix 697HF PWM; fix 697HF VBAT and V5SB alarms; - enhance w83627thf support - Module w83781d: Enhance chip detection; clean up error returns; - fix 697HF and 791D PWM; fix 697HF VBAT and V5SB alarms - Module xeontemp: New - Program decode-dimms.pl: Add Direct Rambus (DRDRAM) - Mark Rambus as unsupported - Program decode-edid.pl: New - Interfaces between our eeprom module and - parse-edid from the read-edid project - Program p4b_smbus: Fix SMP compilation - Program sensord: Add support for IT87 (Mike Black) - Change ADM1025 support to match the changes made to - the library - Program sensors: Rewrite and enhance EEPROM support - Change LM83 and ADM1025 support to match the changes - made to the library - Add DRDRAM support to print_eeprom - Exit(1) on /proc write failure (Malte Starostik) - Add LM90, MAX6650 support - Program sensors-detect: Add support for PCF8574, PCF8574A, SAA1064 - Add support for LM82, LM86, LM89 - Improved W83781D family detection - Add support for AS19927F rev.2, ASB100 Bach - Add support for Asus Mozart-2 (3 types) - Add support for NE1619 - Add support for FSC Hermes - Make sure /sbin is in the user's path - Fix EEPROM detection - Automatic module.conf and /dev/i2c* detection - Improve LM82 and LM83 detection - Handle "to-be-written" cleanly - Add detection for 47M14x Super I/O - Handle the one-address-many-chips-same-driver - case - - -2.8.0 (20030714) - NOTE: Requires i2c-2.8.0 or newer!!! - Dropped all kernel 2.2 and 2.3 compatibility; 2.4.9 or later required; - 2.4.13 or later required for mkpatch. - File i2c-dev.h: Include userspace portion removed from i2c-dev.h in - i2c package - File doc/chips/fscscy: Add watchdog documentation - File sensors.conf.eg: Fix vt1211/vt8231 thermistor calculations - File sensors.h: Now automatically generated - Library: Add support for exponents and logarithms for vt1211/vt8235 temps; - add adm1026, lm83, lm85, w83791d support; - Advance version to 2.0.0 - Makefiles: Generate warnings if new library won't be found by ld.so; - Modules now install in kernel/drivers/i2c/[busses,chips]; - Ensure that headers in /usr/local/include are used first; - Don't use /usr/include headers for modules; - Handle multiple UTS_RELEASE definitions in linux/version.h; - Automatically generate kernel/include/sensors.h; - Remove old gzipped modules; remove old misc directory if empty; - Remove pre-2.4 installation method; - -Wall now the default; - Add new targets user, user_install, and help; - Run depmod after module installation - Modules (all): Cleanups including - - Add #include - - C99 initializers - - Remove #ifdef MODULE - - Remove #ifndef THIS_MODULE - - Remove #ifndef MODULE_LICENSE - - Remove other 2.1/2.2 #ifdefs - - Remove #include "sensors.h", copy SYSCTL defs to module - - Remove excess #includes - - Remove argument in i2c_register_entry() - - Remove dummy xxx_command() definition - - Remove EXPORT_NO_SYMBOLS - - Remove init_MUTEX #define - - Remove xxx_inc_use() and xxx_dec_use() functions; modules - no longer adjust their own refcounts - - Use module_init() and module_exit() - - Update to new i2c_driver struct definition - Modules (bus PCI): Convert to PCI-module-style initialization - Modules (several): Add support for AMD Opteron VRM (VID) encoding - Module adm1021: Set alarm on failed reads and report old value; - merge changes from kernel 2.5.54 - Module adm1026: New - Module bmcsensors: Fix compile when DEBUG=1 - Modules ddcmon, eeprom: Use i2c block reads if possible; - better error handling - Module ds1307: Add to Makefile - Module gl520sm: Fix temperature over/hyst writes - Module lm75: merge changes from kernel 2.5.54 - Module lm83: New - Module lm85: New - Module i2c-ali1535: Check for invalid transaction - Module i2c-ali15x3: Check for invalid transaction - Module i2c-amd756: merge changes from kernel 2.5.54; - check for invalid transaction - Module i2c-amd8111: merge changes from kernel 2.5.54 - Module i2c-i801: Add support for 82801EB (ICH5) - Module i2c-i810: Fix for some chips - Module i2c-nforce2: New - Module i2c-piix4: Check for invalid transaction - Module i2c-sis5595: Check for invalid transaction; add more blacklist IDs - Module i2c-sis645: Add support for SiS648, SiS651, SiS745, and SiS746 - north bridges; SiS962 and SiS963 south bridges - Module i2c-viapro: Check for invalid transaction - Modules mtp008, smsc47m1, vt1211, vt8231, w83781d: Standardize and improve - pwm and pwm enable support; update docs - Module smbus-arp: Check adapter for HW or SW PEC support; - add reset option - Module w83781d: Add support for w83791d - Module w83627hf: New - Program decode-dimms.pl: Recognize DDR and Rambus - Program eeprom: Fix writes for small eeproms - Program eeprom, eepromer: Use local i2c-dev.h for build - Program fancontrol: New - Program lm_sensors.init: Call sensors -s in start() - Program mkpatch: Fix vt8231 compile; keep tsunami from menu on non-alpha; - Add adm1026,lm85 support; - Remove sensors.c file; add sensors_compat.h; - Remove patches to i2c-core.c and drivers/char/mem.c; - Now works only for kernels 2.4.13 or later - Program p4b_smbus: Fix 'make install'; - Install in same place as other modules; - Clear correct bits in config word - Program pwmconfig: New - Program sensors: add adm1026, lm85, w83791d support - Program sensors-detect: Add super i/o detection (smsc47m1, vt1211, - w83627hf, w83627thf, w83697hf); - Add support for SiS651, SiS961, SiS745, SiS746; - Support dmidecode 2.0 and later; - Fix "C" format error; - Add support for adm1026, 82801EB (ICH5), W83791D; - Add support for w83l785ts, nForce2; - Fix UTF-8 incompatibility; - Better support for lm75; - Add support for lm83 - -2.7.0 (20021208) - NOTE: Requires i2c-2.7.0 or newer. - File doc/busses/i2c-ali1535: Add license, miscellaneous changes - File doc/busses/i2c-ali15x3: Add license, miscellaneous changes - File doc/busses/i2c-sis645: Add license - File doc/chips/lm92: Add license, features - File doc/chips/maxilife: Add license, parameters, features - File doc/chips/smartbatt: Complete rewrite - File doc/chips/vt8231: Add license, parameters - File sensors.conf.eg: Add section for lm75; complete the lm78 section - Library: Add support for MC1066; add multiple VRM version support for lm87; - enhance adm1023 support; initial support for Sony Vaio eeprom; - add support for bmcsensors; add hacks for additional dummy drivers - Makefile: Take kernel source location from /lib/modules/x.x.x/build; - add flags for x86_64 compiles - Module adm1021: Add support for MC1066 - Module bmcsensors: New - Module dmi_scan: Rename symbol duplicated in kernel; apply fixes from - kernel 2.5.43; fix 2.2 kernel compiles - Module gl518sm: Iterate allowed only for rev 0x00 - Module i2c-amd756: Configure base address for nForce support; - check for uninitialized base address; - add support for amd8111 (SMBus 1.0) - Module i2c-amd8111: New (SMBus 2.0) - Module i2c-ipmb: New - Module i2c-ipmi: New - Module i2c-keywest: Sync with kernel 2.4.20 - Module i2c-sis630: Add support for SiS730 - Module i2c-sis645: Improve support for SiS645/961; - add support for SiS645DX/961 and SiS735; - fix 2.2 kernel compiles - Module i2c-viapro: Add support for VT8233A (new ID 0x3177) and VT8235 - Module lm87: Add multiple VRM version support - Module vt1211: Fix inx limits and alarms; fix in0 - Module vt8231: Fix inx limits and alarms; fix in0 - Module w83781d: Fix in0/in1 initialization - Module smartbatt: New - Modules (several): Remove #ifndefs, require i2c-2.7.0; HZ fixes - Program decode-dimms.pl: Code cleanup; valid HTML; better HTML output; - stop decoding on checksum error - Program dmidecode: Fix read bug; upgrade to version 1.8 - Program doc-insmod: Complete rewrite; fix author output - Program doc-features: Complete rewrite; handle missing sysctl entries; - handle unknown prefix with suggestion - Program lm_sensors.init: Remove spaces bug; add green/red output - Program mkpatch: Fix dmi_scan module compile; add sis630, sis645, amd8111 - Program rrd: Add sanity limits to newly-created RRD. - Program sensord: (v0.6.2) Add sanity limits to newly-created RRD. - Program sensors: Add support for MC1066, Rambus Rimms; - fix w83781d temp3 alarm; fix gl518sm rev 0x00 recognition; - initial support for Sony Vaio eeprom - Program sensors-detect: Add support for MC1066, smart battery, 8235, - IPMI, AMD8111; add help if no sensors found; - add ACPI method for IBM system detection; - work with old Perl versions again; - initial support for Sony Vaio eeprom - -2.6.5 (20020915) - NOTE: Requires i2c-2.6.1 or newer, or kernel 2.4.13 or newer. - File sensors.conf.eg: Fix temp[23] for as99127f; add vt8231 - Library: Fix fan3_div writes for w8378* and it87; add vt8231 - Module dmi_scan: new - Module ds1621: Fix enable/disable - Module eeprom: Do not corrupt 24RF08's when checksum=1 - Module i2c-i801: Check for uninitialized base address; - enable if not enabled - Module i2c-piix4: Refuse to load on IBM systems to prevent 24RF08 corruption - Module i2c-sis630: new - Module i2c-sis645: new - Module lm92: Fix in-kernel initialization - Module via686a: Remove VT8231 support - Module vt8231: new - Module w83781: recognize Asus "ASB100 Bach" as AS99127F - Program dmidecode: new - Programs i2cdetect, i2cdump, i2cset, isadump: Now installed by 'make install' - Program mkpatch: Add Config.in entries for, lm92, - pcf8574, pcf8591, smsc47m1, vt1211; - add dmi_scan - Program p4b_smbus: Fix compile for SMP and MODVERSIONS; fix PCI ID problem - Program lm_sensors.init: fix stop() - Program sensord: (v0.6.1) Add /usr/local/etc to config file path; - add support for logging loadavg in RRD; - fix down-converting raw labels for RRD; - update chip support, still behind sensors - Program sensors: Add /usr/local/etc to config file path; - fix -c and -u flags; add vt8231 - Program sensors-detect: recognize Asus "ASB100 Bach" as AS99127F; - refuse to run on IBM systems; - fix sysconfig module numbering; - change quick write to not corrupt 24RF08's - -2.6.4 (20020719) - NOTE: Requires i2c-2.6.1 or newer, or kernel 2.4.13 or newer. - File doc/vid: New - File include/sensors_vid.h: New - File sensors.conf.eg: Add vt1211, smsc47m1 - Library: Add multiple VRM version support for adm1025, w83781d; - fix 'flex scanner jammed' on some systems; - add vt1211, smsc47m1, lm92; - fix access mode checking - Makefiles: For 2.4+ kernels, modules now install in - kernel/drivers/[i2c,sensors] , not misc/ , and - 'make install' removes old versions in misc/ . - Use $CFLAGS and $CPPFLAGS if defined. - Module adm1025: Add multiple VID version support - Module ds1307: new - Module i2c-amd756: Add nVidia nForce support; fix block read length; - reliability improvements - Module i2c-hydra: Flush posted writes - Module i2c-i801: Add support for 82801DB (ICH4) - Module i2c-i810: Flush posted writes - Module i2c-savage4: new - Module i2c-viapro: Add support for VT8231 (0x8235), VT8233A (0x3147) - Module i2c-voodoo3: Flush posted writes - Module ds1307: New - Module lm92: New - Module smbus-arp: new - Module smsc47m1: new - Module via686a: Add support for VT8231 sensors - Module vt1211: new - Module w83781d: Add multiple VID version support; fix temp alarms - Program eeprom: new - Program i2cdump: Add smbus block command specification, add PEC support - Program lm_sensors.init: new - Program mkpatch: Add sensors_vid.h, i2c-savage4, lm92, - pcf8574, pcf8591, smsc47m1, vt1211 - Program p4b_smbus: Add support for ICH4 - Program rrd: Fix swapped CPU and MB temps in summ_week.cgi - Program sensord.init: Renamed, was prog/init/sensors - Program sensord: Major update, now requires rrd source; - not compiled by default - Program sensors: Recognize DDR SDRAM; add adm1025 VID; add -A - (don't display algo. and adap.) option; - add vt1211, smsc47m1, lm92 - Program sensors-detect: Add VT8231, VT8233A, several S3 devices; - add 82801DB, LM85; fix perl warnings; - generate /etc/sysconfig/lm_sensors for - lm_sensors.init script - -2.6.3 (20020322) - NOTE: Requires i2c-2.6.1 or newer, or kernel 2.4.13 or newer. - Chip modules (most): Allow THIS_MODULE definition for kernels 2.2.18+ - File doc/chips/it87: add more temp_type help - File sensors.conf.eg: Un-ignore it87 in8, temp3, fan3; - add adm1021 section; add lm87 AIN[1,2] template; - swap negative voltage limits for 782d,783s,627hf, - 697hf,it87; add more it87 help; swap neg. voltage - limits for lm78(-j), lm79, w83781d, as99127f - Library: Add PCF8591, W83697HF, ADM1023 support; - fix w83* fan_min computes; - swap neg. voltage limits for lm78(-j), lm79, w83781d, as99127f - Module adm1024: Add MODULE_LICENSE("GPL") - Module bt869: Add s-video out and DVD resolution support - Module eeprom: Add support for locations 128-255; rename /proc entries in hex - Module fscscy: implement min/max for voltages and fans - Module i2c-amd756: Add support for AMD768 - Module i2c-i810: Add support for 810E - Module i2c-keywest: Big update, sync with kernel 2.4.18 - Module i2c-piix4: Check for uninitialized base address - Module i2c-sis5595: Blacklist 645, 735 - Module i2c-viapro: Check for uninitialized base address - Module gl518sm: Standardize /proc entries in0-3 - Module lm87: Fix in0, in1, in5 initial limits; ain[1,2] -> in[6,7]; - fan -> fan1; fix temp2 limit writes - Module pcf8574: Add support for PCF8574A; /proc interface changed - Module pcf8591: new - Module sis5595: Blacklist 645, 735 - Module w83781d: Add W83697HF support; allow force_subclients parameter - for Tyan 2460 - Programs decode-dimms.pl, decode-xeon.pl: Update for new /proc names - Program decode-vaio.pl: new - Program i2cdump: Add i2c block read capability (requires i2c-2.6.3); - add text output - Program init/sensors: New SysV init script - Program mkpatch.pl: Add support for fscscy, add more help entries - Program p4b_smbus: new - Program rrd: Install summ_week.cgi - Program sensors: Add PCF8591, W83697HF, ADM1023 support, - clean up chassis intrusion prints - Program sensors-detect: Add several Nvidia chips, add PCF8591, add 810E; - fix Via686a and it87 detection; - add AMD768, IPMI-BMC-KCS and -SMIC; add Via 8231; - fix uninitialized values; it87 beats lm78 - -2.6.2 (20011118) - NOTE: Requires i2c-2.6.1 or newer, or kernel 2.4.13 or newer. - Chip Modules (all): malloc.h -> slab.h - Modules (all): Add MODULE_LICENSE("GPL") - File doc/FAQ: More updates and additions - File sensors.conf.eg: Fix it87 in5,in6 (-12,-5) calculations - Library: Add fscpos and fscscy support, fix gl520 in4 ID, - update it87 alarm ID's. - Module fscpos: new (Fujitsu-Siemens Poseidon driver) - Module fscscy: new (Fujitsu-Siemens Scylla driver) - Module i2c-amd756: Improve busy handling/printk's - Module i2c-i801: Add 82801CA/CAM support - Module i2c-keywest: Sync with PPC people, it works now - Module i2c-piix4: Add Intel 82443MX and SMSC Victory66 support - Module i2c-viapro: Add Via VT8233 support - Module it87: Merge alarm_* /proc entries to alarms - Module sis5595: Fix support for rev B0 - Module via686a: Make limit initializations reliable - Module w83781d: Allow init=0 parameter to bypass initialization - Program isadump: Add flat address space (PCI) support - Program mkpatch.pl: Add support for i2c-ali1535, adm1024, ds1621, - fscpos, it87, maxilife, mtp008 - Program sensors: Fix w83781d temp precision - Program sensors-detect: Add ALI1535, Via VT8233, it87 (i2c), - Fujitsu Poseidon and Scylla, - Intel 82443MX and 82801CA/CAM detection, - add ITE 8172G detection (driver in kernel 2.4.10) - -2.6.1 (20010830) - File BUGS: Updated - File doc/FAQ: More updates and additions - File doc/chips/adm1021: Claim support for Philips NE1617, NE1617A - File sensors.conf.eg: Fix/enhance it87 section - Library: ds1621 and it87 updates - Module i2c-ali15x3: Allow force_addr=0xaddr; enable if not enabled. - Module i2c-amd756: Add AMD 766 support - Module i2c-i801: Fix 82801BA detection broken by kernel 2.4.6 - Module i2c-piix4: Add Serverworks CSB5 support - Module i2c-sis5595: Recognize unsupported chips and refuse to load - Module adm1025: Fixed temp2 min/max writes - Module ds1621: Add 12-bit precision mode - Module it87: Enable all alarms, add in8 support, add sensor type selection - Module sensors: Don't initialize i2c-proc (moved to i2c-core); - remove support for module - Module sis5595: Recognize unsupported chips and refuse to load - Module w83781d: Fix fan speed for as99127f (broken by 2.6.0) - Program eepromer: new - Program mkpatch.pl: Fix dependencies on i2c-proc; disallow compilation - of sensors.c as a module in kernel - Program sensors: it87 updates; adjust temp. precision for some chips - Program sensors-detect: Fix ADM1024 and ADM1025 detection; - recognize unsupported SiS chips; - recognize AMD 766 and Serverworks CSB5. - -2.6.0 (20010612) - NOTE: i2c-2.6.0 MUST BE be compiled AND installed first!!! - If your make fails because it can't find , you - forgot this step!!! - File doc/FAQ: Many, many updates and additions - File doc/busses/i2c-sis5595: new - File doc/busses/i2c-tsunami: new - File doc/chips/it87: new - File doc/chips/via686a: Claim support for 686b. - File README.thinkpad: new - File sensors.conf.eg: Adjust as99127f in5 (-12V) and temp2 calculations; - Add lm87, adm9240, ds1780, lm81 templates; - Enhance help comments in file; - Add Tyan S2510 dual-MTP008 example; - Make separate sis5595 section. - Include file i2c-isa.h: No longer required, moved to i2c.h in i2c package - Include file sensors.h: Most contents moved to i2c-proc.h in i2c package - Library: Fix/standardize some lm87 and mtp008 entries; add sis5595 in4; - Add support for maxilife-nba and amd1024; - Change from sensors_* to i2c_* globals for new i2c-proc.[ch] - Chip Modules (all ISA): Remove #include "i2c-isa.h" - Chip Modules (all): Change from sensors_* to i2c_* globals - for new i2c-proc.[ch] - Makefiles: enhance to support Alpha architecture - Module adm1021: Fix lm84 and gl523sm support - Module adm1024: new - Module i2c-i801: Chip detection cleanup - Module i2c-i810: Fixed i2c_i810_init() not found in patched kernel - Module i2c-sis5595: Allow force_addr=0xaddr; enable if not enabled. - Module i2c-tsunami: New - Module i2c-via: Ensure i2c bus is tristated correctly. - Module it87: new driver for IT8705, IT8712, Sis950 chips - Module lm78: Recognize chipid=0x20 - Module lm87: Fix in0, in1 (2.5V and Vccp1) calculations - Module mtp008: Fix temp initializations; - Save BIOS pin configuration of temps and fans; - Fix sensor type reads/writes and fan min writes; - Fix spurious invalid sensor type messages - Module sensors: Disabled, moved to i2c package as i2c-proc.c; only - used for patched kernel now. - Add xxx_init() calls for drivers added to mkpatch in 2.5.5. - Module sis5595: Fix temp, add in4 for chip revision 0xc0; - Allow force_addr=0xaddr - Module via686a: Allow force_addr=0xaddr (for A7V/K7V boards) - Module w83781d: Don't reinitialize as99127f chip; this may cause fan/temp - reading changes; Add messages for subclient - registration failure - Programs i2cdetect, i2cdump: add devfs /dev/i2c/x support - Program i2cset: new - Program isadump: fix for Alpha arch. compiles - Program mkpatch.pl: Fix adm9240 typos; Add more chips to Configure.help; - Remove ltc1710; Fix i2c_sis5595 typo; - Support kernel 2.4.5 makefile change; - Add i2c-tsunami; fixed i2c-voodoo3 configuration - Program sens_update_rrd: new - Program sensord: Add -d (debug) and -p (pid-file) options - Program sensors: Change reported version from 1.3 to the lm_sensors version; - Fix swapped limit and hysteresis on 9240, 5595, 686a; - Change mtp008 temps from max/min to limit/hyst; - Add maxilife-nba, adm1024, it87 support. - Program sensors-detect: Recognize lm78 with chipid=0x20; - Recognize SMSC Victory66 South Bridge; - Add devfs /dev/i2c/x support; - Add adm1024, it87xx support; Add thinkpad warning. - Program tellerstats: new - -2.5.5 (20010115) - NOTE: i2c-2.5.5 MUST BE be compiled and installed first, UNLESS - you have kernel 2.4.0-prerelease or greater. - Chip modules (all): Update mutex definition (works now for new 2.2 kernels) - File doc/developers/proc: new - File sensors.conf.eg: Add mtp008 entries, adm1025 entries - Library: Add ds1621, mtp008 support - Module adm1021: Add support for adm1021a / adm1023 - Modules adm1021, thmc50: Rename /proc entries to temp[1-2] - Module adm1025: Add support for remote temp; rename /proc entries to - in[0-5] and temp[1-2]; fix negative temp readings - Module adm9240: Rename /proc entries to in[0-5] - Module ddcmon: allow force and force_ddcmon parameters - Module ds1621: new - Module i2c-ali1535: Enhance error checking and recovery; add mutex - Module i2c-i810: Add "dummy write" before reads per Intel prog. ref. - Module i2c-piix4: add support for ServerWorks southbridge OSB4 - Module lm87: cleanup, update voltage calculations - Module mtp008: new - Module pcf8574: change update time to 5 seconds - Modules sis5595, i2c-sis5595: Check for uninitialized base addresses - Module w83781d: fix beep setting via /proc - Programs editticket, readticket: new - Program mkpatch.pl: only works with 2.2 and 2.4 kernels; 2.3 support removed - Program mkpatch.pl: more fixes; now adds many more modules - Program sensors: Add ds1621, mtp008 support; add -f (Fahrenheit) option; - add adm1025 temp2; report temp limits correctly as - min/max or limit/hysteresis; print message if no - sensors are found. Removed false errors from lm87 reads. - Program sensors-detect: Add ds1621, mtp008 detection; - add ServerWorks detection - -2.5.4 (20001012) - Module i2c-viapro: Add support for Via 596B (0x3051) - Program m7101: moved to CVS tree, updated for 2.4.0 kernels - Program mkpatch.pl: fixed infinite loop - Program sensors-detect: Detect Via 596B (0x3051) - -2.5.3 (20001008) - NOTE: i2c 2.5.3 MUST BE be compiled and installed first. - File useful_addresses.html: update - Library: Add lm87 support - Module pcf8574: new - Module i2c-ali1535: new - Module i2c-ali15x3: removed force #ifdef. - Module i2c-i801: support Intel 82801BA (815E chipset) - Module i2c-i801: add i2c block write support, fix smbus block bugs - (requires i2c 2.5.3 package) - Module i2c-i810: support Intel 82815 - Module lm87: new - Module sensors: Fix for kernel 2.4.0-test8 - (remove copy_to_user_ret and put_user_ret) - Module w83781d: limit fan divisors to 8 max. for as99127f - Program decode-dimms: Add html output option, update for SPD spec 1.2B. - Program i2cdump: Add smbus block read support - Programs i2cdetect, i2cdump: Improve error reporting - Program sensors: new switch -u (--unknown) - Program sensors-detect: detect Intel 82801BA (815E chipset) - Program sensors-detect: detect Intel 82815 - Program sensors-detect: detect ITE IT8705F / IT8712F (no driver yet) - Program sensors-detect: detect National LM87 - Program sensors-detect: detect nVidia devices supported by i2c-riva.o - Program sensors-detect: Improve error reporting - -2.5.2 (20000709) - File sensors.conf.eg: Fix lm80 in8 calculation - Module w83781d: W83783S no longer crashes on unloading - Program sensors-detect: more robustness in case of unknown i2c adapters - Program sensors-detect, libsensors: fix eeprom size reporting - Program sensord: more flexibility, support for alarm scanning etc. - Program sensors: support for ignore setting on sensor alarms. - Programs: understand /dev/i2c* files (instead of /dev/i2c-*) too. - -2.5.1 (20000618) - Library: Add adm1025 support - Module adm1025: new - Module ddcmon: Fixed bus scan which could hang SMBus - Module i2c-keywest: new - Module maxilife: Add support for Maxilife '99 (NBA) - Module via686a: Enable sensors if not enabled by BIOS - Module w83781d: Improve w83783s support, w83627hf always has 2 pwm - Module w83781d: Fix sensor2&3 selection, enable VBAT (in8) monitoring - Module w83781d: Remove as99127f entries for in7-8, pwm3-4, sensor1-3 - Module w83781d: Fis as99127f fan speed (was 66% too high) - Module w83781d: Improve beep input checking - Program i2cdump: Add Winbond-style bank selection - Program isadump: Add Winbond-style bank selection - Program sensors: Add adm1025 support. - Program sensors: Remove some as99127f entries, fix as99127 "(beep)" - Program sensors-detect: Fix i801 detection, add adm1025 driver entry - File sensors.conf.eg: Add Maxilife '99 entries - File sensors.conf.eg: Remove some as99127f entries. - Note: For as99127f, reinstall sensors.conf.eg manually (make install - won't reinstall it) or else 'sensors -s' will fail. - -2.5.0 (20000312) - Dropped all kernel 2.0 and 2.1 compatibility - Module i2c-i810: new - Module ddcmon: new - Module via686a: new - Module i2c-amd756: fixed region request - Module i2c-voodoo3: Converted to use i2c-algo-bit layer - Module w83781d: Don't change pin settings at initialization; - also fix chip detection. - Library: Support for ddcmon and via686a - Program sensors-detect: Support for ddcmon and via686a - Program sensors: Support for eeprom, ddcmon and via686a - -2.4.5 (20000116) - Introduced DESTDIR installation prefix - Module lm80: fixes, temperature now read and set correctly - Module i2c-voodoo3: driver enhancements - Module w83781d: fixes, AS99127 works much better now - Library: New ignore keyword in config file - Programs: Support for new ignore keyword - Program sensors-detect: Support for MGA detections - -2.4.4 (19991201) - Addition of the alpha release of AMD 756 SMBus host support. - Many fixes and updates to the gl518sm driver - Updates and fixes for device detection - -2.4.0 (19990920) - Too much to list. - i2c and smbus parts are split off to a separate i2c package. - New drivers and other stuff. - -2.3.4 (19990616) - Module matorb: driver for Matrix-Orbital Displays (small LCD and VFDs) - All: Now compiles against kernel 2.0.x (again ;) - Module gl518sm: some updates and refinements - -2.3.3 (19990603) - All: Now compiles against kernel 2.3.x (x >= 1) - Module i2c-voodoo3: Timing issue fixes - Module bt869: Seems to be functional and relatively well tested - Many modules were modified to be more compatible with the new - Mutex structure in the new experimental kernels. - -2.3.2 (19990507) - Module i2c-hydra: Now compiles on 2.0.x kernels - Module i2c-lm75: Slightly better detection - * New, but not compiled by default: - Module i2c-voodoo3: beginning of Voodoo3 I2C bus driver - Module bt869: Beginning of BT869 (PAL/NTSC video converter) driver - -2.3.1 (19990501) - All: Now compiles on PPC - Module i2c-hydra: NEW - Module i2c-proc: Buffer overflow removed: `less /proc/bus-i2c-0' now works - Module w83781d: Removed deadlock (mutex was not initialized) - Documentation: A few glitches removed - Makefile: default module installation directory is now - /lib/modules/current/extra/misc - Program sensors-detect: PPC Hydra now detected - Program sensors: Now prints complete GL518SM information - Program sensors: SIS5595, ADM1021, MAX1617(A), ADM9240, DS1780 added - -2.3.0 (19990422) - All: Many, many changes and improvements - All: Many small bugs and problems removed - Modules: New insmod parameters - Modules: Much improved chip detection - Module maxilife: NEW - Module adm1021: MAX1617A now also supported - Module adm9240: DS1780 now also supported - Module w83781d: W83782D and W83783S now also supported - Program sensors-detect: NEW - Library: All chips now supported - Documentation: Very much improved - -2.2.2 (199903??) - Just some minor updates and bug fixes. - -2.2.1 (19990218) - All: Removed compile warnings - Module i2c-dev: Small bug removed if DEBUG=1 was used - Module sis5595: Now compiles for 2.0 kernels - Module adm1021: Detection corrected - -2.2.0 (19990216) - All: Set copyrights to include 1999 - All: Small bugfixes - I2C: Upgraded to newest archive of Simon Vogl - Module i2c-dev: NEW - Module i2c-ali15x3: NEW - Module i2c-via: This is old module bit-mb, now moved to the main lm_sensors - directories, and somewhat improved - Module sis5595: NEW - Modules: Renamed all bus modules to i2c-*, new directory lay-out - Library: Support for new chip drivers, several small bugs fixed - Library manual pages: NEW - Program i2cdetect: Moved to detect directory - Program detect.pl: NEW - Program doc-features: NEW - Program sensors: Added man-page - Document BUGS: Added cdrom bug and kernel i2c conflict - -2.1.2 (19990116) - Modules lm80.o, w83781d.o: fan-related Segmentation fault corrected - Module gl518sm.o: yet more bug fixes. It should at long last be usable now - Documentation in doc/kernel: NEW - -2.1.1 (19990107) - Module i2c-proc.o: Hack to make /proc/bus/ possible for kernels 2.0.35 - and older - Module gl518sm.o: Miscelaneous bugs and problems solved - Program isadump: NEW - -2.1.0 (19981230) - Library: Completely NEW - Program sensors: NEW - Program grab_busses: NEW - Program decode-dimms: More information - Module bit-mb.o: Removed spurious semicolon; now runs on more VIA chipsets - Module w83781d.o: NEW - Module lm80.o: NEW - Module gl518sm.o: new procfile beep, several small updates - Modules: Now use pin readings, no more scaling within the kernel (use the - library instead) - -2.0.2 (19981214) - Module eeprom.o: NEW - Program decode-dimms: NEW - Modules: fill_inode fix, will stop segfaults on unloading in kernels after - 2.1.58 - Modules: Somewhat less verbose on transfers - Module lm78.o now recognizes and handles lm78-j and lm79 - -2.0.1 (1998121?) - Module gl518sm.o updates, to make it actually work - Module lm75.o high/low-byte swapping write bug fixed - -2.0.0 (19981209) + libsensors: Add support for instantaneous power sensors + Add support for current sensors + Fix error propagation during expression evaluation + Detect excessive recursion depth during expression eval (#2365) + lm_sensors.init: Support new format of /etc/sysconfig/lm_sensors (#2246) + Drop support for kernels 2.4 and earlier + lm_sensors.init.suse: Delete (actual SuSE script is much different) + Makefile: Install sensors.conf.default instead of sensors.conf.eg (#2333) + maxilife scripts: Delete (driver never ported to Linux 2.6) + sensord: Accept negative temperatures in RRD database + Don't bail out on transient errors (#2330) + sensors: Add support for instantaneous power sensors + Add support for current sensors + sensors.conf.8: Lots of additions and reworks + sensors.conf.default: New, minimum version of sensors.conf.eg (#2333) + Add sections for the SMSC SCH311x and SCH5027 + sensors.conf.eg: The LM99 offset is now handled in the lm90 driver + Move help section to sensors.conf.5 + Add a section for the Asus/Fintek F8000 + sensors-detect: Fix detection of ADT7463 and LM96000 + Add VIA VX800/VX820 SMBus support + Fix detection of Intel 5000 series FB-DIMM AMB + Fix detection of ADT7462 + Fix detection of SMSC LPC47M292 + Add SMSC LPC47M233 support + Drop support for Linux 2.4 (#2325) + Handle special case chips more efficiently + Fix SMBus detection of W83627EHF and W83627DHG + Get I2C adapter driver names from sysfs (#2328) + Drop old SiS I2C adapter entries + Drop separate LM78-J entry + Merge all Mozart-2 entries + Merge both GL518SM entries into one + Complete GL520SM detection + Improve GL525SM detection a bit + Let kernel 2.6.28 and later handle chips aliases + Unload kernel drivers when we are done with them (#2329) + Fix handling of bus driver names with an underscore + Simplify loading of bus drivers + Fix bus number prediction logic (#2327) + Suggest the sbs driver for smart batteries + Drop alias detection for Super-I/O chips + Move alias detection after all chip detections + Probe chip types from safest to more risky (#2322) + Add an option to skip ISA probes except IPMI + Skip ISA detection by default if a Super I/O was found (#2322) + Do not scan I2C adapters on multimedia cards by default + Skip SMBus probing by default if a Super I/O was found (#2322) + Display I2C address statictics with --stat + Document the new detection order and rules + Gather DMI data and print it at start-up + Always probe the SMBus on Asus, Tyan and Supermicro boards + Move IPMI interface detection to its own section + Skip IPMI probing on laptops + Add Winbond/Nuvoton W83667HG support + Add Intel Core I7 support + Generate new format for /etc/sysconfig/lm_sensors (#2246) + Print warnings about missing modules on screen + Fix detection of older DS1621 + Add nNidia nForce MCP67, MCP73, MCP79 SMBus support + sensors-detect-stat.pl: Delete (functionality merged into sensors-detect) + sysconfig-lm_sensors-convert: Sample config file conversion script (#2246) + +3.0.3 (2008-09-28) + libsensors: Avoid namespace pollution + fancontrol: Don't use named pipes when we don't need them (#2319) + pwmconfig: Tell the user about gnuplot if it isn't installed + Fix MINSTOP and MINSTART test functions (#2340) + Test MINSTOP before MINSTART + Use better step values for MINSTOP test + Print the revision and date at start-up + Detect and report obviously incorrect fan speeds + Determine MINSTOP automatically + Skip MINSTOP and MINSTART tests if fan can't stop + Change default for MINTEMP from 0 to 20 degrees C + Add support for attributes in the hwmon class device (#2260) + Update manual page + sensors.conf.eg: Drop "label temp#_crit" statements + sensors-detect: Add Intel SCH (bus) support + Add SMSC EMC6D103 support + Improve MAX6657, MAX6658, MAX6659 detection + Cache the byte data reads (#2326) + Add Maxim MAX6654/MAX6690 support + Add National Semiconductor LM95231 support + Add Analog Devices ADT7481 support + Refactor alias detection functions + Fix Andigilog aSC7621 support + Add Texas Instruments THMC51 support + Fix Analog Devices ADT7461 support + Add VIA C7 support + Fix Winbond W83L786NR/NG/R/G support (#2336) + Add Maxim MAX6646/MAX6647/MAX6649 support + Add VIA VT1212 support + Add SMSC EMC2700LPC support + Add ITE IT8720F support + Add Texas Instruments TMP411 support + Prevent misdetection of W83627DHG on I2C as LM78 + W83627DHG has no subclients + Add Maxim MAX1618 support + +3.0.2 (2008-05-18) + documentation: Delete the FAQ, now maintained on the wiki + libsensors: Use __func__ instead of __FUNCTION__ + Parse the configuration file in C locale + Late compute statements override early ones + Support virtual hwmon devices (#2309) + Support power and energy sensors + Support DOS-style configuration files again (#2284) + pwmconfig: Don't create the configuration file before it's needed + Don't preserve configuration file customizations + Fix permissions of the configuration file + Don't start if fancontrol is running (#2299) + fancontrol: Don't start if already running (#2299) + Delete fancontrol.pid at exit time (#2299) + sensord: Fix support of multiple chip names on the command line (#2321) + sensors: Print energy and power sensors with automatically scaled units + sensors-detect: Add SMSC SCH5027D detection + Do not access I/O ports on PPC + Move south bridge sensor detection to the right section + Run chip_special_cases() earlier + New device ID for the SMSC SCH5317 + Add SMSC SCH5127 detection + Add National Semiconductor LM64 detection + Add Asus F8000 detection + Add Intel ICH10 (bus) detection + Don't probe I2C addresses 0x40-0x47 + Fix the parsing of I2C addresses not to scan + Detect and skip 1-register-only I2C devices + Avoid SMBus word transactions where possible + Add Dallas DS1631 detection + +3.0.1 (2008-01-28) + documentation: Update the application writing guidelines + libsensors: No longer depend on libsysfs (#2262) + Don't guess the bus type from the device ID format (#2240) + Add support for attributes in the hwmon class device (#2260) + Makefile: No warnings about ld configuration for staged installations + Document the variable overriding mechanism (#2296) + pwmconfig: Really hide errors on sysfs writes + Deal gracefully with read-only pwm_enable files + Warn about outputs found in automatic mode + Repeat available configuration options before prompt (#2289) + Fix duplicate warning message when config file is broken + fancontrol: Detect improperly formatted FCTEMPS value (#2293) + sensord: Fix rrd support (#2276) + Use the same colors for daily and weekly charts + Drop workaround needed by old versions of rrdtool + sensors: Fix error path on library initialization error + sensors.conf.eg: Fix voltage value references (g520sm, lm80, pc87366) + sensors-detect: Drop PCA9540 detection + Improve sysconfig and modprobe.d integration + Add SMSC SCH5514D-NS detection (no sensors) + Lower the confidence of MAX6650/MAX6651 + Add Fintek F71858DG detection + Add Fintek F81216D detection (no sensors) + unhide_ICH_SMBus: Add support for the 82801AA (ICH) + +3.0.0 (2007-11-24) + Makefile: Fix MODULE_DIR usage in etc + Fix build on PPC + pwmconfig: Better diagnostics in pwmdisable + Give the fans some time to spin up + sensors-detect: Add Texas Instruments TMP401 detection + Mention the f75375s driver + Add SMSC LPC47B367-NC detection (no sensors) + Reduce w83781d/lm78 I2C address probing range + Add Intel Celeron 4xx and Penryn (CPU on 45nm) detection + +3.0.0-rc3 (2007-10-28) + libsensors: Add a default configuration file + Fix memory leaks on initialization error + Make the configuration file optional + Change the default configuration file to /etc/sensors3.conf + sensord: Reload config on SIGHUP rather than automatically + No default configuration file name + sensors: Fix file handle leak on library initialization error + Handle the case where voltage measurements aren't available + No default configuration file name + Install as sensors again + sensors.conf.eg: Install as sensors3.conf + sensors-detect: Fix SMSC LPC47B357/M967 detection + Select the right driver for FSC chips + sensors-detect-stat.pl: Handle alternative chip lists + +3.0.0-rc2 (2007-10-10) + useful_addresses.html: Moved to the wiki + Makefile: Add sensors-conf-convert to make install + libsensors: Notify the caller when writing a value fails + Differentiate between different read error types + Report I/O errors as such + sensord: Log the error code on failure + Drop the configuration file search path mechanism (#2259) + Manual page update + sensors: Fix spurious critical temperature alarm + Print error messages to stderr + Make error messages more helpful and consistent + Better handling of the fault flags + sensors-conf-convert: Add a short help text + sensors-detect: Fix SMSC SCH311x detection + Add AMD K10 CPU sensor detection + +3.0.0-rc1 (2007-09-25) Initial release diff --git a/CONTRIBUTORS b/CONTRIBUTORS index 6375466d..45e2d231 100644 --- a/CONTRIBUTORS +++ b/CONTRIBUTORS @@ -1,103 +1,15 @@ -This package could not have been created without the help of many, many people. -The most notable contributors are listed below. You are probably best off -to use the mailing list (see -http://www.lm-sensors.org/wiki/AuthorsAndContributors) if you have questions, -suggestions or problems. +Here is a list of the main contributors to lm-sensors version 3. -* Alexander Larsson - Wrote the original lm78 module; lm_sensors version 1 was no more than an - extension of this module. He still likes to keep an eye on current - developments, but is usually too busy with other things to do much work - on them -* Philip Edelbrock - Took up the development of the Alex' lm78 module. Responsible for most - SMBus code, and many, many other things. He is still one of the main - developers of the current package. -* Frodo Looijaard - Took up the development of Alex' lm78 module. Large pieces of code were - written by him. Designed lm_sensors version 2, and wrote most of its - core code, including many drivers. -* William Morgan - Helped with some patches in lm_sensors version 1. He provided us with - the original CVS archive, and even managed to explain to us how to use - it. -* Kyösti Mälkki - Author of the i2c-via and i2c-viapro host drivers. Sis5595 hack. - Extended support for GL518SM and GL520SM sensors. -* Mark D. Studebaker - Author of the i2c-ali15x3, i2c-i801, and i2c-i810 bus drivers. - Author (with Bob Dougherty) of the via686a driver. - Added w83782d, w83783s, w83627hf, and as99127f support to the w83781d driver. - Added max1617, thmc10, gl523sm, and lm84 support to the adm1021 driver. - Added lm81 support to the adm9240 driver. - Added DDC support and i2c-algo-bit layer to the i2c-voodoo3 bus driver. - Author of the decode-xeon.pl xeon EEPROM decoder. - Added the RRD interface. - Author of the ddcmon, icspll, smbus-arp, smsc47m1, - vt1211, and vt8231 chip drivers. -* Bob Dougherty - Author (with MDS) of the via686a driver. -* Jonathan Teh Soon Yew and Alex van Kaam - Contributed conversion factor data for the via686a driver. -* Geert Uytterhoeven - Author of the i2c-hydra driver. -* Adrian Baugh (http://www.adrianbaugh.org.uk/) - Original author of wmsensors; - he also tested lots of things, and helped us out on several occasions. -* Fons Rademakers - Author of the maxilife module (which could only be written under NDA) -* Merlin Hughes - Author of the AMD756 module and sensord. -* Constantine Gavrilov - Created and maintains the RPM files -* Simon Vogl - Wrote the new i2c kernel driver. This driver is indispensable for the - workings of lm_sensors version 2. -* Gerd Knorr (?) - Designed the i2c structs, which made it possible to use the smbus-is- - just-an-i2c-extension approach. -* Chen-Yuan Wu - Author of the adm1025 driver. -* Kris Van Hees - Author of the mtp008 chip driver. -* Ken Bowley - Author of the adm1024 driver -* Oleg I. Vdovikin - Author of the DEC Tsunami bus driver. -* Christophe Gauthron - Author of the IT87 driver. -* Hermann Jung - Author of the fscpos driver. -* Aurelien Jarno - Author of the pcf8591 driver. -* Abraham vd Merwe - Author of the LM92 and DS1307 drivers. -* Mark M. Hoffman - Author of the i2c-sis645 bus driver. - Added Asus ASB100 Bach support to the w83781d driver. -* Alexander Malysh - Author of the i2c-sis630 bus driver. - Added Onsemi MC1066 support to the adm1021 driver. -* Jean Delvare - Author of the lm63, lm83, lm90 and w83l785ts SMBus chip drivers. - Author of the f71805f and pc87360 Super-I/O chip drivers. - Author of the i2c-amd756-s4882 and pca9540 SMBus multiplexing drivers. - Author of the decode-vaio.pl Vaio EEPROM decoder. - Author of the decode-edid.pl EDID data decoder. - Perl scripts maintainer, tester, bug fixer, general support. -* Vojtech Pavlik - Author of the i2c-amd8111 bus driver. - Added support for amd8111 SMBus 1.0 controller to i2c-amd756. -* Philip Pokorny - Author of the LM85 chip driver. - Author of the ADM1026 chip driver. -* Sascha Volkenandt - Author of the SAA1064 chip driver. -* John Morris - Author of the MAX6650 chip driver. -* Reinhard Nissl - Author of the fscher driver. -* Alexey Fisher - Author of the max1619 chip driver. -* Rudolf Marek - Various fixes and support handling +* Frodo Looijaard + Original author of libsensors, sensors and isadump. +* Merlin Hughes + Original author of sensord. +* Bob Schlaermann + Dynamic chip feature detection (a.k.a. generic chip support) in + libsensors and sensors. +* Mark M. Hoffman + Many improvements to the libsensors configuration file scanner. +* Jean Delvare + New libsensors API, and migration of sensors and sensord thereto. + Many optimizations in libsensors and sensors. + Configuration file converter. diff --git a/INSTALL b/INSTALL index 3d1e071f..f4dc82f2 100644 --- a/INSTALL +++ b/INSTALL @@ -1,305 +1,83 @@ -============================================================================= +INSTALLATION INSTRUCTIONS +========================= -DETAILED INSTALLATION INSTRUCTIONS -See QUICKSTART for the simple version. - -The driver modules in this package are ONLY for 2.4 kernels 2.4.10 or later! - -This package REQUIRES i2c-2.9.0 or later! The i2c subsystem found in the -Linux 2.4 kernel trees, even the latest ones, is outdated and won't work. - -FOR 2.5/2.6 KERNELS, do not attempt to compile the modules in this package. - Use the drivers already in the 2.5/2.6 kernel tree. - If you are running a 2.5/2.6 kernel, the ONLY thing you need to - do is 'make user' and 'make user_install'. Do NOT follow the rest - of these instructions. Please check the QUICKSTART instead. +The lm-sensors package, version 3, provides user-space support for the +hardware monitoring drivers in Linux 2.6.5 and later. For older kernel +versions, you have to use lm-sensors version 2. -============================================================================= -These are the installation instruction for the lm_sensors package. +Dependencies +============ -There are two ways in which you can compile and install this package. -Option 1 is much easier and is recommended. +Build-time dependencies: +* GNU make +* gcc +* bison +* flex +* rrd header files (optional, for sensord) - 1. Complete separate from kernel compilation - (only for 2.4 kernels 2.4.10 or later) - This will generate a set of modules which can be inserted and removed - as needed; nothing will be written into the kernel tree; - - 2. Patching of the kernel - (only for 2.4 kernels 2.4.13 or later) - This will patch your kernel source tree. You must recompile your kernel - to take advantage of this. But it makes it possible to compile drivers - into the kernel itself, instead of having to add them as modules. - ** AFTER YOU COMPILED AND INSTALLED YOUR KERNEL, YOU WILL STILL HAVE TO - ** COMPILE THIS PACKAGE TO GET THE USERLAND UTILITIES! - ** NOT ALL MODULES ARE PATCHED INTO THE KERNEL. SEE BELOW. +Run-time dependencies: +* perl (for sensors-detect) +* rrdtool >= 1.2.1 (optional, for sensord) +* proper kernel configuration (see below) - -Each of these ways will be described below in detail. - -NOTE: MAKE SURE YOU HAVE THE I2C-ALGO-BIT DRIVER (PART OF THE I2C PACKAGE) - COMPILED INTO YOUR KERNEL OR AVAILABLE AS A MODULE; SOME I2C/SMBUS - MASTER DRIVERS DEPEND ON IT! - -NOTE: IN EACH CASE, YOU WILL HAVE TO GET AND INSTALL THE I2C PACKAGE FIRST! - SET COMPILE_KERNEL TO 0 IN THE MAIN MAKEFILE FOR OPTION 2, UNLESS - YOU NEED ALPHA OR BETA DRIVERS (SEE BELOW) - -NOTE: PLEASE READ THE DOCUMENTATION IN THE DOC SUBDIRECTORY IF YOU GET STUCK! - - -Installing the i2c package -========================== - -This lm_sensors release REQUIRES i2c-2.9.0 or later, which is not in -any 2.4 kernel (and will never be). -Therefore, you must download and install the i2c package with -the same version number or higher as this lm_sensors package. - -All i2c components are distributed in -a separate package. There are install instructions in that package. If -you want to use compilation option 2 (patching the kernel) for lm_sensors, -you will have to use compilation option 3 (patching the kernel) for i2c -too. If you want to use compilation option 1 (compiling as modules) for -lm_sensors, you may use either compilation option 1 or 2 (compiling as -modules) or compilation option 3 (patching the kernel for i2c). See the -table below. - - LM_SENSORS -I2C | option 1 (modules) option 2 (patch kernel) --------------------------+------------------------------------------------ -option 1 (modules) | YES NO -option 2 (modules) | YES YES -option 3 (patch kernel) | YES YES - - -If you use compilation option 1 (compiling as modules) for lm_sensors, you -will have to make very sure the correct i2c header files are found. If you -get weird compilation errors, this is almost certainly going wrong. The -i2c header files are in a i2c subdirectory of either /usr/local/include -(i2c compilation option 1) or /usr/src/linux*/include (i2c compilation -options 2 and 3). Especially if you have in the past placed the header -files in /usr/local/include, this will probably go wrong. See below on -how to fix this. - -NOTE: option 3 only works with 2.4 kernels 2.4.13 or later; - options 1 and 2 only work with 2.4 kernels 2.4.10 or later. - - -Mixing old and new, and using beta drivers (compilation option 1) -================================================================= - -It is possible that you are running a previously patched kernel, or -a very new kernel which already has limited or full i2c or lm_sensors -support, but you want to use newer versions of the drivers. This is -possible, but there are some pitfalls. - -If you had compiled all i2c and lm_sensors drivers as modules, you are -in luck. You can simply compile the newest versions of i2c and -lm_sensors and install them. Just make sure the right modules are -loaded (best bet: remove the old ones first). - -If you have a certain driver compiled into your kernel, you may -encounter bad problems. We do not guarantee to keep internal kernel -interfaces unchanged. In plain language, this means that an older driver -may not work together with a newer driver, and your kernel may crash. -On the other hand, if you know what you are doing, compilation will -be smart. Drivers that are compiled right into your kernel will not -be compiled as a module again. You could do nothing with them anyway. - -Sometimes, you want to patch your kernel, but find that certain alpha -or beta drivers are not included in the patch. This is on purpose: we -do not want to polute the kernel tree with things of which we are not -confident they work. In this case, patch the kernel, compile it, and -then compile lm_sensors with COMPILE_KERNEL set to 1. - - -Having a proper kernel tree (compilation option 1) -================================================== - -Usually, if you compile a user-space application, you can get away with -having a different version of the kernel running than the version of the -kernel header files against which you compiled it. But a perfect match -is needed for the first two compilation options above. - -Let's say you want to use the lm_sensors modules with the kernel 2.4.32 you -are running now. What you need, is the original tree in which you -compiled that 2.4.32 kernel. A freshly unpacked 2.4.32 kernel will not -cut it, because `make *config dep' creates some files that are needed. -And even then, you will run into trouble, because you may not have -selected the exact same configuration variables. Plain advise: if you -do not have your original kernel tree anymore, recompile your kernel -first. - -Note that there is no need for a perfect match at compilation time, just -at run-time. This means you can cross-compile against a different kernel -version, and the Makefile does not check for this. - -Usually problems if the match is imperfect, is that either this package -won't compile at all (because it was a freshly unpacked tree without -some files generated by `make *config dep'), or that you can't insert -modules because of either a `kernel-module version mismatch' or because -of `unresolved kernel symbols'. If you get either of these messages, -check your kernel tree! - -To keep problems to a minimum, please use a 'vanilla' kernel tree, -as distributed on ftp://ftp.kernel/org/pub/linux/kernel, and not one -patched by your distribution. - - -Separate from kernel compilation (compilation option 1) -======================================================= - -This will compile and install the complete lm_sensors package. Though -nothing is written to your kernel tree, a proper tree is still needed -for this. See earlier for what a proper kernel tree is. +Compilation +=========== At the top of the Makefile are a couple of configuration variables that -you may want to change. As far as possible, the Makefile tries to figure -out by itself their settings, but it is possible to overrule them. A list -is found below. Most important are the variables that determine where -your kernel is located (LINUX=/lib/modules/KERNELVERSION/build, usually -links to /usr/src/linux or something similar), where the i2c header files -are (I2C_HEADERS=/usr/local/include) and where you want to install -your modules (MODDIR=/lib/modules/KERNELVERSION) and header files -(LINUX_INCLUDE_DIR=/usr/local/include/linux). You can see that the -installation locations are choosen in such a way that they are separate -from the true kernel. +you may want to change. There's a description of what each variable does +in the Makefile itself. -Compilation is done by `make all'; `make install' installs the package. -You will get a lot of warnings about files which are not found, all -ending on `.*d'. You can safely ignore this; they contain dependency -information, which is regenerated on the spot. +Compilation is done by `make all'. You will get a lot of warnings about +files which are not found, all ending in `.*d'. You can safely ignore +this; they contain dependency information, which is regenerated on the +spot. -Please continue reading this file before you start compiling. +`make install' installs the package (to /usr/local by default). -Makefile configuration variables (compilation option 1) -============================================================== +Kernel configuration +==================== -SHELL (default: /bin/sh) - You may have to specify the full path to Bash here, if /bin/sh is some - other shell. There have been conflicting reports on whether this is - needed. -KERNELVERSION - The version of the currently running kernel. -LINUX (default: /lib/modules/$(KERNELVERSION)/build) - The location of your kernel tree. -COMPILE_KERNEL - Determine whether you want to consider the kernel modules for compilation - at all. By default, compilation option 1 will only compile and install - those modules which are not built into the kernel. - If some modules are built into your kernel, and this package is much - newer, you may find you can not insert the newly compiled modules. - Sorry. - You may want to set this to 0 if you have just patched and compiled - your kernel using the same version of this package, and just want to - compile the user-space tools. -I2C_HEADERS (default: /usr/local/include) - This lists where the i2c headers are found. If you used compilation - option 1 for the i2c package, the default will be right. If you used - compilation options 2 or 3, it will not, and may actually cause - problems if you have the left-overs of a previous installation. - If you have weird compilation problems, try to change this to - $(LINUX_HEADERS). -SMP - This must be set to 1 for a SMP kernel. The magic invocation should - determine this automatically, so you should not have to bother with - this. -MODVER - This must be set to 1 if CONFIG_MODVERSIONS is defined. The magic - invocation should determine this automatically, so you should not - have to bother with this. -WARN (default: 0) - Generate additional compilation warnings; mainly interesting for - developers. -DEBUG (default: 0) - Some drivers will issue more debug information if you set this to - 1. Don't do it, unless you are a developer or are instructed to do - so by the lm_sensors team. -PREFIX (default: /usr/local) - Prefix for almost all installation directories. -MODPREF (default: /lib/modules/$(KERNELVERSION)) - The location where the kernel modules will be installed. -ETCDIR (default: /etc) - Installation location of the sensors.conf configuration file. -LIBDIR (default: $(PREFIX)/lib) - Installation location of all static and shared libraries. -BINDIR (default: $(PREFIX)/bin) - Installation directory of programs useful for users. -SBINDIR (default: $(PREFIX)/sbin) - Installation directory of system administrator-only programs. -INCLUDEDIR (default: $(PREFIX)/include) - Base installation directory for include files (see next two vars). -SYSINCLUDEDIR (default: $(INCLUDEDIR)/linux) - Installation directory for system include files. -LIBINCLUDEDIR (default: $(INCLUDEDIR)/sensors) - Installation directory for libsensors include files. -MANDIR (default: $(PREFIX)/man) - Base installation directory for manual pages. - - -Patching the kernel (compilation option 2) -========================================== - -There is a special script which should be able to generate diffs against -any 2.4 kernel (2.4.10 or later). Please report any problems to our -mailing list. It *is* safe to run it if your kernel already has the -lm_sensors drivers. It will only work if you applied the i2c patches first. - -** Only a subset of the modules in lm_sensors are patched into the ** -** kernel by the script. See the file mkpatch/FILES to see if the ** -** modules you need are included. If a module you need is NOT listed ** -** in mkpatch/FILES, it will not be patched, and you MUST use option 1. ** -** If you are not sure what modules you need, run `sensors-detect' first. ** - -The kernel diffs are generated by the program `mkpatch.pl' in the mkpatch -subdirectory. It needs two arguments: the first one is the root of the -lm_sensors package, the second one is the root of the kernel tree against -which the diffs will be generated. For example: - cd /tmp/lm_sensors-2.10.0 - mkpatch/mkpatch.pl . /usr/src/linux > /tmp/sensors-2.10.0.patch -You can apply the diffs as usual: - cd /usr/src/linux - patch -p1 -E < /tmp/sensors-2.10.0.patch -Generation and application can easily be done in one step: - mkpatch/mkpatch.pl . /usr/src/linux | patch -p1 -E -d /usr/src/linux -The generated diffs are of course only valid for the kernel version -against which mkpatch.pl was run. - -Once you have applied the patches, you can configure and compile your -kernel as usual. You will see the sensors configuration screen under the -`Character Devices' menu in menuconfig, but it will only be available -if you selected base I2C support. +This package assumes that you have a properly configured kernel. If +you run a distribution kernel, that should be the case. If you're +building your own kernel, here are some recommendations: +* Enable "I2C support" (CONFIG_I2C=y or m). On many motherboards, the + sensor chip is connected to the SMBus, which is supported by I2C + in the Linux kernel. +* Enable "I2C device interface" (CONFIG_I2C_CHARDEV=m). sensors-detect + needs this to probe for SMBus hardware monitoring chips. +* In I2C Hardware Bus support, enable all drivers you might need, + preferably as modules. If you're not sure, select them all. +* Enable "Hardware Monitoring support" (CONFIG_HWMON=y or m). +* Enable all hardware monitoring drivers you might need, preferably + as modules. If you're not sure, select them all. Using the sensors package ========================= -You can now load the modules by using `modprobe'. For example, -`modprobe i2c-piix4' will load the i2c-piix4 module, and all i2c modules -on which it depends. - -You can not use demand-loading; you will have to issue explicit modprobe -instructions. - -If you have an older installation, you will probably have to create the -i2c device files in the /dev directory. They are called /dev/i2c-%d, -and are character devices with major device number 89 and minor device -number %d. The script prog/mkdev/mkdev.sh will create the files for you. - There is a scanning program installed called sensors-detect. It -will scan all available I2C and SMBus adapters for all known devices, -and will also look for ISA, PCI and Super-I/O chips with sensors, -and give you a list of what modules you need to insert. +will scan all available I2C and SMBus adapters for all known sensor +devices, and will also look for ISA, PCI and Super-I/O chips with +sensors, and give you a list of what kernel drivers you need to load +(using modprobe). -You can use the installed sensors program to get a report of all detected -sensor devices. There is also a manual page for this program. Calling -`sensors -s' will set the limits and other configuration settings -specified in /etc/sensors.conf. Again, read the manual pages for more -information. +After loading the suggested drivers, you can use the installed sensors +program to get a report of all detected sensor devices. Check the manual +page for available options. + +The initial output of `sensors' will not be perfect. You have to adjust +the configuration file (/etc/sensors3.conf) to match your motherboard. +This includes (re)labelling inputs, ignoring unused inputs, changing +voltage compute lines and setting limits. Write down all the sensor +information your BIOS displays as a hint to what you are supposed to +obtain in the end. Make sure you modify the right chip section. + +Once you are done with editing the configuration file, calling +`sensors -s' will set the new limits. Then the output of `sensors' +should look much better. There are many auxiliary programs not installed. You can find them under the prog subdirectory. A list can be found in doc/progs. diff --git a/Makefile b/Makefile index 279650cd..bb6c4c59 100644 --- a/Makefile +++ b/Makefile @@ -13,56 +13,20 @@ # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software -# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, +# MA 02110-1301 USA. # Everything you may want to change is in the top of this file. Usually, you # can just use the defaults, fortunately. # You need a full complement of GNU utilities to run this Makefile -# successfully; most notably, you need bash, GNU make, flex (>= 2.5.1) +# successfully; most notably, you need GNU make, flex (>= 2.5.1) # and bison. -# If your /bin/sh is not bash, change the below definition so that make can -# find bash. Or you can hope your sh-like shell understands all scripts. -# I think so, but I have not tested it. -#SHELL := /usr/bin/bash - -# The currently running kernel version. This is used right below to -# determine where the kernel sources can be found. -KERNELVERSION := $(shell uname -r) - -# The location of linux itself. This is used to find the kernel headers -# and other things. -#LINUX := /usr/src/linux -LINUX := $(shell if [ -L "/lib/modules/$(KERNELVERSION)/build" ] ; \ - then echo "/lib/modules/$(KERNELVERSION)/build" ; \ - else echo "/usr/src/linux" ; fi) -LINUX_HEADERS := $(LINUX)/include - -# If you have installed the i2c header at some other place (like -# /usr/local/include/linux), set that directory here. Please check this out -# if you get strange compilation errors; the default Linux i2c headers -# may be used mistakenly. Note: This should point to the directory -# *above* the linux/ subdirectory, so to /usr/local/include in the -# above example. -I2C_HEADERS := /usr/local/include -#I2C_HEADERS := $(LINUX_HEADERS) - -ifneq ($(MAKECMDGOALS),user) -ifneq ($(MAKECMDGOALS),user_install) -ifneq ($(MAKECMDGOALS),user_uninstall) -SMP := $(shell if grep -q '^[[:space:]]*\#define[[:space:]]*CONFIG_SMP[[:space:]]*1' $(LINUX_HEADERS)/linux/autoconf.h ; \ - then echo 1; else echo 0; fi) -MODVER := $(shell if grep -q '^[[:space:]]*\#define[[:space:]]*CONFIG_MODVERSIONS[[:space:]]*1' $(LINUX_HEADERS)/linux/autoconf.h ; \ - then echo 1; else echo 0; fi) -endif -endif -endif - # Uncomment the second line if you are a developer. This will enable many # additional warnings at compile-time -WARN := 0 -#WARN := 1 +#WARN := 0 +WARN := 1 # Uncomment the second line if you want to get (loads of) debug information # at run-time. @@ -70,6 +34,9 @@ WARN := 0 DEBUG := 0 #DEBUG := 1 +# Note that all the installation paths below can also be set on the make +# command line (e.g. "make PREFIX=/usr"). + # If you want to install at some other place then at from which you will run # everything, set DESTDIR to the extra prefix. DESTDIR := @@ -80,36 +47,7 @@ PREFIX := /usr/local # Your C compiler CC := gcc -# This is the main modules directory into which the modules will be installed. -# The magic invocation will return something like this: -# /lib/modules/2.4.29 -KERNELVERSION := $(shell $(CC) -I$(LINUX_HEADERS) -E etc/config.c | grep uts_release | cut -f 2 -d'"') -MODPREF := /lib/modules/$(KERNELVERSION) - -# When building userspace for use with 2.4.x series kernels, we turn off -# sysfs support by default. You can override this (e.g. if you want -# to build binaries that work for both 2.4.x, and 2.6.x and above) -# by uncommenting the line after the next endif. Keep in mind, if and only -# if you do this: you will need to install the libsysfs libraries on your -# kernel 2.4.x systems also. -ifeq (,$(findstring /2.4., $(MODPREF))) - SYSFS_SUPPORT := 1 -else - SYSFS_SUPPORT := -endif -#SYSFS_SUPPORT := 1 - -# Prevent 2.6+ users from using improper targets, as this won't work. -ifeq (,$(findstring /2.4., $(MODPREF))) - ifeq (, $(MAKECMDGOALS)) - $(error For 2.6 kernels and later, use "make user") - endif - ifeq (install, $(MAKECMDGOALS)) - $(error For 2.6 kernels and later, use "make user_install") - endif -endif - -# This is the directory where sensors.conf will be installed, if no other +# This is the directory where sensors3.conf will be installed, if no other # configuration file is found ETCDIR := /etc @@ -131,12 +69,8 @@ SBINDIR := $(PREFIX)/sbin # You should not need to change this. It is the basic directory into which # include files will be installed. The actual directory will be -# $(INCLUDEDIR)/linux for system include files, and $(INCLUDEDIR)/sensors -# for library include files. If PREFIX equals the default /usr/local, -# you will be able to use '#include ' regardless of the -# current kernel selected. +# $(INCLUDEDIR)/sensors for library include files. INCLUDEDIR := $(PREFIX)/include -SYSINCLUDEDIR := $(INCLUDEDIR)/linux LIBINCLUDEDIR := $(INCLUDEDIR)/sensors # You should not need to change this. It is the base directory under which the @@ -169,24 +103,12 @@ MACHINE := $(shell uname -m) # to do this. # The subdirectories we need to build things in -SRCDIRS := -ifneq ($(MAKECMDGOALS),user) -ifneq ($(MAKECMDGOALS),user_install) -ifneq ($(MAKECMDGOALS),user_uninstall) -ifneq ($(MAKECMDGOALS),package) -ifneq ($(MAKECMDGOALS),userpackage) -ifneq ($(MAKECMDGOALS),manhtml) -SRCDIRS += mkpatch -SRCDIRS += kernel/busses kernel/chips +SRCDIRS := lib prog/detect prog/pwm \ + prog/sensors ${PROG_EXTRA:%=prog/%} etc +# Only build isadump and isaset on x86 machines. +ifneq (,$(findstring $(MACHINE), i386 i486 i586 i686 x86_64)) +SRCDIRS += prog/dump endif -endif -endif -endif -endif -endif -SRCDIRS += kernel/include -SRCDIRS += lib prog/detect prog/dump prog/eeprom prog/pwm \ - prog/sensors prog/xeon ${PROG_EXTRA:%=prog/%} etc SRCDIRS += lib/test # Some often-used commands with default options @@ -205,11 +127,10 @@ SED := sed # Determine the default compiler flags # Set CFLAGS or CPPFLAGS above to add your own flags to all. # ALLCPPFLAGS/ALLCFLAGS are common flags, plus any user-specified overrides from the environment or make command line. -# MODCPPFLAGS/MODCFLAGS is to create in-kernel object files (modules). -# PROGCPPFLAGS/PROGCFLAGS is to create non-kernel object files (which are linked into executables). +# PROGCPPFLAGS/PROGCFLAGS is to create regular object files (which are linked into executables). # ARCPPFLAGS/ARCFLAGS are used to create archive object files (static libraries). # LIBCPPFLAGS/LIBCFLAGS are for shared library objects. -ALL_CPPFLAGS := -I. -Ikernel/include -I$(I2C_HEADERS) +ALL_CPPFLAGS := -I. ALL_CFLAGS := -Wall ifeq ($(DEBUG),1) @@ -221,67 +142,21 @@ endif ifeq ($(WARN),1) ALL_CFLAGS += -Wstrict-prototypes -Wshadow -Wpointer-arith -Wcast-qual \ - -Wcast-align -Wwrite-strings -Wnested-externs -Winline + -Wcast-align -Wwrite-strings -Wnested-externs -Winline -W \ + -Wmissing-prototypes -Wundef endif ALL_CPPFLAGS += $(CPPFLAGS) ALL_CFLAGS += $(CFLAGS) -MODCPPFLAGS := -MODCFLAGS := -fno-strict-aliasing - -ifeq ($(MACHINE),alpha) -MODCFLAGS += -ffixed-8 -mno-fp-regs -mcpu=ev56 -endif - -ifeq ($(MACHINE),x86_64) -MODCFLAGS += -fno-common -fomit-frame-pointer -mno-red-zone \ - -mcmodel=kernel -fno-reorder-blocks -finline-limit=2000 -fno-strength-reduce -endif - -ifeq ($(MACHINE),mips) -MODCFLAGS += -mabi=32 -mips3 -Wa,-32 -Wa,-mips3 -Wa,--trap -endif - -ifeq ($(MACHINE),sparc32) -MODCFLAGS += -m32 -pipe -mno-fpu -fcall-used-g5 -fcall-used-g7 -endif - -ifeq ($(MACHINE),sparc64) -MODCFLAGS += -m64 -pipe -mno-fpu -mcpu=ultrasparc -mcmodel=medlow \ - -ffixed-g4 -fcall-used-g5 -fcall-used-g7 -Wno-sign-compare \ - -Wa,--undeclared-regs -endif - -ifeq ($(SMP),1) -MODCPPFLAGS += -D__SMP__ -endif - -ifeq ($(MODVER),1) -MODCPPFLAGS += -DMODVERSIONS -include $(LINUX_HEADERS)/linux/modversions.h -endif - -# This magic is from the kernel Makefile. -# Extra cflags for kbuild 2.4. The default is to forbid includes by kernel code -# from user space headers. -kbuild_2_4_nostdinc := -nostdinc $(shell LC_ALL=C $(CC) -print-search-dirs | sed -ne 's/install: \(.*\)/-I \1include/gp') - -MODCPPFLAGS += -D__KERNEL__ -DMODULE -DEXPORT_SYMTAB -fomit-frame-pointer $(ALL_CPPFLAGS) -I$(LINUX_HEADERS) $(kbuild_2_4_nostdinc) -MODCFLAGS += $(ALL_CFLAGS) -PROGCPPFLAGS := -DETCDIR="\"$(ETCDIR)\"" $(ALL_CPPFLAGS) -Wundef +PROGCPPFLAGS := -DETCDIR="\"$(ETCDIR)\"" $(ALL_CPPFLAGS) PROGCFLAGS := $(ALL_CFLAGS) -ARCPPFLAGS := $(ALL_CPPFLAGS) -ifdef SYSFS_SUPPORT -ARCPPFLAGS := $(ARCPPFLAGS) -DSYSFS_SUPPORT -endif +ARCPPFLAGS := -DETCDIR="\"$(ETCDIR)\"" $(ALL_CPPFLAGS) ARCFLAGS := $(ALL_CFLAGS) -LIBCPPFLAGS := $(ALL_CPPFLAGS) -ifdef SYSFS_SUPPORT -LIBCPPFLAGS := $(LIBCPPFLAGS) -DSYSFS_SUPPORT -endif +LIBCPPFLAGS := -DETCDIR="\"$(ETCDIR)\"" $(ALL_CPPFLAGS) LIBCFLAGS := -fpic -D_REENTRANT $(ALL_CFLAGS) -.PHONY: all user clean install user_install uninstall user_uninstall version package +.PHONY: all user clean install user_install uninstall user_uninstall # Make all the default rule all:: @@ -293,15 +168,11 @@ ifneq ($(MAKECMDGOALS),clean) ifneq ($(MAKECMDGOALS),uninstall) ifneq ($(MAKECMDGOALS),user_uninstall) ifneq ($(MAKECMDGOALS),help) -ifneq ($(MAKECMDGOALS),package) -ifneq ($(MAKECMDGOALS),userpackage) include $(INCLUDEFILES) endif endif endif endif -endif -endif # Man pages MANPAGES := $(LIBMAN3FILES) $(LIBMAN5FILES) $(PROGDETECTMAN8FILES) $(PROGDUMPMAN8FILES) \ @@ -309,35 +180,19 @@ MANPAGES := $(LIBMAN3FILES) $(LIBMAN5FILES) $(PROGDETECTMAN8FILES) $(PROGDUMPMAN user :: user_install:: - @echo "*** Important note:" - @echo "*** * The libsensors configuration file ($(ETCDIR)/sensors.conf) is never" + @echo "*** Important notes:" + @echo "*** * The libsensors configuration file ($(ETCDIR)/sensors3.conf) is never" @echo "*** overwritten by our installation process, so that you won't lose" @echo "*** your personal settings in that file. You still can get our latest" - @echo "*** default config file in etc/sensors.conf.eg and manually copy it to" - @echo "*** $(ETCDIR)/sensors.conf if you want. You will then want to edit it" - @echo "*** to fit your needs again." + @echo "*** default config file in etc/sensors.conf.default and manually copy" + @echo "*** it to $(ETCDIR)/sensors3.conf if you want. You will then want to" + @echo "*** edit it to fit your needs again." + @echo "*** * The format of $(ETCDIR)/sensors3.conf changed with lm-sensors 3.0.0." + @echo "*** If you have a custom configuration file using the old format, you" + @echo "*** can convert it using the sensors-conf-convert script. Otherwise just" + @echo "*** overwrite your old configuration file with the new default one." all :: user install :: all user_install -ifeq ($(DESTDIR),) - -if [ -x /sbin/depmod ] ; then \ - if [ -r $(MODPREF)/build/System.map ] ; then \ - /sbin/depmod -a -F $(MODPREF)/build/System.map $(KERNELVERSION) ; \ - elif [ "$(KERNELVERSION)" = "`uname -r`" ] ; then \ - /sbin/depmod -a ; \ - fi \ - fi -else - @echo "*** This is a \`staged' install using \"$(DESTDIR)\" as prefix." - @echo "***" - @echo "*** Once the modules have been moved to their final destination" - @echo "*** you must run the command \"/sbin/depmod -a\"." - @echo "***" - @echo "*** Alternatively, if you build a package (e.g. rpm), include the" - @echo "*** command \"/sbin/depmod -a\" in the post-(un)install procedure." - @echo "***" - @echo "*** The depmod command mentioned above may generate errors. We are" - @echo "*** aware of the problem and are working on a solution." -endif clean:: $(RM) lm_sensors-* lex.backup @@ -345,74 +200,13 @@ clean:: user_uninstall:: uninstall :: user_uninstall - @echo "*** Note:" - @echo "*** * Kernel modules were not uninstalled." - -# This is tricky, but it works like a charm. It needs lots of utilities -# though: cut, find, gzip, ln, tail and tar. -package: version clean - lmversion=`tail -1 version.h|cut -f 2 -d \"`; \ - lmpackage=lm_sensors-$$lmversion; \ - ln -s . $$lmpackage; \ - find $$lmpackage/ -type f | grep -v ^$$lmpackage/$$lmpackage$$ | \ - grep -v ^$$lmpackage/$$lmpackage.tar$$ | \ - grep -v ^$$lmpackage/$$ | \ - grep -v /\\.svn | \ - grep -v /\\.# | \ - tar rvf $$lmpackage.tar -T -; \ - gzip -9 $$lmpackage.tar ;\ - $(RM) $$lmpackage.tar $$lmpackage - cat doc/developers/checklist - -# doesn't work well yet... needs Makefile changes too -userpackage: version clean $(KERNELINCLUDEDIR)/sensors.h - lmversion=`tail -1 version.h|cut -f 2 -d \"`; \ - lmpackage=lm_sensors-user-$$lmversion; \ - ln -s . $$lmpackage; \ - find $$lmpackage/ -type f | grep -v ^$$lmpackage/$$lmpackage$$ | \ - grep -v ^$$lmpackage/$$lmpackage.tar$$ | \ - grep -v ^$$lmpackage/doc/chips | \ - grep -v ^$$lmpackage/doc/busses | \ - grep -v ^$$lmpackage/kernel/chips | \ - grep -v ^$$lmpackage/kernel/busses | \ - grep -v ^$$lmpackage/$$ | \ - grep -v /\\.svn | \ - grep -v /\\.# | \ - tar rvf $$lmpackage.tar -T -; \ - gzip -9 $$lmpackage.tar ;\ - $(RM) $$lmpackage.tar $$lmpackage - cat doc/developers/checklist - -version: - $(RM) version.h - echo '#define LM_DATE "'`date +'%Y%m%d'`\" > version.h - echo -n 'Version: '; \ - echo '#define LM_VERSION "'`read VER; echo $$VER`\" >> version.h help: @echo 'Make targets are:' - @echo ' all (default): build modules and userspace programs' - @echo ' install: install modules and userspace programs' - @echo ' user: build userspace programs' - @echo ' user_install: install userspace programs' - @echo ' user_uninstall: remove userspace programs' + @echo ' all (default): build library and userspace programs' + @echo ' install: install library and userspace programs' + @echo ' uninstall: uninstall library and userspace programs' @echo ' clean: cleanup' - @echo ' package: create a distribution package' - -$(LINUX)/.config: - @echo - @echo "Error - missing file $(LINUX)/.config !! " - @echo " Verify kernel source is in $(LINUX) and then" - @echo " cd to $(LINUX) and run 'make config' !!" - @echo - @echo "Exception: if you're using a stock RedHat kernel..." - @echo " (1) Install the appropriate kernel-source RPM." - @echo " (2) Copy the appropriate config..." - @echo " from $(LINUX)/configs/<...>" - @echo " to $(LINUX)/.config" - @echo " (3) Do *NOT* 'make dep' or 'make config'." - @echo - @exit 1 # Generate html man pages to be copied to the lm_sensors website. # This uses the man2html from here @@ -434,16 +228,6 @@ manhtml: # We need to create dependency files. Tricky. The sed rule puts dir/file.d and # dir/file.c in front of the dependency file rule. -# .o files are used for modules -# depend on the kernel config file! -%.o: %.c $(LINUX)/.config - $(CC) $(MODCPPFLAGS) $(MODCFLAGS) -c $< -o $@ - -%.d: %.c $(LINUX)/.config - $(CC) -M -MG $(MODCPPFLAGS) $(MODCFLAGS) $< | \ - $(SED) -e 's@^\(.*\)\.o:@$*.d $*.o: Makefile '`dirname $*.d`/Module.mk' @' > $@ - - # .ro files are used for programs (as opposed to modules) %.ro: %.c diff --git a/QUICKSTART b/QUICKSTART deleted file mode 100644 index bb964bfc..00000000 --- a/QUICKSTART +++ /dev/null @@ -1,77 +0,0 @@ -LM_SENSORS QUICK INSTALLATION INSTRUCTIONS ------------------------------------------- - -The instructions in this document will generally work if you have a standard -system, but not always!! - -The first part of document is for 2.6 kernel series, second part is for -older 2.4 kernels. - -Quickstart for Kernel 2.6 -------------------------- - -0) Just compile and install lm-sensors userspace tools. You can do that with: - 'make user; make user_install' -1) Make sure your kernel has support for all I2C bus drivers and - 'i2c device interface'. If you are using a distribution kernel, all is - already prepared, you don't need to recompile it. -2) Run 'sensors-detect' command, it will tell you what modules you need to load. -3) Load them and run 'sensors' command, you should see some results. -4) Find right section in /etc/sensors.conf, fix labels, limits, fan divisors -5) Run 'sensors -s' to apply the changes. - -You may also try our installation wizard at: - -http://www.lm-sensors.org/wiki/iwizard/1 - -We are aware that the documentation could be improved, please contact us if -you want to help us with that. - -Quickstart for Kernel 2.4 -------------------------- - -NOTE: PLEASE SKIM THE INSTALL DOCUMENT, OR BETTER YET READ IT CAREFULLY! - -Quickstart for i2c option 1 (modules) and lm_sensors option 1 (modules). -This is by far the EASIEST METHOD. -Other methods are described in INSTALL. ------------------------------------------- - - * Verify you are running a 2.4 kernel, 2.4.10 or later. - - * Make sure you have the kernel tree corresponding to your current - kernel in /lib/modules/$(uname -r)/build. - Even if the source is there, it may not correspond to your running - kernel. If so, you will have to recompile your kernel. - - * Verify that your i2c support in the kernel is configured as - modules or is disabled. If it is compiled-in, you obviously - cannot replace it with modules in the next step. - - * Do `lsmod'. If there are any old i2c or sensors modules loaded, - you MUST remove them (as root) with `rmmod'. - - * Download, build, and install the latest i2c package, - (i2c-2.9.0 or later). The i2c subsystem found in the Linux 2.4 - kernel trees, even the latest ones, is outdated and won't work. - Quickstart for i2c: make; (as root) make install - - * Go back to the lm_sensors directory. Do `make'. - The warnings about .d files at the start are harmless. - - * Do (as root) `make install'. - - * Verify that /usr/local/lib is listed in /etc/ld.so.conf; - if it isn't, add it, then run (as root) `ldconfig'. - - * Run (as root) `prog/mkdev/mkdev.sh' to create the device files, - unless you already have them or are running devfs or udev. - - * Run (as root) `prog/detect/sensors-detect' to detect your hardware, - put the lines it suggests into /etc/modules.conf, and run all - the commands it suggests (`modprobe X', `sensors -s'). - - * Run `sensors' to see your output. - - * That's it! If you have problems, read our excellent FAQ - (doc/FAQ or doc/lm_sensors-FAQ.html). diff --git a/README b/README index 47bf6065..e58aae50 100644 --- a/README +++ b/README @@ -1,161 +1,99 @@ -============================================================================= +OVERVIEW OF THE LM-SENSORS PACKAGE +================================== - FOR QUICK INSTALLATION INSTRUCTIONS SEE THE 'QUICKSTART' FILE. - FOR FULL INSTALLATION INSTRUCTIONS SEE THE 'INSTALL' FILE. - FOR THE FAQ SEE THE 'doc/FAQ' or 'doc/lm_sensors-FAQ.html' FILES. +The lm-sensors package, version 3, provides user-space support for the +hardware monitoring drivers in Linux 2.6.5 and later. For older kernel +versions, you have to use lm-sensors version 2. -============================================================================= +The directories within this package: -OVERVIEW OF THE LM_SENSORS PACKAGE AND SUMMARY OF SUPPORTED DEVICES - -!!! This package is ONLY for 2.6 and 2.4 kernels (2.4.10 or later). !!! -!!! For 2.4 kernels, this package requires i2c-2.9.0 or later. !!! - -FOR 2.6 KERNELS, use only the userspace tools in this package! -Build and install them with 'make user' and 'make user_install'. -The kernel modules in this package will NOT compile for 2.6; -use the drivers already in the 2.6 kernel. Check the QUICKSTART -file for brief installation instructions please. - -============================================================================= - -This is the completely rewritten version 2 of lm_sensors, a collection of -modules for general SMBus[1] access and hardware monitoring. -Version 1 is now officially unsupported. - -WARNING! The drivers in this package will work on reasonably recent 2.4 -kernels only (2.4.10 and later). -Use lm_sensors-2.4.5 for 2.0 kernels. -Use lm_sensors-2.7.0 for 2.2, and early 2.4 (up to 2.4.9) kernels. -Use the drivers already in the kernel for 2.6 kernels; if you need -additional drivers in 2.6 please port and submit them to us. - -HOWEVER, the userspace tools in this package will work for -both 2.4 and 2.6 kernels. - -The I2C[2] package in existing 2.4 kernels is NOT sufficient -for compilation of this package. You need i2c-2.9.0 or later. - -See the lm_sensors download page for further guidance: - http://www.lm-sensors.org/wiki/Download +* doc + Documentation. +* etc + A sample configuration file for libsensors, and a script to convert + lm-sensors version 2 configuration files to work with version 3. +* lib + The user-space sensors support library code (libsensors). +* prog + Several supporting programs. The most important ones are: + - sensors-detect: A program for detecting installed hardware and + recommending specific modules to load. + - sensors: A console tool to report sensor readings and set new + sensor limits. + - sensord: A daemon to watch sensor values and log problems. It + includes RRD support. -============================================================================= +INSTALLING LM-SENSORS +--------------------- -At least the following I2C/SMBus adapters are supported: - Acer Labs M1533, M1535, M1543C and M1563 - AMD 756, 766, 768 and 8111 - AMD 8111 SMBus 2.0 - Apple Hydra (used on some PPC machines) - ATI IXP200, IXP300, IXP400, SB600, SB700, SB800 - DEC 21272/21274 (Tsunami/Typhoon - on Alpha boards) - Intel ICH/ICH0/ICH2/ICH3/ICH4/ICH5/ICH6/ICH7/ICH8/ICH9 (82801xx) - Intel 6300ESB, 631xESB/632xESB (ESB2) - Intel Tolapai, ICH10, PCH - Intel PIIX4 (used in many Intel chipsets) - Intel I810/I810E/I815/I845G GMCH - Intel 82443MX (440MX) - NVidia nForce, nForce2, nForce3, nForce4 - ServerWorks OSB4, CSB5, CSB6, HT-1000 - SiS 5595, 630, 645, 655, 730 - SMSC Victory66 - 3Dfx Voodoo 3 and Banshee - VIA Technologies VT82C586B, VT82C596A/B, VT82C686A/B, VT8231, - VT8233, VT8233A, VT8235, VT8237R/A, VT8251, - CX700, VX800/VX820 +See the INSTALL file. -At least the following hardware sensor chips are supported: - Analog Devices ADM1021, ADM1021A, ADM1022, ADM1023, ADM1024, - ADM1025, ADM1026, ADM1027, ADM1030, ADM1031, - ADM1032, ADM9240, ADT7461 and ADT7463 - Asus AS99127F, ASB100 Bach - Dallas Semiconductor DS75, DS1621, DS1625, DS1775, and DS1780 - Hewlett Packard Maxilife (several revisions including '99 NBA) - Fintek F71805F/FG - Fujitsu Siemens Poseidon, Scylla, Hermes - Genesys Logic GL518SM, GL520SM, GL523SM - Intel Xeon processor embedded sensors - ITE IT8705F, IT8712F - Maxim MAX1617, MAX1617A, MAX1619, MAX6650, MAX6651, - MAX6633, MAX6634, MAX6635, MAX6657, MAX6658, MAX6659 - Microchip TC1068, TCM1617, TCN75 - Myson MTP008 - National Semiconductor LM63, LM75, LM76, LM78, LM78-J, LM79, - LM80, LM81, LM82, LM83, LM84, LM85, LM86, LM87, - LM89, LM90, LM92, LM93, LM99, PC87360, - PC87363, PC87364, PC87365, PC87366 - Philips NE1617, NE1617A, NE1619 - SiS 5595, 950 embedded sensors - SMSC 47M1xx embedded sensors, EMC6D100, EMC6D101, EMC6D102 - TI THMC10 and THMC50 - VIA Technologies VT1211, VT8231 and VT82C686A/B embedded sensors - Winbond W83781D, W83782D, W83783S, W83791D, W83792D, - W83627HF, W83627THF, W83637HF, W83687THF, W83697HF, - W83627EHF/EHG +HARDWARE SUPPORT +---------------- - -We also support some miscellaneous chips: - Dallas DS1307 real time clock - Intel Xeon processor embedded EEPROMs - Linear Technologies LTC1710 - Philips Semiconductors PCF8574, PCF8591 - DDC Monitor embedded EEPROMs - SDRAM Dimms with Serial Presence Detect EEPROMs - Smart Battery sensors - IPMI-BMC sensors - Philips Semiconductors SAA1064 - - -The list above may be out of date; -see our Devices page at http://www.lm-sensors.org/wiki/Devices -for the latest information on supported devices. -You may also refer to doc/chips/SUMMARY for details on what each chip -can monitor. - - -We always appreciate testers. If you own a specific monitoring chip we do -not yet (properly) support, and are willing to help us out, please contact -us. Even if you have no programming knowledge, you could help us by running -new modules and reporting on the results and output. If you want to offer -more substantial help, this is very welcome too, of course. - - -Don't ask us whether we support a particular mainboard; we do not know. -We *do* know what hardware we support, but usually, it is easier to -install everything and run sensors-detect. It will tell you what hardware -you have (and incidentally, what corresponding drivers are needed). - - -SMBus, also known as System Management Bus, is a protocol for communicating -through a I2C ('I squared C') bus. Many modern mainboards have a System -Management Bus. There are a lot of devices which can be connected to a -SMBus; the most notable are modern memory chips with EEPROM memories and -chips for hardware monitoring. +To find out what hardware you have, just run 'sensors-detect' as root. Most modern mainboards incorporate some form of hardware monitoring chips. These chips read things like chip temperatures, fan rotation speeds and voltage levels. There are quite a few different chips which can be used by mainboard builders for approximately the same results. -Hardware monitoring chips often have an SMBus or I2C interface. Some are -connected to ISA bus instead. Some of them can do both, in which case we -either support both access methods (old drivers) or only support ISA -access (new drivers) as it is faster. +Laptops, on the other hand, rarely expose any hardware monitoring +chip. They often have some BIOS and/or ACPI magic to get the CPU +temperature value, but that's about it. For such laptops, the lm-sensors +package is of no use (sensors-detect will not find anything), and you have +to use acpi instead. -Because the SMBus is just a special case of the generalized I2C bus, we can -simulate the SMBus protocol on plain I2C busses. These busses are sometimes -used in other parts of your computer. If a supported chip is attached to -one of these additional busses, they can be used too. +This package doesn't contain chip-specific knowledge. It will support all +the hardware monitoring chips your kernel has drivers for. In other words, +if you find out that you have unsupported hardware (e.g. sensors-detect +told you so) then it means that you need a more recent kernel, or you +even need to wait for a new kernel driver to be written. Updating the +lm-sensors package itself will not help. -Please read INSTALL before trying to compile and install these modules. -There is a lot of additional documentation in the doc/ subdirectory. + +LIBSENSORS +---------- + +The kernel drivers communicate their information through the /sys +interface. Because every motherboard is different, the drivers always +advert the measurements at their pins. This means that the values they +report are not always immediately relevant to you. They have to be +labelled properly, and sometimes they must be scaled to correspond to +real-world values. + +libsensors is a (shared or static) library of access functions. It +offers a simple-to-use interface for applications to access the sensor +chip readings and configure them as you like. It has a configuration +file where you can put all the motherboard-specific labels and +conversion rules. That way, all applications do not need to duplicate +the effort and can simply link with libsensors and work out of the box. + + +APPLICATIONS +------------ + +This package contains an example console program that reports all current +sensors values. This program is called 'sensors'. You can use it as a +reference implementation for more intricate programs. It also contains a +daemon watching for sensor values, logging alarms and feeding an RRD +database with the sensor measurements. + +This package does not contain a nice graphical monitor. See +http://www.lm-sensors.org/wiki/UsefulLinks for pointers to such programs. + + +OTHER INFORMATION +----------------- The developers of this package can be reached through a mailing-list (see http://www.lm-sensors.org/wiki/AuthorsAndContributors). Do not hesitate to mail us if you have questions, suggestions, problems, want to contribute, or just want to report it works for you. But please try to -read the documentation and FAQ before you ask any questions! +read the documentation before you ask any questions! It's all under doc/. +Also make sure you read the FAQ at http://www.lm-sensors.org/wiki/FAQ. The latest version of this package can always be found at: http://www.lm-sensors.org/wiki/Download. Pre-release versions can be @@ -168,8 +106,3 @@ Note that libsensors falls under the GPL, not the LGPL. In more human language, that means it is FORBIDDEN to link any application to the library, even to the shared version, if the application itself does not fall under the GPL. - - ------ -[1] SMBus is a trademark of Intel Corporation -[2] I2C is a trademark of Philips Corporation diff --git a/README.directories b/README.directories deleted file mode 100644 index a2b996ec..00000000 --- a/README.directories +++ /dev/null @@ -1,18 +0,0 @@ -The directories within this package: - -* doc - Documentation about the modules within this package, and all other things. -* etc - A sample configuration file for the 'sensors' program. -* kernel - The kernel modules: I2C/SMBus master drivers, and sensor chip drivers. -* lib - The user-space sensors support library code. -* mkpatch - A script for creating a kernel patch. -* prog - Several supporting programs. Includes programs for detecting installed - hardware and recommending specific modules to install. - Also includes programs to report sensor readings, for use - after the package has been installed. - Some of these use the sensors support library, some do not. diff --git a/README.patches b/README.patches deleted file mode 100644 index 70c2888e..00000000 --- a/README.patches +++ /dev/null @@ -1,30 +0,0 @@ -These patches were pre-made using the i2c and lm_sensors packages. - -In this document, the example version used of this patch is -lm_sensors-2.4.0-i2c-kernel-2.2.12. Your actual version may be -newer than this. - -To use: - -* Download a virgin kernel distribution of the exact version as - this patch distribution. - -* Unpackage and install the kernel source, but do not configure - or 'make' it yet. - -* Apply the I2C patch, for example: - -# patch -d /usr/src/linux -p1 < lm_sensors-2.4.0-i2c-kernel-2.2.12.patch - -* Apply the Lm_sensors patch, for example: - -# patch -d /usr/src/linux -p1 < lm_sensors-2.4.0-lm-kernel-2.2.12.patch - - -The patches must be applied in this order: i2c then lm_sensors - - -Enjoy! - - --- The Lm_sensors Development Team diff --git a/README.thinkpad b/README.thinkpad deleted file mode 100644 index 7ef1b733..00000000 --- a/README.thinkpad +++ /dev/null @@ -1,108 +0,0 @@ - -**** WARNING: IBM Thinkpad users should not install lm_sensors! **** - -The eeprom of some IBM Thinkpads has been corrupted after installing -lm_sensors. - -In our releases through 2.6.4, sensors-detect (our userspace detection script) -corrupts the Atmel 24RF08 eeprom. We have verified this in testing. -After the eeprom is corrupted, the checksum verification in the BIOS -will fail and the Thinkpad will not boot. - -The 24RF08 is an 8K eeprom appearing at addresses 0x54 - 0x57 with -an additional "access protection page" at address 0x5c. -This is an unusual eeprom that contains a RFID (Radio Frequency ID) -port for wireless access, and elaborate access protection mechanisms. -The 24RF08 gets confused (presumably due to a state machine flaw) by -the 'quick write 0' (*) probes our package uses for detection. -This behavior is in violation of the I2C specification. This corruption -mechanism has never been reported to us on any other eeprom, -Atmel or otherwise. - -We made several changes in release 2.6.5 (released September 15, 2002) -to minimize the chance of corruption. -Later evolutions were made and the current state is: - -1) The probing command (quick write 0) has been replaced by a different - command (read byte) for addresses where eeproms are known to live. - This should prevent corruption of 24RF08 eeproms in any system, - IBM or not. A similar change was made to i2cdetect as well, although - no corruption was ever reported using this tool. - -2) The i2c-piix4 module (the bus driver that is used for Intel PIIX4-based - systems, including IBM Thinkpads) now accesses DMI information - in the BIOS to identify the system manufacturer. If the system - manufacturer is IBM, i2c-piix4 will print a message and exit. - As the 24RF08 is on the PIIX4 SMBus, this prevents access to - the 24RF08. - -3) The sequence of probes in the eeprom module (when loaded with - checksum=1) has been changed so that 24RF08 eeproms will - not be corrupted. This *should* prevent corruption of 24RF08 - eeproms in non-IBM systems. - We do not have any reports of this corruption mechanism in releases - 2.6.4 or earlier but have verified that it can happen. - The ddcmon driver was changed in the same way, just in case. - -Even with these changes, we still DO NOT RECOMMEND INSTALLING -lm_sensors 2.6.5 or later on IBM Thinkpads, because: - -1) While these changes will dramatically reduce the chance of 24RF08 - corruption, these changes have not been heavily tested. - -2) lm_sensors won't run on most IBM systems because of these changes. - -3) Most IBM Thinkpads contain a proprietary Embedded Controller which - is used to access sensors. This controller is not on the SMBus, - and IBM will not release the programming interface to the - controller. So lm_sensors isn't useful on these Thinkpads anyway. - -You may want to try ACPI instead, it should let you get some information -about temperatures and fan status. - -As described above, our 2.6.5 release "blacklisted" all IBM systems. -For a moment, we have been planning to refine the system detection -so that only those models containing 24RF08's are blacklisted. After that, -we planned to use a different approach: a "white list" of known-to-be-safe -systems. In both cases, it would require continuous updates of a machines -list. This would have been slow and inefficient. - -The latest idea is to stop using the dangerous command for EEPROM -addresses. That way, risks of corruption are reduced to zero. This was -already done for user-space tools, as mentioned above. Once this will -have been tested and we are sure that there are no drawbacks, we'll -do the same on the kernel side in Linux 2.6. The change won't occur in -Linux 2.4 however, because it implies changes to both i2c modules and -lm_sensors modules. It is possible to use mismatching versions of -these modules, and when doing so, the fix would become more dangerous -than helpful. - -We do not have any reports of 24RF08 eeproms on non-IBM systems. -If there are any such systems with 24RF08 eeproms, these changes will -reduce the chances of corruption. However, there are -theoretical scenarios (involving multiple bus masters, -SMP systems, or simultaneous bus access) in which 24RF08's could -still be corrupted. If you know of any non-IBM systems which contain -these eeproms, please contact us. - - -Thanks to IBM, the Linux Thinkpad Mailing List, and Joe in Australia -for their assistance on this issue. - -For more information, see: - -The Linux Thinkpad Mailing List -http://www.bm-soft.com/~bm/tp_mailing.html - -Joe in Australia's Thinkpad Password Recovery Site -http://www.ja.axxs.net/unlock/ - -Atmel 24RF08 Datasheet -http://www.atmel.com/dyn/products/product_card.asp?part_id=2370 - -Site in the US that sells replacement AT24RF08 chips for all models -http://www.pwcrack.com/ - - -(*) 'Write Quick 0' is not an actual write and should never generate - a write operation to an eeprom location. diff --git a/TODO b/TODO deleted file mode 100644 index e762234c..00000000 --- a/TODO +++ /dev/null @@ -1,104 +0,0 @@ -LM-Sensors TODO list -Contact us if you have comments or wish to help. ------------------------------------------------- - -KERNEL MODULES -============== - -* Harmonize 'smart fan' support. - The following drivers support pwm. The ones that support - automatic or smart fan support are identified. - We have a /proc standard for manual PWM support that allows - for /proc based applications like pwmconfig and fancontrol - in our package. - Without a /proc standard for smart fan support such applications - are much more difficult. - - Driver Manual PWM Smart fan - adm1026 standard not supported - asb100 standard ?? - it87 non-std yes - lm85 standard yes - vt1211 doesn't work not supported - w83627hf standard not supported - w83781d standard not supported (791 only) - - The following drivers are for chips that have manual PWM only. - - Driver Manual PWM - mtp008 standard - smsc47m1 standard - vt8231 standard - w83781d (except 791d) standard - -* Assistance on how to fix module refcounting is welcome. - To my understanding, it does not handle client->adapter->owner - correctly now, and it is possible to rmmod adapter while one of its - clients is in use. - -* "uninstall" Makefile target. - -* ACPI and SMBus host - - ACPI subsystem may access SMBus host too. Locks? - - On my ancient board using i2c-via, suspend and power switch status - seems to be in the same register with SCL and SDA. - -* Suspend-to-disk, losing Vcc - - Reset i2c client to avoid alarms and SCI interrupts. Currently - sensors do not create interrupt with alarms. - -* Return from suspend - - Reinitialize i2c client. - -* Handle -1 returns from i2c layer rather than just delivering 0xFF to - /proc and libsensors; report errors through /proc 'alarms' or - new 'fail' entry? See adm1021 for a partial example. - -* ALL: cleanup_module is void; check also that cleaning up is done - properly, now we know that the module will be unloaded whatever we - do. - -* ALL chip drivers: add a readonly insmod option so we don't cause APM/ACPI - to go insane. - -* gl518sm: using iterate==2 causes a tread to be started. this thread remains - even after setting iterate==1 and/or removing the gl518sm module - - -* LM78 detection: Tom Webster has proven that the reset bit in the - id register can be one (strange!) - -* maxilife.c: Introduce new insmod variables - -* maxilife.c: Round REG_TO_VID correctly - -* Support 10-bit addresses. At this moment, they are supported nowhere, except - in Simon Vogl's i2c modules. - -* adm9240: check whether the current voltage computations are correct. - Probably not, as they are different from the datasheet specifications. - Also check for the supported dallas chip. - -* lm80: Check how OS alarms work. At page 17 of the sheet, it tells - something completely different from the description at page 25. - - -LIBRARY -======= - -* Easier use of /proc and libsensors without knowing the chip type - At the moment a programmer wishing to use the lm_sensors package needs to know - what chips are supported and needs to add all those chips into his package. - If you were to add a field or function to your structures to the effect of - sensor-function a programmer could use the package a lot more simply. - For values you could do something like - - enum sensor-type { volt, fan, temp, volt_min, volt_max, fan_div, fan_min, - temp_over, temp_hyst } - -* Some library routines are pretty inefficient right now. - -* Library should be split in more separate files, for better linking - behaviour. - -* Some adm9240 labels start with a digit; change this, it leads to confusing - syntax in the conf file (they have to be quoted) diff --git a/doc/FAQ b/doc/FAQ deleted file mode 100644 index 65e3488e..00000000 --- a/doc/FAQ +++ /dev/null @@ -1,1582 +0,0 @@ -Short Contents -************** - -lm_sensors -1 PC and Sensor Overview -2 Sensor and Bus Basics -3 Installation and Management -4 Problems -5 How to Ask for Help -6 How to Contribute -Appendix A Revision History of This Document - - -Table of Contents -***************** - -lm_sensors -1 PC and Sensor Overview - 1.1 What sensors are available on my PC? - 1.2 What can a sensor chip like the "LM78" do? - 1.3 Where do I find out more about any of these chips? -2 Sensor and Bus Basics - 2.1 How are these sensors read? - 2.2 What is the SMBus? And the I2C bus? - 2.3 I don't have an ISA bus! - 2.4 What sensors do processors have? - 2.5 How often are the sensor values updated? - 2.6 How are alarms triggered? -3 Installation and Management - 3.1 Why so many modules, and how do I cope with them? - 3.2 How do I know which chips I own? - 3.2.1 What chips are on motherboard XYZ? - 3.2.2 Do you support motherboard XYZ? - 3.2.3 Do you support chip XYZ? - 3.2.4 Anybody working on a driver for chip XYZ? - 3.3 Which modules should I insert? - 3.4 Do I need the configuration file `/etc/sensors.conf'? - 3.4.1 The labels for the voltage and temperature readings in `sensors' are incorrect! - 3.4.2 The min and max for the readings in `sensors' are incorrect! - 3.4.3 The min and max settings in `/etc/sensors.conf' didn't take effect! - 3.4.4 One sensor isn't hooked up on my board! - 3.4.5 I need help with `sensors.conf'! - 3.4.6 Do you have a database of `sensors.conf' entries for specific boards? - 3.5 What about the `No such file or directory' warnings when I compile? - 3.6 I get all kinds of weird compilation errors? - 3.6.1 `No rule to make target xxxx needed by xxxx' - how to fix? - 3.7 It still does not compile or patch! - 3.8 `make install' fails on Mandrake kernels - 3.9 I get unresolved symbols when I `modprobe' modules (Red Hat especially) - 3.10 I2C_DRIVERID_ADM1024 undefined (Red Hat especially) -4 Problems - 4.1 My fans report exactly half/double their values compared to the BIOS? - 4.1.1 Fans sometimes/always read 0!! - 4.1.2 I doubled the fan divisor and the fan still reads 7000! - 4.2 Why do my two LM75's report "-48 degrees"? - 4.3 Why do I have two Vcore readings, I have only one processor! - 4.4 How do those ALARMS work? The current value is within range but there is still an ALARM warning! - 4.5 My voltage readings seem to drift a bit. Is something wrong? - 4.6 Some measurements are way out of range. What happened? - 4.6.1 -5V and -12V readings are way out of range! - 4.7 What are VID lines? Why is the VID reading wrong? - 4.8 I read sensor values several times a second, but they are only updated only each second or so. Why? - 4.9 It sometimes seems to take almost a second before I see the sensor reading results. Why? - 4.10 Can I be alerted when an ALARM occurs? - 4.11 SMBus transactions on my PIIX4 simply don't work (timeouts happen). Why? - 4.12 My BIOS reports a much higher CPU temperature than your modules! - 4.13 I try to read the raw `/proc' files, but the values are strange?!? - 4.14 How do I set new limits? - 4.14.1 I set new limits and it didn't work? - 4.15 Some sensors are doubly detected? - 4.16 I ran sensors-detect, but now I get very strange readings?!? - 4.17 Bad readings from particular chips - 4.17.1 Bad readings from the AS99127F! - 4.17.2 Bad readings from the VIA 686A! - 4.17.3 Bad readings from the MTP008! - 4.17.4 Bad temperature readings from the SIS5595! - 4.17.5 Bad readings from a w8378[12]d! - 4.17.6 Bus hangs on Ali 1543 on Asus P5A boards! - 4.17.7 Bad readings from LM75! - 4.17.8 Bad readings from LM78! - 4.17.9 Bad readings from LM80! - 4.18 How do I configure two chips (LM87) differently? - 4.19 Dmesg says `Upgrade BIOS'! I don't want to! - 4.19.1 Dmesg says `use force_addr=0xaddr'! What address do I use? - 4.20 Sensors says `Can't access procfs/sysfs file' - 4.21 Sensors says `No sensors found!' - 4.22 Sensors output is not correct! - 4.23 What is at I2C address XXX? - 4.23.1 What is at I2C address 0x69? - 4.23.2 What is at I2C addresses 0x50 - 0x57? - 4.23.3 What is at I2C addresses 0x30 - 0x37? - 4.24 Sensors-detect doesn't work at all - 4.24.1 Sensors-detect says "Couldn't open /proc/bus/i2c?!?" - 4.24.2 Sensors-detect says "Can't open /dev/i2c[-/]0" - 4.24.3 Sensors-detect doesn't find any sensors! - 4.25 Sensors says `Error: Line xxx: zzzzzzz' - 4.26 Sensors only gives the name, adapter, and algorithm for my chip - 4.27 Sensors says `ERROR: Can't get xxxxx data!' - 4.28 Sensors doesn't find any sensors, just eeproms. - 4.29 Inserting modules hangs my board - 4.30 Inserting modules slows down my board - 4.31 Problems on particular motherboards - 4.31.1 Asus P4B - 4.31.2 Tyan 2460, 2462 - 4.31.3 Tyan 2466 - 4.31.4 Tyan 2688 - 4.32 Problems on particular systems - 4.33 Problems on 2.6 kernels - 4.33.1 i2c-viapro and via686a - 4.33.2 Where are my EEPROMs? -5 How to Ask for Help - 5.1 What to send us when asking for help - 5.2 What to do if a module won't insert? - 5.3 What to do if it inserts, but nothing happens? - 5.4 What to do if I read only bogus information? - 5.5 What to do if you have other problems? - 5.6 What if it just works like a charm? - 5.7 How do I update a ticket? - 5.8 How do I follow up on a ticket? - 5.9 Why did you decide not to support undocumented chips? -6 How to Contribute - 6.1 How to write a driver - 6.2 How to get SVN access - 6.3 How to donate hardware to the project - 6.4 How to join the project mailing lists - 6.5 How to access mailing list archives - 6.6 How to submit a patch - 6.7 How to REALLY help - 6.8 How to get release announcements -Appendix A Revision History of This Document - - -lm_sensors -********** - -The lm_sensors package includes a collection of modules for general -SMBus access and hardware monitoring. NOTE: this requires special -support which is not in standard 2.2-vintage kernels. - -1 PC and Sensor Overview -************************ - -1.1 What sensors are available on my PC? -======================================== - -Most PC's built since late 1997 now come with a hardware health -monitoring chip. This chip may be accessed via the ISA bus or the -SMBus, depending on the motherboard. - - Some motherboard chipsets, notably the Via 686 and the SiS 5595, -contain hardware monitor functions. - - This FAQ frequently refers to the "LM78". This chip has been -obsoleted by National Semiconductor. Most motherboards today contain a -chip with similar functions. - -1.2 What can a sensor chip like the "LM78" do? -============================================== - -The LM78 is a chip made by National Semiconductor which can monitor 7 -voltages (5 positive, 2 negative) from 0 to 4.08V. The inputs are -usually in series with voltage dividers which lower the +/- 12V and +/- -5V supplies to measurable range. Therefore, the readings for such -inputs need to be re-scaled appropriately by software. - - The LM78 also has 3 fan speed monitoring inputs, an internal -temperature sensor, a chassis intrusion sensor, and a couple maskable -interrupt inputs. The LM78 can also relay the processor's (P6 or Pent -II) VID lines which are hardwired and used to indicate to the power -regulator (usually on the mainboard close to the processor socket/slot) -what voltage to supply to the processor. - - The LM78 can be interfaced to a system via the ISA bus and/or the -SMBus. - - Most other sensor chips have comparable functionality. Each supported -chip is documented in the `doc/chips' directory. - -1.3 Where do I find out more about any of these chips? -====================================================== - -Most semiconductor companies have comprehensive documentation, -including complete datasheets, on their websites. Analog Devices, -Dallas Semiconductor, Maxim, and National Semiconductor have the widest -selection of sensor chips. Their websites are: - - * `http://www.analog.com' - - * `http://www.dalsemi.com' - - * `http://www.maxim-ic.com' - - * `http://www.national.com' - - Please see the file `http://www.lm-sensors.org/wiki/UsefulLinks' for -links to other companies' websites. - -2 Sensor and Bus Basics -*********************** - -2.1 How are these sensors read? -=============================== - -Sensor chips reside on either the ISA bus, the SMBus, or both. See the -file `doc/chips/SUMMARY' in our package for a list. - - To communicate with chips on the ISA bus, the software uses simple -I/O reads and writes. - - To communicate with chips on the SMBus, the software must use an -SMBus interface device, explained below. - -2.2 What is the SMBus? And the I2C bus? -======================================= - -The SMBus is the "System Management Bus". More specifically, it is a -2-wire, low-speed serial communication bus used for basic health -monitoring and hardware management. It is a specific implementation of -the more general I2C (pronunciation: I-squared-C) bus. In fact, both -I2C devices and SMBus devices may be connected to the same (I2C) bus. - - The SMBus (or I2C bus) starts at the host controller, used for -starting transactions on the SMBus. From the host interface, the -devices communicated with are the "slave" devices. Each slave device -has a unique 7-bit address which the host uses to refer to that device. - - For each supported SMBus host, there is a separate kernel module -which implements the communication protocol with the host. Some SMBus -hosts really operate on the SMBus level; these hosts can not cope with -pure I2C devices. Other hosts are in fact I2C hosts: in this case, we -implement the SMBus protocol in terms of I2C operations. But these -hosts can also talk to pure I2C devices. - -2.3 I don't have an ISA bus! -============================ - -We promise, you do, even if you don't have any old ISA slots. The "ISA -Bus" exists in your computer even if you don't have ISA slots; it is -simply a memory-mapped area, 64KB in size (0x0000 - 0xFFFF) where many -"legacy" functions, such as keyboard and interrupt controllers, are -found. It isn't necessarily a separate physical bus. See the file -`/proc/ioports' for a list of devices living on the "ISA Bus" in your -system. If you don't like the term "ISA Bus" think "I/O Space". - -2.4 What sensors do processors have? -==================================== - -Most new processors contain a thermal diode on the die itself. The -electical properties of all diodes and transistors vary slightly with -temperature. The thermal diode is exceptionally accurate because it is -directly on the die. Newer temperature sensor chips, like the Analog -Devices ADM1021 and clones, and the Winbond chips, have circuitry for -measuring the the electrical properties of an external diode and -converting this data to a temperature. Any sensor chip listed in -`doc/chips/SUMMARY' in our package which has support for more than one -temperature supports external temperature sensing. - - Older motherboards and processors without this feature generally use -an LM75 placed close to the processor. This is much less accurate. - - The Pentium 2 'boxed' processor usually has an LM75 very close to the -base of the box. It can be read through the SMBus to report the -approximate temperature of the processor. The processor also contains -an internal temperature sensor (of low accuracy) used as a fail-safe to -disable the processor in case it gets much too hot (usually around 130 -degrees C). And, the Pentium 2 also has a hard-wired signal (VID -lines) on it's SEC (single edge connector) which indicates what power -supply is required to operate the processor. - - The P6 (Pentium-Pro) may have an LM75 in or just under the socket. -P6's also have VID lines. - - Pentiums and Pentium w/ MMX do not have VID lines, and sometimes have -LM75's under the sockets (depends on the mainboard, and how 'modern' the -mainboard is). - - The P2 Xeon was the first Intel processor to include the SMBus -interface on the P2 Xeon SEC. - -2.5 How often are the sensor values updated? -============================================ - -The LM78, and most other sensor chips like it, reads its sensors one by -one. A complete scanning sweep will take about 1.5 seconds. The LM78 -stops readings sensors if you try to access it, so if you access it -very often (by reading sensor values; writing new limits is safe) it -will not find the time to update its sensor values at all! Fortunately, -the kernel module takes care not to do this, and only reads new values -each 1.5 seconds. If you read the values again, you will get the 'old' -values again. - -2.6 How are alarms triggered? -============================= - -It is possible to monitor each sensor and have an alarm go off if it -crosses some pre-determined limits. There are two sorts of interrupts -which can be generated by sensor chips if this happens (it depends a -bit on the actual chip if both are supported; the LM80, for example, -has only IRQ interrupts): IRQ interrupts and SMI interrupts. IRQ -stands for Interrupt Request and are the interrupt lines you can find -in `/proc/interrupts'. SMI stands for System Management Interrupt, and -is a special interrupt which puts the processor in a secure environment -independent of any other things running. SMI is currently not -supported by the Linux kernel. IRQs are supported, of course. - - Even if no interrupt is generated, some bits in a status register -will be set until the register is read the next time. If the alarm -condition persists after that, the bits will be set on the next -scanning sweep, etc. - - Most drivers in our package do not support interrupts at this time. - -3 Installation and Management -***************************** - -3.1 Why so many modules, and how do I cope with them? -===================================================== - -We tried to make this package as modular as possible. This makes it -easy to add new drivers, and unused drivers will take no precious kernel -space. On the other hand, it can be a bit confusing at first. - - Here are two simple guidelines: - * Run `sensors-detect' and do what it tells you. - - * Always use `modprobe', not `insmod'. - - Further information is in `doc/modules'. - -3.2 How do I know which chips I own? -==================================== - -We have an excellent program that scans all your hardware. It is -called `sensors-detect' and is installed in `/usr/local/sbin' by `make -install'. Just execute this script, and it will tell you. - - Chip detection in the drivers is fairly good. That means that it is -usually harmless to insert more chip drivers than you need. However, -this can still lead to problems, so we do not recommend it. - - If sensors-detect didn't find any sensors, either you don't have -any, or the ones you have, we don't support. (Look at your motherboard -for candidates, then *note Help::) - -3.2.1 What chips are on motherboard XYZ? ----------------------------------------- - -*!!!!!!!!! YES THIS IS THE MOST FREQUENT QUESTION WE GET !!!!!!!!!* - - We have no idea. Here is what you should do: - 1. Run sensors-detect. - - If that doesn't work: - 2. Look at your motherboard. - - 3. Check the manufacturer's website or ask their support - - 4. Check the "links" (http://www.lm-sensors.org/wiki/UsefulLinks) - page on our website (http://www.lm-sensors.org) some good - cross-references. - -3.2.2 Do you support motherboard XYZ? -------------------------------------- - -We don't support boards, we support chips. *Note What chips are on -motherboard XYZ: Section 3.2.1. - -3.2.3 Do you support chip XYZ? ------------------------------- - -This we have good answers for. - * Sorted by Manufacturer: `README' - - * Sorted by Manufacturer: `http://www.lm-sensors.org/wiki/Devices' - - * Sorted by Sensor Driver: `doc/chips/SUMMARY' - -3.2.4 Anybody working on a driver for chip XYZ? ------------------------------------------------ - -Newest Driver Status: `http://www.lm-sensors.org/wiki/Devices' - -3.3 Which modules should I insert? -================================== - -`sensors-detect' will tell you. Take the `modprobe' lines it recommends -and paste them into the appropriate `/etc/rc.d/xxxx' file to be -executed at startup. - - You need one module for each sensor chip and bus adapter you own; if -there are sensor chips on the ISA bus, you also need `i2c-isa.o'. for -each type of chip you own. That's all. On my computer, I could use the -following lines: - * `modprobe i2c-isa' - - * `modprobe i2c-piix4' - - * `modprobe lm78' - - * `modprobe lm75' - - * `modprobe i2c-dev' - - * `sensors -s' - -3.4 Do I need the configuration file `/etc/sensors.conf'? -========================================================= - -Yes, for any applications that use `libsensors,' including the -`sensors' application included in our package. It tells libsensors how -to translate the values the chip measures to real-world values. This is -especially important for voltage inputs. The default configuration file -should usually do the trick. It is automatically installed as -`/etc/sensors.conf', but it will not overwrite any existing file with -that name. - -3.4.1 The labels for the voltage and temperature readings in `sensors' are incorrect! -------------------------------------------------------------------------------------- - -Every motherboard is different. You can customize the labels in the -file `/etc/sensors.conf'. That's why it exists! The default labelling -(in `lib/chips.c' and `/etc/sensors.conf') is just a template. - -3.4.2 The min and max for the readings in `sensors' are incorrect! ------------------------------------------------------------------- - -You can customize them in the file `/etc/sensors.conf'. See above. - -3.4.3 The min and max settings in `/etc/sensors.conf' didn't take effect! -------------------------------------------------------------------------- - -You forgot to run `sensors -s'. See above. - -3.4.4 One sensor isn't hooked up on my board! ---------------------------------------------- - -Use an `ignore' line in `/etc/sensors.conf' so it isn't displayed in -`sensors'. - -3.4.5 I need help with `sensors.conf'! --------------------------------------- - -There is detailed help at the top of that file. - -3.4.6 Do you have a database of `sensors.conf' entries for specific boards? ---------------------------------------------------------------------------- - -No. Good idea though. If you would like to set one up on your website -send us mail and we will set up a link to it. - -3.5 What about the `No such file or directory' warnings when I compile? -======================================================================= - -Don't worry about them. The dependency files (which tell which files -should be recompiled when certain files change) are created -dynamically. They are not distributed with the package. The `make' -program notices they are not there, and warns about that - and the -first thing it will do is generate them. So all is well. - -3.6 I get all kinds of weird compilation errors? -================================================ - -Check that the correct i2c header files are used. Depending on how you -installed, they should be under either `/usr/local/include' or -`/usr/src/linux*/include'. Try to edit the `Makefile' for the other -setting. - -3.6.1 `No rule to make target xxxx needed by xxxx' - how to fix? ----------------------------------------------------------------- - - * *Note I get all kinds of weird compilation errors: Section 3.6, - also try `make clean' in `lm_sensors'. - - * If that doesn't work, try `make clean' in `i2c'. - - * If that doesn't work, try `make clean' in the kernel. - - * Also make sure `/usr/include/linux' points to - `/usr/src/linux/include/linux'. - -3.7 It still does not compile or patch! -======================================= - -Have you installed the matching version of the i2c package? Remember, -compilation is not enough, you also need to install it for the header -files to be found! - - If you want to patch the kernel, you will have to apply the i2c -patches first! - -3.8 `make install' fails on Mandrake kernels -============================================ - -Mandrake uses a non-standard `version.h' file which confuses our -`Makefile'. Edit our `Makefile' on the `MODDIR :=' line to hard-code -the module directory. - -3.9 I get unresolved symbols when I `modprobe' modules (Red Hat especially) -=========================================================================== - -Example: - *** Unresolved symbols in /lib/modules/2.4.5/kernel/drivers/i2c/i2c-i810.o - i2c_bit_add_bus_R8c3bc60e - i2c_bit_del_bus_R92b18f49 - - You can also run `depmod -a -e' to see all unresolved symbols. - - These are module versioning problems. Generally you did not compile -against the kernel you are running. Sometimes the Red Hat source you -have is not for the kernel you are running. You must compile our -package against the source for the kernel you are running with -something like `make LINUX=/usr/src/linux-2.4.14'. - - Try the following to be sure: - - * `nm --extern MODULE.o' Filter out the kernel symbols, like - `kmalloc', `printk' etc. and note the number code behind them, - like `printk_R1b7d4074'. If there is no numeric code after them, - note this too. - - * `grep SYMBOL /proc/ksyms' Substitute SYMBOL by the basename of the - symbols above, like `kmalloc', `printk' etc. Note the number code - behind them, or the lack thereof. - - * Compare both sets of symbols. Are they the same? If so, the problem - lies somewhere else. Are they different? If so, you have a module - versioning problem. - -3.10 I2C_DRIVERID_ADM1024 undefined (Red Hat especially) -======================================================== - -In some versions of Redhat, an RPM is included to provide i2c support. -However, this RPM does not place the header files in the kernel -directory structure. When you update kernels, they may persist. To -get rid of these obsolete header files, at a command prompt: - - 1. `rpm -qa | grep i2c' - - 2. Look for `kernel-i2c,' or a similar rpm in the output - - 3. `rpm -ev kernel-i2c' (or the name of the similar package) - If this complains about dependencies, you can try adding - `--nodeps', but this *MAY* break something else. Not likely, as - you have upgraded kernels, and nothing should be using the old i2c - stuff anymore anyway. Just don't use it with abandon. - - 4. Try (in the build directory of `lm_sensors)' - `make clean' - `make' - - 5. _If_ you still have problems, you may have to replace the include - paths in the `.c/.h' files with absolute paths to the header files. - More of a workaround than a real fix, but at least you can get it - to work. - -4 Problems -********** - -4.1 My fans report exactly half/double their values compared to the BIOS? -========================================================================= - -The problem with much of the sensor data is that it is impossible to -properly interpret some of the readings without knowing what the -hardware configuration is. Some fans report one 'tick' each rotation, -some report two 'ticks' each rotation. It is easy to resolve this -through the configuration file `/etc/sensors.conf': - - chip lm78-* # Or whatever chip this relates to - compute fan1 2*@,@/2 # This will double the fan1 reading - # -- or -- - compute fan1 @/2,2*@ # This will halve the fan1 reading - - See `doc/fan-divisors' in our package for further information. - -4.1.1 Fans sometimes/always read 0!! ------------------------------------- - -You may not have a three-wire fan, which is required. - - You may need to increase the 'fan divisor'. See `doc/fan-divisors' -in our package for further information. - -4.1.2 I doubled the fan divisor and the fan still reads 7000! -------------------------------------------------------------- - -Believe it or not, doubling the 'fan divisor' will not halve the fan -reading. You have to add a compute line in `/etc/sensors.conf'. *Note -My fans report exactly half/double their values compared to the BIOS: -Section 4.1, and see `doc/fan-divisors' in our package for further -information. - -4.2 Why do my two LM75's report "-48 degrees"? -============================================== - -For starters, those aren't LM75's. Your mainboard actually has the -Winbond W83781D which emulates two LM75's, but many systems which use -the Winbond chip (such as the Asus P2B) don't have the thermo-resisters -connected to the chip resulting in these strange -48 degree readings. - - In upcoming versions, you will be able to disable non-interesting -readings. - -4.3 Why do I have two Vcore readings, I have only one processor! -================================================================ - -The LM78 has seven voltage sensors. The default way of connecting them -is used in the configuration file. This includes a VCore2, even if you -do not have one. You can easily edit the configuration file to give it -another name, or make this reading disappear using an `ignore' line. - - Note that Vcore2 is often the same as Vcore on motherboards which -only support one processor. Another possibility is that Vcore2 is not -connected at all and will not have a valid reading at all. A third -possibility, is that Vcore2 monitors something else, so you should not -be too surprised if the values are completely different. - -4.4 How do those ALARMS work? The current value is within range but there is still an ALARM warning! -==================================================================================================== - -The ALARM indications in `sensors' are those reported by the sensor -chip itself. They are NOT calculated by `sensors'. `sensors' simply -reads the ALARM bits and reports them. - - An ALARM will go off when a minimum or maximum limit is crossed. -The ALARM is then latched - that is, it will stay there until the -chip's registers are next accessed - which will be the next time you -read these values, but not within (usually) 1.5 seconds since the last -update. - - Reading the registers clears the ALARMS, unless the current value is -still out of range. - - The purpose of this scheme is to tell you if there has been a -problem and report it to the user. Voltage or temperature spikes get -detected without having to read the sensor chip hundreds of times a -second. The implemetation details depend a bit on the kind of chip. -See the specific chip documentation in `doc/chips' and the chip -datasheet for more information. - -4.5 My voltage readings seem to drift a bit. Is something wrong? -================================================================ - -No, probably not. If your motherboard heats up a bit, the sensed -voltages will drift a bit. If your power supply is loaded (because a -disk gets going, for example), the voltages may get a bit lower. Heavy -processor activity, in particular, dramatically increases core voltage -supply load which will often cause variation in the other supplies. As -long as they stay within a sensible range (say 5% of the nominal value -for CPU core voltages, and 10% for other voltages), there is no reason -to worry. - -4.6 Some measurements are way out of range. What happened? -========================================================== - -Each module tries to set limits to sensible values on initialization, -but a module does not know how a chip is actually connected. This is -described in the configuration file, which is not read by kernel -modules. So limits can be strange, if the chip is connected in a -non-standard way. - - Readings can also be strange; there are several reasons for this. -Temperature sensors, for example, can simply not be present, even though -the chip supports them. Also, it can be that the input is used in a -non-standard way. You can use the configuration file to describe how -this measurement should be interpreted; see the comments the example -file for more information. - -4.6.1 -5V and -12V readings are way out of range! -------------------------------------------------- - -It's very frequent that negative voltage lines are not wired because -motherboard manufacturers don't think they're worth monitoring (they -are mostly unused these days). You can just add `ignore inN' lines to -`/etc/sensors.conf' to hide them. - - Another possibility is that these lines are used to monitor different -voltages. Only the motherboard manufacturer can tell for sure. Taking a -look at what voltage values the BIOS displays may provide valuable -hints though. - -4.7 What are VID lines? Why is the VID reading wrong? -===================================================== - -These describe the core voltage for your processor. They are supported -for most processors, however they are not always correctly connected to -the sensor chip, so the readings may be invalid. A reading of 0V, -+3.5V or +2.05V is especially suspect. If this is the case, add a line -`ignore vid' to `/etc/sensors.conf', and change the min and max -settings for the Processor Core voltage (often in0_min and in0_max) in -that file so that they don't depend on vid. - - The CPU nominal voltage is computed from VID lines according to a -formula that depends on the CPU type. Most chips that report a VID -value can be configured to use either VRM 8.2 (for Pentium III) or VRM -9.0 (for Pentium 4 and Athlon). You chose which one you want through -`/etc/sensors.conf'. See `doc/vid' for more information. - -4.8 I read sensor values several times a second, but they are only updated only each second or so. Why? -======================================================================================================= - -If we would read the registers more often, it would not find the time -to update them. So we only update our readings once each 1.5 seconds -(the actual delay is chip-specific; for some chips, it may not be needed -at all). - -4.9 It sometimes seems to take almost a second before I see the sensor reading results. Why? -============================================================================================ - -ISA bus access is fast, but SMBus access is really slow. If you have a -lot of sensors, it just takes a lot of time to access them. Fortunately, -this has almost no impact on the system as a whole, as another job can -run while we are waiting for the transaction to finish. - -4.10 Can I be alerted when an ALARM occurs? -=========================================== - -No, you can't; and it may well be never supported. - - Almost no mainboard we have encountered have actually connected the -IRQ-out pin of sensor chips. That means that we could enable IRQ -reporting, but nothing would happen. Also, even if a motherboard has it -connected, it is unclear what interrupt number would be triggered. And -IRQ lines are a scarce facility, which means that almost nobody would -be able to use it anyway. - - The SMI interrupt is only available on a few types of chips. It is -really a very obscure way to handle interrupts, and supporting it under -Linux might be quite hard to do. - - Your best bet would be to poll the alarm file with a user-land daemon -which alerts you if an alarm is raised. I am not aware of any program -which does the job, though you might want to examine one of the -graphical monitor programs under X, see -`http://www.lm-sensors.org/wiki/UsefulLinks' for addresses. - -4.11 SMBus transactions on my PIIX4 simply don't work (timeouts happen). Why? -============================================================================== - -Some chips which mainboard makers connect to the SMBus are not SMBus -devices. An example is the 91xx clock generator chips. When read, -these devices can lock up the SMBus until the next hard reboot. This -is because they have a similar serial interface (like the I2C), but -don't conform to Intel's SMBus standard. - - Why did they connect these devices to the SMBus if they aren't -compatible? Good question! :') Actually, these devices may support -being written to, but lock things up when they are read. - -4.12 My BIOS reports a much higher CPU temperature than your modules! -===================================================================== - -We display the actual temperature of the sensor. This may not be the -temperature you are interested in, though. If a sensor should measure -the CPU temperature, it must be in thermal contact with it. In -practice, it may be just somewhere nearby. Your BIOS may correct for -this (by adding, for example, thirty degrees to the measured -temperature). The correction factor is regrettably different for each -mainboard, so we can not do this in the module itself. You can do it -through the configuration file, though: - - chip lm75-*-49 # Or whatever chip this relates to - label temp "Processor" - compute temp @*1.2+13,(@-13)/1.2 # Or whatever formula - - However, the offset you are introducing might not be necessary. If -you tried to have Linux idle temperature and BIOS "idle" temperature -match, you may be misguided. We have a Supermicro (370DLE) motherboard -and we know that its BIOS has a closed, almost undelayed while(1) loop -that keeps the CPU busy all the time. Linux reads 26 degrees idle, BIOS -reads 38 degrees. Linux at full load is in the 35-40 degrees range so -this makes sense. - -4.13 I try to read the raw `/proc' files, but the values are strange?!? -======================================================================= - -Remember, these values do not take the configuration file `compute' -lines in account. This is especially obvious for voltage readings -(usually called in? or vin?). Use a program linked to libsensors (like -the provided `sensors' program) instead. - -4.14 How do I set new limits? -============================= - -Change the limit values in `/etc/sensors.conf' and then run `sensors --s'. - -4.14.1 I set new limits and it didn't work? -------------------------------------------- - -You forgot to run `sensors -s'. Put it in a `/etc/rc.d/...' file after -the modprobe lines to run at startup. - -4.15 Some sensors are doubly detected? -====================================== - -Yes, this is still a problem. It is partially solved by alias detection -and confidence values in sensors-detect, but it is really tough. - - Double detections can be caused by two things: sensors can be -detected to both the ISA and the SMBus (and if you have loaded the -approprate adapter drivers, it will be detected on both), and some -chips simulate other chips (the Winbond W83781D simulates LM75 chips on -the SMBus, for example). Remove the offending adapter or chip driver, or -run sensors-detect and add the `ignore=' modprobe parameters it -suggests. - -4.16 I ran sensors-detect, but now I get very strange readings?!? -================================================================= - -Your SMBus (PIIX4?) is probably crashed or hung. There are some -mainboards which connect a clock chip to the SMBus. Unfortunately, this -clock chip hangs the PIIX4 if it is read (it is an I2C device, but not -SMBus compatible). We have found no way of solving this, except for -rebooting your computer. Next time when you run sensors-detect, you -may want to exclude addresses 0x69 and/or 0x6a, by entering `s' when -you are asked whether you want to scan the PIIX4. - -4.17 Bad readings from particular chips -======================================= - -See below for some particularly troublesome chips. Also be sure and -check `doc/chips/xxxxx' for the particular driver. - -4.17.1 Bad readings from the AS99127F! --------------------------------------- - -The Asus AS99127F is a modified version of the Winbond W83781D. Asus -will not release a datasheet. The driver was developed by tedious -experimentation. We've done the best we can. If you want to make -adjustments to the readings please edit `/etc/sensors.conf.' Please -don't ask us to fix the driver. Ask Asus to release a datasheet. - -4.17.2 Bad readings from the VIA 686A! --------------------------------------- - -The Via 686A datasheet is incomplete. Via will not release details. -The driver was developed by tedious experimentation. We've done the -best we can. If you want to make adjustments to the readings please -edit `/etc/sensors.conf.' Please don't ask us to fix the driver. Ask -Via to release a better datasheet. Also, don't forget to `modprobe -i2c-isa'. - -4.17.3 Bad readings from the MTP008! ------------------------------------- - -The MTP008 has programmable temperature sensor types. If your sensor -type does not match the default, you will have to change it. See -`doc/chips/mtp008' for details. Also, MTP008 chips seem to randomly -refuse to respond, for unknown reasons. You can see this as 'XX' -entries in i2cdump. - -4.17.4 Bad temperature readings from the SIS5595! -------------------------------------------------- - -This chip can use multiple thermistor types and there are also two -different versions of the chip. We are trying to get the driver working -better and develop formulas for different thermistors but we aren't -there yet. Sorry. Also, many times the chip isn't really a sis5595 but -it was misidentified. We are working on improving that too. - -4.17.5 Bad readings from a w8378[12]d! --------------------------------------- - -Do you own an ASUS motherboard? Perhaps your chip is being -misidentified. Look on the motherboard for a 'Winbond' or Asus chip. -Often the real device is an Asus as99127f. If so, the driver can be -forced to recognize the as99127f with `force_as99127f=BUS,0x2d' where -`BUS' is your i2c bus number. Cat /proc/bus/i2c to see a list of bus -numbers. Read the w83781d module documentation (`doc/chips/w83781d') -for more details. - -4.17.6 Bus hangs on Ali 1543 on Asus P5A boards! ------------------------------------------------- - -The SMBus tends to hang on this board and it seems to get worse at -higher temperatures. Use ISA accesses to reliably use the w83781d -monitor chip on this board and use the `ignore=1,0x2d' or similar option -to the w83781d module to prevent i2c accesses. - -4.17.7 Bad readings from LM75! ------------------------------- - -The LM75 detection is poor and other hardware is often misdetected as -an LM75. Figure out what you really have *Note What chips are on -motherboard XYZ: Section 3.2.1. - -4.17.8 Bad readings from LM78! ------------------------------- - -The LM78 is no longer manufactured by National Semiconductor. You -probably don't have a real LM78 but something similar that we do not -recogize or support. Figure out what you really have *Note What chips -are on motherboard XYZ: Section 3.2.1. - -4.17.9 Bad readings from LM80! ------------------------------- - -The LM80 detection is poor and other hardware is often misdetected as -an LM80. Figure out what you really have *Note What chips are on -motherboard XYZ: Section 3.2.1. - -4.18 How do I configure two chips (LM87) differently? -===================================================== - -There is a SuperMicro board with two LM87's on it that are not hooked -up in the same way, so they need different defaults. For example, both -CPU temperatures go to one LM87. - - Make two different sections in `/etc/sensors.conf' as follows: - chip "lm87-i2c-*-2c" - put configuration for the chip at 0x2c here - chip "lm87-i2c-*-2d" - put configuration for the chip at 0x2d here - - There is a commented example in `sensors.conf.eg' which should be -helpful. - -4.19 Dmesg says `Upgrade BIOS'! I don't want to! -================================================ - -If the problem is a PCI device is not present in `lspci', the solution -is complex. For the ALI M7101 device, there is a solution which uses the -2.4 kernel's `hotplug' facility. See `prog/hotplug' in our package. -For other PCI devices, you can try to modify the m7101 solution in -`prog/hotplug'. - - If dmesg says `try force_addr', see below. Other drivers generally -do not support the force_addr parameter. Sorry. Check the documentation -for your driver in `doc/[chips,busses]' and if we don't support it you -can send us your request. - -4.19.1 Dmesg says `use force_addr=0xaddr'! What address do I use? ------------------------------------------------------------------ - -If the problem is a PCI device whose base address is not set, you may -be able to set the address with a force parameter. The via686a and -sis5595 chip drivers, and some bus drivers, support the command line -`modprobe via686a force_addr=0xADDRESS' where ADDRESS is the I/O -address. You must select an address that is not in use. `cat -`/proc/ioports'' to check (carefully) for conflicts. A high number like -0xf000 is generally safe. - -4.20 Sensors says `Can't access procfs/sysfs file' -================================================== - - * Linux 2.6 - * Did you `modprobe i2c_sensor'? Check `lsmod'. - - * Do you have sysfs support in your kernel and `/sys' mounted - (is `/sys' there and populated)? Create /sys with `mkdir - /sys' if needed. Then add the following line to `/etc/fstab': - sys /sys sysfs default 0 0 - and `mount /sys'. - - * Linux 2.4 - * Did you `modprobe i2c-proc'? Check `lsmod'. - - * Do you have procfs support in your kernel and `/proc' mounted - (is `/proc' there and populated)? Create /proc with `mkdir - /proc' if needed. Then add the following line to `/etc/fstab': - proc /proc proc defaults 0 0 - and `mount /proc'. - - * If you did `sensors -s', did you run it as root? - -4.21 Sensors says `No sensors found!' -===================================== - - * Did `sensors-detect' find sensors? (If not *note Sensors-detect - doesnt find any sensors::) - - * Did you do what `sensors-detect' said? - - * Did you `modprobe' your sensor modules? - - * Did you `modprobe' your I2C adapter modules? - - * Did you `modprobe i2c-isa' if you have ISA sensor chips? - - * Check `lsmod'. - -4.22 Sensors output is not correct! -=================================== - -What specifically is the trouble? - * Labels: *Note The labels for the voltage and temperature readings - in sensors are incorrect: Section 3.4.1. - - * Min/max readings: *Note The min and max for the readings in - sensors are incorrect: Section 3.4.2, and *Note The min and max - settings didnt take effect: Section 3.4.3. - - * AS99127F: *Note I ran sensors-detect but now I get very strange - readings?: Section 4.16. - - * Via 686A: *Note I ran sensors-detect but now I get very strange - readings?: Section 4.16. - - * Other specific chips: *Note I ran sensors-detect but now I get - very strange readings?: Section 4.16. - - * No output for a particular sensors chip: *Note What to do if it - inserts but nothing happens: Section 5.3. - - * No output at all: *Note Sensors says No sensors found: Section - 4.21, *Note What to do if it inserts but nothing happens: Section - 5.3. - - * Completely bad output for a particular sensor chip: *Note What to - do if I read only bogus information: Section 5.4. - - * One particular sensor readings: - * Maybe it isn't hooked up? - tell 'sensors' to ignore it. - *Note One sensor isnt hooked up on my board: Section 3.4.4. - - * Maybe it is hooked up differently on your motherboard? - - adjust `sensors.conf' calculation. - -4.23 What is at I2C address XXX? -================================ - -In general, we don't know. Start by running `sensors-detect'. If it -doesn't recognize it, try running `i2cdump'. A partial list of -manufacturers' IDs are at the bottom of `doc/chips/SUMMARY'. - -4.23.1 What is at I2C address 0x69? ------------------------------------ - -A clock chip. Often, accessing these clock chips in the wrong way will -instantly crash your computer. Sensors-detect carefully avoids these -chips, and you should do too. You have been warned. - -4.23.2 What is at I2C addresses 0x50 - 0x57? --------------------------------------------- - -EEPROMs on your SDRAM DIMMs. Load the eeprom module to look at some -basic data in `sensors' or use the program -`prog/eeprom/decode-dimms.pl' to get more information than you ever -wanted. - -4.23.3 What is at I2C addresses 0x30 - 0x37? --------------------------------------------- - -These are often 'shadows' of your EEPROMs on your SDRAM DIMMs at -addresses 0x50 - 0x57. They are the 'software write-protect' registers -of the SDRAM Serial Presence Detect EEPROMs. If you try and do a -`i2cdump' on them to read the location, you won't get anything, because -they contain a single write-only register. This register can be used -to permanently write-protect the contents of the eeprom. - -4.24 Sensors-detect doesn't work at all -======================================= - -It could be many things. What was the problem? *Note Problems on -particular motherboards: Section 4.31. - -4.24.1 Sensors-detect says "Couldn't open /proc/bus/i2c?!?" ------------------------------------------------------------ - -You don't have i2c support in your kernel, or the i2c-core module was -not loaded and you did not run sensors-detect as root. - -4.24.2 Sensors-detect says "Can't open /dev/i2c[-/]0" ------------------------------------------------------ - -Your `/dev/i2c-0,' `/dev/i2c0', or `/dev/i2c/0' files do not exist or -you did not run `sensors-detect' as root. Run the script -`prog/mkdev/mkdev.sh' to create the `/dev/i2c-x' files. Run `devfs' in -the kernel to get the `/dev/i2c/x' files. - -4.24.3 Sensors-detect doesn't find any sensors! ------------------------------------------------ - -Either - 1. The board doesn't have any sensors. - - 2. We don't support the sensors on the board. - - 3. The sensors it has are on an I2C bus connected to an I2C bus - adapter that we don't support. - - 4. You don't have the latest version of lm_sensors. - - But in any case you should figure out what is on the board: - 1. Look at your motherboard. - - 2. Check the manufacturer's website. - - When you know what chips you have, check the Driver Status -(http://www.lm-sensors.org/wiki/Devices) web page to see if support has -been added for your chip in a later release or in SVN. - -4.25 Sensors says `Error: Line xxx: zzzzzzz' -============================================ - -These are errors from the libsensors library in reading the -`/etc/sensors.conf' configuration file. Go to that line number and fix -it. If you have a parse error, perhaps you have to put the feature name -in double quotes. - -4.26 Sensors only gives the name, adapter, and algorithm for my chip -==================================================================== - -If `sensors' only says this, for example, and doesn't provide any -actual data at all: - - it87-isa-0290 - Adapter: ISA adapter - Algorithm: ISA algorithm - - Your chip is not currently supported by `sensors' and so all it does -is print out that information. Get the latest release and be sure you -are running the `sensors' program it installed and not some older -`sensors'. - -4.27 Sensors says `ERROR: Can't get xxxxx data!' -================================================ - - * (Linux 2.6) Make sure you are using one of the recommended - kernel/lm_sensors combination - (http://www.lm-sensors.org/wiki/Kernel2.6). - - * You have a `libsensors'/`sensors' mismatch. `sensors' is unable to - get a data entry from `libsensors'. You probably have an old - `libsensors' in your `/etc/ld.so.conf' path. Make sure you did - (as root) a `make install' (Linux 2.4) or `make user_install' - (Linux 2.6) followed by a `ldconfig'. Then check the output of - `ldconfig -v | grep libsensors' to verify that there is only ONE - `libsensors' entry and that it matches the `libsensors' that was - built in the `lib/' directory in `lm_sensors2'. - -4.28 Sensors doesn't find any sensors, just eeproms. -==================================================== - -*Note Sensors-detect doesnt work at all: Section 4.24, if -`sensors-detect' failed to find any sensors. - - If `sensors-detect' did find sensors, did you insert your modules? -For chips on the ISA bus, did you insert i2c-isa? - - *Note What to do if a module wont insert: Section 5.2, if the -modules didn't insert, also *note Sensors says No sensors found: -Section 4.21. - -4.29 Inserting modules hangs my board -===================================== - -There are several possible causes: - 1. Bus driver problems. Insert the bus driver first, before you have - inserted any chip drivers, to verify. - - 2. Wrong chip driver. Verify that you have a chip supported by the - chip driver, see *note What chips are on motherboard XYZ: Section - 3.2.1. - - 3. The chip driver is reinitializing the chip, which undoes critical - initialization done by the BIOS. Try the parameter `init=0' for - the w83781d driver; this is the only driver supporting this - parameter. - - 4. Some chips on the bus don't like to be probed at all. After - inserting the bus driver (but not the chip drivers), run - `i2cdetect' on the bus, then `i2cdump' on each address responding - to `i2cdetect'. This may find the culprit. Do not `i2cdump - address 0x69', the clock chip. - - 5. The chip driver is incorrectly finding a second chip on the bus - and is accessing it. For example, with the Tyan 2688 with a - w83781d at 0x29, use `modprobe - ignore_range=0,0x00,0x28,0,0x2a,0x7f' to prevent access to other - addresses. (`init=0' also req'd for the Tyan 2688). - -4.30 Inserting modules slows down my board -========================================== - -Generally this is caused by an overtemperature alarm output from the -sensor chip. This triggers hardware on the board which automatically -slows down the CPU clock. Be sure that your temperature limits are -above the temperature reading. Put the new limits in -`/etc/sensors.conf' and run `sensors -s'. - -4.31 Problems on particular motherboards -======================================== - -The following boards have unique problems and solutions. - -4.31.1 Asus P4B ---------------- - -See `prog/hotplug/README.p4b' if your SMBus master is not found. - -4.31.2 Tyan 2460, 2462 ----------------------- - -See support tickets 805, 765, 781, 812, 813, and 867 for information. - -4.31.3 Tyan 2466 ----------------- - -See support tickets 941, 840, and 841 for information. - -4.31.4 Tyan 2688 ----------------- - -For board hangs, see support ticket 721 for information. Also *note -Inserting modules hangs my board: Section 4.29. - -4.32 Problems on particular systems -=================================== - -For IBM systems, see `README.thinkpad'. - -4.33 Problems on 2.6 kernels -============================ - -Not all drivers have been ported to 2.6. If your favorite driver is not -in 2.6, the reason is that nobody has ported it, or the ported code did -not get a proper review yet. If you would like to port the driver, see -the file Documentation/i2c/porting-clients in the 2.6 kernel tree for -help, then send us the ported driver when you are done. - -4.33.1 i2c-viapro and via686a ------------------------------ - -Until kernel 2.6.11, there was a PCI resource conflict between -i2c-viapro (the SMBus driver for VIA bridges) and via686a (the -integrated sensors driver for VIA bridges). This caused the second -loaded driver to silently fail working. So do not load both i2c-viapro -and via686a together unless you have a recent kernel. - -4.33.2 Where are my EEPROMs? ----------------------------- - -The 2.6.14-rc1 kernel introduced the hwmon class, which groups all -hardware monitoring drivers in a logical way. The goal was to help -libsensors grab the relevant sensors information in /sys. In particular: - * libsensors will no more need to know about the underlying bus types - (I2C/SMBus, ISA or other); - - * libsensors will no more list non-hardware monitoring chips. - This explains why EEPROMs are no more displayed by `sensors': they -are no hardware monitoring chips. The medium term plan is to drop -eeprom support for all Linux 2.6 kernels, as it didn't fit well in the -library code in the first place. - - Note that you can still obtain information about your EEPROMs by -using the dedicated perl scripts in `prog/eeprom': `ddcmon', -`decode-dimms.pl', `decode-edid.pl' and `decode-vaio.pl'. - -5 How to Ask for Help -********************* - -5.1 What to send us when asking for help -======================================== - -We are always willing to answer questions if things don't work out. -Post your question to our discussion list -(http://lists.lm-sensors.org/mailman/listinfo/lm-sensors), and not the -individual authors, unless you have something private to say. - - Instead of using email, you can also use the web-based support area, -at `http://www.lm-sensors.org/wiki/FeedbackAndSupport'. You will be -helped just as fast, and others may profit from the answer too. You -will be emailed automatically when your question has been answered. - - Here's what you should send us: - - * The dmesg or syslog output if applicable - - * The output of (as root) `prog/detect/sensors-detect' - - * The output of `lsmod' - - * If a PCI chip problem: - * The output of `lspci -n' - - * If an I2C sensor chip problem: - * The output of (as root) `prog/detect/i2cdetect X' where X = - the bus number (run `i2cdetect' with no arguments to list the - busses) (please send this only if it's not all `XX') - - * If an ISA sensor chip problem: - * The output of (as root) `prog/dump/isadump 0x295 0x296' (only - if it's not all `XX') - - * Part numbers of chips on your motherboard you think are the sensor - chips (look at your motherboard) - - * Motherboard type - - * Sensors version - - * Kernel version - -5.2 What to do if a module won't insert? -======================================== - -Did you use `modprobe' instead of `insmod'??? Don't use insmod. - - Were there unresolved symbols? Did you run `depmod -a'? Run `depmod --a -e' to see where the symbol problem is. - - ALWAYS inspect the output of `dmesg'. That's where the error -messages come out!!! Don't rely on the generic message from `modprobe'. -If you still can't figure it out, send us the information listed above. - -5.3 What to do if it inserts, but nothing happens? -================================================== - -For an ISA sensor chip, did you also `modprobe i2c-isa'? It must be -inserted. - - For an I2C sensor chip, did you also `modprobe i2c-xxx' where xxx is -your I2C bus adapter? It must be inserted. - - Always inspect the output of `dmesg'. That's where the error -messages come out. If you still can't figure it out, send us the -information listed above. - -5.4 What to do if I read only bogus information? -================================================ - -It may be that this was a mis-detection: the chip may not be present. -If you are convinced there is something wrong, verify that you indeed -have the devices on your motherboard that you think you do. Look at -the motherboard and make sure. If you are still stuck, please send us -the usual information (*note Help::) - -5.5 What to do if you have other problems? -========================================== - -Again, send the output listed above. - -5.6 What if it just works like a charm? -======================================= - -Drop us a mail if you feel like it, mentioning the mainboard and -detected chip type. That way, we have some positive feedback, too! - -5.7 How do I update a ticket? -============================= - -You can't. Only developers can. Follow up by emailing us and reference -your ticket number in the subject. Please don't enter a new ticket with -follow-up information, email us instead. Thanks. - -5.8 How do I follow up on a ticket? -=================================== - -Follow up by emailing us and reference your ticket number in the -subject. - -5.9 Why did you decide not to support undocumented chips? -========================================================= - -There are several reasons why we are generally not interested in writing -drivers for undocumented chips: - - * Writing a driver without a datasheet is much harder, as you have to - guess most things. Remember that, most of the time, we write - drivers for fun and for free, so there is no reason we would write - a driver in conditions that promise more pain than fun. - - * If we hit a problem, we are certain never to get any support from - the chip manufacturer. This means that we may spend days on code - which will finally never work. - - * There are several chips out there which are fully documented and - lack a driver. This is natural for us to give these the priority - when we finally have some spare time to spend on driver coding. - - * Hardware monitoring chips are not toys. Misprogramming them can - result in data loss or hardware breakage. This is obviously more - likely to happen with undocumented chips. This is a responsability - we do not want to endorse (the GPL is pretty clear than we are not - legally liable, but still). - - There are also several reasons why we do not want to support such -drivers, even if they were written by other people: - - * Problems are much more likely to happen with such drivers. This - means increased needs of support. User support if very - time-consuming and we are usually short of time. - - * Support should be done by the driver author (as only him/her knows - the driver and chip) but in the reality of facts, people will - always ask us for help if the driver is part of our package. - Redirecting all user requests to the driver's author manually is - boring. - - * The lack of datasheet usually results in an original driver which - works relatively fine for its author, but will happen not to work - completely for other users. This means that the driver will need - many more additions and fixes than other drivers do, resulting in - an increased maitainance workload, which we can hardly afford. Of - course this too should be handled by the original driver author, - but we never know whether he/she will actually do the work. - - Lastly, there are other considerations, some of which are -deliberately political: - - * We do not want to trick hardware buyers into thinking that a chip - is fully supported under Linux when in fact it is only partly - supported by a driver which was written without a datasheet. - Clearly stating that such chips are not supported makes it much - easier for anyone who really needs fully working hardware - monitoring under Linux to avoid motherboards with these partly - supported chips. - - * Drivers written without a datasheet are a pain for developers and - users, but are a complete win for the manufacturers of these chips: - they don't have to write the driver, they don't have to help us, - they don't have to support the users, and they still sell their - hardware. We do not want to encourage such a selfish behavior. - - That being said, authors of such drivers can still submit their code -to the Linux kernel folks for inclusion into Linux 2.6. Their driver -may be accepted there, under conditions. - - If such a driver is ever accepted into the Linux 2.6 tree, and -someone provides a patch to libsensors and/or sensors to add support -for this driver, we will apply it. This generic code is unlikely to -cause trouble. - -6 How to Contribute -******************* - -6.1 How to write a driver -========================= - -See `doc/developers/new_drivers' in our package for instructions. - -6.2 How to get SVN access -========================= - -For anonymous SVN read access, see the instructions on our download -page (http://www.lm-sensors.org/wiki/Download). - - For write access, please contact us. - -6.3 How to donate hardware to the project -========================================= - -Contact us (http://www.lm-sensors.org/wiki/FeedbackAndSupport). - -6.4 How to join the project mailing lists -========================================= - -There are two lists you can subscribe to: - - * A general discussion list - (http://lists.lm-sensors.org/mailman/listinfo/lm-sensors), meant - for both development and user support. You do not need to be - subscribed to post. - - * A CVS commits list - (http://lists.lm-sensors.org/mailman/listinfo/lm-sensors-commit), - for watching the changes made to the CVS repositories. This list - is read-only. - -6.5 How to access mailing list archives -======================================= - -The primary mailing list archive is at: -`http://lists.lm-sensors.org/pipermail/lm-sensors/'. It contains -messages since October 28, 2001. - - There is another mailing list archive at: -`http://news.gmane.org/gmane.linux.drivers.sensors'. It contains -messages since December 31, 2004. This archive may also be accessed -via a news reader: `nntp://news.gmane.org/gmane.linux.drivers.sensors' -and RSS: `http://rss.gmane.org/gmane.linux.drivers.sensors'. - - And last there is a legacy archive at: -`http://archives.andrew.net.au/lm-sensors'. It contains messages from -October 28, 2001 through May 16, 2005. - -6.6 How to submit a patch -========================= - -Check out the latest from CVS, then copy the directory to another -directory, and make your changes. Generate the diff with `diff -u2 -r -DIR1 DIR2'. Or you can generate the diff in CVS with `cvs diff -u2'. -Send us the patch in an email and tell us what it does. - -6.7 How to REALLY help -====================== - -Believe it or not, what we really need help with are: - * Answering email - - * Answering support tickets - - * Porting drivers to Linux 2.6 - - * Creating a sensors.conf database - - * Reviewing patches - - If you are willing to help, simply join our discussion list -(http://lists.lm-sensors.org/mailman/listinfo/lm-sensors), and we'll -help you help us. - -6.8 How to get release announcements -==================================== - -We don't have a separate release announcement mailing list; however, we -put all our releases on freshmeat: `http://freshmeat.net' and you can -register on our freshmeat project page -`http://freshmeat.net/projects/lm_sensors' to 'subscribe to new -releases' and then freshmeat will email you announcement. - -Appendix A Revision History of This Document -******************************************** - - * Rev 2.18 (JD) Removed version 1 specifics part, 2005-12-17 - - * Rev 2.17 (JD) Added 5.9 (why we don't support undocumented chips), - removed 6.9 (doesn't apply to the new mailing list), 2005-10-05 - - * Rev 2.16 (JD) Added 4.33.2, 2005-09-06 - - * Rev 2.15 (JD) Updates, including mailing-list change, 2005-05-21 - - * Rev 2.14 (MDS) Updated 4.12, 2004-11-26 - - * Rev 2.13 (JD) Added 4.6.1, updated 4.7, 2004-06-23 - - * Rev 2.12 (JD) Updated 4.27, 2004-04-11 - - * Rev 2.11 (JD) Various updates, 2004-01-18 - - * Rev 2.10 (MDS) Various updates, 2004-01-03 - - * Rev 2.9 (CP) Converted to Gnu texinfo format, 2002-09-10 - - * Rev 2.8 (MDS) Minor updates 2002-07-10, released with lm_sensors - 2.6.4 - - * Rev 2.7 (MDS) Minor updates 2002-04-25 - - * Rev 2.6 (MDS) Minor updates 2002-01-15, released with lm_sensors - 2.6.3 - - * Rev 2.5 (MDS) Minor updates 2001-11-11, released with lm_sensors - 2.6.2 - - * Rev 2.4 (MDS) Minor updates 2001-07-22 - - * Rev 2.3 (MDS) General update, 2001-02-24, released with lm_sensors - 2.6.0. - - * Rev 2.2 (Frodo) Corrections for lm_sensors 2.4, 1999-09-20 - - * Rev 2.1 (Frodo) Corrections for lm_sensors 2.2, 1999-01-12 - - * Rev 2.0 (Frodo) Major revision for lm_sensors 2.1, 1998-12-29 - - * Rev 1.10 (Frodo) Modified 3.8, updated some other things, - 1998-09-24 - - * Rev 1.9 (Frodo) Added 3.15, 1998-09-06 - - * Rev 1.8 (Frodo) Added 3.14, 1998-09-05 - - * Rev 1.7 (Phil) Added 3.13 and some other minor changes, 1998-09-01 - - * Rev 1.6 (Frodo) Added 4, 4.1, 4.2, 4.3, 4.4, 4.5, 1998-09-01 - - * Rev 1.5 (Frodo) Added 2.3, 2.4, 3.9, 3.10, 3.11, 1998-08-26 - - * Rev 1.4 (Frodo) Added some more Winbond information, and 3.5-3.8, - 1998-08-17 - - * Rev 1.3 (Phil) Added info on the Winbond chip, 1998-08-16 - - * Rev 1.2 (Frodo) Adapation, 1998-08-10 - - * Rev 1.1 (Phil) Modifications, 1998-08-09 - - * Rev 1.0 (Phil) First version, 1998-08-03 - diff --git a/doc/Makefile b/doc/Makefile deleted file mode 100644 index cecedc70..00000000 --- a/doc/Makefile +++ /dev/null @@ -1,14 +0,0 @@ -# -# quick makefile for the FAQ. -# So that both the text and html FAQ are accessible on the web -# they are checked into SVN along with the .texi source. -# Don't forget to update version.texi. -# Run 'make' and then check in all 4 files after editing the .texi source. -# -all:: lm_sensors-FAQ.html FAQ - -%.html: %.texi version.texi - LANG=C makeinfo --html --no-split --number-sections $< - -FAQ: lm_sensors-FAQ.texi - LANG=C makeinfo --no-headers --number-sections -o FAQ $< diff --git a/doc/busses/i2c-ali1535 b/doc/busses/i2c-ali1535 deleted file mode 100644 index 17612e44..00000000 --- a/doc/busses/i2c-ali1535 +++ /dev/null @@ -1,53 +0,0 @@ -Kernel driver `i2c-ali1535.o' - -Status: Beta; block reads/writes untested (not used by any current chip - driver) - -Supported adapters: - * Acer Labs, Inc. ALI 1535 (south bridge) - Datasheet: Available at the Acer Labs website (password may be required) - -Author: Frodo Looijaard , Philip Edelbrock - , Mark D. Studebaker and - Dan Eaton - -License: GPL - - -Module Parameters ------------------ - -(none) - - -Description ------------ - -This is the driver for the SMB Host controller on -Acer Labs Inc. (ALI) M1535 South Bridge. - -The M1535 is a South bridge for portable systems. -It is very similar to the M15x3 South bridges also produced -by Acer Labs Inc. Some of the registers within the part -have moved and some have been redefined slightly. Additionally, -the sequencing of the SMBus transactions has been modified -to be more consistent with the sequencing recommended by -the manufacturer and observed through testing. These -changes are reflected in this driver and can be identified -by comparing this driver to the i2c-ali15x3 driver. -For an overview of these chips see http://www.acerlabs.com - -The SMB controller is part of the 7101 device, which is an -ACPI-compliant Power Management Unit (PMU). - -The whole 7101 device has to be enabled for the SMB to work. -You can't just enable the SMB alone. -The SMB and the ACPI have separate I/O spaces. -We make sure that the SMB is enabled. We leave the ACPI alone. - - -Features --------- - -This driver controls the SMB Host only. -This driver does not use interrupts. diff --git a/doc/busses/i2c-ali15x3 b/doc/busses/i2c-ali15x3 deleted file mode 100644 index e531694f..00000000 --- a/doc/busses/i2c-ali15x3 +++ /dev/null @@ -1,135 +0,0 @@ -Kernel driver `i2c-ali15x3.o' - -Status: Complete and tested; block reads/writes untested (not used by any - current chip driver) - -Supported adapters: - * Acer Labs, Inc. ALI 1533 and 1543C (south bridge) - Datasheet: Available at the Acer Labs website (password required) - -Author: Frodo Looijaard , Philip Edelbrock - , and Mark D. Studebaker - -License: GPL - - -Module Parameters ------------------ - -* force_addr: int - Initialize the base address of the i2c controller - - -Notes ------ - -The force_addr parameter is useful for boards that don't set the address -in the BIOS. Does not do a PCI force; the device must still be present -in lspci. Don't use this unless the driver complains that the -base address is not set. -Example: 'modprobe i2c-ali15x3 force_addr=0xe800' - -SMBus periodically hangs on ASUS P5A motherboards and can only be -cleared by a power cycle. Cause unknown (see Issues below). - - -Description ------------ - -This is the driver for the SMB Host controller on -Acer Labs Inc. (ALI) M1541 and M1543C South Bridges. - -The M1543C is a South bridge for desktop systems. -The M1541 is a South bridge for portable systems. -They are part of the following ALI chipsets: - "Aladdin Pro 2": Includes the M1621 Slot 1 North bridge - with AGP and 100MHz CPU Front Side bus - - "Aladdin V": Includes the M1541 Socket 7 North bridge - with AGP and 100MHz CPU Front Side bus - Some Aladdin V motherboards: - Asus P5A - Atrend ATC-5220 - BCM/GVC VP1541 - Biostar M5ALA - Gigabyte GA-5AX (** Generally doesn't work because the BIOS doesn't - enable the 7101 device! **) - Iwill XA100 Plus - Micronics C200 - Microstar (MSI) MS-5169 - - "Aladdin IV": Includes the M1541 Socket 7 North bridge - with host bus up to 83.3 MHz. - -For an overview of these chips see http://www.acerlabs.com -At this time the full data sheets on the web site are password protected, -however if you contact the ALI office in San Jose -they may give you the password. - -The M1533/M1543C devices appear as FOUR separate devices -on the PCI bus. An output of lspci will show something similar -to the following: - - 00:02.0 USB Controller: Acer Laboratories Inc. M5237 (rev 03) - 00:03.0 Bridge: Acer Laboratories Inc. M7101 <= THIS IS THE ONE WE NEED - 00:07.0 ISA bridge: Acer Laboratories Inc. M1533 (rev c3) - 00:0f.0 IDE interface: Acer Laboratories Inc. M5229 (rev c1) - -** IMPORTANT ** -** If you have a 1533 or 1543C on the board and you get -** "ali15x3.o: Error: Can't detect ali15x3!" -** then run lspci. -** If you see the 1533 and 5229 devices but NOT the 7101 device, -** then you must enable ACPI, the PMU, SMB, or something similar -** in the BIOS. If you can't figure out how to enable the -** 7101 device in the BIOS, you can try one of the "hotplug" modules - -** see below. -** The driver won't work if it can't find the 7101 device. - -The SMB controller is part of the 7101 device, which is an -ACPI-compliant Power Management Unit (PMU). - -The whole 7101 device has to be enabled for the SMB to work. -You can't just enable the SMB alone. -The SMB and the ACPI have separate I/O spaces. -We make sure that the SMB is enabled. We leave the ACPI alone. - - -Features --------- -This driver controls the SMB Host only. -The SMB Slave controller on the M15X3 is not enabled. -This driver does not use interrupts. - - -Issues ------- -This driver requests the I/O space for only the SMB -registers. It doesn't use the ACPI region. - -On the ASUS P5A motherboard, there are several reports that -the SMBus will hang and this can only be resolved by -powering off the computer. It appears to be worse when the board -gets hot, for example under heavy CPU load, or in the summer. -There may be electrical problems on this board. -On the P5A, the W83781D sensor chip is on both the ISA and -SMBus. Therefore the SMBus hangs can generally be avoided -by accessing the W83781D on the ISA bus only. - - -Hot Plug Modules ----------------- - -There are EXPERIMENTAL "hotplug" modules which will enable the -m7101 device if it is not enabled on your motherboard. -Use these at your own risk. Read the README file carefully. - -m7101 Version 0.1 for 2.2 and early 2.3 kernels: - README: http://www.netroedge.com/~lm78/misc/README-m7101.txt - source and README: http://www.netroedge.com/~lm78/misc/m7101-0.1.tar.gz - -m7101 Version 0.2 for 2.4 and later 2.3 kernels: - In the directory prog/hotplug in this package. - Must be built separately. - - diff --git a/doc/busses/i2c-amd756 b/doc/busses/i2c-amd756 deleted file mode 100644 index 77b02350..00000000 --- a/doc/busses/i2c-amd756 +++ /dev/null @@ -1,30 +0,0 @@ -Kernel driver `i2c-amd756.o' - -Status: Complete and somewhat tested - -Supported adapters: - * AMD 756 - * AMD 766 - * AMD 768 - * AMD 8111 - Datasheets: Publicly available on AMD website - - * nVidia nForce - Datasheet: Unavailable - - -Module Parameters ------------------ - -(none) - - -Description ------------ - -This driver supports the AMD 756, 766, 768 and 8111 Peripheral Bus Controllers, and -the nVidia nForce. - -Note that for the 8111, there are two SMBus adapters. The SMBus 1.0 adapter is -supported by this driver, and the SMBus 2.0 adapter is supported -by the i2c-amd8111 driver. diff --git a/doc/busses/i2c-amd8111 b/doc/busses/i2c-amd8111 deleted file mode 100644 index 784883bb..00000000 --- a/doc/busses/i2c-amd8111 +++ /dev/null @@ -1,48 +0,0 @@ -Kernel driver `i2c-adm8111.o' - -Status: Slightly tested. - -Supported adapters: - * AMD-8111 SMBus 2.0 PCI interface - -Datasheets: - AMD datasheet not yet available, but almost everything can be found - in the publicly available ACPI 2.0 specification, which the adapter - follows. - -Author: Vojtech Pavlik - -Module Parameters ------------------ - -None. - -Description ------------ - -If you see something like this: - -00:07.2 SMBus: Advanced Micro Devices [AMD] AMD-8111 SMBus 2.0 (rev 02) - Subsystem: Advanced Micro Devices [AMD] AMD-8111 SMBus 2.0 - Flags: medium devsel, IRQ 19 - I/O ports at d400 [size=32] - -in your 'lspci -v', then this driver is for your chipset. - -Process Call Support --------------------- - -Supported. - -SMBus 2.0 Support ------------------ - -Supported. Both PEC and block process call support is implemented. -Slave mode or host notification are not yet implemented. - -Notes ------ - -Note that for the 8111, there are two SMBus adapters. The SMBus 2.0 adapter is -supported by this driver, and the SMBus 1.0 adapter is supported -by the i2c-amd756 driver. diff --git a/doc/busses/i2c-hydra b/doc/busses/i2c-hydra deleted file mode 100644 index 55bee71e..00000000 --- a/doc/busses/i2c-hydra +++ /dev/null @@ -1,35 +0,0 @@ -Kernel driver `i2c-hydra.o' - -Status: Complete and somewhat tested - -Supported adapters: - * Apple `Hydra' Mac I/O - Datasheet: Was publicly available from the Apple website, now seems to - have disappeared?!? - -Author: Geert Uytterhoeven - - -Module Parameters ------------------ - -(none) - - -Description ------------ - -i2c-hydra is an i2c bus driver for CHRP motherboards with the Apple Hydra Mac -I/O. - -Your /proc/pci or lspci listing must show this : - - Unknown class: Apple Hydra (rev 2) - -To install this driver, simply do - # modprobe i2c-hydra - -This driver uses the i2c-algo-bit module which must be -modprobed and/or enabled in your kernel -(Character Devices -> I2C Support -> I2C Bit-Banging Interfaces). - diff --git a/doc/busses/i2c-i801 b/doc/busses/i2c-i801 deleted file mode 100644 index 3d96016a..00000000 --- a/doc/busses/i2c-i801 +++ /dev/null @@ -1,110 +0,0 @@ -Kernel driver `i2c-i801.o' - -Status: Tested and stable. - Block reads/writes lightly tested. - HW PEC support Beta. - I2C Block Read support Beta. - -Supported adapters: - * Intel 82801AA and 82801AB (ICH and ICH0 - part of the - '810' and '810E' chipsets) - * Intel 82801BA (ICH2 - part of the '815E' chipset) - * Intel 82801CA/CAM (ICH3) - * Intel 82801DB (ICH4) - * Intel 82801EB/ER (ICH5) - * Intel 6300ESB/ESB2 - * Intel 82801FB/FR/FW/FRW (ICH6) - * Intel ICH7/ICH8/ICH9 - * Intel EP80579 (Tolapai) - * Intel 82801JI (ICH10) - * Intel PCH - Datasheets: Publicly available at the Intel website - -Authors: Frodo Looijaard , Philip Edelbrock - , and Mark Studebaker - - -Module Parameters ------------------ - -* force_addr: int - Forcibly enable the ICH at the given address. EXTREMELY DANGEROUS! - - -Description ------------ - -The ICH (properly known as the 82801AA), ICH0 (82801AB), -ICH2 (82801BA), ICH3 (82801CA/CAM) and later devices -are Intel chips that are a part of -Intel's '810' chipset for Celeron-based PCs, -'810E' chipset for Pentium-based PCs, '815E' chipset, and others. - -The ICH chips contain at least SEVEN separate PCI functions -in TWO logical PCI devices. -An output of lspci will show something similar to the following: - - 00:1e.0 PCI bridge: Intel Corporation: Unknown device 2418 (rev 01) - 00:1f.0 ISA bridge: Intel Corporation: Unknown device 2410 (rev 01) - 00:1f.1 IDE interface: Intel Corporation: Unknown device 2411 (rev 01) - 00:1f.2 USB Controller: Intel Corporation: Unknown device 2412 (rev 01) - 00:1f.3 Unknown class [0c05]: Intel Corporation: Unknown device 2413 (rev 01) - -The SMBus controller is function 3 in device 1f. -Class 0c05 is SMBus Serial Controller. - -If you do NOT see the 24x3 device at function 3, and you can't -figure out any way in the BIOS to enable it, -(and especially if you have an Asus P4B board), -see prog/hotplug/README.p4b. - -The ICH chips are quite similar to Intel's PIIX4 chip, -at least in the SMBus controller. - -See the file i2c-piix4 for some additional information. - - -Process Call Support --------------------- - -Not supported. - - -I2C Block Read Support ----------------------- - -The ICH4 supports a special 3-byte address (command code -plus 2 more bytes) I2C block read. -The driver and the kernel i2c protocol stack do not -support this. -The ICH5 and higher support a standard 1-byte address (command code) -I2C block read. The driver does support this. - - -SMBus 2.0 Support ------------------ - -The 82801DB (ICH4) and later chips support several SMBus 2.0 features. -Kernel and driver support are as follows: - -Feature Kernel Driver -Slave mode no no -Host notify no no -Block PEC yes yes -Hardware PEC yes yes - - -Other ICH4 and later Features ------------------------------ - -The following additional features are also _not_ supported: - -32 Byte buffer - - -********************** -The lm_sensors project gratefully acknowledges the support of -Texas Instruments in the initial development of this driver. - -The lm_sensors project gratefully acknowledges the support of -Intel in the development of SMBus 2.0 / ICH4 features of this driver. diff --git a/doc/busses/i2c-i810 b/doc/busses/i2c-i810 deleted file mode 100644 index fcc44ffa..00000000 --- a/doc/busses/i2c-i810 +++ /dev/null @@ -1,66 +0,0 @@ -Kernel driver `i2c-i810.o' - -Status: Stable - -Supported adapters: - * Intel 82810, 82810-DC100, 82810E, and 82815 (GMCH) - * Intel 82845G (GMCH) - -Author: Frodo Looijaard , Philip Edelbrock - , - Kyösti Mälkki , - and Mark D. Studebaker - -Main contact: Mark Studebaker - - -Module Parameters ------------------ -(none) - - -Description ------------ -This driver uses the i2c-algo-bit module which must be -modprobed and/or enabled in your kernel -(Character Devices -> I2C Support -> I2C Bit-Banging Interfaces). - -WARNING: If you have an '810' or '815' motherboard, your standard I2C -temperature sensors are most likely on the 801's I2C bus. -You want the i2c-i801.o driver for those, not this driver. - -Now for the i2c-i810... - -The GMCH chip contains two I2C interfaces. - -The first interface is used for DDC (Data Display Channel) -which is a serial channel through the VGA monitor connector -to a DDC-compliant monitor. This interface is defined by the -Video Electronics Standards Association (VESA). The standards -are available for purchase at http://www.vesa.org . - -The second interface is a general-purpose I2C bus. -It may be connected to a TV-out chip such as the BT869 or possibly -to a digital flat-panel display. - -Stability ---------- -Apparently stable. - - -Supported Devices ------------------ -See above. - - -Features --------- -Both busses use the i2c-algo-bit driver for 'bit banging' and support -for specific transactions is provided by i2c-algo-bit. - - -Issues ------- -If you enable bus testing in i2c-algo-bit (insmod i2c-algo-bit bit_test=1), -the test may fail; if so, the i2c-i810 driver won't be inserted. -However, we think this has been fixed. diff --git a/doc/busses/i2c-ipmb b/doc/busses/i2c-ipmb deleted file mode 100644 index 06d3a026..00000000 --- a/doc/busses/i2c-ipmb +++ /dev/null @@ -1,55 +0,0 @@ -Kernel driver `i2c-ipmb.o' - -Status: IN DEVELOPMENT - DOESN'T WORK AT ALL - DON'T BOTHER TRYING IT - -Supported adapters: - * IPMI BMC - -Author: Mark D. Studebaker - - -Module Parameters ------------------ -(none) - - -Description ------------ -This is an adapter which provides access to the IPMB -(Intelligent Platform Management Bus) and other I2C / SMBus busses -behind the BMC (Baseboard Management Controller) via -IPMI (Intelligent Platform Management Interface). - -This provides low-level access to all devices on busses -behind the BMC. For high-level access to sensors known -to the BMC, use the i2c-ipmi and bmcsensors modules. - -This module REQUIRES the IPMI kernel patch by Corey Minyard, -v13 or higher, available at http://openipmi.sourceforge.net . -Other IPMI drivers are not supported. - -See http://www.intel.com/design/servers/ipmi/ for -IPMI standards information. - -You must configure the following features in your kernel -(under Character Devices): - IPMI top-level message handler - IPMI KCS handler -The IPMI device interface and IPMI watchdog handler are not required. - -If the KCS handler (ipmi_kcs_drv) is configured as a module, -you must modprobe it separately, it will not load automatically -when you modprobe i2c-ipmi or ipmi_msghandler (unless you set up -/etc/modules.conf to load ipmi_kcs_drv when ipmi_msghandler is loaded). - -Issues ------- -Only one BMC is supported - shouldn't be a problem. - -Alpha! - - - -********************** -The lm_sensors project gratefully acknowledges the support of -Hewlett Packard (Ft. Collins) in the development of this driver. diff --git a/doc/busses/i2c-ipmi b/doc/busses/i2c-ipmi deleted file mode 100644 index 7832c776..00000000 --- a/doc/busses/i2c-ipmi +++ /dev/null @@ -1,61 +0,0 @@ -Kernel driver `i2c-ipmi.o' - -Status: Alpha - -Supported adapters: - * IPMI BMC - -Author: Mark D. Studebaker - - -Module Parameters ------------------ -(none) - - -Description ------------ -This is a "dummy" adapter which provides access to the -BMC (Baseboard Management Controller) via IPMI (Intelligent Platform -Management Interface). It is used by the bmcsensors module. - -Together with the bmcsensors module, this provides high-level -access to sensors known by the BMC. For low-level access to -IPMB (I2C/SMBus) busses behind the BMC, use the i2c-ipmb module. - -This module REQUIRES the IPMI kernel patch by Corey Minyard, -v13 or higher, available at http://openipmi.sourceforge.net . -Other IPMI drivers are not supported. - -See http://www.intel.com/design/servers/ipmi/ for -IPMI standards information. - -You must configure the following features in your kernel -(under Character Devices): - IPMI top-level message handler - IPMI KCS handler -The IPMI device interface and IPMI watchdog handler are not required. - -If the KCS handler (ipmi_kcs_drv) is configured as a module, -you must modprobe it separately, it will not load automatically -when you modprobe i2c-ipmi or ipmi_msghandler (unless you set up -/etc/modules.conf to load ipmi_kcs_drv when ipmi_msghandler is loaded). - -Issues ------- -Only one BMC is supported - shouldn't be a problem. - -Only one client is supported - to be fixed. - -Libsensors was hacked to support this dummy driver; only -the ISA dummy driver was supported previously. -The library needs further enhancements for full -dummy driver support. - -Alpha! - - - -********************** -The lm_sensors project gratefully acknowledges the support of -Hewlett Packard (Ft. Collins) in the development of this driver. diff --git a/doc/busses/i2c-nforce2 b/doc/busses/i2c-nforce2 deleted file mode 100644 index 49f16b25..00000000 --- a/doc/busses/i2c-nforce2 +++ /dev/null @@ -1,55 +0,0 @@ -Kernel driver i2c-nforce2 -------------------------- - -Status: Well tested - -Supported adapters: - * nVidia nForce2 SMBus PCI interface - (10de:0064, included in nForce2 MCP, - 10de:0084, included in nForce2 Ultra 400 MCP) - Datasheet: not publicly available, but seems to be similar to the - AMD-8111 SMBus 2.0 adapter. - - * nVidia nForce3 SMBus PCI interface - (10de:00d4, included in nForce3 Pro150 MCP, - 10de:00e4, included in nForce3 250Gb MCP) - Datasheet: same as for nForce2 SMBus PCI interface - - * nVidia nForce4 SMBus PCI interface - (10de:0052, included in nForce4 MCP) - (10de:0034, included in nForce4 MCP-04) - (10de:0264, included in nForce4 MCP51) - (10de:0368, included in nForce4 MCP55) - (10de:03eb, included in nForce MCP61) - (10de:0446, included in nForce MCP65) - Datasheet: same as for nForce2 SMBus PCI interface - -Author: Hans-Frieder Vogt - - -Description ------------ - -i2c-nforce2 is a driver for the SMBuses included in the nVidia nForce2, -nForce3 and nForce4 MCP. - -If your 'lspci -v' listing shows something like the following, - -00:01.1 SMBus: nVidia Corporation: Unknown device 0064 (rev a2) - Subsystem: Asustek Computer, Inc.: Unknown device 0c11 - Flags: 66Mhz, fast devsel, IRQ 5 - I/O ports at c000 [size=32] - Capabilities: - -then this driver should support the SMBuses of your motherboard. - - -Notes ------ - -The SMBus adapter in the nForce2/3/4 chipset seems to be very similar to the -SMBus 2.0 adapter in the AMD-8111 southbridge. However, I could only get the -driver to work with direct I/O access, which is different to the EC interface -of the AMD-8111. -Tested on Asus A7N8X. The ACPI DSDT table of the Asus A7N8X lists two SMBuses, -both of which are supported by this driver. diff --git a/doc/busses/i2c-piix4 b/doc/busses/i2c-piix4 deleted file mode 100644 index 4a631502..00000000 --- a/doc/busses/i2c-piix4 +++ /dev/null @@ -1,100 +0,0 @@ -Kernel driver `i2c-piix4.o' - -Status: Complete and well-tested - except for Victory66 support which is Alpha. - -Supported adapters: - * Intel 82371AB PIIX4 and PIIX4E - * Intel 82443MX (440MX) - Datasheet: Publicly available at the Intel website - * ServerWorks OSB4, CSB5, CSB6 and HT-1000 southbridges - Datasheet: Only available via NDA from ServerWorks - * ATI IXP200, IXP300, IXP400, SB600, SB700 and SB800 southbridges - Datasheet: Not publicly available - * Standard Microsystems (SMSC) SLC90E66 (Victory66) southbridge - Datasheet: Publicly available at the SMSC website http://www.smsc.com - -Author: Frodo Looijaard and Philip Edelbrock - - - -Module Parameters ------------------ - -* force: int - Forcibly enable the PIIX4. DANGEROUS! -* force_addr: int - Forcibly enable the PIIX4 at the given address. EXTREMELY DANGEROUS! - - -Description ------------ - -The PIIX4 (properly known as the 82371AB) is an Intel chip with a lot of -functionality. Among other things, it implements the PCI bus. One of its -minor functions is implementing a System Management Bus. This is a true -SMBus - you can not access it on I2C levels. The good news is that it -natively understands SMBus commands and you do not have to worry about -timing problems. The bad news is that non-SMBus devices connected to it -can confuse it mightily. Yes, this is known to happen... - -Cat /proc/pci, and see whether it contains an entry like this: - - Bus 0, device 1, function 3: - Bridge: Intel 82371AB PIIX4 ACPI (rev 1). - Medium devsel. Fast back-to-back capable. - -Bus and device numbers may differ, but the function number must be identical -(like many PCI devices, the PIIX4 incorporates a number of different -'functions', which can be considered as separate devices). If you find such -an entry, you have a PIIX4 SMBus controller. - -On some computers (most notably, some Dells), the SMBus is disabled by -default. If you use the insmod parameter 'force=1', the kernel module - will try to enable it. THIS IS VERY DANGEROUS! If the BIOS did not -set up a correct address for this module, you could get in big trouble -(read: crashes, data corruption, etc.). Try this only as a last resort -(try BIOS updates first, for example), and backup first! An even more -dangerous option is 'force_addr='. This will not only enable the -PIIX4 like 'force' foes, but it will also set a new base I/O port address. -The SMBus parts of the PIIX4 needs a range of 8 of these addresses to -function correctly. If these addresses are already reserved by some other -device, you will get into big trouble! DON'T USE THIS IF YOU ARE NOT VERY -SURE ABOUT WHAT YOU ARE DOING! - -The PIIX4E is just an new version of the PIIX4; it is supported as well. The -PIIX/PIIX3 does not implement an SMBus or I2C bus, so you can't use this -driver on those mainboards. - -The ServerWorks Southbridges, the Intel 440MX, -and the Victory66 are identical to the PIIX4 in I2C/SMBus support. - -If you own Force CPCI735 motherboard or other OSB4 based systems you may need -to change the SMBus Interrupt Select register so the SMBus controller uses -the SMI mode. - -1) Use lspci command and locate the PCI device with the SMBus controller: - 00:0f.0 ISA bridge: ServerWorks OSB4 South Bridge (rev 4f) - The line may vary for different chipsets. Please consult the driver source - for all possible PCI ids (and lspci -n to match them). Lets assume the - device is located at 00:0f.0. -2) Now you just need to change the value in 0xD2 register. Get it first with - command: lspci -xxx -s 00:0f.0 - If the value is 0x3 then you need to change it to 0x1 - setpci -s 00:0f.0 d2.b=1 - -Please note that you don't need to do that in all cases, just when the SMBus is -not working properly. - - -Hardware-specific issues ------------------------- - -This driver will refuse to load on IBM systems with an Intel PIIX4 SMBus. -Some of these machines have an RFID EEPROM (24RF08) connected to the SMBus, -which can easily get corrupted due to a state machine bug. These are mostly -Thinkpad laptops, but desktop systems may also be affected. We have no list -of all affected systems, so the only safe solution was to prevent access to -the SMBus on all IBM systems (detected using DMI data.) - -For additional information, read README.thinkpad. diff --git a/doc/busses/i2c-savage4 b/doc/busses/i2c-savage4 deleted file mode 100644 index bce8110b..00000000 --- a/doc/busses/i2c-savage4 +++ /dev/null @@ -1,42 +0,0 @@ -Kernel driver `i2c-savage4.o' - -Status: Alpha - -Supported adapters: - * Savage4 - * Savage2000 - -Author: Frodo Looijaard , Philip Edelbrock - , Ralph Metzler , - Alexander Wold, and Mark D. Studebaker - -Main contact: Sensors mailing list - - -Module Parameters ------------------ - -(none) - - -Description ------------ - -The Savage4 chips contain two I2C interfaces (aka a I2C 'master' -or 'host'). - -The first interface is used for DDC (Data Display Channel) -which is a serial channel through the VGA monitor connector -to a DDC-compliant monitor. This interface is defined by the -Video Electronics Standards Association (VESA). The standards -are available for purchase at http://www.vesa.org . -The DDC bus is not yet supported because its register is not -directly memory-mapped. - -The second interface is a general-purpose I2C bus. -This is the only interface supported by the driver at the moment. - -This driver uses the i2c-algo-bit module which must be -modprobed and/or enabled in your kernel -(Character Devices -> I2C Support -> I2C Bit-Banging Interfaces). - diff --git a/doc/busses/i2c-sis5595 b/doc/busses/i2c-sis5595 deleted file mode 100644 index 9997d32d..00000000 --- a/doc/busses/i2c-sis5595 +++ /dev/null @@ -1,56 +0,0 @@ -Kernel driver `i2c-sis5595.o' - -Status: Beta - -Supported adapters: - * Silicon Integrated Systems Corp. SiS5595 Southbridge - Datasheet: Publicly available at the Silicon Integrated Systems Corp. site. - -Author: Frodo Looijaard and - Mark D. Studebaker - - Note: all have mfr. ID 0x1039. - SUPPORTED PCI ID - 5595 0008 - - Note: The chips below contain a 0008 device which is incompatible with the - 5595. We recognize these by the presence of the listed - "blacklist" PCI ID and refuse to load. - - NOT SUPPORTED PCI ID BLACKLIST PCI ID - 540 0008 0540 - 550 0008 0550 - 5513 0008 5511 - 5581 0008 5597 - 5582 0008 5597 - 5597 0008 5597 - 5598 0008 5597/5598 - 630 0008 0630 - 645 0008 0645 - 730 0008 0730 - 735 0008 0735 - -Module Parameters ------------------ - -force_addr=0xaddr Set the I/O base address. Useful for boards - that don't set the address in the BIOS. Does not do a - PCI force; the device must still be present in lspci. - Don't use this unless the driver complains that the - base address is not set. - Example: 'modprobe i2c-sis5595 force_addr=0x290' - - -Description ------------ - -i2c-sis5595 is a true SMBus host driver for motherboards with the -SiS5595 southbridges. - -WARNING: If you are trying to access the integrated sensors on the -SiS5595 chip, you want the sis5595.o driver for those, not this driver. -This driver is a BUS driver, not a CHIP driver. -A BUS driver is used by other CHIP drivers to access chips on the bus. - -To install this driver, simply do - # modprobe i2c-sis5595 diff --git a/doc/busses/i2c-sis630 b/doc/busses/i2c-sis630 deleted file mode 100644 index 40a73761..00000000 --- a/doc/busses/i2c-sis630 +++ /dev/null @@ -1,63 +0,0 @@ -Kernel driver `i2c-sis630.o' - -Status: beta - -Supported adapters: - * Silicon Integrated Systems Corp (SiS) - 630 chipset (Datasheet: available at http://amalysh.bei.t-online.de/docs/SIS/) - 730 chipset - * Possible other SiS chipsets ? - -Author: Alexander Malysh - - -License: GPL - - -Module Parameters ------------------ - -force = [1|0] Forcibly enable the SIS630. DANGEROUS! - This can be interesting for chipsets not named - above to check if it works for you chipset, but DANGEROUS! -high_clock = [1|0] Forcibly set Host Master Clock to 56KHz (default,what your BIOS use). - DANGEROUS! This should be a bit faster, but freeze some systems (i.e. - my Laptop). - - -Description ------------ - -This SMBus only driver is known to work on motherboards with the above named -chipsets. - -If you see something like this: - -00:00.0 Host bridge: Silicon Integrated Systems [SiS] 630 Host (rev 31) -00:01.0 ISA bridge: Silicon Integrated Systems [SiS] 85C503/5513 - -or like this: - -00:00.0 Host bridge: Silicon Integrated Systems [SiS] 730 Host (rev 02) -00:01.0 ISA bridge: Silicon Integrated Systems [SiS] 85C503/5513 - -in your 'lspci' output , then this driver is for your chipset. - -Note: kernel versions later than 2.4.18 not tested. - -If anyone owns a board with those chips AND is willing to risk crashing & -burning an otherwise well-behaved kernel in the name of progress... please -contact me at or via the project's mailing list: see -http://www.lm-sensors.org/wiki/AuthorsAndContributors. Please send bug reports -and/or success stories as well. - - -Thank Yous ------------ -Philip Edelbrock -- testing SiS730 support -Mark M. Hoffman -- bug fixes - -To anyone else which I forgot here ;), thanks! - diff --git a/doc/busses/i2c-sis645 b/doc/busses/i2c-sis645 deleted file mode 100644 index 2bdcbfed..00000000 --- a/doc/busses/i2c-sis645 +++ /dev/null @@ -1,85 +0,0 @@ -Kernel driver `i2c-sis645.o' - -Status: Beta - -Supported adapters: - * Silicon Integrated Systems Corp (SiS) - Any combination of these host bridges: - 645, 645DX (aka 646), 648, 650, 651, 655, 735, 745, 746 - and these south bridges: - 961, 962, 963(L) - -Author: Mark M. Hoffman - -License: GPL - - -Module Parameters ------------------ - -(none) - - -Description ------------ - -This SMBus only driver is known to work on motherboards with the above named -chipset combinations. The driver was developed without benefit of a proper -datasheet from SiS. The SMBus registers are assumed compatible with those of -the SiS630, although they are located in a completely different place. Thanks -to Alexander Malysh for providing the SiS630 datasheet (and -driver). - -The command "lspci" as root should produce something like these lines: - -00:00.0 Host bridge: Silicon Integrated Systems [SiS]: Unknown device 0645 -00:02.0 ISA bridge: Silicon Integrated Systems [SiS] 85C503/5513 -00:02.1 SMBus: Silicon Integrated Systems [SiS]: Unknown device 0016 - -or perhaps this... - -00:00.0 Host bridge: Silicon Integrated Systems [SiS]: Unknown device 0645 (rev 02) -00:02.0 ISA bridge: Silicon Integrated Systems [SiS]: Unknown device 0961 -00:02.1 SMBus: Silicon Integrated Systems [SiS]: Unknown device 0016 - -(kernel versions later than 2.4.18 may fill in the "Unknown"s) - -If the SMBus line is missing, then the BIOS on the board has disabled the -device. This driver is capable of enabling it, as long as the kernel has -CONFIG_HOTPLUG enabled. In that case, the SMBus device will appear in "lspci" -after the driver is loaded. Note that you need to rebuild lm_sensors AFTER -running "make config" or equivalent on your kernel, otherwise the i2c-sis645 -driver will not build in this support. - -I suspect that this driver could be made to work for the following SiS chipsets -as well: 635, and 635T. -If anyone owns a board with those chips AND is willing to risk crashing & -burning an otherwise well-behaved kernel in the name of progress... please -contact me at or via the project's mailing list: -see http://www.lm-sensors.org/wiki/AuthorsAndContributors. Please send bug reports -and/or success stories as well. - - -TO DOs ------------ -* The driver does not support SMBus block reads/writes; I may add them if a -scenario is found where they're needed. - - -Thank Yous ------------ -Mark D. Studebaker - - design hints and bug fixes -Alexander Maylsh - - ditto, plus an important datasheet... almost the one I really wanted -Hans-Günter Lütke Uphues - - patch for SiS735 -Robert Zwerus - - testing for SiS645DX -Kianusch Sayah Karadji - - patch for SiS645DX/962 -Ken Healy - - patch for Sis655 - -To anyone else who has written w/ feedback, thanks! - diff --git a/doc/busses/i2c-tsunami b/doc/busses/i2c-tsunami deleted file mode 100644 index 7679ab9c..00000000 --- a/doc/busses/i2c-tsunami +++ /dev/null @@ -1,46 +0,0 @@ -Kernel driver `i2c-tsunami.o' - -Status: Stable - -Supported adapters: - * DEC Tsunami 21272/Typhoon 21274 based boards - -Author: Oleg I. Vdovikin - -Main contact: Oleg I. Vdovikin - - -Module Parameters ------------------ -(none) - - -Description ------------ -The Tsunami/Typhoon chipsets' "Cchip" supports I2C busses via MPD registers -and appropriate open drain pins. This bus is usually used to read -SPD SDRAM DIMMs, however there may be other devices on -the bus also. These chips are used with wide range of 21264A boards. - -This driver uses the i2c-algo-bit module which must be -modprobed and/or enabled in your kernel -(Character Devices -> I2C Support -> I2C Bit-Banging Interfaces). - - -Stability ---------- -Apparently stable. - -Supported Devices ------------------ -This driver was written and tested on the 'API UP2000(+) -boards'. As seems it should work with any Tsunami based system. - -Features --------- -I2C busses use the i2c-algo-bit driver for 'bit banging' and support -for specific transactions is provided by i2c-algo-bit. - -Issues ------- -Not known. diff --git a/doc/busses/i2c-via b/doc/busses/i2c-via deleted file mode 100644 index b484b509..00000000 --- a/doc/busses/i2c-via +++ /dev/null @@ -1,50 +0,0 @@ -Kernel driver `i2c-via.o' - -Status: Complete and well-tested - -Supported adapters: - * VIA Technologies, InC. VT82C586B - Datasheet: Publicly available at the VIA website - -Author: Kyösti Mälkki - - -Module Parameters ------------------ - -(none) - - -Description ------------ - -i2c-via is an i2c bus driver for motherboards with VIA chipset. - -The following VIA pci chipsets are supported: - - MVP3, VP3, VP2/97, VPX/97 - - others with South bridge VT82C586B - -Your /proc/pci or lspci listing must show this : - - Bridge: VIA Technologies, Inc. VT82C586B ACPI (rev 10) - -To install this driver, simply do - # modprobe i2c-via - -This driver uses the i2c-algo-bit module which must be -modprobed and/or enabled in your kernel -(Character Devices -> I2C Support -> I2C Bit-Banging Interfaces). - - Problems? - - Q: You have VT82C586B on the motherboard, but not in the listing. - - A: Go to your BIOS setup, section PCI devices or similar. - Turn USB support on, and try again. - - Q: No error messages, but still i2c doesn't seem to work. - - A: This can happen. This driver uses the pins VIA recommends in their - datasheets, but there are several ways the motherboard manufacturer - can actually wire the lines. - diff --git a/doc/busses/i2c-viapro b/doc/busses/i2c-viapro deleted file mode 100644 index cf677092..00000000 --- a/doc/busses/i2c-viapro +++ /dev/null @@ -1,65 +0,0 @@ -Kernel driver `i2c-viapro.o' - -Status: Stable - -Supported adapters: - * VIA Technologies, Inc. VT82C596A/B - Datasheet: Sometimes available at the VIA website - - * VIA Technologies, Inc. VT82C686A/B - Datasheet: Sometimes available at the VIA website - - * VIA Technologies, Inc. VT8231, VT8233, VT8233A, VT8235, VT8237R/A, VT8251 - Datasheet: available on request and under NDA from VIA - - * VIA Technologies, Inc. CX700 - Datasheet: available on request and under NDA from VIA - - * VIA Technologies, Inc. VX800/VX820 - Datasheet: available on http://linux.via.com.tw - -Authors: - Kyösti Mälkki - Mark D. Studebaker - Jean Delvare - - -Module Parameters ------------------ - -* force: int - Forcibly enable the SMBus controller. DANGEROUS! -* force_addr: int - Forcibly enable the SMBus at the given address. EXTREMELY DANGEROUS! - - -Description ------------ - -i2c-viapro is a true SMBus host driver for motherboards with one of the -supported VIA south bridges. - -Your /proc/pci or lspci -n listing must show one of these : - - device 1106:3050 (VT82C596A function 3) - device 1106:3051 (VT82C596B function 3) - device 1106:3057 (VT82C686 function 4) - device 1106:3074 (VT8233) - device 1106:3147 (VT8233A) - device 1106:8235 (VT8231 function 4) - device 1106:3177 (VT8235) - device 1106:3227 (VT8237R) - device 1106:3337 (VT8237A) - device 1106:3287 (VT8251) - device 1106:8324 (CX700) - device 1106:8353 (VX800/VX820) - -If none of these show up, you should look in the BIOS for settings like -enable ACPI / SMBus or even USB. - -Except for the oldest chips (VT82C596A/B, VT82C686A and most probably -VT8231), this driver supports I2C block transactions. Such transactions -are mainly useful to read from and write to EEPROMs. - -The CX700/VX800/VX820 additionally appears to support SMBus PEC, although -this driver doesn't implement it. diff --git a/doc/busses/i2c-virtual b/doc/busses/i2c-virtual deleted file mode 100644 index 45341505..00000000 --- a/doc/busses/i2c-virtual +++ /dev/null @@ -1,102 +0,0 @@ -Virtual i2c bus -Brian Kuschak - - -I2C devices must have a unique 7 bit address on the bus to which they -are attached. Many I2C chips have one or more input lines which can be -used to configure one or more of their address bits. This allows the -hardware designer to include multiple chips on a single bus by selecting -different addresses for each one. However, some chips have fixed addresses -which present a problem if more than one of them are required on a board. -Also, sometimes there are more devices than there are selectable addresses. - -A common solution is to break the i2c bus into disjoint segments, by using -a multiplexor or i2c bus switch. This electrically isolates the individual -bus segments. Then the devices with duplicate addresses are placed on -separate bus segments, to prevent address conflicts. - -This seems to be a very common approach in certain types of applications, -such as bladed chassis, where many identical 'blades' or cards are inserted -into a common backplane. The I2C bus on each blade is then located behind -a mux or i2c bus switch. This solution works great from the hardware -perspective, but presents some complexities for software. - -The 'virtual i2c adapter' driver is an attempt to provide a flexible software -abstraction to simiplify these issues, while minimizing the impact on -existing code and fitting nicely into the i2c driver framework. - - -What is a 'virtual i2c adapter' -=============================== - -Think of this adapter as a layer above the existing algorithm and adapter -drivers. The virtual i2c adapter is the handle by which you access a -specific multiplexed bus segment. Each disjoint bus segment becomes a new -virtual bus. The virtual adapter is associated with a 'real' adapter and a -set of multiplexor control variables. - -For example: you have an i2c-0 bus with one multiplexor or i2c bus switch, -and the mux has four outputs which can be electrically connected to the -i2c-0 bus. You would register four virtual i2c busses, one for each position -of the mux. As part of the registration, you provide callback functions to -select and deselect the mux as well as the selector values to be passed to -these functions. - - --------- <--------> i2c-1 virtual - | i2c mux | <--------> i2c-2 virtual - i2c-0 <-------> | | <--------> i2c-3 virtual - ibm_ocp | 0x74 | <--------> i2c-4 virtual - --------- - ^ - | - +--- (or externally controlled) - -The mux may be i2c-controlled, in which case the mux_addr is set to the -slave address (0x74) and the mux_val would be the port number to select (0-3). -Alternatively, the mux could be controlled by some fixed memory-mapped register -in which case only the mux_val would be needed. The callback functions -are hardware specific and written by the user. - -Once the virtual busses are registered, you may talk to any devices behind -the mux simply the using the i2c-1, i2c-2, i2c-3, etc. adapters instead of -the i2c-0 adapter. This makes the mux essentially transparent to the -i2c_client. - -The great advantage of course is that all the existing sensor drivers and -other i2c client drivers automatically work, and the mux becomes transparent -to them. - - -Additional capabilities -======================= - -This driver also supports multiple levels of muxing, by allowing the -user to register a virtual bus which has a different virtual bus as its -'real' adapter. In addition, each virtual bus may have different kinds of -multiplexors, with each bus having its own set of callback functions. -This allows you to easily support some very complex topologies. - -In addition to multiplexing, some systems require that you obtain hardware -access to the bus behind the mux before talking on it. (Again, bladed chassis -typically 'fence' other blades off the bus to prevent a crashed blade from -bringing down the whole backplane.) Before talking on this bus, you have to -arbitrate with the other blades to acquire exclusive access to the bus. This -requirement is met by the addition of two new function pointers to the -algorithm drivers, acquire_exclusive() and release_exclusive(). Traditional -adapters will not use these and they can safely be left NULL. If they are -non-null, the virtual bus driver will call the acquire_exclusive() function -before attempting any operations on that virtual bus. This function may block, -and this is done before acquiring the lock on the underlying 'real' bus to -allow transactions on the real bus to continue unimpeded while waiting for -arbitrartion. In addition the ownership is only held for as long as it takes -to complete the transfer. - - -Files -===== - -drivers/i2c/i2c-virtual.c: The 'algorithm' and 'adapter' driver -include/linux/i2c-virtual.h: Header file with the mux control structure - and callback prototypes. - - diff --git a/doc/busses/i2c-voodoo3 b/doc/busses/i2c-voodoo3 deleted file mode 100644 index bc1ca497..00000000 --- a/doc/busses/i2c-voodoo3 +++ /dev/null @@ -1,83 +0,0 @@ -Kernel driver `i2c-voodoo3.o' - -Status: 'Beta' and still under development and testing - -Supported adapters: - * 3dfx Voodoo3 based cards - * Voodoo Banshee based cards - -Author: Frodo Looijaard , Philip Edelbrock - , Ralph Metzler , - and Mark D. Studebaker - -Main contact: Philip Edelbrock - -The code is based upon Ralph's test code (he did the hard stuff ;') - - -Module Parameters ------------------ - -(none) - - -Description ------------ - -The 3dfx Voodoo3 chip contains two I2C interfaces (aka a I2C 'master' -or 'host'). - -The first interface is used for DDC (Data Display Channel) -which is a serial channel through the VGA monitor connector -to a DDC-compliant monitor. This interface is defined by the -Video Electronics Standards Association (VESA). The standards -are available for purchase at http://www.vesa.org . - -The second interface is a general-purpose I2C bus. -The intent by 3dfx was to allow manufacturers to add extra -chips to the video card such as a TV-out chip such as the BT869 or possibly -even I2C based temperature sensors like the ADM1021 or LM75. - -The 'feature' set of this driver is based on the i2c-piix4 (SMBus) -features. I.e., SMBus byte reads and writes, as well as detected faults in -transmission. Quick reads/writes, block transactions, word transactions, -are yet unwritten but are probably not too hard to add. - -This driver uses the i2c-algo-bit module which must be -modprobed and/or enabled in your kernel -(Character Devices -> I2C Support -> I2C Bit-Banging Interfaces). - -Stability ---------- -Seems to be stable on the test machine, but needs more testing on other -machines. - -Simultaneous accesses of the DDC and I2C busses may cause errors. - - -Supported Devices ------------------ -Specifically, this driver was written and tested on the '3dfx Voodoo3 AGP -3000' which has a tv-out feature (s-video or composite). According to the -docs and discussions, this code should work for any Voodoo3 based cards as -well as Voodoo Banshee based cards. The DDC interface has been tested -on a Voodoo Banshee card. - -Features --------- -This driver controls the I2C controller of the Voodoo3 chip. 'byte read' -transactions and 'data_byte write' transactions are supported, but all else -is not (but is probably easy to add if the need arises). - -Issues ------- -Probably many, but it seems to work OK on my system. :') - - -External Device Connection --------------------------- -The digital video input jumpers give availability to the I2C bus. -Specifically, pins 13 and 25 (bottom row middle, and bottom right-end) are -the I2C clock and I2C data lines, respectively. +5V and GND are probably -also easily available making the addition of extra I2C/SMBus devices easy -to implement. diff --git a/doc/chips/SUMMARY b/doc/chips/SUMMARY index e30379d1..44097a6e 100644 --- a/doc/chips/SUMMARY +++ b/doc/chips/SUMMARY @@ -204,6 +204,9 @@ pc87360 pc87365 2 11 3 3 pwm no yes (LPC) pc87366 3-4 11 3 3 pwm no yes (LPC) +pcf8591 + pcf8591 - 2-4 - 1 dac yes no + sis5595 sis5595 0-1 4-5 2 - no yes @@ -244,9 +247,6 @@ w83627hf w83687thf 3 7 3 3 pw/da no yes (LPC) w83697hf 2 8 2 2 pwm no yes (LPC) -w83627ehf - w83627ehf 3 10 3-5 4 pwm no yes (LPC) - w83781d as99127f 3 7 3 - yes no w83781d 3 7 3 - yes yes @@ -265,51 +265,6 @@ xeontemp xeontemp 1 - - - yes no - -SUPPORTED NON-SENSOR CHIPS --------------------------- - -Driver Chips ------- ----- - -bmcsensors - An interface to an IPMI BMC (Baseboard management controller) - -bt869 - bt869 video modulator chip - -ddcmon - DDC-compliant monitor integrated eeproms - reads locations only - -ds1307 - real-time clock - -eeprom - Memory SPD (serial presence detect) eeproms - reads locations only - Xeon scratch eeproms - reads locations only - -ltc1710 - ltc1710 two switches only - -matorb - Matrix Orbital LCD displays - -pca9540 - 2-channel I2C multiplexer - -pcf8574 & pcf8574a - Simple eight-bit parallel I/O - -pcf8591 - Quad A/D + one D/A - -saa1064 - 4-digit LED-driver - -smbus-arp - An SMBus 2.0 ARP client - - ----------------------------------------------------------------------------- COMPANY ID LIST @@ -320,25 +275,22 @@ Many SMBus chips have a company ID at location 0x3E or 0xFE. Here is a partial list. This may help identify a chip after doing a 'i2cdump [bus] [address]'. -0x00 National (on LM84) 0x01 National 0x12C3 Asus (at 0x4F) 0x1934 Fintek (at 0x5D-0x5E) -0x23 Analog Devices -0x41 Analog Devices (also at 0x16) +0x23 Analog Devices (old products) or Fintek +0x41 Analog Devices (new products) 0x49 TI 0x4D Maxim 0x54 On Semi -0x54 Microchip (at 0x7) 0x5C SMSC 0x5D SMSC 0x55 SMSC 0x5CA3 Winbond (at 0x4F) 0x61 Andigilog 0x90 ITE (at 0x58) -0xA1 Philips (at 0x05 too) +0xA1 Philips 0xA3 Winbond (at 0x4F) -0xAC Myson (at 0x58) 0xC3 Asus (at 0x4F) 0xDA Dallas diff --git a/doc/chips/adm1021 b/doc/chips/adm1021 deleted file mode 100644 index c3bb602b..00000000 --- a/doc/chips/adm1021 +++ /dev/null @@ -1,415 +0,0 @@ -Kernel driver `adm1021.o' -========================= - -Status: Complete; tested for most devices except Xeon. - -Supported chips: - * Analog Devices ADM1021 - Prefix: 'adm1021' - Addresses scanned: I2C 0x18 - 0x1a, 0x29 - 0x2b, 0x4c - 0x4e - Datasheet: Publicly available at the Analog Devices website - * Analog Devices ADM1021A/ADM1023 - Prefix: 'adm1023' - Addresses scanned: I2C 0x18 - 0x1a, 0x29 - 0x2b, 0x4c - 0x4e - Datasheet: Publicly available at the Analog Devices website - * Genesys Logic GL523SM - Prefix: 'gl523sm' - Addresses scanned: I2C 0x18 - 0x1a, 0x29 - 0x2b, 0x4c - 0x4e - Datasheet: - * Intel Xeon Processor - Prefix - any other - may require 'force_adm1021' parameter - - see MODPARMS and xeontemp files for more information - Addresses scanned: none - Datasheet: Publicly available at Intel website - Status: Alpha, untested. - * Maxim MAX1617 - Prefix: 'max1617' - Addresses scanned: I2C 0x18 - 0x1a, 0x29 - 0x2b, 0x4c - 0x4e - Datasheet: Publicly available at the Maxim website - * Maxim MAX1617A - Prefix: 'max1617a' - Addresses scanned: I2C 0x18 - 0x1a, 0x29 - 0x2b, 0x4c - 0x4e - Datasheet: Publicly available at the Maxim website - * National Semiconductor LM84 - Prefix: 'lm84' - Addresses scanned: I2C 0x18 - 0x1a, 0x29 - 0x2b, 0x4c - 0x4e - Datasheet: Publicly available at the National Semiconductor website - * Philips NE1617 - Prefix: 'max1617' (probably detected as a max1617) - Addresses scanned: I2C 0x18 - 0x1a, 0x29 - 0x2b, 0x4c - 0x4e - Datasheet: Publicly available at the Philips website - * Philips NE1617A - Prefix: 'max1617' (probably detected as a max1617) - Addresses scanned: I2C 0x18 - 0x1a, 0x29 - 0x2b, 0x4c - 0x4e - Datasheet: Publicly available at the Philips website - * TI THMC10 - Prefix: 'thmc10' - Addresses scanned: I2C 0x18 - 0x1a, 0x29 - 0x2b, 0x4c - 0x4e - Datasheet: Publicly available at the TI website - * Onsemi MC1066 - Prefix: 'mc1066' - Addresses scanned: I2C 0x18 - 0x1a, 0x29 - 0x2b, 0x4c - 0x4e - Datasheet: Publicly available at the Onsemi website - - -Author: Frodo Looijaard and Philip Edelbrock - - -License: GPL - - -Module Parameters ------------------ - -* force: short array (min = 1, max = 48) - List of adapter,address pairs to boldly assume to be present -* force_adm1021: short array (min = 1, max = 48) - List of adapter,address pairs which are unquestionably assumed to contain - a `adm1021' chip -* force_adm1023: short array (min = 1, max = 48) - List of adapter,address pairs which are unquestionably assumed to contain - a `adm1023' chip -* force_max1617: short array (min = 1, max = 48) - List of adapter,address pairs which are unquestionably assumed to contain - a `max1617' chip -* force_max1617a: short array (min = 1, max = 48) - List of adapter,address pairs which are unquestionably assumed to contain - a `max1617a' chip -* force_thmc10: short array (min = 1, max = 48) - List of adapter,address pairs which are unquestionably assumed to contain - a `thmc10' chip -* force_lm84: short array (min = 1, max = 48) - List of adapter,address pairs which are unquestionably assumed to contain - a `lm84' chip -* force_gl523sm: short array (min = 1, max = 48) - List of adapter,address pairs which are unquestionably assumed to contain - a `gl523sm' chip -* force_mc1066: short array (min = 1, max = 48) - List of adapter,address pairs which are unquestionably assumed to contain - a `mc1066' chip -* probe: short array (min = 1, max = 48) - List of adapter,address pairs to scan additionally -* probe_range: short array (min = 1, max = 48) - List of adapter,start-addr,end-addr triples to scan additionally -* ignore: short array (min = 1, max = 48) - List of adapter,address pairs not to scan -* ignore_range: short array (min = 1, max = 48) - List of adapter,start-addr,end-addr triples not to scan -* read_only: int - Don't set any values, read only mode - - -Description ------------ - -The chips supported by this driver are very similar. The Maxim MAX1617 -is the oldest; it has the problem that it is not very well detectable. -The MAX1617A solves that. The ADM1021 is a straight clone of the MAX1617A. -Ditto for the THMC10. -From here on, we will refer to all these chips as ADM1021-clones. - -ADM1021-clones implement two temperature sensors. One of them is internal, -and measures the temperature of the chip itself; the other is external -and is realised in the form of a transistor-like device. A special alarm -indicates whether the remote sensor is connected. - -Each sensor has its own low and high limits. When they are crossed, the -corresponding alarm is set and remains on as long as the temperature stays -out of range. Temperatures are measured in degrees Celsius. Measurements -are possible between -65 and +127 degrees, with a resolution of one degree. - -The ADM1021 reports a die code, which is a sort of revision code. This -can help us pinpoint problems; it is not very useful otherwise. - -If an alarm triggers, it will remain triggered until the hardware register -is read at least once. This means that the cause for the alarm may -already have disappeared! - -This driver only updates its values each 1.5 seconds; reading it more often -will do no harm, but will return 'old' values. It is possible to make -ADM1021-clones do faster measurements, but there is really no good reason -for that. - - -Xeon support ------------- -Some Xeon processors have real max1617, adm1021, or compatible chips -with in them, with two temperature sensors. - -Other Xeons have chips with only one sensor. - -If you have a Xeon, and the adm1021 module loads, and both -temperatures appear valid, then things are good. - -If the adm1021 module doesn't load, you should try two things: - 1) modprobe adm1021 force_adm1021=BUS,ADDRESS - ADDRESS can only be 0x18, 0x1a, 0x29, 0x2b, 0x4c, or 0x4e. - See if you have one or two valid temperatures - - 2) modprobe xeontemp - See if you have one valid temperature. - -If you have dual Xeons you may have appear to have two separate -adm1021-compatible chips, or two single-temperature sensors, -at distinct addresses. - -Pick the best module for your processor based on the results. -See the xeontemp documentation for further information. - - -Chip Features -------------- - -Chip 'adm1021' - -LABEL LABEL CLASS COMPUTE CLASS MODE MAGN -temp - - R- 0 -temp_low temp temp RW 0 -temp_over temp temp RW 0 -remote_temp - - R- 0 -remote_temp_low remote_temp remote_temp RW 0 -remote_temp_over remote_temp remote_temp RW 0 -alarms - - R- 0 -die_code - - R- 0 - -LABEL FEATURE SYMBOL SYSCTL FILE:N -temp SENSORS_ADM1021_TEMP temp1:3 -temp_low SENSORS_ADM1021_TEMP_HYST temp1:2 -temp_over SENSORS_ADM1021_TEMP_OVER temp1:1 -remote_temp SENSORS_ADM1021_REMOTE_TEMP temp2:3 -remote_temp_low SENSORS_ADM1021_REMOTE_TEMP_HYST temp2:2 -remote_temp_over SENSORS_ADM1021_REMOTE_TEMP_OVER temp2:1 -alarms SENSORS_ADM1021_ALARMS alarms:1 -die_code SENSORS_ADM1021_DIE_CODE die_code:1 - - -Chip 'adm1023' - -LABEL LABEL CLASS COMPUTE CLASS MODE MAGN -temp - - R- 0 -temp_low temp temp RW 0 -temp_over temp temp RW 0 -remote_temp - - R- 3 -remote_temp_low remote_temp remote_temp RW 3 -remote_temp_over remote_temp remote_temp RW 3 -alarms - - R- 0 - -LABEL FEATURE SYMBOL SYSCTL FILE:N -temp SENSORS_ADM1021_TEMP temp1:3 -temp_low SENSORS_ADM1021_TEMP_HYST temp1:2 -temp_over SENSORS_ADM1021_TEMP_OVER temp1:1 -remote_temp SENSORS_ADM1021_REMOTE_TEMP temp2:4 -remote_temp_low SENSORS_ADM1021_REMOTE_TEMP_HYST temp2:2 -remote_temp_over SENSORS_ADM1021_REMOTE_TEMP_OVER temp2:1 -alarms SENSORS_ADM1021_ALARMS alarms:1 - - -Chip 'max1617' - -LABEL LABEL CLASS COMPUTE CLASS MODE MAGN -temp - - R- 0 -temp_low temp temp RW 0 -temp_over temp temp RW 0 -remote_temp - - R- 0 -remote_temp_low remote_temp remote_temp RW 0 -remote_temp_over remote_temp remote_temp RW 0 -alarms - - R- 0 - -LABEL FEATURE SYMBOL SYSCTL FILE:N -temp SENSORS_MAX1617_TEMP temp1:3 -temp_low SENSORS_MAX1617_TEMP_HYST temp1:2 -temp_over SENSORS_MAX1617_TEMP_OVER temp1:1 -remote_temp SENSORS_MAX1617_REMOTE_TEMP temp2:3 -remote_temp_low SENSORS_MAX1617_REMOTE_TEMP_HYST temp2:2 -remote_temp_over SENSORS_MAX1617_REMOTE_TEMP_OVER temp2:1 -alarms SENSORS_MAX1617_ALARMS alarms:1 - - -Chip 'max1617a' - -LABEL LABEL CLASS COMPUTE CLASS MODE MAGN -temp - - R- 0 -temp_low temp temp RW 0 -temp_over temp temp RW 0 -remote_temp - - R- 0 -remote_temp_low remote_temp remote_temp RW 0 -remote_temp_over remote_temp remote_temp RW 0 -alarms - - R- 0 - -LABEL FEATURE SYMBOL SYSCTL FILE:N -temp SENSORS_MAX1617A_TEMP temp1:3 -temp_low SENSORS_MAX1617A_TEMP_HYST temp1:2 -temp_over SENSORS_MAX1617A_TEMP_OVER temp1:1 -remote_temp SENSORS_MAX1617A_REMOTE_TEMP temp2:3 -remote_temp_low SENSORS_MAX1617A_REMOTE_TEMP_HYST temp2:2 -remote_temp_over SENSORS_MAX1617A_REMOTE_TEMP_OVER temp2:1 -alarms SENSORS_MAX1617A_ALARMS alarms:1 - - -Chip 'thmc10' - -LABEL LABEL CLASS COMPUTE CLASS MODE MAGN -temp - - R- 0 -temp_low temp temp RW 0 -temp_over temp temp RW 0 -remote_temp - - R- 0 -remote_temp_low remote_temp remote_temp RW 0 -remote_temp_over remote_temp remote_temp RW 0 -alarms - - R- 0 -die_code - - R- 0 - -LABEL FEATURE SYMBOL SYSCTL FILE:N -temp SENSORS_ADM1021_TEMP temp1:3 -temp_low SENSORS_ADM1021_TEMP_HYST temp1:2 -temp_over SENSORS_ADM1021_TEMP_OVER temp1:1 -remote_temp SENSORS_ADM1021_REMOTE_TEMP temp2:3 -remote_temp_low SENSORS_ADM1021_REMOTE_TEMP_HYST temp2:2 -remote_temp_over SENSORS_ADM1021_REMOTE_TEMP_OVER temp2:1 -alarms SENSORS_ADM1021_ALARMS alarms:1 -die_code SENSORS_ADM1021_DIE_CODE die_code:1 - - -Chip 'lm84' - -LABEL LABEL CLASS COMPUTE CLASS MODE MAGN -temp - - R- 0 -temp_low temp temp RW 0 -temp_over temp temp RW 0 -remote_temp - - R- 0 -remote_temp_low remote_temp remote_temp RW 0 -remote_temp_over remote_temp remote_temp RW 0 -alarms - - R- 0 -die_code - - R- 0 - -LABEL FEATURE SYMBOL SYSCTL FILE:N -temp SENSORS_ADM1021_TEMP temp1:3 -temp_low SENSORS_ADM1021_TEMP_HYST temp1:2 -temp_over SENSORS_ADM1021_TEMP_OVER temp1:1 -remote_temp SENSORS_ADM1021_REMOTE_TEMP temp2:3 -remote_temp_low SENSORS_ADM1021_REMOTE_TEMP_HYST temp2:2 -remote_temp_over SENSORS_ADM1021_REMOTE_TEMP_OVER temp2:1 -alarms SENSORS_ADM1021_ALARMS alarms:1 -die_code SENSORS_ADM1021_DIE_CODE die_code:1 - - -Chip 'gl523' - -LABEL LABEL CLASS COMPUTE CLASS MODE MAGN -temp - - R- 0 -temp_low temp temp RW 0 -temp_over temp temp RW 0 -remote_temp - - R- 0 -remote_temp_low remote_temp remote_temp RW 0 -remote_temp_over remote_temp remote_temp RW 0 -alarms - - R- 0 -die_code - - R- 0 - -LABEL FEATURE SYMBOL SYSCTL FILE:N -temp SENSORS_ADM1021_TEMP temp1:3 -temp_low SENSORS_ADM1021_TEMP_HYST temp1:2 -temp_over SENSORS_ADM1021_TEMP_OVER temp1:1 -remote_temp SENSORS_ADM1021_REMOTE_TEMP temp2:3 -remote_temp_low SENSORS_ADM1021_REMOTE_TEMP_HYST temp2:2 -remote_temp_over SENSORS_ADM1021_REMOTE_TEMP_OVER temp2:1 -alarms SENSORS_ADM1021_ALARMS alarms:1 -die_code SENSORS_ADM1021_DIE_CODE die_code:1 - - -Chip 'mc1066' - -LABEL LABEL CLASS COMPUTE CLASS MODE MAGN -temp - - R- 0 -temp_low temp temp RW 0 -temp_over temp temp RW 0 -remote_temp - - R- 0 -remote_temp_low remote_temp remote_temp RW 0 -remote_temp_over remote_temp remote_temp RW 0 -alarms - - R- 0 - -LABEL FEATURE SYMBOL SYSCTL FILE:N -temp SENSORS_MAX1617_TEMP temp1:3 -temp_low SENSORS_MAX1617_TEMP_HYST temp1:2 -temp_over SENSORS_MAX1617_TEMP_OVER temp1:1 -remote_temp SENSORS_MAX1617_REMOTE_TEMP temp2:3 -remote_temp_low SENSORS_MAX1617_REMOTE_TEMP_HYST temp2:2 -remote_temp_over SENSORS_MAX1617_REMOTE_TEMP_OVER temp2:1 -alarms SENSORS_MAX1617_ALARMS alarms:1 - - - - - -Old Documentation (may be outdated) ------------------------------------ - -This file documents the adm1021 directories for the Analog Devices ADM1021 -and MAX1617 temperature sensor chip. Note that this last chip should be -fully compatible; it is not yet well-tested, though. - -There will be one directory created for each detected ADM1021 chip. As -ADM1021 chips can only be on a SMBus, they will be called adm1021-i2c-?-??, with -the first question mark being the number of the i2c bus (see /proc/bus/i2c -for a list of them, if i2c-proc is loaded), and the SMBus (I2C) address -of the chip at the end. An ADM1021 is uniquely characterised with these -two numbers. Likewise, for each MAX1617 chip, a directory max1617-i2c-?-?? -will be created. /proc/sys/dev/sensors/chips contains the SYSCTL values for -all chip directories. - -Within each ADM1021 or MAX1617 directory, you can find the following files: -* die_code (ADM1021_SYSCTL_DIE_CODE) - Silicon die (mask) revision code. This driver was written using a sample - device of die code 3. Normally this kind of information isn't reported - in its own proc file, but for a device this simple I didn't think it - would hurt. -* status (ADM1021_SYSCTL_STATUS) - This is an intergral number composed of 8-bits, which indicate the - different alarms and conversion status's of the chip. Here is what - each bit indicates: - 7 BUSY 1 When ADC Converting. - 6 LHIGH# 1 When Local High Temp Limit Tripped. - 5 LLOW# 1 When Local Low Temp Limit Tripped. - 4 RHIGH# 1 When Remote High Temp Limit Tripped. - 3 RLOW# 1 When Remote Low Temp Limit Tripped. - 2 OPEN# 1 When Remote Sensor Open-Circuit. (i.e., no connected remote - sensor) - 1-0 Reserved. - Note: # - These flags stay high until the status register is read or they - are reset by POR. -* temp1 (ADM1021_SYSCTL_TEMP) - A list of three numbers. The first number is the Overtemperature Shutdown - value, the second number is Low limit value, and the third number is the - current temperature. The first two values can be modified. Each value can - be set and read to full-degree accuracy. All values are in degrees Celsius. - An alarm is issued (usually to a connected ADM9240) when the temperature - gets higher then the Overtemperature Shutdown value; it stays on until - the temperature falls back below the Overtemperature Shutdown value. - NOTE: This is different than the way most remote temperature sensors work - (e.g. the LM75), they usually use the lower limit to clear the alarm set - from initially going above the Overtemperature limit. Instead, the - ADM1021 acts much the way that voltage limits work on, say, the LM78 or - ADM9240. A disadvantage to this is that the alarm doesn't have a - hysteresis (like a shmidt-trigger or thermostat) type of function for - doing things like controlling over-heat fans and such. Instead, the - lower limit can be used to signal an alarm if (goodness forbid!) the - computer gets too cold. - If accessed through sysctl, this is a list of longs, each being the - temperature times 10. -* temp2 (ADM1021_SYSCTL_REMOTE_TEMP) - Works exactly the same way as 'temp1', but uses an external temperature - probe for the sensing. The temperature probe is of a silicon diode type - and not of a thermal-resistive type. A probe can easily be made from a - common transister (see the ADM1021 for qualification specs) by shorting - the base to the collector. From the docs: "Transistors such as 2N3904, - 2N3906 or equivalents in SOT-23 package are suitable to use." - -The data for each chip is updated each 1.5 seconds, but only if it is -actually read. And, any alarms triggered between reads which always be -present in the next read just after the alarm was triggered (regardless if -the alarm situation has been resolved or not). - -This driver was written and is maintained by Philip Edelbrock -. Please send corrections/comments to him. For -further technical information on this chip, please get the Acrobat PDF -documentation available from www.analog.com. We'd also like to thank -Analog Devices for helping us with correspondance and free samples to make -this driver (and other Analog Devices drivers) possible. diff --git a/doc/chips/adm1024 b/doc/chips/adm1024 deleted file mode 100644 index 4965fa61..00000000 --- a/doc/chips/adm1024 +++ /dev/null @@ -1,12 +0,0 @@ -Kernel driver `adm1024.o' -========================= - -Status: Complete; Alpha. - -Supported chips: - * Analog Devices ADM1024 - Prefix: 'adm1024' - Addresses scanned: I2C 0x2c - 0x2e - Datasheet: Publicly available at the Analog Devices website - -Author: Ken Bowley diff --git a/doc/chips/adm1025 b/doc/chips/adm1025 deleted file mode 100644 index 0a2ab693..00000000 --- a/doc/chips/adm1025 +++ /dev/null @@ -1,135 +0,0 @@ -Kernel driver `adm1025.o' -========================= - -Status: Complete, known to work but not heavily tested - -Supported chips: - * Analog Devices ADM1025 - Prefix: 'adm1025' - Addresses scanned: I2C 0x2c - 0x2e - Datasheet: Publicly available at the Analog Devices website - * Philips NE1619 - Prefix: 'ne1619' - Addresses scanned: I2C 0x2c - 0x2d - Datasheet: Publicly available at the Philips website - -The NE1619 presents some differences with the original ADM1025: - * Only two possible addresses (0x2c - 0x2d). - * No temperature offset register, but we don't use it anyway. - * No INT mode for pin 16. We don't play with it anyway. - -Author: Chen-Yuan Wu and Jean Delvare - -License: GPL - - -Module Parameters ------------------ - -* force: short array (min = 1, max = 48) - List of adapter,address pairs to boldly assume to be present -* force_adm1025: short array (min = 1, max = 48) - List of adapter,address pairs which are unquestionably assumed to contain - a `adm1025' chip -* force_ne1619: short array (min = 1, max = 48) - List of adapter,address pairs which are unquestionably assumed to contain - a `ne1619' chip -* probe: short array (min = 1, max = 48) - List of adapter,address pairs to scan additionally -* probe_range: short array (min = 1, max = 48) - List of adapter,start-addr,end-addr triples to scan additionally -* ignore: short array (min = 1, max = 48) - List of adapter,address pairs not to scan -* ignore_range: short array (min = 1, max = 48) - List of adapter,start-addr,end-addr triples not to scan - - -Description ------------ - -(This is from Analog Devices.) The ADM1025 is a complete system hardware -monitor for microprocessor-based systems, providing measurement and limit -comparison of various system parameters. Five voltage measurement inputs -are provided, for monitoring +2.5V, +3.3V, +5V and +12V power supplies and -the processor core voltage. The ADM1025 can monitor a sixth power-supply -voltage by measuring its own VCC. One input (two pins) is dedicated to a -remote temperature-sensing diode and an on-chip temperature sensor allows -ambient temperature to be monitored. - -One specificity of this chip is that the pin 11 can be hardwired in two -different manners. It can act as the +12V power-supply voltage analog -input, or as the a fifth digital entry for the VID reading (bit 4). It's -kind of strange since both are useful, and the reason for designing the -chip that way is obscure at least to me. The bit 5 of the configuration -register can be used to define how the chip is hardwired. Please note -that it is not a choice you have to make as the user. The choice was -already made by your motherboard's maker. If the configuration bit isn't -set properly, you'll have a wrong +12V reading or a wrong VID reading. -The way the driver handles that is to preserve this bit through the -initialization process, assuming that the BIOS set it up properly -beforehand. If it turns out not to be true in some cases, we'll provide -a module parameter to force modes. - - -Chip Features -------------- - -Chips 'adm1025' and 'ne1619' - -LABEL LABEL CLASS COMPUTE CLASS MODE MAGN -in0 - - R- 2 -in1 - - R- 2 -in2 - - R- 2 -in3 - - R- 2 -in4 - - R- 2 -in5 - - R- 2 -in0_min in0 in0 RW 2 -in1_min in1 in1 RW 2 -in2_min in2 in2 RW 2 -in3_min in3 in3 RW 2 -in4_min in4 in4 RW 2 -in5_min in5 in5 RW 2 -in0_max in0 in0 RW 2 -in1_max in1 in1 RW 2 -in2_max in2 in2 RW 2 -in3_max in3 in3 RW 2 -in4_max in4 in4 RW 2 -in5_max in5 in5 RW 2 -temp1 - - R- 1 -temp1_low temp1 temp1 RW 1 -temp1_high temp1 temp1 RW 1 -temp2 - - R- 1 -temp2_low temp2 temp2 RW 1 -temp2_high temp2 temp2 RW 1 -vid - - R- 3 -vrm - - RW 1 -alarms - - R- 0 - -LABEL FEATURE SYMBOL SYSCTL FILE:N -in0 SENSORS_ADM1025_IN0 in0:3 -in1 SENSORS_ADM1025_IN1 in1:3 -in2 SENSORS_ADM1025_IN2 in2:3 -in3 SENSORS_ADM1025_IN3 in3:3 -in4 SENSORS_ADM1025_IN4 in4:3 -in5 SENSORS_ADM1025_IN5 in5:3 -in0_min SENSORS_ADM1025_IN0_MIN in0:1 -in1_min SENSORS_ADM1025_IN1_MIN in1:1 -in2_min SENSORS_ADM1025_IN2_MIN in2:1 -in3_min SENSORS_ADM1025_IN3_MIN in3:1 -in4_min SENSORS_ADM1025_IN4_MIN in4:1 -in5_min SENSORS_ADM1025_IN5_MIN in5:1 -in0_max SENSORS_ADM1025_IN0_MAX in0:2 -in1_max SENSORS_ADM1025_IN1_MAX in1:2 -in2_max SENSORS_ADM1025_IN2_MAX in2:2 -in3_max SENSORS_ADM1025_IN3_MAX in3:2 -in4_max SENSORS_ADM1025_IN4_MAX in4:2 -in5_max SENSORS_ADM1025_IN5_MAX in5:2 -temp1 SENSORS_ADM1025_TEMP1 temp1:3 -temp1_low SENSORS_ADM1025_TEMP1_LOW temp1:2 -temp1_high SENSORS_ADM1025_TEMP1_HIGH temp1:1 -temp2 SENSORS_ADM1025_TEMP2 temp2:3 -temp2_low SENSORS_ADM1025_TEMP2_LOW temp2:2 -temp2_high SENSORS_ADM1025_TEMP2_HIGH temp2:1 -vid SENSORS_ADM1025_VID vid:1 -vrm SENSORS_ADM1025_VRM vrm:1 -alarms SENSORS_ADM1025_ALARMS alarms:1 diff --git a/doc/chips/adm1026 b/doc/chips/adm1026 deleted file mode 100644 index 6330927a..00000000 --- a/doc/chips/adm1026 +++ /dev/null @@ -1,217 +0,0 @@ -Kernel driver `adm1026.o' -====================== - -Status: In development - -Supported chips: - * Analog Devices ADM1026 - Prefix: 'adm1026' - Addresses scanned: I2C 0x2c, 0x2d, 0x2e - -Author: Philip Pokorny - for Penguin Computing - - -Module Parameters ------------------ - -* force: short array (min = 1, max = 48) - List of adapter,address pairs to boldly assume to be present -* force_adm1026: short array (min = 1, max = 48) - List of adapter,address pairs which are unquestionably assumed to contain - an `adm1026' chip -* ignore: short array (min = 1, max = 48) - List of adapter,address pairs not to scan -* ignore_range: short array (min = 1, max = 48) - List of adapter,start-addr,end-addr triples not to scan -* probe: short array (min = 1, max = 48) - List of adapter,address pairs to scan additionally -* probe_range: short array (min = 1, max = 48) - List of adapter,start-addr,end-addr triples to scan additionally - -The following only apply to the first ADM1026 detected. These are a -workaround for if your BIOS hasn't setup your chip. - -* gpio_input: int array (min = 1, max = 17) - List of GPIO pins (0-16) to program as inputs -* gpio_output: int array (min = 1, max = 17) - List of GPIO pins (0-16) to program as outputs -* gpio_inverted: int array (min = 1, max = 17) - List of GPIO pins (0-16) to program as inverted -* gpio_normal: int array (min = 1, max = 17) - List of GPIO pins (0-16) to program as normal/non-inverted -* gpio_fan: int array (min = 1, max = 8) - List of GPIO pins (0-7) to program as fan tachs - - -Description ------------ - -This driver implements support for the Analog Devices ADM1026. Analog -Devices calls it a "complete thermal system management controller." - -The ADM1026 implements three (3) temperature sensors, 17 voltage -sensors, 16 general purpose digital I/O lines, eight (8) fan speed -sensors (8-bit), an analog output and a PWM output along with limit, -alarm and mask bits for all of the above. There is even 8k bytes of -EEPROM memory on chip. - -Temperatures are measured in degrees Celsius. There are two external -sensor inputs and one internal sensor. Each sensor has a high and low -limit. If the limit is exceeded, an interrupt (#SMBALERT) can be -generated. The interrupts can be masked. In addition, there are -over-temp limits for each sensor. If this limit is exceeded, the -#THERM output will be asserted. The current temperature and limits -have a resolution of 1 degree. - -Fan rotation speeds are reported in RPM (rotations per minute) but -measured in counts of a 22.5kHz internal clock. Each fan has a high -limit which corresponds to a minimum fan speed. If the limit is -exceeded, an interrupt can be generated. Each fan can be programmed -to divide the reference clock by 1, 2, 4 or 8. Not all RPM values can -accurately be represented, so some rounding is done. With a divider of -8, the slowest measureable speed of a one pulse per rev fan is 1323 -RPM. Two pulse per rev fans can be measured as slow as 661 RPM. - -Voltage sensors (in0 to in16) report their values in volts. An alarm -is triggered if the voltage has crossed a programmable minimum or -maximum limit. Note that minimum in this case always means 'closest -to zero'; this is important for negative voltage measurements. -Several inputs have integrated attenuators so they can measure higher -voltages directly. 3.3V, 5V, 12V, -12V and battery voltage all have -dedicated inputs. There are several inputs scaled to 0-3V full-scale -range for SCSI terminator power. The remaining inputs are not scaled -and have a 0-2.5V full-scale range. A 2.5V or 1.82V reference voltage -is provided for negative voltage measurements. - -If an alarm triggers, it will remain triggered until the hardware -register is read at least once. This means that the cause for the -alarm may already have disappeared! Note that in the current -implementation, all hardware registers are read whenever any data is -read (unless it is less than 2.0 seconds since the last update). This -means that you can easily miss once-only alarms. - -The ADM1026 measures continuously. Analog inputs are measured about 4 -times a second. Fan speed measurement time depends on fan speed and -divisor. It can take as long as 1.5 seconds to measure all fan -speeds. - -The ADM1026 has the ability to automaticaly control fan speed based on -the temperature sensor inputs. Both the PWM output and the DAC output -can be used to control fan speed. Usually only one of these two -outputs will be used. Write the minimum PWM or DAC value to the -appropriate control register. Then set the low temperature limit in -the tmin values for each temperature sensor. The range of control is -fixed at 20 degC, and the largest difference between current and tmin -of the temperature sensors sets the control output. See the datasheet -for several example circuits for controlling fan speed with the PWM -and DAC outputs. The fan speed sensors do not have PWM compensation, -so it is probably best to control the fan voltage from the power -lead rather than on the ground lead. - -The datasheet shows an example application with VID signals attached -to GPIO lines. Unfortunately, the chip may not be connected to the -VID lines in this way. The driver assumes that the chips *is* -connected this way to get a vid voltage. If the VID value is wrong or -not wired as shown in the example, then you will need to write the -correct VID value to the driver either based on the GPIO values or -setting it directly. The value written to VID should be the *raw* VID -value (0 to 0x3f) or -1 (to restore the default value). When read, -the vid interface returns the scaled voltage according to the VRM spec -selected. - -Example sensors.conf --------------------- - -Here is an example sensors.conf configuration section for the ADM1026. - ---------- cut here --------- -chip "adm1026-*" - -# Voltage inputs - label in0 "V2.25_0" # Scaled for "SCSI terminator"? - label in1 "V2.25_1" # supply voltage? - label in2 "V2.25_2" - label in3 "V2.25_3" - label in4 "V2.25_4" - label in5 "V2.25_5" - - label in6 "V1.875_0" # Unscaled inputs - label in7 "V1.875_1" - -# If temp3 is enabled, in8 and in9 are disabled. -# label in8 "V1.875_2" -# label in9 "V1.875_3" - ignore in8 - ignore in9 - -# Dedicated voltage inputs - label in10 "Vbat" - label in11 "V3.3STBY" - label in12 "V3.3MAIN" - label in13 "V5" - label in14 "Vccp" - label in15 "V12" - label in16 "V-12" - -# Temperature inputs - label temp1 "Board" - label temp2 "CPU0" - label temp3 "CPU1" - -# Fan inputs - label fan0 "CPU_Fan" - label fan1 "Fan1" - label fan2 "Fan2" - label fan3 "Fan3" - label fan4 "Fan4" - label fan5 "Fan5" - label fan6 "Fan6" - label fan7 "Fan7" - -# PWM Outputs - label pwm "PWM" - -# Voltage scaling is done on-chip. No 'compute' directive -# should be necessary. If in0-in9 have external scaling, -# set it here. - -# compute in0 @ * 2.5, @ / 2.5 - -# Adjust fans speeds for actual pulses per rev -# compute fan0 @ / 2, @ * 2 # 2 pulse per rev -# compute fan1 @ / 3, @ * 3 # 3 pulse per rev -# compute fan2 @ / 4, @ * 4 # 4 pulse per rev -# compute fan3 @ / 8, @ * 8 # 8 pulse per rev - -# Set VRM version - set vrm 9.1 -# set vid 1.580 - -# Set voltage limits - set in10_min 3.0 * 0.95 - set in10_max 3.0 * 1.05 - set in11_min 3.3 * 0.95 - set in11_max 3.3 * 1.05 - set in12_min 3.3 * 0.95 - set in12_max 3.3 * 1.05 - set in13_min 5.0 * 0.95 - set in13_max 5.0 * 1.05 -# Uncomment if VID is wired or set above -# set in14_min vid * 0.95 -# set in14_max vid * 1.05 - set in15_min 12 * 0.95 - set in15_max 12 * 1.05 - set in16_min -12 * 0.95 - set in16_max -12 * 1.05 - -# Set Fan limits - set fan0_min 7000 - set fan1_min 7000 - set fan2_min 7000 - set fan3_min 7000 - set fan4_min 3000 - set fan5_min 3000 - set fan6_min 3000 - set fan7_min 3000 - diff --git a/doc/chips/adm1031 b/doc/chips/adm1031 deleted file mode 100644 index 6d1e0162..00000000 --- a/doc/chips/adm1031 +++ /dev/null @@ -1,109 +0,0 @@ -Kernel driver `adm1031.o' -========================= - -Status: Driver supports basic temp and fan readings, min/max/crit settings - alarms. This driver does not support auto fan control. - -Supported chips: - * Analog Devices ADM1030 - Prefix: 'adm1030' - Addresses scanned: I2C 0x2c to 0x2e - Datasheet: Publicly available at the Analog Devices website - http://www.analog.com/en/prod/0,2877,ADM1030,00.html - - * Analog Devices ADM1031 - Prefix: 'adm1031' - Addresses scanned: I2C 0x2c to 0x2e - Datasheet: Publicly available at the Analog Devices website - http://www.analog.com/en/prod/0,2877,ADM1031,00.html - - -Author: Alexandre d'Alton - -License: GPL - - -Module Parameters ------------------ - -* force: short array (min = 1, max = 48) - List of adapter,address pairs to boldly assume to be present -* force_adm1030: short array (min = 1, max = 48) - List of adapter,address pairs which are unquestionably assumed to contain - a `adm1030' chip -* force_adm1031: short array (min = 1, max = 48) - List of adapter,address pairs which are unquestionably assumed to contain - a `adm1031' chip -* probe: short array (min = 1, max = 48) - List of adapter,address pairs to scan additionally -* probe_range: short array (min = 1, max = 48) - List of adapter,start-addr,end-addr triples to scan additionally -* ignore: short array (min = 1, max = 48) - List of adapter,address pairs not to scan -* ignore_range: short array (min = 1, max = 48) - List of adapter,start-addr,end-addr triples not to scan - - -Description ------------ - -ADM1030 and ADM1031 are digital temperature sensors and fan controllers. -They sense their own temperature as well as the temperature of up to one -(ADM1030) or two (ADM1031) external diodes. - -All temperature values are given in degrees Celsius. Resolution -is 0.5 degree for the local temperature, 0.125 degree for the remote -temperatures. - -Each temperature channel has its own high and low limits, plus a critical -limit. - -The ADM1030 monitors a single fan speed, while the ADM1031 monitors up to -two. Each fan channel has its own low speed limit. - - -Chip Features -------------- - -Chip 'adm1030' - -LABEL LABEL CLASS COMPUTE CLASS MODE MAGN -temp1 - - R- 3 -temp1_high temp1 temp1 RW 3 -temp1_low temp1 temp1 RW 3 -temp1_crit temp1 temp1 RW 3 -temp2 - - R- 3 -temp2_high temp2 temp2 RW 3 -temp2_low temp2 temp2 RW 3 -temp2_crit temp2 temp2 RW 3 - -fan1_input - - R- 0 -fan1_min fan1 fan1 RW 0 -fan1_div fan1 - RW 0 - -alarms - - R- 0 - -Chip 'adm1031' - -LABEL LABEL CLASS COMPUTE CLASS MODE MAGN -temp1 - - R- 3 -temp1_high temp1 temp1 RW 3 -temp1_low temp1 temp1 RW 3 -temp1_crit temp1 temp1 RW 3 -temp2 - - R- 3 -temp2_high temp2 temp2 RW 3 -temp2_low temp2 temp2 RW 3 -temp2_crit temp2 temp2 RW 3 -temp3 - - R- 3 -temp3_high temp3 temp3 RW 3 -temp3_low temp3 temp3 RW 3 -temp3_crit temp3 temp3 RW 3 - -fan1_input - - R- 0 -fan1_min fan1 fan1 RW 0 -fan1_div fan1 - RW 0 -fan2_input - - R- 0 -fan2_min fan2 fan2 RW 0 -fan2_div fan2 - RW 0 - -alarms - - R- 0 diff --git a/doc/chips/adm9240 b/doc/chips/adm9240 deleted file mode 100644 index bdad871d..00000000 --- a/doc/chips/adm9240 +++ /dev/null @@ -1,424 +0,0 @@ -Kernel driver `adm9240.o' -========================= - -Status: Complete and tested - -Supported chips: - * Analog Devices ADM9240 - Prefix: 'adm9240' - Addresses scanned: I2C 0x2c - 0x2f - Datasheet: Publicly available at the Analog Devices website - * Dallas Semiconductor DS1780 - Prefix: 'ds1780' - Addresses scanned: I2C 0x2c - 0x2f - Datasheet: Publicly available at the Dallas Semiconductor website - * National Semiconductor LM81 - Prefix: 'lm81' - Addresses scanned: I2C 0x2c - 0x2f - Datasheet: Publicly available at the National Semiconductor website - - -Author: Frodo Looijaard and Philip Edelbrock - - - -Module Parameters ------------------ - -* force: short array (min = 1, max = 48) - List of adapter,address pairs to boldly assume to be present -* force_adm9240: short array (min = 1, max = 48) - List of adapter,address pairs which are unquestionably assumed to contain - a `adm9240' chip -* force_ds1780: short array (min = 1, max = 48) - List of adapter,address pairs which are unquestionably assumed to contain - a `ds1780' chip -* force_lm81: short array (min = 1, max = 48) - List of adapter,address pairs which are unquestionably assumed to contain - a `lm81' chip -* ignore: short array (min = 1, max = 48) - List of adapter,address pairs not to scan -* ignore_range: short array (min = 1, max = 48) - List of adapter,start-addr,end-addr triples not to scan -* probe: short array (min = 1, max = 48) - List of adapter,address pairs to scan additionally -* probe_range: short array (min = 1, max = 48) - List of adapter,start-addr,end-addr triples to scan additionally - - -Description ------------ - -This driver implements support for the Analog Devices ADM9240, -Dallas Semiconductor DS1780, and National Semiconductor LM81 chips. -These chips appear to be completely -identical, except for the manufacturer IDs encoded in two registers, and -the speed with which they update their sensor readings. - -The chips implement six voltage sensors, a temperature sensor, -two fan rotation speed sensors, VID lines and some miscellaneous stuff. - -Temperatures are measured in degrees Celsius. An alarm is triggered whenever -the temperature is above the hot limit, and will continue to be generated -until the temperature has dropped beneath the hysteresis limit. Measurements -are guaranteed between -40 and +125 degrees. The current temperature -has a resolution of 0.5 degrees, the limits of 1 degree. - -Fan rotation speeds are reported in RPM (rotations per minute). An alarm is -triggered if the rotation speed has dropped below a programmable limit. Fan -readings can be divided by a programmable divider (1, 2, 4 or 8) to give -the readings more range or accuracy. Not all RPM values can accurately be -represented, so some rounding is done. With a divider of 2, the lowest -representable value is around 2600 RPM. - -Voltage sensors (also known as IN sensors) report their values in volts. -An alarm is triggered if the voltage has crossed a programmable minimum -or maximum limit. Note that minimum in this case always means 'closest to -zero'; this is important for negative voltage measurements. -IMPORTANT: The current voltage measurement system is very probably broken. -Please report back to us if you have a ADM9240 or DS1780! - -The VID lines encode the core voltage value: the voltage level your processor -should work with. This is hardcoded by the mainboard and/or processor itself. -It is a value in volts. When it is unconnected, you will often find the -value 3.50 V here. - -The analog output can be programmed separatedly. It can take values -between 0 and 255. What it actually does is mainboard-dependent; it -might influence the fan speed. Please report to us whether this is -the case with your ADM9240. - -In addition to the alarms described above, the CHAS alarm triggers -if your computer case is open. - -If an alarm triggers, it will remain triggered until the hardware register -is read at least once. This means that the cause for the alarm may -already have disappeared! Note that in the current implementation, all -hardware registers are read whenever any data is read (unless it is less -than 1.5 seconds since the last update). This means that you can easily -miss once-only alarms. - -Thes ADM9240 only updates its values every 0.5 seconds; the DS1780 one -every 2 seconds; and the LM81 every 0.4 seconds. -Reading them more often will do no harm, but will return -'old' values. (NB: theoretically, this could be done much faster for the -ADM9240, but there is no real reason to do so, and this way the SMBus use -is kept within reasonable limits) - - -Chip Features -------------- - -Chip `adm9240' - LABEL LABEL CLASS COMPUTE CLASS ACCESS MAGNITUDE - 2.5V NONE NONE R 2 - Vccp1 NONE NONE R 2 - 3.3V NONE NONE R 2 - 5V NONE NONE R 2 - 12V NONE NONE R 2 - Vccp2 NONE NONE R 2 - 2.5V_min 2.5V 2.5V RW 2 - Vccp1_min Vccp1 Vccp1 RW 2 - 3.3V_min 3.3V 3.3V RW 2 - 5V_min 5V 5V RW 2 - 12V_min 12V 12V RW 2 - Vccp2_min Vccp2 Vccp2 RW 2 - 2.5V_max 2.5V 2.5V RW 2 - Vccp1_max Vccp1 Vccp1 RW 2 - 3.3V_max 3.3V 3.3V RW 2 - 5V_max 5V 5V RW 2 - 12V_max 12V 12V RW 2 - Vccp2_max Vccp2 Vccp2 RW 2 - fan1 NONE NONE R 0 - fan2 NONE NONE R 0 - fan1_min fan1 fan1 RW 0 - fan2_min fan2 fan2 RW 0 - temp NONE NONE R 1 - temp_hyst temp temp RW 1 - temp_over temp temp RW 1 - vid NONE NONE R 2 - fan1_div fan1 NONE RW 0 - fan2_div fan2 NONE RW 0 - alarms NONE NONE R 0 - analog_out NONE NONE RW 0 - - LABEL FEATURE SYMBOL SYSCTL FILE:NR - 2.5V SENSORS_ADM9240_IN0 2.5V:3 - Vccp1 SENSORS_ADM9240_IN1 Vccp1:3 - 3.3V SENSORS_ADM9240_IN2 3.3V:3 - 5V SENSORS_ADM9240_IN3 5V:3 - 12V SENSORS_ADM9240_IN4 12V:3 - Vccp2 SENSORS_ADM9240_IN5 Vccp2:3 - 2.5V_min SENSORS_ADM9240_IN0_MIN 2.5V:1 - Vccp1_min SENSORS_ADM9240_IN1_MIN Vccp1:1 - 3.3V_min SENSORS_ADM9240_IN2_MIN 3.3V:1 - 5V_min SENSORS_ADM9240_IN3_MIN 5V:1 - 12V_min SENSORS_ADM9240_IN4_MIN 12V:1 - Vccp2_min SENSORS_ADM9240_IN5_MIN Vccp2:1 - 2.5V_max SENSORS_ADM9240_IN0_MAX 2.5V:2 - Vccp1_max SENSORS_ADM9240_IN1_MAX Vccp1:2 - 3.3V_max SENSORS_ADM9240_IN2_MAX 3.3V:2 - 5V_max SENSORS_ADM9240_IN3_MAX 5V:2 - 12V_max SENSORS_ADM9240_IN4_MAX 12V:2 - Vccp2_max SENSORS_ADM9240_IN5_MAX Vccp2:2 - fan1 SENSORS_ADM9240_FAN1 fan1:2 - fan2 SENSORS_ADM9240_FAN2 fan2:2 - fan1_min SENSORS_ADM9240_FAN1_MIN fan1:1 - fan2_min SENSORS_ADM9240_FAN2_MIN fan2:1 - temp SENSORS_ADM9240_TEMP temp:3 - temp_hyst SENSORS_ADM9240_TEMP_HYST temp:2 - temp_over SENSORS_ADM9240_TEMP_OVER temp:1 - vid SENSORS_ADM9240_VID vid:1 - fan1_div SENSORS_ADM9240_FAN1_DIV fan_div:1 - fan2_div SENSORS_ADM9240_FAN2_DIV fan_div:2 - alarms SENSORS_ADM9240_ALARMS alarms:1 - analog_out SENSORS_ADM9240_ANALOG_OUT analog_out:1 - - -Chip `ds1780' - LABEL LABEL CLASS COMPUTE CLASS ACCESS MAGNITUDE - 2.5V NONE NONE R 2 - Vccp1 NONE NONE R 2 - 3.3V NONE NONE R 2 - 5V NONE NONE R 2 - 12V NONE NONE R 2 - Vccp2 NONE NONE R 2 - 2.5V_min 2.5V 2.5V RW 2 - Vccp1_min Vccp1 Vccp1 RW 2 - 3.3V_min 3.3V 3.3V RW 2 - 5V_min 5V 5V RW 2 - 12V_min 12V 12V RW 2 - Vccp2_min Vccp2 Vccp2 RW 2 - 2.5V_max 2.5V 2.5V RW 2 - Vccp1_max Vccp1 Vccp1 RW 2 - 3.3V_max 3.3V 3.3V RW 2 - 5V_max 5V 5V RW 2 - 12V_max 12V 12V RW 2 - Vccp2_max Vccp2 Vccp2 RW 2 - fan1 NONE NONE R 0 - fan2 NONE NONE R 0 - fan1_min fan1 fan1 RW 0 - fan2_min fan2 fan2 RW 0 - temp NONE NONE R 1 - temp_hyst temp temp RW 1 - temp_over temp temp RW 1 - vid NONE NONE R 2 - fan1_div fan1 NONE RW 0 - fan2_div fan2 NONE RW 0 - alarms NONE NONE R 0 - analog_out NONE NONE RW 0 - - LABEL FEATURE SYMBOL SYSCTL FILE:NR - 2.5V SENSORS_DS1780_IN0 2.5V:3 - Vccp1 SENSORS_DS1780_IN1 Vccp1:3 - 3.3V SENSORS_DS1780_IN2 3.3V:3 - 5V SENSORS_DS1780_IN3 5V:3 - 12V SENSORS_DS1780_IN4 12V:3 - Vccp2 SENSORS_DS1780_IN5 Vccp2:3 - 2.5V_min SENSORS_DS1780_IN0_MIN 2.5V:1 - Vccp1_min SENSORS_DS1780_IN1_MIN Vccp1:1 - 3.3V_min SENSORS_DS1780_IN2_MIN 3.3V:1 - 5V_min SENSORS_DS1780_IN3_MIN 5V:1 - 12V_min SENSORS_DS1780_IN4_MIN 12V:1 - Vccp2_min SENSORS_DS1780_IN5_MIN Vccp2:1 - 2.5V_max SENSORS_DS1780_IN0_MAX 2.5V:2 - Vccp1_max SENSORS_DS1780_IN1_MAX Vccp1:2 - 3.3V_max SENSORS_DS1780_IN2_MAX 3.3V:2 - 5V_max SENSORS_DS1780_IN3_MAX 5V:2 - 12V_max SENSORS_DS1780_IN4_MAX 12V:2 - Vccp2_max SENSORS_DS1780_IN5_MAX Vccp2:2 - fan1 SENSORS_DS1780_FAN1 fan1:2 - fan2 SENSORS_DS1780_FAN2 fan2:2 - fan1_min SENSORS_DS1780_FAN1_MIN fan1:1 - fan2_min SENSORS_DS1780_FAN2_MIN fan2:1 - temp SENSORS_DS1780_TEMP temp:3 - temp_hyst SENSORS_DS1780_TEMP_HYST temp:2 - temp_over SENSORS_DS1780_TEMP_OVER temp:1 - vid SENSORS_DS1780_VID vid:1 - fan1_div SENSORS_DS1780_FAN1_DIV fan_div:1 - fan2_div SENSORS_DS1780_FAN2_DIV fan_div:2 - alarms SENSORS_DS1780_ALARMS alarms:1 - analog_out SENSORS_DS1780_ANALOG_OUT analog_out:1 - - -Chip `lm81' - LABEL LABEL CLASS COMPUTE CLASS ACCESS MAGNITUDE - 2.5V NONE NONE R 2 - Vccp1 NONE NONE R 2 - 3.3V NONE NONE R 2 - 5V NONE NONE R 2 - 12V NONE NONE R 2 - Vccp2 NONE NONE R 2 - 2.5V_min 2.5V 2.5V RW 2 - Vccp1_min Vccp1 Vccp1 RW 2 - 3.3V_min 3.3V 3.3V RW 2 - 5V_min 5V 5V RW 2 - 12V_min 12V 12V RW 2 - Vccp2_min Vccp2 Vccp2 RW 2 - 2.5V_max 2.5V 2.5V RW 2 - Vccp1_max Vccp1 Vccp1 RW 2 - 3.3V_max 3.3V 3.3V RW 2 - 5V_max 5V 5V RW 2 - 12V_max 12V 12V RW 2 - Vccp2_max Vccp2 Vccp2 RW 2 - fan1 NONE NONE R 0 - fan2 NONE NONE R 0 - fan1_min fan1 fan1 RW 0 - fan2_min fan2 fan2 RW 0 - temp NONE NONE R 1 - temp_hyst temp temp RW 1 - temp_over temp temp RW 1 - vid NONE NONE R 2 - fan1_div fan1 NONE RW 0 - fan2_div fan2 NONE RW 0 - alarms NONE NONE R 0 - analog_out NONE NONE RW 0 - - LABEL FEATURE SYMBOL SYSCTL FILE:NR - 2.5V SENSORS_ADM9240_IN0 2.5V:3 - Vccp1 SENSORS_ADM9240_IN1 Vccp1:3 - 3.3V SENSORS_ADM9240_IN2 3.3V:3 - 5V SENSORS_ADM9240_IN3 5V:3 - 12V SENSORS_ADM9240_IN4 12V:3 - Vccp2 SENSORS_ADM9240_IN5 Vccp2:3 - 2.5V_min SENSORS_ADM9240_IN0_MIN 2.5V:1 - Vccp1_min SENSORS_ADM9240_IN1_MIN Vccp1:1 - 3.3V_min SENSORS_ADM9240_IN2_MIN 3.3V:1 - 5V_min SENSORS_ADM9240_IN3_MIN 5V:1 - 12V_min SENSORS_ADM9240_IN4_MIN 12V:1 - Vccp2_min SENSORS_ADM9240_IN5_MIN Vccp2:1 - 2.5V_max SENSORS_ADM9240_IN0_MAX 2.5V:2 - Vccp1_max SENSORS_ADM9240_IN1_MAX Vccp1:2 - 3.3V_max SENSORS_ADM9240_IN2_MAX 3.3V:2 - 5V_max SENSORS_ADM9240_IN3_MAX 5V:2 - 12V_max SENSORS_ADM9240_IN4_MAX 12V:2 - Vccp2_max SENSORS_ADM9240_IN5_MAX Vccp2:2 - fan1 SENSORS_ADM9240_FAN1 fan1:2 - fan2 SENSORS_ADM9240_FAN2 fan2:2 - fan1_min SENSORS_ADM9240_FAN1_MIN fan1:1 - fan2_min SENSORS_ADM9240_FAN2_MIN fan2:1 - temp SENSORS_ADM9240_TEMP temp:3 - temp_hyst SENSORS_ADM9240_TEMP_HYST temp:2 - temp_over SENSORS_ADM9240_TEMP_OVER temp:1 - vid SENSORS_ADM9240_VID vid:1 - fan1_div SENSORS_ADM9240_FAN1_DIV fan_div:1 - fan2_div SENSORS_ADM9240_FAN2_DIV fan_div:2 - alarms SENSORS_ADM9240_ALARMS alarms:1 - analog_out SENSORS_ADM9240_ANALOG_OUT analog_out:1 - - - - -Old Documentation ------------------ - -Supports the Analog Devices ADM9240 and the Dallas Semiconductor DS1780. -These chips are apparently identical except for the manufacturer ID -register. -The proc directory will be adm9240-i2c-x-xx for the adm9240 and -ds1780-i2c-x-xx for the ds1780. - ------------------------------------------------------------------------ - -This file documents the adm9240 directories for the Analog Devices -ADM9240 hardware health monitoring chip found on some Intel mainboards -(and others?). - -There will be one directory created for each detected ADM9240 chip. -Each chip must be on the SMBus. Directories are called things -like adm9240-i2c-1-2c. /proc/sys/dev/sensors/chips contains the SYSCTL -values for all chip directories. - -Within each ADM9240 directory, you can find the following files: -* alarms (ADM9240_SYSCTL_ALARMS) - A number which indicates which alarms are on. An alarm gets triggered when - some limit has been crossed. This number is composed from a 16 bit - value which is the combination of the Interrupt Status Register 1 - (low byte) and 2 (high byte). - This file can not be written to. - The number is the logical OR of the following components (bit # - followed by a description): - -0 +2.5 V_Error Read Only A "1" indicates a high or low limit has been exceeded. -1 VCCP_Error Read Only A "1" indicates a high or low limit has been exceeded. -2 +3.3 V_Error Read Only A "1" indicates a high or low limit has been exceeded. -3 +5 V_Error Read Only A "1" indicates a high or low limit has been exceeded. -4 Temp_Error Read Only A "1" indicates that a temperature interrupt has been set. -5 Reserved Read Only Undefined. -6 FAN1_Error Read Only A "1" indicates that a fan count limit has been exceeded. -7 FAN2_Error Read Only A "1" indicates that a fan count limit has been exceeded. -8 +12 V_Error Read Only A "1" indicates a high or low limit has been exceeded. -9 VCCP2_Error Read Only A "1" indicates a high or low limit has been exceeded. -10 Reserved Read Only Undefined. -11 Reserved Read Only Undefined. -12 Chassis_Error Read Only A "1" indicates chassis intrusion has gone high. -13 Reserved Read Only Undefined. -14 Reserved Read Only Undefined. -15 Reserved Read Only Undefined. - - If accessed through sysctl, this value is a long. -* fan[1-3] (ADM9240_SYSCTL_FAN[1-2]) - A list of two numbers. The first is the minimum fan rotation limit; the - second is the current fan rotation speed. Both are in RPM (rotations per - minute). An alarm is triggered if the rotation speed drops below the - limit. The first value can be changed. Not all RPM values can accurately - be represented, so some rounding is done. - If accessed through sysctl, this is a list of longs. -* fan_div (LM78_SYSCTL_FAN_DIV) - A list of two numbers, one for each fan. Each number can be either 1, 2, - 4 or 8. It is the internal scaling factor used for the fan rotations. If - you change this number, the fan readings get more or less detailed, but - the range in which they can be read too. Higher numbers give better - resolution, but less range. The first two numbers can be changed, the - third not. - If accessed through sysctl, this is a list of longs. -* 2.5V, Vccp1, 3.3V, 5V, 12V, and Vccp2 (ADM9240_SYSCTL_IN[0-5] in the - order shown) - A list of three numbers. The first is the minimum limit, the second is the - maximum limit, and the third is the current value. Note that - minimum means 'closest to zero'; so if the normal value equals -10, a - minimum could equal -9, and a maximum -11. Vccp1 and Vccp2 reflect core - voltages; they are by default set from the vid values, or set to 2.80V - if the vid lines seem to be unconnected. Not all voltage values - can be accurately represented, so some rounding is done. - The first two numbers can be changed, the third not. - If accessed through sysctl, this is a list of longs, each being the voltage - times 100. -* temp - A list of three numbers. The first number is the Overtemperature Shutdown - value; the second is the Hysteresis value and the third number is the - current value. The first two values can be modified. All values are in - degrees Celsius. An alarm is issued when the temperature first gets above - the Overtemperature Shutdown value; no more alarms are issued until the - temperature gets below the Hysteresis value, at which moment another alarm - is issued, and the state is reset. A more useful behaviour can be found - by setting the Hysteresis value to +127 degrees Celsius; in this case, - alarms are issued during all the time when the actual temperature is - above the Overtemperature Shutdown value. - The first two numbers can be changed, the third not. - If accessed through sysctl, this is a list of longs, each being the - temperature in degrees Celsius times 10. -* vid - The core voltage value (the voltage level your processor should work with), - in volts. This is the value IN0 and IN1 are initialized to. If unconnected, - it usually reads 3.50V. - This number can not be changed. - If accessed through sysctl, this is a long, being the voltage times 100. -* analog_out - This is feature is specific to the ADM9240. It is a DAC voltage - control register for the Analog-Out pin. Valid values are from 255 - to 0 (with 255 being the highest voltage, and 0 the lowest). From - the docs: "The ADM9240 has a single analog output from an unsigned - 8-bit DAC which produces 0 V - 1.25 V." - -The data for each ADM9240 is updated each 1.5 seconds, -but only if it is actually read. - -Note: Much of this documentation is copied from the LM78 documenation -(the device from which most featuers of the ADM9240 is modelled from). -The maintainer of the ADM9240 is Philip Edelbrock -; please forward corrections, suggestions, etc. -to him. For further technical information on this chip, I suggest -getting the Acrobat PDF documentation from www.analog.com. - -Dallas documentation is at http://www.dalsemi.com. diff --git a/doc/chips/asb100 b/doc/chips/asb100 deleted file mode 100644 index ab099b68..00000000 --- a/doc/chips/asb100 +++ /dev/null @@ -1,89 +0,0 @@ -Kernel driver `asb100.o' -======================== - -Status: Work in progress - -Supported Chips: - * Asus ASB100 and ASB100-A "Bach" - Prefix: 'asb100' - Addresses scanned: I2C 0x2d - Datasheet: none released - -Author: Mark M. Hoffman - -Module Parameters ------------------ - - - -Asus' BIOS is often broken --------------------------- - -If you have an Asus P4PE, you need to read prog/hotplug/README.p4b. - -If you have any other (Asus) board for which sensors-detect finds neither -asb100 nor an I2C bus, please read prog/hotplug/README.p4b before sending -a bug report. - -Description ------------ - -This driver implements support for the Asus ASB100 and ASB100-A "Bach". These -are custom ASICs available only on Asus mainboards. Asus refuses to supply a -datasheet for these chips. Thanks go to many people who helped investigate -their hardware, including: - -Vitaly V. Bursov -Alexander van Kaam (author of MBM for Windows) -Bertrik Sikken - -The ASB100 implements seven voltage sensors, three fan rotation speed sensors, -four temperature sensors, VID lines and alarms. In addition to these, the -ASB100-A also implements a single PWM controller for fans 2 and 3 (i.e. one -setting controls both.) If you have a plain ASB100, the pwm controller will -simply not work (or maybe it will for you... it doesn't for me). - -Temperatures are measured and reported in degrees Celsius. - -Fan speeds are reported in RPM (rotations per minute). An alarm is triggered -if the rotation speed has dropped below a programmable limit. - -Voltage sensors (also known as IN sensors) report values in volts. - -The VID lines encode the core voltage value: the voltage level your processor -should work with. This is hardcoded by the mainboard and/or processor itself. -It is a value in volts. - -Alarms: (TODO question marks indicate may or may not work) - -0x0001 => in0 (?) -0x0002 => in1 (?) -0x0004 => in2 -0x0008 => in3 -0x0010 => temp1 (1) -0x0020 => temp2 -0x0040 => fan1 -0x0080 => fan2 -0x0100 => in4 -0x0200 => in5 (?) (2) -0x0400 => in6 (?) (2) -0x0800 => fan3 -0x1000 => chassis switch -0x2000 => temp3 - -Alarm Notes: - -(1) This alarm will only trigger if the hysteresis value is 127C. -I.e. it behaves the same as w83781d. - -(2) The min and max registers for these values appear to -be read-only or otherwise stuck at 0x00. - -TODO: -* Experiment with fan divisors > 8. -* Experiment with temp. sensor types. -* Are there really 13 voltage inputs? Probably not... -* Fix bogus client deregistration (like w83781d in 2.6). -* Fix fan divisor / fan minimum interaction (like lm78). -* Cleanups, no doubt... - diff --git a/doc/chips/bmcsensors b/doc/chips/bmcsensors deleted file mode 100644 index b2aac3a1..00000000 --- a/doc/chips/bmcsensors +++ /dev/null @@ -1,140 +0,0 @@ -Kernel driver `bmcsensors.o' -========================== - -Status: Alpha - -Supported chips: - * IPMI BMC - Prefix: 'bmc' - Requires dummy adapter i2c-ipmi; - Driver will be registered as bmc-ipmi-0000. - -Author: M. Studebaker - -License: GPL - - -Module Parameters ------------------ - -None. - - -Detection ---------- - -Registers only with i2c-ipmi. - - -Description ------------ - -Together with the i2c-ipmi module, this provides high-level -access to sensors known by the BMC. For low-level access to -IPMB (I2C/SMBus) busses behind the BMC, use the i2c-ipmb module -and individual chip drivers. - -This module REQUIRES the IPMI kernel patch by Corey Minyard, -v13 or higher, available at http://openipmi.sourceforge.net . -Other IPMI drivers are not supported. - -See http://www.intel.com/design/servers/ipmi/ for -IPMI standards information. - -You must configure the following features in your kernel -(under Character Devices): - IPMI top-level message handler - IPMI KCS handler -The IPMI device interface and IPMI watchdog handler are not required. - -You must modprobe i2c-ipmi separately, it will not -load automatically when you modprobe bmcsensors. - -If the KCS handler (ipmi_kcs_drv) is configured as a module, -you must also modprobe it separately, it will not load automatically -when you modprobe i2c-ipmi or ipmi_msghandler (unless you set up -/etc/modules.conf to load ipmi_kcs_drv when ipmi_msghandler is loaded). - - -/proc entries -------------- - -The BMC SDR's (Sensor Data Records) are scanned and -the /proc table is built dynamically. Sensor types and quantities -depend on what the BMC supports. - - curr1-n Currents. Max, min, and reading in amps. - fan1-n Fan speeds. Min and reading in RPM. - in1-n Voltages. Max, min, and reading in volts. - temp1-n Temps. Max, hysteresis or min, and reading in degrees C. - -Thresholds will appear as 0 if unsupported or unreadable, as indicated -in the SDR. - -If the thresholds are not settable (as indicated in the SDR), the -/proc permissions for that sensor will be 444. - -After the SDR's are scanned, the module will print -the sensor names and bindings to syslog/dmesg. -Cut these messages out and paste them to /etc/sensors.conf -so that 'sensors' has correct labeling. - - -Issues ------- -The module will not register in /proc/sys/dev/sensors until -the SDR's are scanned. This may take several seconds. - -The driver uses a very simple state machine. It only sends -one message at a time and then waits for a response. -This makes the driver relatively slow. -If a response is an error or does not arrive, the driver -will probably be stuck. - -/proc access kicks off an update but returns the old data, -not the new; need to wait for update to finish and then return. - -Probably there are some locking issues. - -Every attempt is made to present the sensor data in /proc in a -manner consistent with lm_sensors /proc standards, as defined -in doc/developers/proc. Given the wide variation in possible SDR definitions, -this may not generate expected or useful data. - -IPMI supports up to 4 max and 4 min thresholds (non-recoverable, critical, -non-critical, and hysteresis) for each sensor. This driver -tries to pick out the best one and exports it as the max and min -to /proc. - -ins start at 1, other modules start at in0. - -Alarms and thresholds are not yet supported. - -Threshold-only sensors are not supported. - -Threshold setting is not yet supported. - -1's and 2's complement formats not yet supported. - -Non-linear conversions not supported, except for 1/x. - -Fan divs are not supported (or required) - should the driver -export a fan_div entry (1 1 1 ...) for compatibility? - -Supports only sensor types 1-4 (temp, voltage, current, and fan). - -Libsensors can't handle dynamic /proc entries so the table -in lib/chips.c must be static and contain the max number of -each sensor. Bmcsensors can register more of a sensor type -than libsensors supports in its static table. - -Only one BMC is supported - shouldn't be a problem. - -Alpha! - - - - -********************** -The lm_sensors project gratefully acknowledges the support of -Hewlett Packard (Ft. Collins) in the development of this driver. diff --git a/doc/chips/bt869 b/doc/chips/bt869 deleted file mode 100644 index 9a3b1470..00000000 --- a/doc/chips/bt869 +++ /dev/null @@ -1,397 +0,0 @@ -Kernel driver `bt869.o' -====================== - -Status: 'Beta' and needs further development and testing - -Supported chips: - * Brooktree BT869 Video Modulator chips - Prefix: 'bt869' - Addresses scanned: I2C 0x44 - 0x45 - Datasheet: Publicly available at the brooktree web site - (www.brooktree.com) - -Author: Frodo Looijaard , Philip Edelbrock - , Ralph Metzler - Steve Davies added the 720x576 and - 720x480 support, and the svideo configuration. - -Main Contact: Philip Edelbrock - -Module Parameters ------------------ -* force: short array (min = 1, max = 48) - List of adapter,address pairs to boldly assume to be present -* force_bt869: short array (min = 1, max = 48) - List of adapter,address pairs which are unquestionably assumed to contain - a `bt869' chip -* ignore: short array (min = 1, max = 48) - List of adapter,address pairs not to scan -* ignore_range: short array (min = 1, max = 48) - List of adapter,start-addr,end-addr triples not to scan -* probe: short array (min = 1, max = 48) - List of adapter,address pairs to scan additionally -* probe_range: short array (min = 1, max = 48) - List of adapter,start-addr,end-addr triples to scan additionally - - -Description ------------ - -This driver provides some access to the Brooktree bt869 found on some -video cards (like the 'Voodoo3 3000'). Typically, the output can be -either an s-video connection or composite video. Resolutions -supported using the chip's built in configurations are 640x480 or -800x600. In addition, a 720x576 PAL mode and a 720x480 NTSC mode, -both without overscan compensation, are supported - a convenient -configuration for video playback. - -Other possible implementations may allow for double resolutions with some -decimations (e.g., a monitor running at 1280x960 but the TV out getting every -other pixel for 640x480). - - -Driver Features ---------------- -Standards: (US) NTSC or PAL -Resolutions: 640x480, 800x600, 720x576 (PAL only), 720x480 (NTSC only) -Depths: 16, 24 or 32 bits -Colorbars: Switch on the built-in color bar generator. (FYI- using a blue -filter, you should see only alternating bright stripes of equal brightness. -Adjust your TV's color and saturation if this isn't the case.) -SVideo: composite or s-video output. Also, theoretically, RGB output, though -this isn't tested and will require that your card presents all three DAC outputs -(the 3dfx Voodoo3 doesn't) - -In your XF86Config file, you should have these entries for NTSC output: - -ModeLine "640x480NTSC" 28.195793 640 656 658 784 480 520 525 600 -ModeLine "720x480NTSC" 27.5 720 744 800 872 480 483 485 525 -ModeLine "800x600NTSC" 38.769241 800 812 814 880 600 646 649 735 - -or for PAL - -ModeLine "640x480PAL" 29.50 640 675 678 944 480 530 535 625 -ModeLine "720x576PAL" 27.50 720 744 800 880 576 581 583 625 -ModeLine "800x600PAL" 36.00 800 818 820 960 600 653 655 750 - -Also, don't forget to add these modes to the resolutions list in the -'screen' sections of XF86Config. You can change modes on the fly in X by -pressing (usually) ctrl-alt-+ or ctrl-alt-(minus) with + and - being the -keys on your numeric 10-key pad. - -BTW- My monitor doesn't like these entries very much, and as I've read: -don't run your monitor out of spec or else it will burst into fire. So, -having the monitor turned on while in any of these modes is at your own -risk. (I've never heard of a monitor breaking from this, but it seems to -be fashionable to warn about it.) - - -Chip Features -------------- -The chip is very flexible and customizable for many standards. Right -now the driver sticks with the chip's built in NTSC and PAL standards, -with the addition of the 720x576PAL and 720x480NTSC modes. It also -does some other wacky stuff like closed-captioning, Macro-vision -copy-protection, and other things. Check out the datasheet for more -info. - - -Issues ------- -The depth register doesn't seem to do much? If you have troubles or -aren't sure the output is working, turn the color-bars on. If they display -OK, then the chip is syncing correctly. The next thing to try is the depth -setting. Lastly, turning off your computer and back on with your TV -connected but you monitor not, may force the video card to configure and -use the BT869 as your primary output device (all bets are off once X is -started). Let me know if you have problems which you can't figure out -(phil@netroedge.com). - --------------------------------- - -On May 3rd, 2001 (My birthday, as it happens to be :') Tomi Ollila sent me -a how-to from a user's perspective on using the BT869 with a 3Dfx card. -It should also provide insight for other video card users who have a -BT869 on board. Here is his document: - - -How-To ------- - - -This text describes my successful attempt to eventually get the TV-Out -feature of 3DFX Voodoo 3 3000 (PAL) working in a Linux environment. -I've successfully configured the 800x600 mode -- And currently I am -not interested in 640x480 -- hardware scaling rules in all cases -I need the tv-out. My monitor works much less worse w/ 800x600PAL... - -All the information is based on my best knowledge but there might be -some mistakes. In any case, THE ENTIRE RISK OF USING THIS INFORMATION -IS WITH YOU, AND NO ONE ELSE IS LIABLE OF ANY PROBLEMS ENCOUNTERED. -Please fix any mistakes, inaccuracies, writing errors, etc. you -notice in this document. - -I was about to write briefly, but sorry due to limited resources -I did not have time to write briefly (too much thinking ;). -Well, browse through the text and skip all irrelevant parts -to proceed... - -Tomi Ollila - - -The first time I got the the tv-out working I was working w/ Linux kernel -2.4.3. Now I am redoing the work w/ Linux 2.4.4 and recording the steps -in this document. Description of my system and software used is as follows: - -RedHat 7.0 linux distribution (probably any distribution will do, since -all of the needed software is compiled from packages that are not RH-pagkaged) -(maybe if anything is important, are modutils-2.3.14-3 and kernel-headers-2.4.0-0.26) - -XFree-4.0.3. I don't see any reason anyone uses any older. HW acceleration -of Voodoo3 3000 works out of the box with this. Also Windowed!!! - -lm_sensors-2.5.5: Get this or newer. I have not used any older. - -i2c-2.5.5: Probably 2.4.x -kernel distributions has recent enough version -of i2c. Since I also have IOmega BUZ and it's (working) versions require -i2c-old, I cannot use the one's kernel provided. Since I cannot say anything -about not using this i2c as separate package I suggest you do the same -and compile this also. - -I have used kgcc that comes in RedHat 7.0 -distribution to compile all -stuff. Probably all other recent gcc -compilers will produce good results -also: kgcc -v outputs: -Reading specs from /usr/lib/gcc-lib/i386-glibc21-linux/egcs-2.91.66/specs -gcc version egcs-2.91.66 19990314/Linux (egcs-1.1.2 release) - --- - -1) The work starts w/ kernel compilation (or skip to step 2, I quess it will - work w/ any recent 2.2 and 2.4 -kernels) - - # run make config, make menuconfig or make xconfig (I suggest 'xconfig') - - For sure you need kernel module support and /proc -filesystem support - (XXX add more absolute requirements) - - Now I cannot say for sure, if following things needs to be compiled - at kernel compilation time or does i2c-2.5.5 bring all these: - character devices->i2c support->i2c support - character devices->i2c support->i2c bit-banging interfaces (*) - character devices->i2c support->i2c devices (**) - character devices->/dev/agpart support - character devices->Direct Rendering Manager (XFree86 DRI support) (+) - character devices->3dfx banshee/Voodoo3+ - - make above as modules. - - (*) I already forgot why I wanted some special attention for this - (**) It seems I never need this - (+) Hmm, It seems I have compiled this as part of the kernel binary - - There is of course lot of other options you need to choose but these - are probably the ones needed... - - # run make dep - # run make bzImage - # run make modules - # run make modules_install (as root) - # copy arch/i386/boot/bzImage to /boot/vmlinuz-2.4.4 (as root) - # edit /etc/lilo.conf and run lilo (as root) - -2) In order to (the most easiest way) compile separate i2c and lm_sensors - -package, symlink your linux source tree to /usr/src/linux (unless it is - there already) and do the following - - # tar zxvf i2c-2.5.5.tar.gz - # cd i2c-2.5.5 - # make - # make install (as root) - # cd .. - # tar zxvf lm_sensors-2.5.5.tar.gz - # cd lm_sensors-2.5.5 - # make - # make install (as root) - # cd .. - - Now you have all necessary modules installed on the system (and - /usr/local/bin/sensors and /usr/local/sbin/sensors-detect). - - But there is some configuration missing in order to activate - the needed functionality of the modules... - -3) Now, before going any further, let's take a look the modifications that - is required in XFree86 -configuration so that X is ready for the - tv-out functionality next time it is started. - - XFree86-4.x uses the configuration file /etc/X11/XF86Config-4. Older - configuration files needed "ModeLine"s for all display resolutions - that are needed, but XFree86 version 4 can figure out those by itself. - But what it cannot figure out, are some special ModeLines that may - be reguired in various cases... and this is one of these. - - For Voodoo 3 3000 TV out feature, special modelines are needed for - the supported resolutions, 640x480 and 800x600 (there might be others - but I don't know enough of the issue. In this document, I only - activate the 800x600 mode. - - Make backup copy of your /etc/X11/XF86Config-4 in case you accidentally - screw something up so you can then reuse the old file if this happens. - - Open /etc/X11/XF86Config-4 in your favourite editor and find line - that contains `Section "Monitor"'. At the end of that section, - just before line `EndSection', add the following lines: - -ModeLine "640x480PAL" 29.50 640 675 678 944 480 530 535 625 -ModeLine "800x600PAL" 36.00 800 818 820 960 600 653 655 750 - - Then, find lines that starts with something like: - -Section "Screen" - Identifier "Screen0" - Device "3Dfx Interactive, Inc.|Voodoo 3" - Monitor "" - DefaultDepth 16 -... - Subsection "Display" - Depth 16 -# Modes "1024x768" "640x480" "800x600" "800x600PAL" #"400x300" - Modes "1024x768" "800x600PAL" - EndSubSection - - Make sure that `DefaultDepth' is set 16 (I don't know if any other works) - Then you notice there my resolutions as `Modes' -lines. I have outcommented - the first `Modes' -line so that testing is easier. You can do what - you widh here, just make sure to add that `"800x600PAL"' -line there. - Save the file and exit editor. - - -4) It's is time to reboot (with new kernel), that is the easiest way to - continue. - -5) After rebooting, and X startup `lsmod' in my machine output following: - Module Size Used by - tdfx 54536 1 - es1371 28500 0 - ac97_codec 8808 0 [es1371] - - tdfx -module was loaded by X, and sound module by some RH -startup script. - - Now you could run /usr/local/sbin/sensors-detect. After that was run in - my PII class -machine it suggested I add the following: - - to /etc/modules.conf - alias char-major-89 i2c-dev - - to some startup script (i choose append to /etc/rc.local) - # I2C adapter drivers - /sbin/modprobe i2c-piix4 - /sbin/modprobe i2c-voodoo3 - # I2C chip drivers - /sbin/modprobe w83781d - /sbin/modprobe eeprom - - (you run the prg and add the stuff it suggests) - - Let's now /sbin/modprobe -v i2c-voodoo3. Now I have: - - Module Size Used by - i2c-voodoo3 3012 0 (unused) - i2c-algo-bit 7796 2 [i2c-voodoo3] - i2c-core 12844 0 [i2c-algo-bit] - tdfx 54536 1 - es1371 28500 0 - ac97_codec 8808 0 [es1371] - - I think this is the only one of the above that is required for the task. - (If that is not true, I'll revise this text and you never know I though - such a thing) - - Now, turn on your TV set (unless it is already open) and make sure it - is getting (either s-video or composite... I personally have only - tested composite) input from your voodoo3 card. Don't change any - screen resolution just yet... - - You notice the tv set screen is still blank. Changing screen resolutions - won't do any change on that, don't bother trying. - - So, how to continue from there. The answer was found looking through - all the files that are found with zsh command line in lm_sensors dir: - grep -i voodoo3 **/*(.) | less - The file doc/chips/bt869 contains interesting information, with it - and some other information I found somewhere else, don't remember - either, I did: - - modprobe -v bt869 (or insmod /lib/modules/2.x.x/misc/bt869) - - NOW! you should see some noise on your TV-Set screen. - - and `lsmod' returns (on my machine) - - Module Size Used by - bt869 5392 0 (unused) - i2c-voodoo3 3012 0 (unused) - sensors 6140 0 [bt869] - i2c-algo-bit 7796 2 [i2c-voodoo3] - i2c-core 12844 0 [bt869 sensors i2c-algo-bit] - tdfx 54536 1 - es1371 28500 0 - ac97_codec 8808 0 [es1371] - - If you now try to change mode to `800x600PAL' The noise pattern just - changes. That's because there are various parameters for bt869 to - make it operate in different systems. - - The configuration entries for bt869 live somewhere in `proc' filesystem - and since it is so hard to remember, the following commands helps out: - - # find /proc -name "bt869*" -print - - In my system that output: /proc/sys/dev/sensors/bt869-i2c-0-44. Since - the last few characters may be different on your system I'll use... - - # ls /proc/sys/dev/sensors/bt869* ... and this outputs: - - colorbars: Output colorbars instead of display data. Default `0'. - depth: Display depth. Seems to be `16' on my system. - half: No idea. Default `0'. - ntsc: 1: use NTSC, 0: use PAL. Default: `1'. - res; Screen resolution to use. Defaut: `640 480'. - status: Outputs some status info I do not know what that is. - - For me, in order to get TV sync with incoming signal (or is it Voodoo3 - that needs syncing), I first put colorbars on, and when I get colorbars - visible I shut colorbars off -- and then I have part of my 1024x768 - displayed on TV-screen. Normal WIMP screen doesn't look so nice, but - games, pictures, etc. Looks just fine. And HW acceleration rules. - - Do the following to achieve this: - - # echo 1 > /proc/sys/dev/sensors/bt869*/colorbars - # echo 0 > /proc/sys/dev/sensors/bt869*/ntsc - # echo 800 600 > /proc/sys/dev/sensors/bt869*/res - - Press ctrl-alt-num_keypad_+ - - Now you should see vertical colorbars on your TV-Set - - # echo 0 > /proc/sys/dev/sensors/bt869*/colorbars - - Now (part of) your computer display should be visible on your TV-Set. - - - ... Ok, I did just that... after ctrl-alt-num_keypad_+ I did not get - synchronized colorbar output visible on my TV. So, at this time I - re-did... - - # echo 1 > /proc/sys/dev/sensors/bt869*/colorbars - - ... and got colorbars, and ... - - # echo 0 > /proc/sys/dev/sensors/bt869*/colorbars - - ... got my computer display visible on my TV. - - -#EOF - diff --git a/doc/chips/ddcmon b/doc/chips/ddcmon deleted file mode 100644 index 63ef0aa3..00000000 --- a/doc/chips/ddcmon +++ /dev/null @@ -1,272 +0,0 @@ -Kernel driver `ddcmon.o' -======================== - -Status: As complete as we want it to be, lightly tested - -Supported chips: - * Any DDC Monitor EDID EEPROM chip at 0x50 - Prefix: 'ddcmon' - Addresses scanned: I2C 0x50 - Standards: available for purchase from VESA http://www.vesa.org - Datasheets: Publicly available from Atmel (www.atmel.com), - Fairchild (www.fairchildsemi.com), and - Microchip (www.microchip.com) - - Chip Size (bits) Address - 24C01 1K 0x50 (shadows at 0x51 - 0x57) - (Typical device in monitors) - 24C01A 1K 0x50 - 0x57 (Typical device in monitors) - 24C02 2K 0x50 - 0x57 - 24C04 4K 0x50, 0x52, 0x54, 0x56 - (additional data at 0x51, 0x53, 0x55, 0x57) - 24C08 8K 0x50, 0x54 (additional data at 0x51, 0x52, - 0x53, 0x55, 0x56, 0x57) - 24C16 16K 0x50 (additional data at 0x51 - 0x57) - - -Author: Frodo Looijaard , Philip Edelbrock - , Mark Studebaker and - Jean Delvare - -Special assistance on DDC provided by Petr Vandrovec - -License: GPL - - -Module Parameters ------------------ - -* force: short array (min = 1, max = 48) - List of adapter,address pairs to boldly assume to be present -* force_ddcmon: short array (min = 1, max = 48) - Same as 'force' -* ignore: short array (min = 1, max = 48) - List of adapter,address pairs not to scan -* ignore_range: short array (min = 1, max = 48) - List of adapter,start-addr,end-addr triples not to scan -* probe: short array (min = 1, max = 48) - List of adapter,address pairs to scan additionally -* probe_range: short array (min = 1, max = 48) - List of adapter,start-addr,end-addr triples to scan additionally -* checksum: int - Only accept eeproms whose checksum is correct - - -Description ------------ - -This is a simple module for reading the EEPROM on a DDC-compliant monitor. -DDC (Display Data Channel) is the I2C-based communication channel -to the monitor. The EEPROM contains a 128-byte data structure defined -by the EDID (Extended Display Identification Data) standard. - -Use: - -After inserting the module (and any other required smbus/i2c modules), you -should have a directory in /proc/sys/dev/sensors/ with a name such -as "ddcmon-i2c-3-50". Inside each of these is a series of files which -represent interesting data from the DDC monitor. - -/proc entries: - - dpms: bitmask - DPMS support flags - 0x20 Active Off - 0x40 Suspend - 0x80 Standby - - edid: 2 integers - EDID version and revision - - gamma: 1 float - gamma factor - - id: 2 integers - manufacturer ID and product ID - Manufacturer ID is encoded, see 'sensors' - source ../../prog/sensors/chips.c. - - maxclock: 1 integer - max pixel clock (also known as video bandwidth) (MHz) - 0 if not available. - - serial: 1 integer - serial number - Encoding depends on the manufacturer, don't expect the - real serial number here. 0 probably means "not available". - - size: 2 integers - vertical monitor size (cm) - horizontal monitor size (cm) - - sync: 4 integers - minimum vertical sync frequency (Hz) - maximum vertical sync frequency (Hz) - minimum horizontal sync frequency (KHz) - maximum horizontal sync frequency (KHz) - 0 0 0 0 if not available. - - time: 2 integers - Manufacture year and week - - timing[1-8]: 3 integers - supported standard timing - horizontal resolution - vertical resolution - (vertical) refresh rate - 0 0 0 if not used. - - timings: bitmask - supported established timings - 0x000001 720x400@70Hz (VGA 640x400, IBM) - 0x000002 720x400@88Hz (XGA2) - 0x000004 640x480@60Hz (VGA) - 0x000008 640x480@67Hz (Mac II, Apple) - 0x000010 640x480@72Hz (VESA) - 0x000020 640x480@75Hz (VESA) - 0x000040 800x600@56Hz (VESA) - 0x000080 800x600@60Hz (VESA) - 0x000100 800x600@72Hz (VESA) - 0x000200 800x600@75Hz (VESA) - 0x000400 832x624@75Hz (Mac II) - 0x000800 1024x768@87Hz interlaced (8514A) - 0x001000 1024x768@60Hz (VESA) - 0x002000 1024x768@70Hz (VESA) - 0x004000 1024x768@75Hz (VESA) - 0x008000 1280x1024@75Hz (VESA) - 0x010000 - 0x800000 Manufacturer reserved - 0x800000 1152x870 @ 75 Hz (Mac II, Apple)? - - -Chip Features -------------- - -Chip 'ddcmon' - -LABEL LABEL CLASS COMPUTE CLASS MODE MAGN -Manufacturer ID - - R- 0 -Model Number - - R- 0 -Monitor Size (cm) - - R- 0 -hsize Monitor Size (cm) - R- 0 -Vertical Sync (Hz) - - R- 0 -v_sync_max Vertical Sync (Hz) - R- 0 -Horizontal Sync (KHz) - - R- 0 -h_sync_max Horizontal Sync (KHz) - R- 0 -Established Timings - - R- 0 -Serial Number - - R- 0 -Manufacture Time - - R- 0 -week Manufacture Time - R- 0 -EDID Version - - R- 0 -revision EDID Version - R- 0 -Gamma Factor - - R- 2 -DPMS Modes - - R- 0 -Standard Timing 1 - - R- 0 -vertical Standard Timing 1 - R- 0 -refresh Standard Timing 1 - R- 0 -Standard Timing 2 - - R- 0 -vertical Standard Timing 2 - R- 0 -refresh Standard Timing 2 - R- 0 -Standard Timing 3 - - R- 0 -vertical Standard Timing 3 - R- 0 -refresh Standard Timing 3 - R- 0 -Standard Timing 4 - - R- 0 -vertical Standard Timing 4 - R- 0 -refresh Standard Timing 4 - R- 0 -Standard Timing 5 - - R- 0 -vertical Standard Timing 5 - R- 0 -refresh Standard Timing 5 - R- 0 -Standard Timing 6 - - R- 0 -vertical Standard Timing 6 - R- 0 -refresh Standard Timing 6 - R- 0 -Standard Timing 7 - - R- 0 -vertical Standard Timing 7 - R- 0 -refresh Standard Timing 7 - R- 0 -Standard Timing 8 - - R- 0 -vertical Standard Timing 8 - R- 0 -refresh Standard Timing 8 - R- 0 -Max Pixel Clock (MHz) - - R- 0 - -LABEL FEATURE SYMBOL SYSCTL FILE:N -Manufacturer ID SENSORS_DDCMON_MAN_ID id:1 -Model Number SENSORS_DDCMON_PROD_ID id:2 -Monitor Size (cm) SENSORS_DDCMON_VERSIZE size:1 -hsize SENSORS_DDCMON_HORSIZE size:2 -Vertical Sync (Hz) SENSORS_DDCMON_VERSYNCMIN sync:1 -v_sync_max SENSORS_DDCMON_VERSYNCMAX sync:2 -Horizontal Sync (KHz) SENSORS_DDCMON_HORSYNCMIN sync:3 -h_sync_max SENSORS_DDCMON_HORSYNCMAX sync:4 -Established Timings SENSORS_DDCMON_TIMINGS timings:1 -Serial Number SENSORS_DDCMON_SERIAL serial:1 -Manufacture Time SENSORS_DDCMON_YEAR time:1 -week SENSORS_DDCMON_WEEK time:2 -EDID Version SENSORS_DDCMON_EDID_VER edid:1 -revision SENSORS_DDCMON_EDID_REV edid:2 -Gamma Factor SENSORS_DDCMON_GAMMA gamma:1 -DPMS Modes SENSORS_DDCMON_DPMS dpms:1 -Standard Timing 1 SENSORS_DDCMON_TIMING1_HOR timing1:1 -vertical SENSORS_DDCMON_TIMING1_VER timing1:2 -refresh SENSORS_DDCMON_TIMING1_REF timing1:3 -Standard Timing 2 SENSORS_DDCMON_TIMING2_HOR timing2:1 -vertical SENSORS_DDCMON_TIMING2_VER timing2:2 -refresh SENSORS_DDCMON_TIMING2_REF timing2:3 -Standard Timing 3 SENSORS_DDCMON_TIMING3_HOR timing3:1 -vertical SENSORS_DDCMON_TIMING3_VER timing3:2 -refresh SENSORS_DDCMON_TIMING3_REF timing3:3 -Standard Timing 4 SENSORS_DDCMON_TIMING4_HOR timing4:1 -vertical SENSORS_DDCMON_TIMING4_VER timing4:2 -refresh SENSORS_DDCMON_TIMING4_REF timing4:3 -Standard Timing 5 SENSORS_DDCMON_TIMING5_HOR timing5:1 -vertical SENSORS_DDCMON_TIMING5_VER timing5:2 -refresh SENSORS_DDCMON_TIMING5_REF timing5:3 -Standard Timing 6 SENSORS_DDCMON_TIMING6_HOR timing6:1 -vertical SENSORS_DDCMON_TIMING6_VER timing6:2 -refresh SENSORS_DDCMON_TIMING6_REF timing6:3 -Standard Timing 7 SENSORS_DDCMON_TIMING7_HOR timing7:1 -vertical SENSORS_DDCMON_TIMING7_VER timing7:2 -refresh SENSORS_DDCMON_TIMING7_REF timing7:3 -Standard Timing 8 SENSORS_DDCMON_TIMING8_HOR timing8:1 -vertical SENSORS_DDCMON_TIMING8_VER timing8:2 -refresh SENSORS_DDCMON_TIMING8_REF timing8:3 -Max Pixel Clock (MHz) SENSORS_DDCMON_MAXCLOCK maxclock:1 - - -Notes ------ - -- The eeprom.o module will also attach to a DDC monitor. Install the - ddcmon.o module before the eeprom.o module to prevent this. - Alternatively, give the eeprom.o module an ignore= parameter or - a checksum= parameter. The ddcmon.o module will not attach to non-DDC - eeproms because it checks for a DDC 'signature' at the beginning - of the DDC Monitor's eeprom. Additionally, you can give it a checksum= - parameter. - -- If a DDC monitor eeprom lacks the 'signature', you may use the - 'force' parameter (modprobe ddcmon force=x,0x50 where 'x' is the - i2c bus number). - -- This module requires a bus driver for your video chip to access the - DDC bus. In this package, drivers exist for Voodoo3/Banshee chips. - See documentation for those drivers in ../busses. Other drivers - (Matrox and NVidia, for example) are available in the kernel or - elsewhere. See our 'Supported Devices' web page for details. - -- There is a checksum over the 128 bytes in the eeprom. The driver - used not to check it, now it does (providing you give it a - checksum= parameter). - -- More information is available in the eeprom which could be made - available by enhancing the driver. - To see the entire eeprom, use the eeprom.o module instead of ddcmon.o. - However, then you lose the DDC-specific formatting. - Also see ../../prog/eeprom/decode-edid.pl. - -- This driver does not support the DDC/CI (DDC2Bi) bidirectional - communications channel to the monitor for controlling the monitor. - -- The driver caches the data from the monitor and only rereads it - from the eeprom if the cache is more than 5 minutes old. - -- X 4.0 also accesses the DDC monitor EEPROM to auto-configure itself. - There could possibly be conflicts from these multiple accesses, but - none were ever reported so far. diff --git a/doc/chips/ds1307 b/doc/chips/ds1307 deleted file mode 100644 index 217c40ca..00000000 --- a/doc/chips/ds1307 +++ /dev/null @@ -1,25 +0,0 @@ -Kernel driver `ds1307.o' -======================== - -Status: Complete and well-tested - -Supported chips: - * Dallas Semiconductor DS1307 Real-time clock - -Author: Abraham vd Merwe - - -Module Parameters ------------------ - -There are no module parameters. The driver only scans address 0x68 for -presence of the real-time clock chip (which is the only possible address). - - -Description ------------ - -This module provides an API for drivers RTC and NVRAM drivers to use in -order to access the DS1307 real-time clock. Examples of drivers that uses -this API are the frodo-nvram and frodo-rtc drivers. - diff --git a/doc/chips/ds1621 b/doc/chips/ds1621 deleted file mode 100644 index 9cf89b4e..00000000 --- a/doc/chips/ds1621 +++ /dev/null @@ -1,237 +0,0 @@ -Kernel driver `ds1621.o' -======================== - -Status: Complete and tested; enhanced features experimental - -Supported chips: - * Dallas Semiconductor DS1621 - Prefix: 'ds1621' - Addresses scanned: I2C 0x48 - 0x4f - Datasheet: Publicly available at the Dallas Semiconductor website - http://www.dalsemi.com/ - * Dallas Semiconductor DS1625 - Prefix: 'ds1621' - Addresses scanned: I2C 0x48 - 0x4f - Datasheet: Publicly available at the Dallas Semiconductor website - http://www.dalsemi.com/ - -Author: Christian W. Zuckschwerdt -valueable contributions by Jan M. Sendler - - -Module Parameters ------------------ - -* force: short array (min = 1, max = 48) - List of adapter,address pairs to boldly assume to be present -* force_ds1621: short array (min = 1, max = 48) - List of adapter,address pairs which are unquestionably assumed to - contain a `ds1621' chip -* ignore: short array (min = 1, max = 48) - List of adapter,address pairs not to scan -* ignore_range: short array (min = 1, max = 48) - List of adapter,start-addr,end-addr triples not to scan -* probe: short array (min = 1, max = 48) - List of adapter,address pairs to scan additionally -* probe_range: short array (min = 1, max = 48) - List of adapter,start-addr,end-addr triples to scan additionally - - -Description ------------ - -The DS1621 is a (one instance) digital thermometer and thermostat. It -has both high and low temperature limits which can be user defined -(i. e. programmed into non-volatile on-chip registers). -Temperature range is -55 degree Celsius to +125 in 0.5 increments. You -may convert this into a Fahrenheit range of -67 to +257 degrees with -0.9 steps. Unfortunally though, you will need a hash table or even a -conversion routine for that. - -Temperature readings are internally converted into a 9bit value to be -read straight via the i2c-bus, but higher resolutions may be obtained -with little effort via 'precise_temp' access or using a simple algorithm. - -As for the thermostat, behavior can also be programmed using the -polarity toggle. -On the one hand ("heater"), the thermostat output of the chip, Tout, -will trigger when the low limit temperature is met or underrun and -stays high until the high limit is met or exceeded. On the other hand -("cooler"), vice versa. -That way "heater" equals "active low", whereas "conditioner" equals -"active high". Please note that the DS1621 data sheet is somewhat -misleading in this point since setting the polarity bit does not -simply invert Tout. - - -A second thing is that, during extensive testing, Tout showed a -tolerance of up to +/- 0.5 degrees even when compared against precise -temperature readings. -Be sure to have a high vs. low temperature limit gap of al least 1.0 -degree Celsius to avoid Tout "bouncing", though! - -As for alarms, you can read the alarm status of the DS1621 via the -'alarms' proc file interface. The result consits mainly of bit 6 and 5 -of the configuration register of the chip; bit 6 (0x40 or 64) is the -high alarm bit and bit 5 (0x20 or 32) the low one. These bits are set -when the high or low limits are met or exceeded and are reset by the -module as soon as the respective temperature ranges are left. - -The alarm registers are in no way suitable to find out about the -actual status of Tout. They will only tell you about its history, -whether or not any of the limits have ever been met or exceeded since -last power-up or reset. Be aware: When testing, it showed that the -status of Tout can change with neither of the alarms set. - -Temperature conversion of the DS1621 takes up to 1000ms; internal -access to non-volatile registers may last for 10ms or below. - -This driver also detects DS1625. As this chip is discontinued, you -should use a DS1621 instead. Detected 1625s also get the -"ds1621"-prefix, but the accuracy registers are not supported. -The latest modification of this driver was not checked against 1625s, -though, but should work well with them. - -Default values written into the DS1621 upon detection are: -Temperature limits: High 60.0; low 0.0 degree Celsius; -Continuous mode (not enabled), Tout active high, alarms reset. - - -Accessing DS1621 via /proc interface (part I) ---------------------------------------------- - -On detection (i.e. insmod, modprobe et al.), directories are being -created for each detected DS1621: - -/proc/sys/dev/sensors/ds1621-<0>-<1>/ -where <0> is the bus the chip was detected on (e. g. i2c-0) -and <1> the chip address ([48..4f]): ./ds1621-i2c-0-48/ - -Inside these directories, there are five files each: -alarms, continuous, enable, polarity and temp. - -The temp, alarms and enable are LM75-like for compatibility reasons: - -The temp file is rw. Reading gives TEMP_HIGH:TEMP_HYST:TEMP, where -TEMP_HIGH is the upper limit temp, TEMP_HYST is the hysteresis (lower -limit) temp and TEMP is the actual temperature. (For things like -ONE_SHOT, see below.) - Writing takes two results (read: input -values): TEMP_HIGH:TEMP_HYST. This provides an easy way to set limits. - -The alarms file is ro. Basically, it is 0x40 ("64") for the high alarm -bit set plus 0x20 ("32") for the low one. Since alarms are being reset -by the module when the limit conditions are no longer met, you should -first read the alarms before you do anything else (such as reading the -temperature), or the information may be lost. - -The polarity file is rw. Reading gives "0" for active high, which -describes a need for cooling corresponds to Tout status. "1" means -active low, so you can connect a powerful heater directly to Tout -(DON'T TRY!). - Writing accepts "0" and "1" accordingly. Again, note -that the statements on page 5 of the DS1621 data sheet are misleading; -change the orientation of the vertical arrows in the sketch there -instead. - -To understand the use of the other things, it is useful to have a -brief look at the internal DS1621 procedures: - - -High Accuracy Temperature Reading ---------------------------------- - -As said before, the temperature issued via the 9bit i2c-bus data is -somewhat arbitrary. Internally, the temperature conversion is of a -different kind that is explained (not so...) well in the DS1621 data -sheet. To cut the long story short: Inside the DS1621 there are two -oscillators, both of them biassed by a temperature coefficient. - -Higher accuracy of the temperature reading can be achieved using the -internal projection, which means taking account of REG_COUNT and -REG_SLOPE (the driver manages them): - -Taken from Dallas Semiconductors App Note 068: 'Increasing Temperature -Resolution on the DS1620' and App Note 105: 'High Resolution -Temperature Measurement with Dallas Direct-to-Digital Temperature -Sensors' - -- Read the 9bit temperature and strip the LSB (Truncate the .5 degs) -- The resulting value is TEMP_READ. -- Then, read REG_COUNT. -- And then, REG_SLOPE. - - TEMP = TEMP_READ - 0.25 + ((REG_SLOPE - REG_COUNT) / REG_SLOPE) - -Note that this is what the DONE bit in the DS1621 configuration -register is good for: Internally, one temperature conversion takes up -to 1000ms. Before that conversion is complete you will not be able to -read valid things out of REG_COUNT and REG_SLOPE. The DONE bit, as you -may have guessed by now, tells you whether the conversion is complete -("done", in plain english) and thus, whether the values you read are -good or not. - -The DS1621 has two modes of operation: "Continuous" conversion, which -can be understood as the default stand-alone mode where the chip gets -the temperature and controls external devices via its Tout pin or -tells other i2c's about it if they care. The other mode is called -"1SHOT", that means that it only figures out about the temperature -when it is explicitly told to do so; this can be seen as power saving -mode. - -Now if you want to read REG_COUNT and REG_SLOPE, you have to either -stop the continuous conversions until the contents of these registers -are valid, or, in 1SHOT mode, you have to have one conversion made. - - - -Accessing DS1621 via /proc interface (part II and end) ------------------------------------------------------- - -The continuous file is rw. Reading gives "1" when the chip is in -continuous mode and "0" for 1SHOT. - Writing accepts "1" to put it -into continuous mode or "0" for 1SHOT. - -The enable file is rw. Reading gives "1" if in continuous mode the -DS1621 is "running" or if in 1SHOT mode it is "shooting". In fact, the -value returned here is the negated DONE bit, just like a "BUSY" -flag. This means, that the "1" tells you that the values in REG_COUNT -and REG_SLOPE are not valid. "0", on the other hand, means that the -continuous conversion had been stopped long enough to provide valid -readings and that one shot has successfully been fi- red, -respectively. - Writing accepts "1" to start continuous conversion or -to pull the trigger in 1SHOT mode, and "0" stops continuous conversion -to allow for valid readings. Writing "0" in 1SHOT doesn't make much -sense since you cannot catch a bullet, can you? No, the thing is that -DS1621 does only do one conversion then anyway, and after that, -there's nothing to stop. - -Last, but best try writing "0" to the "continuous" file and after that -"1" to the "enable" file. This gives you the precise temperature with -two digits after the radix (decimal point). -The precise results are only updated if the DONE bit was set, thus you -have to stop continuous conversion early enough prior to reading, -i. e. 1000ms. And, on the other hand, you shouldn't forget to fire off -1SHOT in order to get the actual temperature rather than that of the -day before yesterday. So read enable before any of these. - - -Chip Features -------------- - -Chip `ds1621' - LABEL LABEL CLASS COMPUTE CLASS ACCESS MAGNITUDE - temp NONE NONE R 1 - temp_hyst temp temp RW 1 - temp_over temp temp RW 1 - alarms NONE NONE R 0 - enable NONE NONE RW 0 - continuous NONE NONE RW 0 - polarity NONE NONE RW 0 - - LABEL FEATURE SYMBOL SYSCTL FILE:OFFSET - temp SENSORS_DS1621_TEMP temp:3 - temp_hyst SENSORS_DS1621_TEMP_HYST temp:2 - temp_over SENSORS_DS1621_TEMP_OVER temp:1 - alarms SENSORS_DS1621_ALARMS alarms:1 - enable SENSORS_DS1621_ENABLE enable:1 - continuous SENSORS_DS1621_CONTINUOUS continuous:1 - polarity SENSORS_DS1621_POLARITY polarity:1 diff --git a/doc/chips/eeprom b/doc/chips/eeprom deleted file mode 100644 index 7d14c711..00000000 --- a/doc/chips/eeprom +++ /dev/null @@ -1,228 +0,0 @@ -Kernel driver `eeprom.o' -======================== - -Status: Complete and well-tested - -Supported chips: - * Any EEPROM chip in the designated address range - Prefix: 'eeprom' - Addresses scanned: I2C 0x50 - 0x57 - Datasheets: Publicly available from: - Atmel (www.atmel.com), - Catalyst (www.catsemi.com), - Fairchild (www.fairchildsemi.com), - Microchip (www.microchip.com), - Philips (www.semiconductor.philips.com), - Rohm (www.rohm.com), - ST (www.st.com), - Xicor (www.xicor.com), - and others. - - Chip Size (bits) Address - 24C01 1K 0x50 (shadows at 0x51 - 0x57) - 24C01A 1K 0x50 - 0x57 (Typical device on DIMMs) - 24C02 2K 0x50 - 0x57 - 24C04 4K 0x50, 0x52, 0x54, 0x56 - (additional data at 0x51, 0x53, 0x55, 0x57) - 24C08 8K 0x50, 0x54 (additional data at 0x51, 0x52, - 0x53, 0x55, 0x56, 0x57) - 24C16 16K 0x50 (additional data at 0x51 - 0x57) - Sony 2K 0x57 - - Atmel 34C02B 2K 0x50 - 0x57, SW write protect at 0x30-37 - Catalyst 34FC02 2K 0x50 - 0x57, SW write protect at 0x30-37 - Catalyst 34RC02 2K 0x50 - 0x57, SW write protect at 0x30-37 - Fairchild 34W02 2K 0x50 - 0x57, SW write protect at 0x30-37 - Microchip 24AA52 2K 0x50 - 0x57, SW write protect at 0x30-37 - ST M34C02 2K 0x50 - 0x57, SW write protect at 0x30-37 - - -Author: Frodo Looijaard and Philip Edelbrock - - - -Module Parameters ------------------ - -* checksum: int - Only accept eeproms whose checksum is correct -* force: short array (min = 1, max = 48) - List of adapter,address pairs to boldly assume to be present -* force_eeprom: short array (min = 1, max = 48) - List of adapter,address pairs which are unquestionably assumed to contain - a `eeprom' chip -* ignore: short array (min = 1, max = 48) - List of adapter,address pairs not to scan -* ignore_range: short array (min = 1, max = 48) - List of adapter,start-addr,end-addr triples not to scan -* probe: short array (min = 1, max = 48) - List of adapter,address pairs to scan additionally -* probe_range: short array (min = 1, max = 48) - List of adapter,start-addr,end-addr triples to scan additionally - - -Description ------------ - -This is a simple EEPROM module meant to enable reading the first 256 bytes -of an EEPROM (on a SDRAM DIMM for example). However, it will access serial -EEPROMs on any I2C adapter. The supported devices are generically -called 24Cxx, and are listed above; however the numbering -for these industry-standard devices may vary by manufacturer. - -This module was a programming exercise to get used to the new project -organization laid out by Frodo, but it should be at least completely -effective for decoding the contents of EEPROMs on DIMMs. - -DIMMS will typically contain a 24C01A or 24C02, or the 34C02 variants. -The other devices will not be found on a DIMM because -they respond to more than one address. - -DDC Monitors may contain any device. Often a 24C01, which responds -to all 8 addresses, is found. See the 'ddcmon' driver which has -specialized /proc entries for DDC monitors. If the eeprom driver is -loaded before the ddcmon driver and there is no 'ignore' line in the -/etc/sensors.conf file, the eeprom driver will latch onto the DDC monitor -eeprom. - -Recent Sony Vaio laptops have an EEPROM at 0x57. We couldn't get the -specification, so it is guess work and far from being complete. - -The Microchip 24AA52/24LCS52, ST M34C02, and others support an additional -software write protect register at 0x30 - 0x37 (0x20 less than the -memory location). The chip responds to "write quick" detection at this -address but does not respond to byte reads. -If this register is present, the lower 128 bytes of the memory -array are not write protected. Any byte data write to this address -will write protect the memory array permanently, and the device -will no longer respond at the 0x30-37 address. -The eeprom driver does not support this register. - -Lacking functionality: - -* Full support for larger devices (24C04, 24C08, 24C16). These are -not typically found on a PC. These devices will appear as separate -devices at multiple addresses. - -* Support for really large devices (24C32, 24C64, 24C128, 24C256, 24C512). -These devices require two-byte address fields and are not supported. - -* Enable Writing. Again, no technical reason why not, but making it easy -to change the contents of the EEPROMs (on DIMMs anyway) also makes it easy -to disable the DIMMs (potentially preventing the computer from booting) -until the values are restored somehow. - - -Use: - -After inserting the module (and any other required smbus/i2c modules), you -should have some EEPROM directories in /proc/sys/dev/sensors/ of names such -as "eeprom-i2c-0-50". Inside each of these is a series of files which -represent 16 bytes blocks from the EEPROM. The data is in decimal (base -10) delimited by spaces. - -Note: - -EEPROMs reported are not nessesarily all from DIMMs. Xeon processors, for -example, have serial EEPROMs in them connected to the SMBus which will be -found by the module. Take care to ignore the output of decode-dimms.pl for -these EEPROMs. There is decode-xeon.pl for them. Same applies to Vaio -EEPROMs, which have decode-vaio.pl. - -The driver caches the data from the monitor and only rereads it -from the eeprom if the cache is more than 5 minutes old. - - -Decode-dimms.pl ---------------- - -This Perl script attempts to make sense of the first 128 bytes of a SDRAM -PC-100 DIMM. Using the 'Serial Presence Detect (SPD)' Spec (Rev1.2a)** from -Intel. When finished, it will decode and report all the values defined in -the spec. Much of the information is technical timing and interfacing info -(probably not all used by the BIOS or clocking IC). - -Note: During testing, we noticed that many DIMMs have trucated SPD records. -I'm not sure if these conform to an old spec, or if the manufacturers are -simply just taking shortcuts. But, many DIMMs have all zeros stored past -byte 21. I asked an Intel SDRAM tester, Sat Kolli (skolli@smartm.com), -about this and this is what he had to say: - -"[...] Now in terms of SPD contents, you are right that people do all kinds -of things. The way to insure that any module works is to look for the most -basic information, such as module bank density, number of banks, and device -addresses. That will give you the module size and what devices are used. It -is very difficult to verify if the module is PC-100, because of -inconsistencies between spd data from different manufacturers. You could -read the timing information or the special Intel bytes (126 & 127) but I do -not know how many program that information. These inconsistencies may be -minimized if you or your customers stay with some of the better known -manufacturers." (Thanks goes to Sat Kolli for his comments and help.) - -Use: - -After inserting the necessary modules, run the script! - -Notes: - -The script assumes that Perl can be found at /usr/bin/perl. If different, -you will need to adjust the first line of the file accordingly, or else -you will get a strange "decode-dimms.pl: no such file or directory" error. - -Also note that the script assumes that _all_ the eeproms belong to DIMMs, -which may not be the case. - - -Decode-vaio.pl --------------- - -This Perl script looks for a Sony Vaio EEPROM at 0x57. If your system is not -a Sony Vaio laptop, you just don't care. If your system is an old Vaio, you -probably don't have an EEPROM on it and this script will be useless to you -as well. - -Use: - -After inserting the necessary modules, run the script! - -Notes: - -The script assumes that Perl can be found at /usr/bin/perl. If different, -you will need to adjust the first line of the file accordingly, or else -you will get a strange "decode-vaio.pl: no such file or directory" error. - - -Decode-edid.pl - -This Perl script acts as an interface between the eeprom module and -parse-edid, which is part of read-edid. Read-edid is a tool for gathering -information on VESA PNP monitors. It is somewhat similar to what our -ddcmon driver does, except that ddcmon outputs user-oriented data while -read-edid generates a a computer oriented configuration file (primarily -for XFree86). - -Read-edid is made of two components, get-edid which retrieves binary data -from the monitor, and parse-edid which decodes the data into useful -information. Get-edid uses low level functions, and relies on compliance -of both the video card and the monitor to some standard (DCC as it is -called). It may not work for everyone. On the other hand, some video -cards make this information available on an I2C bus and we are able to -get it using our eeprom module. That's why we wrote this script that -converts the data as exported by our eeprom module into what parse-edid -expects from get-edid. That way, users who can't get get-edid to work -still have a chance to be able to retrieve the wanted information thanks -to the lm_sensors modules and tools. - -Use: - -Unload the ddcmon if it was loaded, load the eeprom module instead. Then, -run the script. The script will try to figure out on which I2C bus and at -which address is the eeprom, but it may fail. In this case, you can pass -the parameters to the script. Examples: - - decode-edid.pl 1 - decode-edid.pl 2 0x50 - -You will find additional details in the script itself. Read-edid is avilable -there: - http://john.fremlin.de/programs/linux/read-edid/ diff --git a/doc/chips/f71805f b/doc/chips/f71805f deleted file mode 100644 index 40ee929a..00000000 --- a/doc/chips/f71805f +++ /dev/null @@ -1,107 +0,0 @@ -Kernel driver `f71805f.o' -========================= - -Status: Beta. - -Supported chips: - * Fintek F71805F/FG - Addresses scanned: none, address read from Super I/O config space - Prefix: 'f71805f' - Datasheet: Provided by Fintek on request - -Author: Jean Delvare - -Thanks to Denis Kieft from Barracuda Networks for the donation of a -test system (custom Jetway K8M8MS motherboard, with CPU and RAM) and -for providing initial documentation. - -Thanks to Kris Chen from Fintek for answering technical questions and -providing additional documentation. - -Thanks to Chris Lin from Jetway for providing wiring schematics and -answering technical questions. - - -Description ------------ - -The Fintek F71805F/FG Super I/O chip includes complete hardware monitoring -capabilities. It can monitor up to 9 voltages (counting its own power -source), 3 fans and 3 temperature sensors. - -This chip also has fan controlling features, using either DC or PWM, in -three different modes (one manual, two automatic). The driver doesn't -support these features yet. - -The driver assumes that no more than one chip is present, which seems -reasonable. - - -Voltage Monitoring ------------------- - -Voltages are sampled by an 8-bit ADC with a LSB of 8 mV. The supported -range is thus from 0 to 2.040 V. Voltage values outside of this range -need external resistors. An exception is in0, which is used to monitor -the chip's own power source (+3.3V), and is divided internally by a -factor 2. - -The two LSB of the voltage limit registers are not used (always 0), so -you can only set the limits in steps of 32 mV (before scaling). - -The wirings and resistor values suggested by Fintek are as follow: - - pin expected - name use R1 R2 divider raw val. - -in0 VCC VCC3.3V int. int. 2.00 1.65 V -in1 VIN1 VTT1.2V 10K - 1.00 1.20 V -in2 VIN2 VRAM 100K 100K 2.00 ~1.25 V (1) -in3 VIN3 VCHIPSET 47K 100K 1.47 2.24 V (2) -in4 VIN4 VCC5V 200K 47K 5.25 0.95 V -in5 VIN5 +12V 200K 20K 11.00 1.05 V -in6 VIN6 VCC1.5V 10K - 1.00 1.50 V -in7 VIN7 VCORE 10K - 1.00 ~1.40 V (1) -in8 VIN8 VSB5V 200K 47K 1.00 0.95 V - -(1) Depends on your hardware setup. -(2) Obviously not correct, swapping R1 and R2 would make more sense. - -These values can be used as hints at best, as motherboard manufacturers -are free to use a completely different setup. As a matter of fact, the -Jetway K8M8MS uses a significantly different setup. You will have to -find out documentation about your own motherboard, and edit sensors.conf -accordingly. - -Each voltage measured has associated low and high limits, each of which -triggers an alarm when crossed. - - -Fan Monitoring --------------- - -Fan rotation speeds are reported as 12-bit values from a gated clock -signal. Speeds down to 366 RPM can be measured. There is no theoretical -high limit, but values over 6000 RPM seem to cause problem. The effective -resolution is much lower than you would expect, the step between different -register values being 10 rather than 1. - -The chip assumes 2 pulse-per-revolution fans. - -An alarm is triggered if the rotation speed drops below a programmable -limit or is too low to be measured. - - -Temperature Monitoring ----------------------- - -Temperatures are reported in degrees Celsius. Each temperature measured -has a high limit, those crossing triggers an alarm. There is an associated -hysteresis value, below which the temperature has to drop before the -alarm is cleared. - -All temperature channels are external, there is no embedded temperature -sensor. Each channel can be used for connecting either a thermal diode -or a thermistor. The driver reports the currently selected mode, but -doesn't allow changing it. In theory, the BIOS should have configured -everything properly. diff --git a/doc/chips/fscher b/doc/chips/fscher deleted file mode 100644 index 2b8fee45..00000000 --- a/doc/chips/fscher +++ /dev/null @@ -1,266 +0,0 @@ -Kernel driver `fscher.o' -======================= - -Status: Stable - Tested with motherboard D1562 - - Think twice before you're using the write mode of some - variables, especially the watchdog - - -Supported chips: - * Fujitsu-Siemens Hermes chip - Prefix: 'fscher' - Addresses scanned: I2C 0x73 - -Author: Reinhard Nissl based on work from Hermann Jung - , Frodo Looijaard and Philip Edelbrock - - -License: GPL - - -Module Parameters ------------------ - -* force: short array (min = 1, max = 48) - List of adapter,address pairs to boldly assume to be present -* force_fscher: short array (min = 1, max = 48) - List of adapter,address pairs which are unquestionably assumed to contain - a `fscher' chip -* probe: short array (min = 1, max = 48) - List of adapter,address pairs to scan additionally -* probe_range: short array (min = 1, max = 48) - List of adapter,start-addr,end-addr triples to scan additionally -* ignore: short array (min = 1, max = 48) - List of adapter,address pairs not to scan -* ignore_range: short array (min = 1, max = 48) - List of adapter,start-addr,end-addr triples not to scan - - -Description ------------ - -This driver implements support for the Fujitsu-Siemens Hermes chip. -It is described in the 'Register Set Specification BMC Hermes based -Systemboard' from Fujitsu-Siemens. - -The Hermes chip implements a hardware-based system management, -e.g. for controlling fan speed and core voltage. -There is also a watchdog counter on the chip which can trigger -an alarm and even shut the system down. - -The chip provides three temperature values (CPU, motherboard and auxiliary), -three voltage values (+12V, +5V and battery) and three fans (power supply, -CPU and auxiliary). - -Temperatures are measured in degrees Celsius. The resolution is 1 degree. - -Fan rotation speeds are reported in RPM (rotations per minute). -The value can be divided by a programmable divider (1, 2 or 4) which -is stored on the chip. - -Voltage sensors (also known as "in" sensors) report their values in volts. - -All values are reported as final values from the driver. -There is no need for further calculations. - - -Detailed description --------------------- - -Below you'll find a single line description of all the bit values. With this -information, you're able to decode e. g. alarms, wdog, etc. -To make use of the watchdog, you'll need to set the watchdog time and enable -the watchdog. After that it is necessary to restart the watchdog time within -the specified period of time, or a system reset will occur. - -* rev:1 - READING & 0xff = 0x??: HERMES revision identification - -* alarms:1 - READING & 0x80 = 0x80: CPU throttling active - READING & 0x80 = 0x00: CPU running at full speed - - READING & 0x10 = 0x10: software event (see control:1) - READING & 0x10 = 0x00: no software event - - READING & 0x08 = 0x08: watchdog event (see wdog:2) - READING & 0x08 = 0x00: no watchdog event - - READING & 0x02 = 0x02: thermal event (see temp*:1) - READING & 0x02 = 0x00: no thermal event - - READING & 0x01 = 0x01: fan event (see fan*:1) - READING & 0x01 = 0x00: no fan event - - READING & 0x13 ! 0x00: ALERT LED is flashing - -* control:1 - READING & 0x01 = 0x01: software event - READING & 0x01 = 0x00: no software event - - WRITING & 0x01 = 0x01: set software event - WRITING & 0x01 = 0x00: clear software event - -* wdog:3 - READING & 0x80 = 0x80: power off on watchdog event while thermal event - READING & 0x80 = 0x00: watchdog power off disabled (just system reset enabled) - - READING & 0x40 = 0x40: watchdog timebase 60 seconds (see also wdog:1) - READING & 0x40 = 0x00: watchdog timebase 2 seconds - - READING & 0x10 = 0x10: watchdog enabled - READING & 0x10 = 0x00: watchdog disabled - - WRITING & 0x80 = 0x80: enable "power off on watchdog event while thermal event" - WRITING & 0x80 = 0x00: disable "power off on watchdog event while thermal event" - - WRITING & 0x40 = 0x40: set watchdog timebase to 60 seconds - WRITING & 0x40 = 0x00: set watchdog timebase to 2 seconds - - WRITING & 0x20 = 0x20: disable watchdog - - WRITING & 0x10 = 0x10: enable watchdog / restart watchdog time - -* wdog:2 - READING & 0x02 = 0x02: watchdog system reset occurred - READING & 0x02 = 0x00: no watchdog system reset occurred - - WRITING & 0x02 = 0x02: clear watchdog event - -* wdog:1 - READING & 0xff = 0x??: configured watch dog time in units (see wdog:3 0x40) - - WRITING & 0xff = 0x??: configure watch dog time in units - -* in*:1 (0: +5V, 1: +12V, 2: onboard 3V battery) - READING: actual voltage value - -* temp*:1 (1: CPU sensor, 2: onboard sensor, 3: auxiliary sensor) - READING & 0x02 = 0x02: thermal event (overtemperature) - READING & 0x02 = 0x00: no thermal event - - READING & 0x01 = 0x01: sensor is working - READING & 0x01 = 0x00: sensor is faulty - - WRITING & 0x02 = 0x02: clear thermal event - -* temp*:2 (1: CPU sensor, 2: onboard sensor, 3: auxiliary sensor) - READING: actual temperature value - -* fan*:1 (1: power supply fan, 2: CPU fan, 3: auxiliary fan) - READING & 0x04 = 0x04: fan event (fan fault) - READING & 0x04 = 0x00: no fan event - - WRITING & 0x04 = 0x04: clear fan event - -* fan*:2 (1: power supply fan, 2: CPU fan, 3: auxiliary fan) - READING & 0x03 = 0x03: 8 ripples are one fan turn - READING & 0x03 = 0x02: 4 ripples are one fan turn - READING & 0x03 = 0x01: 2 ripples are one fan turn - - WRITING & 0x03 = 0x03: set prescaler to "8 ripples are one fan turn" - WRITING & 0x03 = 0x02: set prescaler to "4 ripples are one fan turn" - WRITING & 0x03 = 0x01: set prescaler to "2 ripples are one fan turn" - -* fan*:3 (1: power supply fan, 2: CPU fan, 3: auxiliary fan) - READING & 0xff = 0x00: fan may be switched off - READING & 0xff = 0x01: fan must run at least at minimum speed (supply: 6V) - READING & 0xff = 0xff: fan must run at maximum speed (supply: 12V) - READING & 0xff = 0x??: fan must run at least at given speed (supply: 6V..12V) - - WRITING & 0xff = 0x00: fan may be switched off - WRITING & 0xff = 0x01: fan must run at least at minimum speed (supply: 6V) - WRITING & 0xff = 0xff: fan must run at maximum speed (supply: 12V) - WRITING & 0xff = 0x??: fan must run at least at given speed (supply: 6V..12V) - -* fan*:4 (1: power supply fan, 2: CPU fan, 3: auxiliary fan) - READING: actual RPM value - - -Limitations ------------ - -* Measuring fan speed -It seems that the chip counts "ripples" (typical fans produce 2 ripples per -rotation while VERAX fans produce 18) in a 9-bit register. This register is -read out every second, then the ripple prescaler (2, 4 or 8) is applied and -the result is stored in the 8 bit output register. Due to the limitation of -the counting register to 9 bits, it is impossible to measure a VERAX fan -properly (even with a prescaler of 8). At its maximum speed of 3500 RPM the -fan produces 1080 ripples per second which causes the counting register to -overflow twice, leading to only 186 RPM. - -* Measuring input voltages -in2 ("battery") reports the voltage of the onboard lithium battery and not -+3.3V from the power supply. - -* Undocumented features -Fujitsu-Siemens Computers has not documented all features of the chip so far. -Their software, System Guard, shows that there are a still some features which -cannot be controled by this implementation. - - -Chip Features -------------- - -Chip 'fscher' - -LABEL LABEL CLASS COMPUTE CLASS MODE MAGN -rev - - R- 0 -alarms - - R- 0 -control - - RW 0 -in0 - - R- 2 -in1 - - R- 2 -in2 - - R- 2 -temp1 - - R- 0 -temp2 - - R- 0 -temp3 - - R- 0 -temp1_state temp1 temp1 RW 0 -temp2_state temp2 temp2 RW 0 -temp3_state temp3 temp3 RW 0 -fan1 - - R- 0 -fan2 - - R- 0 -fan3 - - R- 0 -fan1_min fan1 fan1 RW 0 -fan2_min fan2 fan2 RW 0 -fan3_min fan3 fan3 RW 0 -fan1_state fan1 fan1 RW 0 -fan2_state fan2 fan2 RW 0 -fan3_state fan3 fan3 RW 0 -fan1_ripple fan1 fan1 RW 0 -fan2_ripple fan2 fan2 RW 0 -fan3_ripple fan3 fan3 RW 0 -wdog_preset - - RW 0 -wdog_state wdog_preset wdog_preset RW 0 -wdog_control wdog_preset wdog_preset RW 0 - -LABEL FEATURE SYMBOL SYSCTL FILE:N -rev SENSORS_FSCHER_REV rev:1 -alarms SENSORS_FSCHER_EVENT alarms:1 -control SENSORS_FSCHER_CONTROL control:1 -in0 SENSORS_FSCHER_VOLTAGE1 in0:1 -in1 SENSORS_FSCHER_VOLTAGE2 in1:1 -in2 SENSORS_FSCHER_VOLTAGE3 in2:1 -temp1 SENSORS_FSCHER_TEMP1 temp1:2 -temp2 SENSORS_FSCHER_TEMP2 temp2:2 -temp3 SENSORS_FSCHER_TEMP3 temp3:2 -temp1_state SENSORS_FSCHER_TEMP1_STATE temp1:1 -temp2_state SENSORS_FSCHER_TEMP2_STATE temp2:1 -temp3_state SENSORS_FSCHER_TEMP3_STATE temp3:1 -fan1 SENSORS_FSCHER_FAN1 fan1:4 -fan2 SENSORS_FSCHER_FAN2 fan2:4 -fan3 SENSORS_FSCHER_FAN3 fan3:4 -fan1_min SENSORS_FSCHER_FAN1_MIN fan1:2 -fan2_min SENSORS_FSCHER_FAN2_MIN fan2:2 -fan3_min SENSORS_FSCHER_FAN3_MIN fan3:2 -fan1_state SENSORS_FSCHER_FAN1_STATE fan1:1 -fan2_state SENSORS_FSCHER_FAN2_STATE fan2:1 -fan3_state SENSORS_FSCHER_FAN3_STATE fan3:1 -fan1_ripple SENSORS_FSCHER_FAN1_RIPPLE fan1:3 -fan2_ripple SENSORS_FSCHER_FAN2_RIPPLE fan2:3 -fan3_ripple SENSORS_FSCHER_FAN3_RIPPLE fan3:3 -wdog_preset SENSORS_FSCHER_WDOG_PRESET wdog:1 -wdog_state SENSORS_FSCHER_WDOG_STATE wdog:2 -wdog_control SENSORS_FSCHER_WDOG_CONTROL wdog:3 diff --git a/doc/chips/fscpos b/doc/chips/fscpos deleted file mode 100644 index 0707dc0d..00000000 --- a/doc/chips/fscpos +++ /dev/null @@ -1,122 +0,0 @@ -Kernel driver `fscpos.o' -====================== - -Status: Beta - Tested with motherboard d1107 - - Think twice before you're using the write mode of some - variables, especially the watchdog - - -Supported chips: - * Fujitsu Siemens Poseidon chip - Prefix: 'fscpos' - Addresses scanned: I2C 0x73 - -Author: Hermann Jung - - -Module Parameters ------------------ - -* force: short array (min = 1, max = 48) - List of adapter,address pairs to boldly assume to be present -* ignore: short array (min = 1, max = 48) - List of adapter,address pairs not to scan -* ignore_range: short array (min = 1, max = 48) - List of adapter,start-addr,end-addr triples not to scan -* probe: short array (min = 1, max = 48) - List of adapter,address pairs to scan additionally -* probe_range: short array (min = 1, max = 48) - List of adapter,start-addr,end-addr triples to scan additionally - - -Description ------------ - -This driver implements support for the Fujitsu Siemens Poseidon chip. -It is descibed in the 'Register Set Specification BMC Poseidon based -Systemboard' from Fujitsu Siemens. - -The poseidon chip implements a hardware based system management, -e.g. for controlling fan speed and core voltage. -There is also a watchdog counter on the chip which can trigger -an alarm and even shutdown the system. - -The chip provides three temperature values (cpu, motherboard and auxiliary), -three current values (12 volt, 5 volt and battery) and -three fans (power supply, cpu and auxiliary). - -Temperatures are measured in degrees Celsius. The resolution is 1 degree. - -Fan rotation speeds are reported in RPM (rotations per minute). -The value can be divided by a programmable divider (1, 2, 4 or 8) which -is stored on the chip. - -Voltage sensors (also known as IN sensors) report their values in volts. - -All values are reported as final values from the driver. -There is no need for further calculations. - -Chip Features -------------- - -Chip `fscpos' - LABEL LABEL CLASS COMPUTE CLASS ACCESS MAGNITUDE - rev NONE NONE R 0 - event NONE NONE R 0 - control NONE NONE RW 0 - volt12 NONE NONE R 2 - volt5 NONE NONE R 2 - voltbatt NONE NONE R 2 - temp1 NONE NONE R 0 - temp2 NONE NONE R 0 - temp3 NONE NONE R 0 - temp1_state temp1 temp1 RW 0 - temp2_state temp2 temp2 RW 0 - temp3_state temp3 temp3 RW 0 - fan1 NONE NONE R 0 - fan2 NONE NONE R 0 - fan3 NONE NONE R 0 - fan1_min fan1 fan1 RW 0 - fan2_min fan2 fan2 RW 0 - fan1_state fan1 fan1 RW 0 - fan2_state fan2 fan2 RW 0 - fan3_state fan3 fan3 RW 0 - fan1_ripple fan1 fan1 RW 0 - fan2_ripple fan2 fan2 RW 0 - fan3_ripple fan3 fan3 RW 0 - wdog_preset NONE NONE RW 0 - wdog_state wdog_preset wdog_preset RW 0 - wdog_control wdog_preset wdog_preset RW 0 - - - - LABEL FEATURE SYMBOL SYSCTL FILE:OFFSET - rev FSCPOS_SYSCTL_REV rev:1 - event FSCPOS_SYSCTL_EVENT event:1 - control FSCPOS_SYSCTL_CONTROL control:1 - volt12 FSCPOS_SYSCTL_VOLTAGE1 volt0:1 - volt5 FSCPOS_SYSCTL_VOLTAGE2 volt1:1 - voltbatt FSCPOS_SYSCTL_VOLTAGE3 volt2:1 - temp1 FSCPOS_SYSCTL_TEMP1 temp0:2 - temp2 FSCPOS_SYSCTL_TEMP2 temp1:2 - temp3 FSCPOS_SYSCTL_TEMP3 temp2:2 - temp1_state FSCPOS_SYSCTL_TEMP1_STATE temp0:1 - temp2_state FSCPOS_SYSCTL_TEMP2_STATE temp1:1 - temp3_state FSCPOS_SYSCTL_TEMP3_STATE temp2:1 - fan1 FSCPOS_SYSCTL_FAN1 fan0:4 - fan2 FSCPOS_SYSCTL_FAN2 fan1:4 - fan3 FSCPOS_SYSCTL_FAN3 fan2:4 - fan1_min FSCPOS_SYSCTL_FAN1_MIN fan0:2 - fan2_min FSCPOS_SYSCTL_FAN2_MIN fan1:2 - fan1_state FSCPOS_SYSCTL_FAN1_STATE fan0:1 - fan2_state FSCPOS_SYSCTL_FAN2_STATE fan1:1 - fan3_state FSCPOS_SYSCTL_FAN3_STATE fan2:1 - fan1_ripple FSCPOS_SYSCTL_FAN1_RIPPLE fan0:3 - fan2_ripple FSCPOS_SYSCTL_FAN2_RIPPLE fan1:3 - fan3_ripple FSCPOS_SYSCTL_FAN3_RIPPLE fan2:3 - wdog_preset FSCPOS_SYSCTL_WDOG_PRESET wdog:1 - wdog_state FSCPOS_SYSCTL_WDOG_STATE wdog:2 - wdog_control FSCPOS_SYSCTL_WDOG_CONTROL wdog:3 - diff --git a/doc/chips/fscscy b/doc/chips/fscscy deleted file mode 100644 index 6cc2f2ee..00000000 --- a/doc/chips/fscscy +++ /dev/null @@ -1,251 +0,0 @@ -Kernel driver `fscscy.o' -====================== - -Status: Beta - Tested with motherboard D1230 - Should also work with D1204, D1306 and D1307 - - Think twice before you're using the write mode of some - variables, especially the watchdog (Not my comment, but it makes - good sense to observe :-) - - -Supported chips: - * Fujitsu Siemens Scylla chip - Prefix: 'fscscy' - Addresses scanned: I2C 0x73 - -Author: Martin Knoblauch - -Acknowledgement: - This code has been greatly inspired by Hermann Jung - and his work on the Poseidon driver (fscpos) - - -Module Parameters ------------------ - -* force: short array (min = 1, max = 48) - List of adapter,address pairs to boldly assume to be present -* ignore: short array (min = 1, max = 48) - List of adapter,address pairs not to scan -* ignore_range: short array (min = 1, max = 48) - List of adapter,start-addr,end-addr triples not to scan -* probe: short array (min = 1, max = 48) - List of adapter,address pairs to scan additionally -* probe_range: short array (min = 1, max = 48) - List of adapter,start-addr,end-addr triples to scan additionally - - -Description ------------ - -This driver implements support for the Fujitsu Siemens Scylla chip. -The code is based on the "fscpos" driver for the FSC Poseidon chip. -In fact, it seems the Scylla is a superset of the "Poseidon", "Poseidon II" -and "Hydra" chips. - -The register readings/setting have been deduced from the 'Register Set -Specification BMC Poseidon based Systemboard' by Fujitsu Siemens and the -"sbbmon.ini" file from the Fujitsu-Siemens ServerView software. - -The scylla chip implements a hardware based system management, -e.g. for controlling fan speed and core voltage. -There is also a watchdog counter on the chip which can trigger -an alarm and even shutdown the system. See above for more details about using -the watchdog feature. - -The chip provides four temperature values (cpu0/1, motherboard and auxiliary), -three current values (12 volt, 5 volt and battery) and up to -six fans (power supply, cpu and auxiliary). - -Temperatures are measured in degrees Celsius. The resolution is 1 degree. -In addition to state and actual temperature, the temperature sensors also export -a LIMIT temperature for each sensor. The meaning of the information itself is -obvious. The rest is guesswork. It likely triggers an alarm/event as soon as it is -reached. The authors feeling is that it is even a writeable register. But beeing of -the cautios kind he did not implement writing the LIMIT resister. The driver itself -keeps track of the minimum and maximum temperatures since module load. The more often -the module is accessed, the more meaningful these values are. - -Fan rotation speeds are reported in RPM (rotations per minute). -The value can be divided by a programmable divider (1, 2, 4 or 8) which -is stored on the chip. - -Voltage sensors (also known as IN sensors) report their values in volts. - -All values are reported as final values from the driver. -There is no need for further calculations. - - -Using The Watchdog ------------------- - -This part was mostly contributed by A'rpi . Thanks! -I (Jean Delvare) edited the text for greater clarity, mainly to integrate -the e-mail exchange I and A'rpi had as a sequel of the original report. -Here it goes. - -I've spent few hours experiencing with the watchdog feature of the Fujitsu -Siemens server board (don't ask the model name, what I know is that it uses -Serverworks CSB5 chipset) using lm_sensors' fscscy driver. - -OK, so there is /proc/sys/dev/sensors/fscscy-i2c-0-73/wdog, containing 3 -8-bit values for the 3 watchdog registers. - -The first one is the time counter, it counts backwards. It's in 2 seconds -base, so writting 30 there means 60 seconds delay. It seems the whole range -(0 to 255) is supported, so up to 510 seconds (8.5 minutes). Writting 0 means -immediate hardware reset. The value you can read back is the same as you wrote -there, not the current value of the counter (as I expected). - -The second number is supposed to be a state register. It doesn't matter what -value I put there. It's always 0. Even if I write a non-zero value there, i got -0 back. Maybe it's non-zero at the moment of reset :) - -The third is the control register, with 5th (value 16), 6th (value 32) and 8th -(value 128) bits used only. If I write 16 or 144 (128+16), it means system -reset when the counter reaches 0. If I add 32 (for a value of 48 or 176), no -reset will occur. - -So, the world's simplest watchdog using this mainboard: - -while true ; do - echo 30 0 16 > /proc/sys/dev/sensors/fscscy-i2c-0-73/wdog - sleep 10 -done - -It does hardware reset after 1 minute, if this script is killed or system -hang-up occurs. Adjust the 30 and 10 values according to you needs, but -remember you must sleep less than the reset countdown time (here, 30*2-10 -gives us a 50 seconds margin, which is more than enough). - -Also note that BIOS has a strange setting, named 'OS Boot Retry Count', set -to 0 by default, it changes watchdog behaviour to power off instead of reset. -(0=poweroff 1..7=reset). It took me a while to find this. This behavior is -probably related to the "Reset Limit" parameter defined by the ACPI -specification (3.3.24 System Reset (Type 23)). It sets how many unintentional -resets can be performed in a row before giving up (and shut down). - -Please add the above to the documentation (doc/chips/fscscy), so i can save -a few hours of resetting for other people :) - - -Chip Features -------------- - -Chip `fscscy' - LABEL LABEL CLASS COMPUTE CLASS ACCESS MAGNITUDE - rev NONE NONE R 0 - event NONE NONE R 0 - control NONE NONE RW 0 - volt12 NONE NONE R 2 - volt5 NONE NONE R 2 - voltbatt NONE NONE R 2 - temp1 NONE NONE R 0 - temp2 NONE NONE R 0 - temp3 NONE NONE R 0 - temp4 NONE NONE R 0 - temp1_state temp1 temp1 RW 0 - temp2_state temp2 temp2 RW 0 - temp3_state temp3 temp3 RW 0 - temp4_state temp4 temp4 RW 0 - temp1_lim temp1 temp1 R* 0 - temp2_lim temp2 temp2 R* 0 - temp3_lim temp3 temp3 R* 0 - temp4_lim temp4 temp4 R* 0 - temp1_min temp1 temp1 R 0 - temp2_min temp2 temp2 R 0 - temp3_min temp3 temp3 R 0 - temp4_min temp4 temp4 R 0 - temp1_max temp1 temp1 R 0 - temp2_max temp2 temp2 R 0 - temp3_max temp3 temp3 R 0 - temp4_max temp4 temp4 R 0 - fan1 NONE NONE R 0 - fan2 NONE NONE R 0 - fan3 NONE NONE R 0 - fan4 NONE NONE R 0 - fan5 NONE NONE R 0 - fan6 NONE NONE R 0 - fan1_min fan1 fan1 RW 0 - fan2_min fan2 fan2 RW 0 - fan3_min fan3 fan3 RW 0 - fan4_min fan4 fan4 RW 0 - fan5_min fan5 fan5 RW 0 - fan6_min fan6 fan6 RW 0 - fan1_state fan1 fan1 RW 0 - fan2_state fan2 fan2 RW 0 - fan3_state fan3 fan3 RW 0 - fan4_state fan4 fan4 RW 0 - fan5_state fan5 fan5 RW 0 - fan6_state fan6 fan6 RW 0 - fan1_ripple fan1 fan1 RW 0 - fan2_ripple fan2 fan2 RW 0 - fan3_ripple fan3 fan3 RW 0 - fan4_ripple fan4 fan4 RW 0 - fan5_ripple fan5 fan5 RW 0 - fan6_ripple fan6 fan6 RW 0 - wdog_preset NONE NONE RW 0 - wdog_state wdog_preset wdog_preset RW 0 - wdog_control wdog_preset wdog_preset RW 0 - - R*: Maybe writable, but due to lack of documentation the author did not dare - to implement it :-) - - - LABEL FEATURE SYMBOL SYSCTL FILE:OFFSET - rev FSCSCY_SYSCTL_REV rev:1 - event FSCSCY_SYSCTL_EVENT event:1 - control FSCSCY_SYSCTL_CONTROL control:1 - volt12 FSCSCY_SYSCTL_VOLTAGE1 volt0:1 - volt5 FSCSCY_SYSCTL_VOLTAGE2 volt1:1 - voltbatt FSCSCY_SYSCTL_VOLTAGE3 volt2:1 - temp1 FSCSCY_SYSCTL_TEMP1 temp0:2 - temp2 FSCSCY_SYSCTL_TEMP2 temp1:2 - temp3 FSCSCY_SYSCTL_TEMP3 temp2:2 - temp4 FSCSCY_SYSCTL_TEMP4 temp3:2 - temp1_state FSCSCY_SYSCTL_TEMP1_STATE temp0:1 - temp2_state FSCSCY_SYSCTL_TEMP2_STATE temp1:1 - temp3_state FSCSCY_SYSCTL_TEMP3_STATE temp2:1 - temp4_state FSCSCY_SYSCTL_TEMP4_STATE temp3:1 - temp1_lim FSCSCY_SYSCTL_TEMP1_LIM temp0:3 - temp2_lim FSCSCY_SYSCTL_TEMP2_LIM temp1:3 - temp3_lim FSCSCY_SYSCTL_TEMP3_LIM temp2:3 - temp4_lim FSCSCY_SYSCTL_TEMP4_LIM temp3:3 - temp1_min FSCSCY_SYSCTL_TEMP1_MIN temp0:4 - temp2_min FSCSCY_SYSCTL_TEMP2_MIN temp1:4 - temp3_min FSCSCY_SYSCTL_TEMP3_MIN temp2:4 - temp4_min FSCSCY_SYSCTL_TEMP4_MIN temp3:4 - temp1_max FSCSCY_SYSCTL_TEMP1_MIN temp0:5 - temp2_max FSCSCY_SYSCTL_TEMP2_MIN temp1:5 - temp3_max FSCSCY_SYSCTL_TEMP3_MIN temp2:5 - temp4_max FSCSCY_SYSCTL_TEMP4_MIN temp3:5 - fan1 FSCSCY_SYSCTL_FAN1 fan0:4 - fan2 FSCSCY_SYSCTL_FAN2 fan1:4 - fan3 FSCSCY_SYSCTL_FAN3 fan2:4 - fan4 FSCSCY_SYSCTL_FAN4 fan3:4 - fan5 FSCSCY_SYSCTL_FAN5 fan4:4 - fan6 FSCSCY_SYSCTL_FAN6 fan5:4 - fan1_min FSCSCY_SYSCTL_FAN1_MIN fan0:2 - fan2_min FSCSCY_SYSCTL_FAN2_MIN fan1:2 - fan3_min FSCSCY_SYSCTL_FAN3_MIN fan2:2 - fan4_min FSCSCY_SYSCTL_FAN4_MIN fan3:2 - fan5_min FSCSCY_SYSCTL_FAN5_MIN fan4:2 - fan6_min FSCSCY_SYSCTL_FAN6_MIN fan5:2 - fan1_state FSCSCY_SYSCTL_FAN1_STATE fan0:1 - fan2_state FSCSCY_SYSCTL_FAN2_STATE fan1:1 - fan3_state FSCSCY_SYSCTL_FAN3_STATE fan2:1 - fan4_state FSCSCY_SYSCTL_FAN4_STATE fan3:1 - fan5_state FSCSCY_SYSCTL_FAN5_STATE fan4:1 - fan6_state FSCSCY_SYSCTL_FAN6_STATE fan5:1 - fan1_ripple FSCSCY_SYSCTL_FAN1_RIPPLE fan0:3 - fan2_ripple FSCSCY_SYSCTL_FAN2_RIPPLE fan1:3 - fan3_ripple FSCSCY_SYSCTL_FAN3_RIPPLE fan2:3 - fan4_ripple FSCSCY_SYSCTL_FAN3_RIPPLE fan3:3 - fan5_ripple FSCSCY_SYSCTL_FAN3_RIPPLE fan4:3 - fan6_ripple FSCSCY_SYSCTL_FAN3_RIPPLE fan5:3 - wdog_preset FSCSCY_SYSCTL_WDOG_PRESET wdog:1 - wdog_state FSCSCY_SYSCTL_WDOG_STATE wdog:2 - wdog_control FSCSCY_SYSCTL_WDOG_CONTROL wdog:3 - diff --git a/doc/chips/gl518sm b/doc/chips/gl518sm deleted file mode 100644 index 02aaa6e5..00000000 --- a/doc/chips/gl518sm +++ /dev/null @@ -1,184 +0,0 @@ -Kernel driver `gl518sm.o' -========================= - -Status: Complete and well-tested - -Supported chips: - * Genesys Logic GL518SM release 0x00 - Prefix: 'gl518sm' - Addresses scanned: I2C 0x2c and 0x2d - Datasheet: http://www.genesyslogic.com/pdf - * Genesys Logic GL518SM release 0x80 - Prefix: 'gl518sm' - Addresses scanned: I2C 0x2c and 0x2d - Datasheet: http://www.genesyslogic.com/pdf - -Author: Frodo Looijaard , - Kyösti Mälkki - - -Module Parameters ------------------ - -* force: short array (min = 1, max = 48) - List of adapter,address pairs to boldly assume to be present -* force_gl518sm_r00: short array (min = 1, max = 48) - List of adapter,address pairs which are unquestionably assumed to contain - a `gl518sm_r00' chip -* force_gl518sm_r80: short array (min = 1, max = 48) - List of adapter,address pairs which are unquestionably assumed to contain - a `gl518sm_r80' chip -* ignore: short array (min = 1, max = 48) - List of adapter,address pairs not to scan -* ignore_range: short array (min = 1, max = 48) - List of adapter,start-addr,end-addr triples not to scan -* probe: short array (min = 1, max = 48) - List of adapter,address pairs to scan additionally -* probe_range: short array (min = 1, max = 48) - List of adapter,start-addr,end-addr triples to scan additionally - -Description ------------ - -IMPORTANT: For the revision 0x00 chip, the - in0, in1, and in2 values (+5, +3, and +12) CANNOT be read - unless you use the slow 'iterate' method. Limits will still - work even when iterate=0. See below. This is a limitation - of the chip, not the driver. - Note that the 'iterate' method was trimmed while porting the - driver to Linux 2.6 as we considered it too ugly for the thin - benefit. - - -This driver supports the Genesys Logic GL518SM chip. There are at least -two revision of this chip, which we call revision 0x00 and 0x80. Revision -0x80 chips support the reading of voltages directly, 0x00 only for VIN3. - -The GL518SM implements one temperature sensor, two fan rotation speed -sensors, and four voltage sensors. It can report alarms through the -computer speakers. - -Temperatures are measured in degrees Celsius. An alarm goes off while the -temperature is above the over temperature limit, and has not yet dropped -below the hysteresis limit. The alarm always reflects the current situation. -Measurements are guaranteed between -10 degrees and +110 degrees, with -a resolution of +-3 degrees. - -Fan rotation speeds are reported in RPM (rotations per minute). An alarm is -triggered if the rotation speed has dropped below a programmable limit. -In case when you have selected to turn Fan1 off, no Fan1 alarm is triggered. - -Fan readings can be divided by a programmable divider (1, 2, 4 or 8) to give -the readings more range or accuracy. Not all RPM values can accurately be -represented, so some rounding is done. With a divider of 2, the lowest -representable value is around 1900 RPM. - -Voltage sensors (also known as VIN sensors) report their values in volts. An -alarm is triggered if the voltage has crossed a programmable minimum or -maximum limit. Note that minimum in this case always means 'closest to -zero'; this is important for negative voltage measurements. The VDD input -measures voltages between 0.000 and 5.865 volt, with a resolution of 0.023 -volt. The other inputs measure voltages between 0.000 and 4.845 volt, with a -resolution of 0.019 volt. Note that revision 0x00 chips do not support -reading the current voltage of any input except for VIN3; limit setting and -alarms work fine, though. There is code to compute them by iterating. - -When an alarm goes off, you can be warned by a beeping signal through -your computer speaker. It is possible to enable all beeping globally, -or only the beeping for some alarms. - -If an alarm triggers, it will remain triggered until the hardware register -is read at least once (except for temperature alarms). This means that the -cause for the alarm may already have disappeared! Note that in the current -implementation, all hardware registers are read whenever any data is read -(unless it is less than 1.5 seconds since the last update). This means that -you can easily miss once-only alarms. - -The GL518SM only updates its values each 1.5 seconds; reading it more often -will do no harm, but will return 'old' values. - -Iteration Code --------------- - -IMPORTANT: For the revision 0x00 chip only, -you may select between three modes to read the vin0-2 inputs with -the following lines in /etc/sensors.conf: - - set iterate 0 Don't read in0-in2 inputs. - set iterate 1 Run the iteration loop, this takes up to 10 seconds. - set iterate 2 Show the results of the last iteration loop, - and start a new loop to run in the background. - -You may also set the iteration type with -'echo n > /proc/sys/dev/sensors/gl518sm-i2c-x-y/iterate'. - -If you have a rev 0x80 chip, the in0-in2 inputs are readable. -In this case, 'iterate' will be read-only and the read value is 3. - -This does NOT apply to the Linux 2.6 kernel driver, where the 'iteration' -code was dropped for being too ugly. - - -Chip Features -------------- - -Chip `gl518sm' - LABEL LABEL CLASS COMPUTE CLASS ACCESS MAGNITUDE - vdd NONE NONE R 2 - vin1 NONE NONE R 2 - vin2 NONE NONE R 2 - vin3 NONE NONE R 2 - vdd_min vdd vdd RW 2 - vin1_min vin1 vin1 RW 2 - vin2_min vin2 vin2 RW 2 - vin3_min vin3 vin3 RW 2 - vdd_max vdd vdd RW 2 - vin1_max vin1 vin1 RW 2 - vin2_max vin2 vin2 RW 2 - vin3_max vin3 vin3 RW 2 - fan1 NONE NONE R 0 - fan2 NONE NONE R 0 - fan1_min fan1 fan1 RW 0 - fan2_min fan2 fan2 RW 0 - temp NONE NONE R 1 - temp_hyst temp temp RW 1 - temp_over temp temp RW 1 - fan1_div fan1 NONE RW 0 - fan2_div fan2 NONE RW 0 - alarms NONE NONE R 0 - beep_enable alarms NONE RW 0 - beeps alarms alarms RW 0 - fan1_off NONE NONE RW 0 - fan1_off_pin NONE NONE RW 0 - iterate NONE NONE RW 0 - - - LABEL FEATURE SYMBOL SYSCTL FILE:NR - vdd SENSORS_GL518_VDD vdd:3 - vin1 SENSORS_GL518_VIN1 vin1:3 - vin2 SENSORS_GL518_VIN2 vin2:3 - vin3 SENSORS_GL518_VIN3 vin3:3 - vdd_min SENSORS_GL518_VDD_MIN vdd:1 - vin1_min SENSORS_GL518_VIN1_MIN vin1:1 - vin2_min SENSORS_GL518_VIN2_MIN vin2:1 - vin3_min SENSORS_GL518_VIN3_MIN vin3:1 - vdd_max SENSORS_GL518_VDD_MAX vdd:2 - vin1_max SENSORS_GL518_VIN1_MAX vin1:2 - vin2_max SENSORS_GL518_VIN2_MAX vin2:2 - vin3_max SENSORS_GL518_VIN3_MAX vin3:2 - fan1 SENSORS_GL518_FAN1 fan1:2 - fan2 SENSORS_GL518_FAN2 fan2:2 - fan1_min SENSORS_GL518_FAN1_MIN fan1:1 - fan2_min SENSORS_GL518_FAN2_MIN fan2:1 - temp SENSORS_GL518_TEMP temp:3 - temp_hyst SENSORS_GL518_TEMP_HYST temp:2 - temp_over SENSORS_GL518_TEMP_OVER temp:1 - fan1_div SENSORS_GL518_FAN1_DIV fan_div:1 - fan2_div SENSORS_GL518_FAN2_DIV fan_div:2 - alarms SENSORS_GL518_ALARMS alarms:1 - beep_enable SENSORS_GL518_BEEP_ENABLE beep:1 - beeps SENSORS_GL518_BEEPS beep:2 - fan1_off SENSORS_GL518_FAN1OFF fan1off:1 - fan1_off_pin SENSORS_GL518_FAN1PIN fan1off:2 - iterate SENSORS_GL518_ITERATE iterate:1 - diff --git a/doc/chips/gl520sm b/doc/chips/gl520sm deleted file mode 100644 index 17d7c84a..00000000 --- a/doc/chips/gl520sm +++ /dev/null @@ -1,146 +0,0 @@ -Kernel driver `gl520sm.o' -========================= - -Status: Complete but experimental - -Supported chips: - * Genesys Logic GL520SM release 0x00 - Prefix: 'gl520sm' - Addresses scanned: I2C 0x2c and 0x2d - Datasheet: Not openly available - -Author: Frodo Looijaard , - Kyösti Mälkki - - -Module Parameters ------------------ - -* force: short array (min = 1, max = 48) - List of adapter,address pairs to boldly assume to be present -* ignore: short array (min = 1, max = 48) - List of adapter,address pairs not to scan -* ignore_range: short array (min = 1, max = 48) - List of adapter,start-addr,end-addr triples not to scan -* probe: short array (min = 1, max = 48) - List of adapter,address pairs to scan additionally -* probe_range: short array (min = 1, max = 48) - List of adapter,start-addr,end-addr triples to scan additionally - -Description ------------ - -This driver supports the Genesys Logic GL520SM chip. - -The GL520SM implements one temperature sensor, two fan rotation speed -sensors, four voltage sensors and the cpu VID lines. In addition, one input -can be configured as either a temperature or voltage sensor. -The sensor can report alarms through the computer speakers. - -Temperatures are measured in degrees Celsius. An alarm goes off while the -temperature is above the over temperature limit, and has not yet dropped -below the hysteresis limit. The alarm always reflects the current situation. -Measurements are guaranteed between 0 degrees and +110 degrees, with -a resolution of +-3 degrees. - -Fan rotation speeds are reported in RPM (rotations per minute). An alarm is -triggered if the rotation speed has dropped below a programmable limit. -In case when you have selected to turn Fan1 off, no Fan1 alarm is triggered -if measured temperature is below 'over temperature' limit. - -Fan readings can be divided by a programmable divider (1, 2, 4 or 8) to give -the readings more range or accuracy. Not all RPM values can accurately be -represented, so some rounding is done. With a divider of 2, the lowest -representable value is around 1900 RPM. - -Voltage sensors (also known as VIN sensors) report their values in volts. An -alarm is triggered if the voltage has crossed a programmable minimum or -maximum limit. Note that minimum in this case always means 'closest to -zero'; this is important for negative voltage measurements. The VDD input -measures voltages between 0.000 and 5.865 volt, with a resolution of 0.023 -volt. The other inputs measure voltages between 0.000 and 4.845 volt, with a -resolution of 0.019 volt. - -When an alarm goes off, you can be warned by a beeping signal through -your computer speaker. It is possible to enable all beeping globally, -or only the beeping for some alarms. - -If an alarm triggers, it will remain triggered until the hardware register -is read at least once (except for temperature alarms). This means that the -cause for the alarm may already have disappeared! Note that in the current -implementation, all hardware registers are read whenever any data is read -(unless it is less than 1.5 seconds since the last update). This means that -you can easily miss once-only alarms. - -The GL520SM only updates its values each 1.5 seconds; reading it more often -will do no harm, but will return 'old' values. - -Chip Features -------------- - -Chip `gl520sm' - LABEL LABEL CLASS COMPUTE CLASS ACCESS MAGNITUDE - vdd NONE NONE R 2 - vin1 NONE NONE R 2 - vin2 NONE NONE R 2 - vin3 NONE NONE R 2 - vin4 NONE NONE R 2 - vdd_min vdd vdd RW 2 - vin1_min vin1 vin1 RW 2 - vin2_min vin2 vin2 RW 2 - vin3_min vin3 vin3 RW 2 - vin4_min vin4 vin4 RW 2 - vdd_max vdd vdd RW 2 - vin1_max vin1 vin1 RW 2 - vin2_max vin2 vin2 RW 2 - vin3_max vin3 vin3 RW 2 - vin4_max vin4 vin4 RW 2 - fan1 NONE NONE R 0 - fan2 NONE NONE R 0 - fan1_min fan1 fan1 RW 0 - fan2_min fan2 fan2 RW 0 - temp1 NONE NONE R 1 - temp2 NONE NONE R 1 - temp1_hyst temp1 temp1 RW 1 - temp2_hyst temp2 temp2 RW 1 - temp1_over temp1 temp1 RW 1 - temp2_over temp2 temp2 RW 1 - fan1_div fan1 NONE RW 0 - fan2_div fan2 NONE RW 0 - alarms NONE NONE R 0 - beep_enable alarms NONE RW 0 - beeps alarms alarms RW 0 - two_temps NONE NONE RW 0 - - LABEL FEATURE SYMBOL SYSCTL FILE:NR - vdd SENSORS_GL520_VDD vdd:3 - vin1 SENSORS_GL520_VIN1 vin1:3 - vin2 SENSORS_GL520_VIN2 vin2:3 - vin3 SENSORS_GL520_VIN3 vin3:3 - vin4 SENSORS_GL520_VIN4 vin3:3 - vdd_min SENSORS_GL520_VDD_MIN vdd:1 - vin1_min SENSORS_GL520_VIN1_MIN vin1:1 - vin2_min SENSORS_GL520_VIN2_MIN vin2:1 - vin3_min SENSORS_GL520_VIN3_MIN vin3:1 - vin4_min SENSORS_GL520_VIN4_MIN vin3:1 - vdd_max SENSORS_GL520_VDD_MAX vdd:2 - vin1_max SENSORS_GL520_VIN1_MAX vin1:2 - vin2_max SENSORS_GL520_VIN2_MAX vin2:2 - vin3_max SENSORS_GL520_VIN3_MAX vin3:2 - vin4_max SENSORS_GL520_VIN4_MAX vin3:2 - fan1 SENSORS_GL520_FAN1 fan1:2 - fan2 SENSORS_GL520_FAN2 fan2:2 - fan1_min SENSORS_GL520_FAN1_MIN fan1:1 - fan2_min SENSORS_GL520_FAN2_MIN fan2:1 - temp1 SENSORS_GL520_TEMP1 temp1:3 - temp2 SENSORS_GL520_TEMP2 temp2:3 - temp1_hyst SENSORS_GL520_TEMP1_HYST temp1:2 - temp2_hyst SENSORS_GL520_TEMP2_HYST temp2:2 - temp1_over SENSORS_GL520_TEMP1_OVER temp1:1 - temp2_over SENSORS_GL520_TEMP2_OVER temp2:1 - fan1_div SENSORS_GL520_FAN1_DIV fan_div:1 - fan2_div SENSORS_GL520_FAN2_DIV fan_div:2 - alarms SENSORS_GL520_ALARMS alarms:1 - beep_enable SENSORS_GL520_BEEP_ENABLE beep:1 - beeps SENSORS_GL520_BEEPS beep:2 - two_temps SENSORS_GL520_TWOTEMPS config:1 diff --git a/doc/chips/it87 b/doc/chips/it87 deleted file mode 100644 index f39d5f51..00000000 --- a/doc/chips/it87 +++ /dev/null @@ -1,273 +0,0 @@ -Kernel driver `it87.o' -====================== - -Status: Complete, stable - -Supported chips: - * IT8705F - Prefix: 'it87' - Addresses scanned: ISA autodetected - Datasheet: Publicly available at the ITE website - http://www.ite.com.tw/ - * IT8712F - Prefix: 'it8712' - Addresses scanned: I2C 0x28 - 0x2f, ISA autodetected - Datasheet: Publicly available at the ITE website - http://www.ite.com.tw/ - * SiS950 [clone of IT8705F] - Prefix: 'it87' - Addresses scanned: ISA autodetected - Datasheet: No longer publicly available - -Author: Christophe Gauthron - - -Module Parameters ------------------ - -* force: short array (min = 1, max = 48) - List of adapter,address pairs to boldly assume to be present -* ignore: short array (min = 1, max = 48) - List of adapter,address pairs not to scan -* ignore_range: short array (min = 1, max = 48) - List of adapter,start-addr,end-addr triples not to scan -* probe: short array (min = 1, max = 48) - List of adapter,address pairs to scan additionally -* probe_range: short array (min = 1, max = 48) - List of adapter,start-addr,end-addr triples to scan additionally -* update_vbat: integer 0 if vbat should report power on value, 1 if - vbat should be updated after each read. Default is 0. - On some boards the battery voltage is provided by either the battery or - the onboard power supply. Only the first reading at power on will be - the actual battery voltage (which the chip does automatically). On other - boards the battery voltage is always fed to the chip so can be read at - any time. Excessive reading may decrease battery life but no information - is given in the datasheet. -* reset: integer 1 if the registers of the chip should be reset at - module load time, 0 to not reset the registers. Default is 0. - - -Description ------------ - -This driver implements support for the IT8705F, IT8712F and SiS950 chips. - -These chips are 'Super I/O chips', supporting floppy disks, infrared ports, -joysticks and other miscellaneous stuff. For hardware monitoring, -they include an 'environmnent controller' with 3 temperature sensors, -3 fan rotation speed sensors, 8 voltage sensors, and associated alarms. -The IT8712F additionally features VID inputs. - -Temperatures are measured in degrees Celsius. An alarm is triggered once -when the Overtemperature Shutdown limit is crossed. - -Fan rotation speeds are reported in RPM (rotations per minute). An alarm is -triggered if the rotation speed has dropped below a programmable limit. Fan -readings can be divided by a programmable divider (1, 2, 4 or 8) to give -the readings more range or accuracy. Not all RPM values can accurately be -represented, so some rounding is done. With a divider of 2, the lowest -representable value is around 2600 RPM. - -Voltage sensors (also known as IN sensors) report their values in volts. -An alarm is triggered if the voltage has crossed a programmable minimum -or maximum limit. Note that minimum in this case always means 'closest to -zero'; this is important for negative voltage measurements. All voltage -inputs can measure voltages between 0 and 4.08 volts, with a resolution -of 0.016 volt. The battery voltage in8 does not have limit registers. - -The VID lines (IT8712F only) encode the core voltage value: the voltage level -your processor should work with. This is hardcoded by the mainboard and/or -processor itself. It is a value in volts. - -If an alarm triggers, it will remain triggered until the hardware register -is read at least once. This means that the cause for the alarm may -already have disappeared! Note that in the current implementation, all -hardware registers are read whenever any data is read (unless it is less -than 1.5 seconds since the last update). This means that you can easily -miss once-only alarms. - -The IT87xx only updates its values each 1.5 seconds; reading it more often -will do no harm, but will return 'old' values. - -The sensor type can be set at runtime as of release 2.8.2. -To change sensor N to a thermistor, 'echo 2 > sensorN' -where N is 1, 2, or 3. -To change sensor N to a thermal diode, 'echo 3 > sensorN'. -Give 0 for unused sensor. Any other value is invalid. -To configure this at startup, put the following lines in the it87 section -of /etc/sensors.conf. -(2 = thermistor; 3 = thermal diode; 0 = unused) - set sensor1 3 - set sensor2 3 - set sensor3 3 - -If you set a sensor to 0, you'll also want to ignore its value: - ignore tempN - -The fan speed control features can be enabled by setting the bits 0-2 of -the fan_ctl register to 1. (Note: bits 6-4 of this register must be set to -1 to enable the fan monitoring). - 0x40 : enable fan speed monitoring for fan3 - 0x20 : enable fan speed monitoring for fan2 - 0x10 : enable fan speed monitoring for fan1 - 0x04 : enable fan smart guardian mode for fan3 - 0x02 : enable fan smart guardian mode for fan2 - 0x01 : enable fan smart guardian mode for fan1 - -If a fan's smart guardian bit is not set this fan is in on-off mode. -It can be switched on or off by setting/clearing the corresponding bit 0-2 -of the second fan control register fan_on_off. This register has no effect if -a fan is in smart guardian mode. - 0x04 : fan3 is on - 0x02 : fan2 is on - 0x01 : fan1 is on - -Bit 7 of the pwm[1-3] registers enables/disables the chip's automatic -temperature control mode for the specified fan. If Bit 7 is set the bits -1 and 0 encode the number of the temperature sensor used for this feature. -Possible register values are: - 0x00-0x7f direct power control for the fan speed - 0x80 automatic smart guardian mode use temperature sensor 1 - 0x81 automatic smart guardian mode use temperature sensor 2 - 0x82 automatic smart guardian mode use temperature sensor 3 - -In automatic smart guardian mode pwm values for low, medium and high speed -can be set in sg_pwm[1-3]. The temperature limits for fan off, low, medium, -hi speed and over temperature are set in sg_tl[1-3]. While the sensor's -temperature is between the low and medium speed value the fan will run in -low speed. When the sensor's temperature is between the medium and high speed -value the fan spins in medium speed. When the sensor's temperature is between -the high speed and over temperature value the fan spins in high speed. -If the sensor's temperature is higher than the over temperature limit the -fan will spin with the highest possible speed. - -Example: -The preconfigured (BIOS set) values of the Shuttle XPC SN41G2 Barebone. -The MB uses temp2 to monitor the CPU temperature and fan3 as the fan for their -special ICE heatpipe cooling system. - $ cat fan_ctl - 116 - $ cat tan_on_off - 215 - $ cat pwm3 - 129 - $ cat sg_tl3 - 16.0 16.0 48.0 54.0 58.0 - $ cat sg_pwm3 - 3 4 9 - -Explanation: - fan_ctl -> 116 = 0x74 = 01110100 : fan monitoring on for all fans, - and fan3 is in smart guardian mode. - fan_on_off -> 215 = 0xd7 =11010111 : all fans are on this setting is - ignored for fan3 which is in smart guardian mode - pwm3 -> 129 = 0x81 = 10000001 : fan3 is in automatic mode and uses - temp2 for speed control - sg_tl3 -> 16.0 16.0 48.0 54.0 58.0 : off, low, med, high, and - over temperature limits of fan3 - sg_pwm3 -> 3 4 9 : pwm values for low, medium and high fan speed of fan3. - - - -Chip features -------------- - -Chip `it87` - LABEL LABEL CLASS COMPUTE CLASS ACCESS MAGNITUDE - in0 NONE NONE R 2 - in1 NONE NONE R 2 - in2 NONE NONE R 2 - in3 NONE NONE R 2 - in4 NONE NONE R 2 - in5 NONE NONE R 2 - in6 NONE NONE R 2 - in7 NONE NONE R 2 - in8 NONE NONE R 2 - in0_min in0 in0 RW 2 - in1_min in1 in1 RW 2 - in2_min in2 in2 RW 2 - in3_min in3 in3 RW 2 - in4_min in4 in4 RW 2 - in5_min in5 in5 RW 2 - in6_min in6 in6 RW 2 - in7_min in6 in6 RW 2 - in0_max in0 in0 RW 2 - in1_max in1 in1 RW 2 - in2_max in2 in2 RW 2 - in3_max in3 in3 RW 2 - in4_max in4 in4 RW 2 - in5_max in5 in5 RW 2 - in6_max in6 in6 RW 2 - in7_max in6 in6 RW 2 - fan1 NONE NONE R 0 - fan2 NONE NONE R 0 - fan3 NONE NONE R 0 - fan1_min fan1 fan1 RW 0 - fan2_min fan2 fan2 RW 0 - fan3_min fan3 fan3 RW 0 - temp1 NONE NONE R 1 - temp2 NONE NONE R 1 - temp3 NONE NONE R 1 - temp1_low temp temp RW 1 - temp1_over temp temp RW 1 - temp2_low temp temp RW 1 - temp2_over temp temp RW 1 - temp3_low temp temp RW 1 - temp3_over temp temp RW 1 - vid NONE NONE R 2 - fan1_div fan1 NONE RW 0 - fan2_div fan2 NONE RW 0 - fan3_div fan3 NONE R 0 - alarms_vin NONE NONE R 0 - alarms_fan NONE NONE R 0 - alarms_temp NONE NONE R 0 - - LABEL FEATURE SYMBOL SYSCTL FILE:OFFSET - in0 SENSORS_IT87_IN0 in0:3 - in1 SENSORS_IT87_IN1 in1:3 - in2 SENSORS_IT87_IN2 in2:3 - in3 SENSORS_IT87_IN3 in3:3 - in4 SENSORS_IT87_IN4 in4:3 - in5 SENSORS_IT87_IN5 in5:3 - in6 SENSORS_IT87_IN6 in6:3 - in7 SENSORS_IT87_IN7 in7:3 - in0_min SENSORS_IT87_IN0_MIN in0:1 - in1_min SENSORS_IT87_IN1_MIN in1:1 - in2_min SENSORS_IT87_IN2_MIN in2:1 - in3_min SENSORS_IT87_IN3_MIN in3:1 - in4_min SENSORS_IT87_IN4_MIN in4:1 - in5_min SENSORS_IT87_IN5_MIN in5:1 - in6_min SENSORS_IT87_IN6_MIN in6:1 - in7_min SENSORS_IT87_IN7_MIN in7:1 - in0_max SENSORS_IT87_IN0_MAX in0:2 - in1_max SENSORS_IT87_IN1_MAX in1:2 - in2_max SENSORS_IT87_IN2_MAX in2:2 - in3_max SENSORS_IT87_IN3_MAX in3:2 - in4_max SENSORS_IT87_IN4_MAX in4:2 - in5_max SENSORS_IT87_IN5_MAX in5:2 - in6_max SENSORS_IT87_IN6_MAX in6:2 - in7_max SENSORS_IT87_IN7_MAX in7:2 - fan1 SENSORS_IT87_FAN1 fan1:2 - fan2 SENSORS_IT87_FAN2 fan2:2 - fan3 SENSORS_IT87_FAN3 fan3:2 - fan1_min SENSORS_IT87_FAN1_MIN fan1:1 - fan2_min SENSORS_IT87_FAN2_MIN fan2:1 - fan3_min SENSORS_IT87_FAN3_MIN fan3:1 - temp1 SENSORS_IT87_TEMP1 temp1:3 - temp2 SENSORS_IT87_TEMP2 temp2:3 - temp3 SENSORS_IT87_TEMP3 temp3:3 - temp1_low SENSORS_IT87_TEMP1_LOW temp1:2 - temp1_over SENSORS_IT87_TEMP1_HIGH temp1:1 - temp2_low SENSORS_IT87_TEMP2_LOW temp2:2 - temp2_over SENSORS_IT87_TEMP2_HIGH temp2:1 - temp3_low SENSORS_IT87_TEMP3_LOW temp3:2 - temp3_over SENSORS_IT87_TEMP3_HIGH temp3:1 - vid SENSORS_IT87_VID vid:1 - fan1_div SENSORS_IT87_FAN1_DIV fan_div:1 - fan2_div SENSORS_IT87_FAN2_DIV fan_div:2 - fan3_div SENSORS_IT87_FAN3_DIV fan_div:3 - alarms_fan SENSORS_IT87_ALARMS_FAN alarms_fan:1 - alarms_vin SENSORS_IT87_ALARMS_VIN alarms_vin:1 - alarms_temp SENSORS_IT87_ALARMS_TEMP alarms_temp:1 - - diff --git a/doc/chips/lm63 b/doc/chips/lm63 deleted file mode 100644 index d40397a7..00000000 --- a/doc/chips/lm63 +++ /dev/null @@ -1,102 +0,0 @@ -Kernel driver `lm63.o' -====================== - -Status: Complete, lightly tested - -Supported chips: - * National Semiconductor LM63 - Prefix: 'lm63' - Addresses scanned: I2C 0x4c - Datasheet: Publicly available at the National Semiconductor website - http://www.national.com/pf/LM/LM63.html - - -Author: Jean Delvare - -Thanks go to Tyan and especially Alex Buckingham for setting up a remote -access to their S4882 test platform for this driver. - http://www.tyan.com/ - -License: GPL - - -Module Parameters ------------------ - -* force: short array (min = 1, max = 48) - List of adapter,address pairs to boldly assume to be present -* force_lm63: short array (min = 1, max = 48) - List of adapter,address pairs which are unquestionably assumed to contain - a `lm63' chip -* probe: short array (min = 1, max = 48) - List of adapter,address pairs to scan additionally -* probe_range: short array (min = 1, max = 48) - List of adapter,start-addr,end-addr triples to scan additionally -* ignore: short array (min = 1, max = 48) - List of adapter,address pairs not to scan -* ignore_range: short array (min = 1, max = 48) - List of adapter,start-addr,end-addr triples not to scan - - -Description ------------ - -The LM63 is a digital temperature sensor with integrated fan monitoring -and control. - -All temperature values are given in degrees Celsius. Resolution is 1.0 -degree for the local temperature, 0.125 degree for the remote temperature. - -The fan speed is measured using a tachometer. Contrary to most chips which -store the value in an 8-bit register and have a selectable clock divider -to make sure that the result will fit in the register, the LM63 uses 16-bit -value for measuring the speed of the fan. It can measure fan speeds down to -83 RPM, at least in theory. - -Note that the pin used for fan monitoring is shared with an alert out -function. Depending on how the board designer wanted to use the chip, fan -speed monitoring will or will not be possible. The proper chip configuration -is left to the BIOS, and the driver will blindly trust it. - -A PWM output can be used to control the speed of the fan. The LM63 has two -PWM modes: manual and automatic. Automatic mode is not fully implemented yet -(you cannot define your custom pwm/temperature curve), and mode change isn't -supported either. - -The lm63 driver will not update its values more frequently than every -second; reading them more often will do no harm, but will return 'old' -values. - - -Chip Features -------------- - -Chip 'lm63' - -LABEL LABEL CLASS COMPUTE CLASS MODE MAGN -temp1 - - R- 0 -temp1_high temp1 temp1 RW 0 -temp2 - - R- 3 -temp2_high temp2 temp2 RW 3 -temp2_low temp2 temp2 RW 3 -temp2_crit temp2 temp2 R- 0 -temp2_crit_hyst temp2 temp2 RW 0 -fan1 - - R- 0 -fan1_low fan1 fan1 RW 0 -pwm1 - - RW 0 -pwm1_enable pwm1 - R- 0 -alarms - - R- 0 - -LABEL FEATURE SYMBOL SYSCTL FILE:N -temp1 SENSORS_LM63_LOCAL_TEMP temp1:2 -temp1_high SENSORS_LM63_LOCAL_HIGH temp1:1 -temp2 SENSORS_LM63_REMOTE_TEMP temp2:3 -temp2_high SENSORS_LM63_REMOTE_HIGH temp2:1 -temp2_low SENSORS_LM63_REMOTE_LOW temp2:2 -temp2_crit SENSORS_LM63_REMOTE_TCRIT temp2_crit:1 -temp2_crit_hyst SENSORS_LM63_REMOTE_TCRIT_HYST temp2_crit_hyst:1 -fan1 SENSORS_LM63_FAN fan1:2 -fan1_low SENSORS_LM63_FAN_LOW fan1:1 -pwm1 SENSORS_LM63_PWM pwm1:1 -pwm1_enable SENSORS_LM63_PWM_ENABLE pwm1:2 -alarms SENSORS_LM63_ALARMS alarms:1 diff --git a/doc/chips/lm75 b/doc/chips/lm75 deleted file mode 100644 index 697ebbde..00000000 --- a/doc/chips/lm75 +++ /dev/null @@ -1,107 +0,0 @@ -Kernel driver `lm75.o' -===================== - -Status: Complete and well-tested - -Supported chips: - * National Semiconductor LM75 - Prefix: 'lm75' - Addresses scanned: I2C 0x48 - 0x4f - Datasheet: Publicly available at the National Semiconductor website - http://www.national.com/ - * Dallas Semiconductor DS75 - Prefix: 'lm75' - Addresses scanned: I2C 0x48 - 0x4f - Datasheet: Publicly available at the Maxim website - http://www.maxim-ic.com/ - * Dallas Semiconductor DS1775 - Prefix: 'lm75' - Addresses scanned: I2C 0x48 - 0x4f - Datasheet: Publicly available at the Maxim website - http://www.maxim-ic.com/ - * Maxim MAX6625, MAX6626 - Prefix: 'lm75' - Addresses scanned: I2C 0x48 - 0x4b - Datasheet: Publicly available at the Maxim website - http://www.maxim-ic.com/ - * Microchip (TelCom) TCN75 - Prefix: 'lm75' - Addresses scanned: I2C 0x48 - 0x4f - Datasheet: Publicly available at the Microchip website - http://www.microchip.com/ - * Texas Instruments TMP100, TMP101 - Prefix: 'lm75' - Addresses scanned: I2C 0x48 - 0x4f - Datasheet: Publicly available at the TI website - http://www.ti.com/ - -Author: Frodo Looijaard - - -Module Parameters ------------------ - -* force: short array (min = 1, max = 48) - List of adapter,address pairs to boldly assume to be present -* force_lm75: short array (min = 1, max = 48) - List of adapter,address pairs which are unquestionably assumed to contain - a `lm75' chip -* ignore: short array (min = 1, max = 48) - List of adapter,address pairs not to scan -* ignore_range: short array (min = 1, max = 48) - List of adapter,start-addr,end-addr triples not to scan -* probe: short array (min = 1, max = 48) - List of adapter,address pairs to scan additionally -* probe_range: short array (min = 1, max = 48) - List of adapter,start-addr,end-addr triples to scan additionally - - -Description ------------ - -The LM75 implements one temperature sensor. Limits can be set through the -Overtemperature Shutdown register and Hysteresis register. Each value can be -set and read to half-degree accuracy. -An alarm is issued (usually to a connected LM78) when the temperature -gets higher then the Overtemperature Shutdown value; it stays on until -the temperature falls below the Hysteresis value. -All temperatures are in degrees Celsius, and are guaranteed within a -range of -55 to +125 degrees. - -The LM75 only updates its values each 1.5 seconds; reading it more often -will do no harm, but will return 'old' values. - -The LM75 is usually used in combination with LM78-like chips, to measure -the temperature of the processor(s). - -The DS75, DS1775, MAX6625, MAX6626, and others are supported as well. -They are not distinguished from an LM75. While most of these chips -have three additional bits of accuracy (12 vs. 9 for the LM75), -the additional bits are not supported. Not only that, but these chips will -not be detected if not in 9-bit precision mode (use the force parameter if -needed). -The prefix in the /proc directory is still 'lm75'. - -The LM75 is essentially an industry standard; there may be other -LM75 clones not listed here, with or without various enhancements, -that are supported. - -The LM77 is not supported, contrary to what we pretended for a long time. -Both chips are simply not compatible, value encoding differs. - - -Chip Features -------------- - -Chip `lm75' - LABEL LABEL CLASS COMPUTE CLASS ACCESS MAGNITUDE - temp NONE NONE R 1 - temp_hyst temp temp RW 1 - temp_over temp temp RW 1 - - LABEL FEATURE SYMBOL SYSCTL FILE:OFFSET - temp SENSORS_LM75_TEMP temp:3 - temp_hyst SENSORS_LM75_TEMP_HYST temp:2 - temp_over SENSORS_LM75_TEMP_OVER temp:1 - - diff --git a/doc/chips/lm78 b/doc/chips/lm78 deleted file mode 100644 index 9151973d..00000000 --- a/doc/chips/lm78 +++ /dev/null @@ -1,337 +0,0 @@ -Kernel driver `lm78.o' -====================== - -Status: Complete and well-tested - -Supported chips: - * National Semiconductor LM78 - Prefix: 'lm78' - Addresses scanned: I2C 0x20 - 0x2f, ISA 0x290 (8 I/O ports) - Datasheet: Publicly available at the National Semiconductor website - * National Semiconductor LM78-J - Prefix: 'lm78-j' - Addresses scanned: I2C 0x20 - 0x2f, ISA 0x290 (8 I/O ports) - Datasheet: Publicly available at the National Semiconductor website - * National Semiconductor LM79 - Prefix: 'lm79' - Addresses scanned: I2C 0x20 - 0x2f, ISA 0x290 (8 I/O ports) - Datasheet: Publicly available at the National Semiconductor website - -Author: Frodo Looijaard - - -Module Parameters ------------------ - -* force: short array (min = 1, max = 48) - List of adapter,address pairs to boldly assume to be present -* force_lm78: short array (min = 1, max = 48) - List of adapter,address pairs which are unquestionably assumed to contain - a `lm78' chip -* force_lm78j: short array (min = 1, max = 48) - List of adapter,address pairs which are unquestionably assumed to contain - a `lm78j' chip -* force_lm79: short array (min = 1, max = 48) - List of adapter,address pairs which are unquestionably assumed to contain - a `lm79' chip -* ignore: short array (min = 1, max = 48) - List of adapter,address pairs not to scan -* ignore_range: short array (min = 1, max = 48) - List of adapter,start-addr,end-addr triples not to scan -* probe: short array (min = 1, max = 48) - List of adapter,address pairs to scan additionally -* probe_range: short array (min = 1, max = 48) - List of adapter,start-addr,end-addr triples to scan additionally - - -Description ------------ - -This driver implements support for the National Semiconductor LM78, LM78-J -and LM79. They are described as `Microprocessor System Hardware Monitors'. - -There is almost no difference between the three supported chips. Functionally, -the LM78 and LM78-J are exactly identical. The LM79 has one more VID line, -which is used to report the lower voltages newer Pentium processors use. -From here on, LM7* means either of these three types. - -The LM7* implements one temperature sensor, three fan rotation speed sensors, -seven voltage sensors, VID lines, alarms, and some miscellaneous stuff. - -Temperatures are measured in degrees Celsius. An alarm is triggered once -when the Overtemperature Shutdown limit is crossed; it is triggered again -as soon as it drops below the Hysteresis value. A more useful behaviour -can be found by setting the Hysteresis value to +127 degrees Celsius; in -this case, alarms are issued during all the time when the actual temperature -is above the Overtemperature Shutdown value. Measurements are guaranteed -between -55 and +125 degrees, with a resolution of 1 degree. - -Fan rotation speeds are reported in RPM (rotations per minute). An alarm is -triggered if the rotation speed has dropped below a programmable limit. Fan -readings can be divided by a programmable divider (1, 2, 4 or 8) to give -the readings more range or accuracy. Not all RPM values can accurately be -represented, so some rounding is done. With a divider of 2, the lowest -representable value is around 2600 RPM. - -Voltage sensors (also known as IN sensors) report their values in volts. -An alarm is triggered if the voltage has crossed a programmable minimum -or maximum limit. Note that minimum in this case always means 'closest to -zero'; this is important for negative voltage measurements. All voltage -inputs can measure voltages between 0 and 4.08 volts, with a resolution -of 0.016 volt. - -The VID lines encode the core voltage value: the voltage level your processor -should work with. This is hardcoded by the mainboard and/or processor itself. -It is a value in volts. When it is unconnected, you will often find the -value 3.50 V here. - -In addition to the alarms described above, there are a couple of additional -ones. There is a BTI alarm, which gets triggered when an external chip has -crossed its limits. Usually, this is connected to all LM75 chips; if at -least one crosses its limits, this bit gets set. The CHAS alarm triggers -if your computer case is open. The FIFO alarms should never trigger; it -indicates an internal error. The SMI_IN alarm indicates some other chip -has triggered an SMI interrupt. As we do not use SMI interrupts at all, -this condition usually indicates there is a problem with some other -device. - -If an alarm triggers, it will remain triggered until the hardware register -is read at least once. This means that the cause for the alarm may -already have disappeared! Note that in the current implementation, all -hardware registers are read whenever any data is read (unless it is less -than 1.5 seconds since the last update). This means that you can easily -miss once-only alarms. - -The LM7* only updates its values each 1.5 seconds; reading it more often -will do no harm, but will return 'old' values. - - -Chip features -------------- - -Chip `lm78' - LABEL LABEL CLASS COMPUTE CLASS ACCESS MAGNITUDE - in0 NONE NONE R 2 - in1 NONE NONE R 2 - in2 NONE NONE R 2 - in3 NONE NONE R 2 - in4 NONE NONE R 2 - in5 NONE NONE R 2 - in6 NONE NONE R 2 - in0_min in0 in0 RW 2 - in1_min in1 in1 RW 2 - in2_min in2 in2 RW 2 - in3_min in3 in3 RW 2 - in4_min in4 in4 RW 2 - in5_min in5 in5 RW 2 - in6_min in6 in6 RW 2 - in0_max in0 in0 RW 2 - in1_max in1 in1 RW 2 - in2_max in2 in2 RW 2 - in3_max in3 in3 RW 2 - in4_max in4 in4 RW 2 - in5_max in5 in5 RW 2 - in6_max in6 in6 RW 2 - fan1 NONE NONE R 0 - fan2 NONE NONE R 0 - fan3 NONE NONE R 0 - fan1_min fan1 fan1 RW 0 - fan2_min fan2 fan2 RW 0 - fan3_min fan3 fan3 RW 0 - temp NONE NONE R 1 - temp_hyst temp temp RW 1 - temp_over temp temp RW 1 - vid NONE NONE R 2 - fan1_div fan1 NONE RW 0 - fan2_div fan2 NONE RW 0 - fan3_div fan3 NONE R 0 - alarms NONE NONE R 0 - - LABEL FEATURE SYMBOL SYSCTL FILE:OFFSET - in0 SENSORS_LM78_IN0 in0:3 - in1 SENSORS_LM78_IN1 in1:3 - in2 SENSORS_LM78_IN2 in2:3 - in3 SENSORS_LM78_IN3 in3:3 - in4 SENSORS_LM78_IN4 in4:3 - in5 SENSORS_LM78_IN5 in5:3 - in6 SENSORS_LM78_IN6 in6:3 - in0_min SENSORS_LM78_IN0_MIN in0:1 - in1_min SENSORS_LM78_IN1_MIN in1:1 - in2_min SENSORS_LM78_IN2_MIN in2:1 - in3_min SENSORS_LM78_IN3_MIN in3:1 - in4_min SENSORS_LM78_IN4_MIN in4:1 - in5_min SENSORS_LM78_IN5_MIN in5:1 - in6_min SENSORS_LM78_IN6_MIN in6:1 - in0_max SENSORS_LM78_IN0_MAX in0:2 - in1_max SENSORS_LM78_IN1_MAX in1:2 - in2_max SENSORS_LM78_IN2_MAX in2:2 - in3_max SENSORS_LM78_IN3_MAX in3:2 - in4_max SENSORS_LM78_IN4_MAX in4:2 - in5_max SENSORS_LM78_IN5_MAX in5:2 - in6_max SENSORS_LM78_IN6_MAX in6:2 - fan1 SENSORS_LM78_FAN1 fan1:2 - fan2 SENSORS_LM78_FAN2 fan2:2 - fan3 SENSORS_LM78_FAN3 fan3:2 - fan1_min SENSORS_LM78_FAN1_MIN fan1:1 - fan2_min SENSORS_LM78_FAN2_MIN fan2:1 - fan3_min SENSORS_LM78_FAN3_MIN fan3:1 - temp SENSORS_LM78_TEMP temp:3 - temp_hyst SENSORS_LM78_TEMP_HYST temp:2 - temp_over SENSORS_LM78_TEMP_OVER temp:1 - vid SENSORS_LM78_VID vid:1 - fan1_div SENSORS_LM78_FAN1_DIV fan_div:1 - fan2_div SENSORS_LM78_FAN2_DIV fan_div:2 - fan3_div SENSORS_LM78_FAN3_DIV fan_div:3 - alarms SENSORS_LM78_ALARMS alarms:1 - - -Chip `lm78-j' - LABEL LABEL CLASS COMPUTE CLASS ACCESS MAGNITUDE - in0 NONE NONE R 2 - in1 NONE NONE R 2 - in2 NONE NONE R 2 - in3 NONE NONE R 2 - in4 NONE NONE R 2 - in5 NONE NONE R 2 - in6 NONE NONE R 2 - in0_min in0 in0 RW 2 - in1_min in1 in1 RW 2 - in2_min in2 in2 RW 2 - in3_min in3 in3 RW 2 - in4_min in4 in4 RW 2 - in5_min in5 in5 RW 2 - in6_min in6 in6 RW 2 - in0_max in0 in0 RW 2 - in1_max in1 in1 RW 2 - in2_max in2 in2 RW 2 - in3_max in3 in3 RW 2 - in4_max in4 in4 RW 2 - in5_max in5 in5 RW 2 - in6_max in6 in6 RW 2 - fan1 NONE NONE R 0 - fan2 NONE NONE R 0 - fan3 NONE NONE R 0 - fan1_min fan1 fan1 RW 0 - fan2_min fan2 fan2 RW 0 - fan3_min fan3 fan3 RW 0 - temp NONE NONE R 1 - temp_hyst temp temp RW 1 - temp_over temp temp RW 1 - vid NONE NONE R 2 - fan1_div fan1 NONE RW 0 - fan2_div fan2 NONE RW 0 - fan3_div fan3 NONE R 0 - alarms NONE NONE R 0 - - LABEL FEATURE SYMBOL SYSCTL FILE:OFFSET - in0 SENSORS_LM78J_IN0 in0:3 - in1 SENSORS_LM78J_IN1 in1:3 - in2 SENSORS_LM78J_IN2 in2:3 - in3 SENSORS_LM78J_IN3 in3:3 - in4 SENSORS_LM78J_IN4 in4:3 - in5 SENSORS_LM78J_IN5 in5:3 - in6 SENSORS_LM78J_IN6 in6:3 - in0_min SENSORS_LM78J_IN0_MIN in0:1 - in1_min SENSORS_LM78J_IN1_MIN in1:1 - in2_min SENSORS_LM78J_IN2_MIN in2:1 - in3_min SENSORS_LM78J_IN3_MIN in3:1 - in4_min SENSORS_LM78J_IN4_MIN in4:1 - in5_min SENSORS_LM78J_IN5_MIN in5:1 - in6_min SENSORS_LM78J_IN6_MIN in6:1 - in0_max SENSORS_LM78J_IN0_MAX in0:2 - in1_max SENSORS_LM78J_IN1_MAX in1:2 - in2_max SENSORS_LM78J_IN2_MAX in2:2 - in3_max SENSORS_LM78J_IN3_MAX in3:2 - in4_max SENSORS_LM78J_IN4_MAX in4:2 - in5_max SENSORS_LM78J_IN5_MAX in5:2 - in6_max SENSORS_LM78J_IN6_MAX in6:2 - fan1 SENSORS_LM78J_FAN1 fan1:2 - fan2 SENSORS_LM78J_FAN2 fan2:2 - fan3 SENSORS_LM78J_FAN3 fan3:2 - fan1_min SENSORS_LM78J_FAN1_MIN fan1:1 - fan2_min SENSORS_LM78J_FAN2_MIN fan2:1 - fan3_min SENSORS_LM78J_FAN3_MIN fan3:1 - temp SENSORS_LM78J_TEMP temp:3 - temp_hyst SENSORS_LM78J_TEMP_HYST temp:2 - temp_over SENSORS_LM78J_TEMP_OVER temp:1 - vid SENSORS_LM78J_VID vid:1 - fan1_div SENSORS_LM78J_FAN1_DIV fan_div:1 - fan2_div SENSORS_LM78J_FAN2_DIV fan_div:2 - fan3_div SENSORS_LM78J_FAN3_DIV fan_div:3 - alarms SENSORS_LM78J_ALARMS alarms:1 - - -Chip `lm79' - LABEL LABEL CLASS COMPUTE CLASS ACCESS MAGNITUDE - in0 NONE NONE R 2 - in1 NONE NONE R 2 - in2 NONE NONE R 2 - in3 NONE NONE R 2 - in4 NONE NONE R 2 - in5 NONE NONE R 2 - in6 NONE NONE R 2 - in0_min in0 in0 RW 2 - in1_min in1 in1 RW 2 - in2_min in2 in2 RW 2 - in3_min in3 in3 RW 2 - in4_min in4 in4 RW 2 - in5_min in5 in5 RW 2 - in6_min in6 in6 RW 2 - in0_max in0 in0 RW 2 - in1_max in1 in1 RW 2 - in2_max in2 in2 RW 2 - in3_max in3 in3 RW 2 - in4_max in4 in4 RW 2 - in5_max in5 in5 RW 2 - in6_max in6 in6 RW 2 - fan1 NONE NONE R 0 - fan2 NONE NONE R 0 - fan3 NONE NONE R 0 - fan1_min fan1 fan1 RW 0 - fan2_min fan2 fan2 RW 0 - fan3_min fan3 fan3 RW 0 - temp NONE NONE R 1 - temp_hyst temp temp RW 1 - temp_over temp temp RW 1 - vid NONE NONE R 2 - fan1_div fan1 NONE RW 0 - fan2_div fan2 NONE RW 0 - fan3_div fan3 NONE R 0 - alarms NONE NONE R 0 - - LABEL FEATURE SYMBOL SYSCTL FILE:OFFSET - in0 SENSORS_LM79_IN0 in0:3 - in1 SENSORS_LM79_IN1 in1:3 - in2 SENSORS_LM79_IN2 in2:3 - in3 SENSORS_LM79_IN3 in3:3 - in4 SENSORS_LM79_IN4 in4:3 - in5 SENSORS_LM79_IN5 in5:3 - in6 SENSORS_LM79_IN6 in6:3 - in0_min SENSORS_LM79_IN0_MIN in0:1 - in1_min SENSORS_LM79_IN1_MIN in1:1 - in2_min SENSORS_LM79_IN2_MIN in2:1 - in3_min SENSORS_LM79_IN3_MIN in3:1 - in4_min SENSORS_LM79_IN4_MIN in4:1 - in5_min SENSORS_LM79_IN5_MIN in5:1 - in6_min SENSORS_LM79_IN6_MIN in6:1 - in0_max SENSORS_LM79_IN0_MAX in0:2 - in1_max SENSORS_LM79_IN1_MAX in1:2 - in2_max SENSORS_LM79_IN2_MAX in2:2 - in3_max SENSORS_LM79_IN3_MAX in3:2 - in4_max SENSORS_LM79_IN4_MAX in4:2 - in5_max SENSORS_LM79_IN5_MAX in5:2 - in6_max SENSORS_LM79_IN6_MAX in6:2 - fan1 SENSORS_LM79_FAN1 fan1:2 - fan2 SENSORS_LM79_FAN2 fan2:2 - fan3 SENSORS_LM79_FAN3 fan3:2 - fan1_min SENSORS_LM79_FAN1_MIN fan1:1 - fan2_min SENSORS_LM79_FAN2_MIN fan2:1 - fan3_min SENSORS_LM79_FAN3_MIN fan3:1 - temp SENSORS_LM79_TEMP temp:3 - temp_hyst SENSORS_LM79_TEMP_HYST temp:2 - temp_over SENSORS_LM79_TEMP_OVER temp:1 - vid SENSORS_LM79_VID vid:1 - fan1_div SENSORS_LM79_FAN1_DIV fan_div:1 - fan2_div SENSORS_LM79_FAN2_DIV fan_div:2 - fan3_div SENSORS_LM79_FAN3_DIV fan_div:3 - alarms SENSORS_LM79_ALARMS alarms:1 diff --git a/doc/chips/lm80 b/doc/chips/lm80 deleted file mode 100644 index 7930124d..00000000 --- a/doc/chips/lm80 +++ /dev/null @@ -1,149 +0,0 @@ -Kernel driver `lm80.o' -====================== - -Status: Complete and tested - -Supported chips: - * National Semiconductor LM80 - Prefix: 'lm80' - Addresses scanned: I2C 0x20 - 0x2f - -Author: Frodo Looijaard and Philip Edelbrock - - - -Module Parameters ------------------ - -* force: short array (min = 1, max = 48) - List of adapter,address pairs to boldly assume to be present -* force_lm80: short array (min = 1, max = 48) - List of adapter,address pairs which are unquestionably assumed to contain - a `lm80' chip -* ignore: short array (min = 1, max = 48) - List of adapter,address pairs not to scan -* ignore_range: short array (min = 1, max = 48) - List of adapter,start-addr,end-addr triples not to scan -* probe: short array (min = 1, max = 48) - List of adapter,address pairs to scan additionally -* probe_range: short array (min = 1, max = 48) - List of adapter,start-addr,end-addr triples to scan additionally - - -Description ------------ - -This driver implements support for the National Semiconductor LM80. -It is descibed as a `Serial Interface ACPI-Compatible Microprocessor -System Hardware Monitor'. - -The LM80 implements one temperature sensor, two fan rotation speed sensors, -seven voltage sensors, alarms, and some miscellaneous stuff. - -Temperatures are measured in degrees Celsius. There are two sets of limits -which operate independently. When the HOT Temperature Limit is crossed, -this will cause an alarm that will be reasserted until the temperature -drops below the HOT Hysteresis. The Overtemperature Shotdown (OS) limits -should work in the same way (but this must be checked; the datasheet -is unclear about this). Measurements are guaranteed between -55 and -+125 degrees. The current temperature measurement has a resolution of -0.0625 degrees; the limits have a resolution of 1 degree. - -Fan rotation speeds are reported in RPM (rotations per minute). An alarm is -triggered if the rotation speed has dropped below a programmable limit. Fan -readings can be divided by a programmable divider (1, 2, 4 or 8) to give -the readings more range or accuracy. Not all RPM values can accurately be -represented, so some rounding is done. With a divider of 2, the lowest -representable value is around 2600 RPM. - -Voltage ensors (also known as IN sensors) report their values in volts. -An alarm is triggered if the voltage has crossed a programmable minimum -or maximum limit. Note that minimum in this case always means 'closest to -zero'; this is important for negative voltage measurements. All voltage -inputs can measure voltages between 0 and 2.55 volts, with a resolution -of 0.01 volt. - -If an alarm triggers, it will remain triggered until the hardware register -is read at least once. This means that the cause for the alarm may -already have disappeared! Note that in the current implementation, all -hardware registers are read whenever any data is read (unless it is less -than 2.0 seconds since the last update). This means that you can easily -miss once-only alarms. - -The LM80 only updates its values each 1.5 seconds; reading it more often -will do no harm, but will return 'old' values. - - -Chip Features -------------- - -Chip `lm80' - LABEL LABEL CLASS COMPUTE CLASS ACCESS MAGNITUDE - in0 NONE NONE R 2 - in1 NONE NONE R 2 - in2 NONE NONE R 2 - in3 NONE NONE R 2 - in4 NONE NONE R 2 - in5 NONE NONE R 2 - in6 NONE NONE R 2 - in0_min in0 in0 RW 2 - in1_min in1 in1 RW 2 - in2_min in2 in2 RW 2 - in3_min in3 in3 RW 2 - in4_min in4 in4 RW 2 - in5_min in5 in5 RW 2 - in6_min in6 in6 RW 2 - in0_max in0 in0 RW 2 - in1_max in1 in1 RW 2 - in2_max in2 in2 RW 2 - in3_max in3 in3 RW 2 - in4_max in4 in4 RW 2 - in5_max in5 in5 RW 2 - in6_max in6 in6 RW 2 - fan1 NONE NONE R 0 - fan2 NONE NONE R 0 - fan1_min fan1 NONE RW 0 - fan2_min fan2 NONE RW 0 - temp NONE NONE R 2 - temp_hot_hyst temp temp RW 2 - temp_hot_max temp temp RW 2 - temp_os_hyst temp temp RW 2 - temp_os_max temp temp RW 2 - fan1_div fan1 NONE RW 0 - fan2_div fan2 NONE RW 0 - alarms NONE NONE R 0 - - LABEL FEATURE SYMBOL SYSCTL FILE:OFFSET - in0 SENSORS_LM80_IN0 in0:3 - in1 SENSORS_LM80_IN1 in1:3 - in2 SENSORS_LM80_IN2 in2:3 - in3 SENSORS_LM80_IN3 in3:3 - in4 SENSORS_LM80_IN4 in4:3 - in5 SENSORS_LM80_IN5 in5:3 - in6 SENSORS_LM80_IN6 in6:3 - in0_min SENSORS_LM80_IN0_MIN in0:1 - in1_min SENSORS_LM80_IN1_MIN in1:1 - in2_min SENSORS_LM80_IN2_MIN in2:1 - in3_min SENSORS_LM80_IN3_MIN in3:1 - in4_min SENSORS_LM80_IN4_MIN in4:1 - in5_min SENSORS_LM80_IN5_MIN in5:1 - in6_min SENSORS_LM80_IN6_MIN in6:1 - in0_max SENSORS_LM80_IN0_MAX in0:2 - in1_max SENSORS_LM80_IN1_MAX in1:2 - in2_max SENSORS_LM80_IN2_MAX in2:2 - in3_max SENSORS_LM80_IN3_MAX in3:2 - in4_max SENSORS_LM80_IN4_MAX in4:2 - in5_max SENSORS_LM80_IN5_MAX in5:2 - in6_max SENSORS_LM80_IN6_MAX in6:2 - fan1 SENSORS_LM80_FAN1 fan1:2 - fan2 SENSORS_LM80_FAN2 fan2:2 - fan1_min SENSORS_LM80_FAN1_MIN fan1:1 - fan2_min SENSORS_LM80_FAN2_MIN fan2:1 - temp SENSORS_LM80_TEMP temp:5 - temp_hot_hyst SENSORS_LM80_TEMP_HOT_HYST temp:2 - temp_hot_max SENSORS_LM80_TEMP_HOT_MAX temp:1 - temp_os_hyst SENSORS_LM80_TEMP_OS_HYST temp:4 - temp_os_max SENSORS_LM80_TEMP_OS_MAX temp:3 - fan1_div SENSORS_LM80_FAN1_DIV fan_div:1 - fan2_div SENSORS_LM80_FAN2_DIV fan_div:2 - alarms SENSORS_LM80_ALARMS alarms:1 diff --git a/doc/chips/lm83 b/doc/chips/lm83 deleted file mode 100644 index d7f64690..00000000 --- a/doc/chips/lm83 +++ /dev/null @@ -1,156 +0,0 @@ -Kernel driver `lm83.o' -===================== - -Status: Complete and lightly tested - -Supported chips: - * National Semiconductor LM83 - Prefix: 'lm83' - Addresses scanned: I2C 0x18 - 0x1a, 0x29 - 0x2b, 0x4c - 0x4e - Datasheet: Publicly available at the National Semiconductor website - http://www.national.com/pf/LM/LM83.html - * National Semiconductor LM82 - Addresses scanned: I2C 0x18 - 0x1a, 0x29 - 0x2b, 0x4c - 0x4e - Datasheet: Publicly available at the National Semiconductor website - http://www.national.com/pf/LM/LM82.html - - -Author: Jean Delvare - -License: GPL - - -Module Parameters ------------------ - -* force: short array (min = 1, max = 48) - List of adapter,address pairs to boldly assume to be present -* force_lm83: short array (min = 1, max = 48) - List of adapter,address pairs which are unquestionably assumed to contain - a `lm83' chip -* probe: short array (min = 1, max = 48) - List of adapter,address pairs to scan additionally -* probe_range: short array (min = 1, max = 48) - List of adapter,start-addr,end-addr triples to scan additionally -* ignore: short array (min = 1, max = 48) - List of adapter,address pairs not to scan -* ignore_range: short array (min = 1, max = 48) - List of adapter,start-addr,end-addr triples not to scan - - -Description ------------ - -The LM83 is a digital temperature sensor. It senses its own temperature as -well as the temperature of up to three external diodes. The LM82 is -a stripped down version of the LM83 that only supports one external diode. -Both are compatible with many other devices such as the LM84 and all -other ADM1021 clones. The main difference between the LM83 and the LM84 -in that the later can only sense the temperature of one external diode. - -Using the adm1021 driver for a LM83 should work, but only two temperatures -will be reported instead of four. - -The LM83 is only found on a handful of motherboards. Both a confirmed -list and an unconfirmed list follow. If you can confirm or infirm the -fact that any of these motherboards do actually have an LM83, please -contact us. Note that the LM90 can easily be misdetected as a LM83. - -Confirmed motherboards: - SBS P014 - SBS PSL09 - -Unconfirmed motherboards: - Gigabyte GA-8IK1100 - Iwill MPX2 - Soltek SL-75DRV5 - -The LM82 is confirmed to have been found on most AMD Geode reference -designs and test platforms. - -The driver has been successfully tested by Magnus Forsström, who I'd -like to thank here. More testers will be of course welcome. - -The fact that the LM83 is only scarcely used can be easily explained. -Most motherboards come with more than just temperature sensors for -health monitoring. They also have voltage and fan rotation speed -sensors. This means that temperature-only chips are usually used as -secondary chips coupled with another chip such as an IT8705F or similar -chip, which provides more features. Since systems usually need three -temperature sensors (motherboard, processor, power supply) and primary -chips provide some temperature sensors, the secondary chip, if needed, -won't have to handle more than two temperatures. Thus, ADM1021 clones -are sufficent, and there is no need for a four temperatures sensor -chip such as the LM83. The only case where using an LM83 would make -sense is on SMP systems, such as the above-mentioned Iwill MPX2, -because you want an additional temperature sensor for each additional -CPU. - -On the SBS P014, this is different, since the LM83 is the only hardware -monitoring chipset. One temperature sensor is used for the motherboard -(actually measuring the LM83's own temperature), one is used for the -CPU. The two other sensors must be used to measure the temperature of -two other points of the motherboard. We suspect these points to be the -north and south bridges, but this couldn't be confirmed. - -All temperature values are given in degrees Celsius. Local temperature -is given within a range of 0 to +85 degrees. Remote temperatures are -given within a range of 0 to +125 degrees. Resolution is 1.0 degree, -accuracy is guaranteed to 3.0 degrees (see the datasheet for more -details). - -Each sensor has its own high limit, but the critical limit is common to -all four sensors. There is no hysteresis mechanism as found on most -recent temperature sensors. - -The lm83 driver will not update its values more frequently than every -other second; reading them more often will do no harm, but will return -'old' values. - - -Chip Features -------------- - -Chip 'lm83' - -LABEL LABEL CLASS COMPUTE CLASS MODE MAGN -temp1 - - R- 0 -temp1_high temp1 temp1 RW 0 -temp2 - - R- 0 -temp2_high temp2 temp2 RW 0 -temp3 - - R- 0 -temp3_high temp3 temp3 RW 0 -temp4 - - R- 0 -temp4_high temp4 temp4 RW 0 -tcrit - - RW 0 -alarms - - R- 0 - -LABEL FEATURE SYMBOL SYSCTL FILE:N -temp1 SENSORS_LM83_LOCAL_TEMP temp1:2 -temp1_high SENSORS_LM83_LOCAL_HIGH temp1:1 -temp2 SENSORS_LM83_REMOTE1_TEMP temp2:2 -temp2_high SENSORS_LM83_REMOTE1_HIGH temp2:1 -temp3 SENSORS_LM83_REMOTE2_TEMP temp3:2 -temp3_high SENSORS_LM83_REMOTE2_HIGH temp3:1 -temp4 SENSORS_LM83_REMOTE3_TEMP temp4:2 -temp4_high SENSORS_LM83_REMOTE3_HIGH temp4:1 -tcrit SENSORS_LM83_TCRIT tcrit:1 -alarms SENSORS_LM83_ALARMS alarms:1 - -Chip 'lm82' - -LABEL LABEL CLASS COMPUTE CLASS MODE MAGN -temp1 - - R- 0 -temp1_high temp1 temp1 RW 0 -temp3 - - R- 0 -temp3_high temp3 temp3 RW 0 -tcrit - - RW 0 -alarms - - R- 0 - -LABEL FEATURE SYMBOL SYSCTL FILE:N -temp1 SENSORS_LM83_LOCAL_TEMP temp1:2 -temp1_high SENSORS_LM83_LOCAL_HIGH temp1:1 -temp3 SENSORS_LM83_REMOTE2_TEMP temp3:2 -temp3_high SENSORS_LM83_REMOTE2_HIGH temp3:1 -tcrit SENSORS_LM83_TCRIT tcrit:1 -alarms SENSORS_LM83_ALARMS alarms:1 diff --git a/doc/chips/lm85 b/doc/chips/lm85 deleted file mode 100644 index a0df8296..00000000 --- a/doc/chips/lm85 +++ /dev/null @@ -1,527 +0,0 @@ -Kernel driver `lm85.o' -====================== - -Status: Complete and somewhat tested - -Supported chips: - * National Semiconductor LM85 (B and C versions) - Prefix: 'lm85' - Addresses scanned: I2C 0x2c, 0x2d, 0x2e - Datasheet: http://www.national.com/pf/LM/LM85.html - * Analog Devices ADM1027 - Prefix: 'adm1027' - Addresses scanned: I2C 0x2c, 0x2d, 0x2e - Datasheet: http://www.analog.com/en/prod/0,,766_825_ADM1027,00.html - * Analog Devices ADT7463 - Prefix: 'adt7463' - Addresses scanned: I2C 0x2c, 0x2d, 0x2e - Datasheet: http://www.analog.com/en/prod/0,,766_825_ADT7463,00.html - * SMSC EMC6D100, SMSC EMC6D101 - Prefix: 'emc6d100' - Addresses scanned: I2C 0x2c, 0x2d, 0x2e - Datasheet: http://www.smsc.com/main/tools/discontinued/6d100.pdf - * SMSC EMC6D102, SMSC EMC6D101 - Prefix: 'emc6d102' - Addresses scanned: I2C 0x2c, 0x2d, 0x2e - Datasheet: http://www.smsc.com/main/catalog/emc6d102.html - -Authors: - Philip Pokorny - Frodo Looijaard - Richard Barrington - - -Module Parameters ------------------ - -* force: short array (min = 1, max = 48) - List of adapter,address pairs to assume to be present. Autodetection - of the target device will still be attempted. Use one of the more - specific force directives below if this doesn't detect the device. -* force_lm85b: short array (min = 1, max = 48) - List of adapter,address pairs which are unquestionably assumed to contain - a `lm85-B' chip -* force_lm85c: short array (min = 1, max = 48) - List of adapter,address pairs which are unquestionably assumed to contain - a `lm85-C' chip -* force_adm1027: short array (min = 1, max = 48) - List of adapter,address pairs which are unquestionably assumed to contain - a `adm1027' chip -* force_adt7463: short array (min = 1, max = 48) - List of adapter,address pairs which are unquestionably assumed to contain - a `adt7463' chip -* ignore: short array (min = 1, max = 48) - List of adapter,address pairs not to scan -* ignore_range: short array (min = 1, max = 48) - List of adapter,start-addr,end-addr triples not to scan -* probe: short array (min = 1, max = 48) - List of adapter,address pairs to scan additionally -* probe_range: short array (min = 1, max = 48) - List of adapter,start-addr,end-addr triples to scan additionally - - -Description ------------ - -This driver implements support for the National Semiconductor LM85 -and compatible chips including the Analog Devices ADM1027 and ADT7463, -and SMSC EMC6D100, EMC6D101 and EMC6D102. - -The LM85 uses the 2-wire interface compatible with the SMBUS 2.0 -specification. Using an analog to digital converter it measures three -(3) temperatures and five (5) voltages. It has four (4) 16-bit -counters for measuring fan speed. Five (5) digital inputs are -provided for sampling the VID signals from the processor to the VRM. -Lastly, there are three (3) PWM outputs that can be used to control -fan speed. - -The voltage inputs have internal scaling resistors so that the -following voltage can be measured without external resistors: - - 2.5V, 3.3V, 5V, 12V, and CPU core voltage (2.25V) - -The temperatures measured are one internal diode, and two remote -diodes. Remote 1 is generally the CPU temperature. These inputs are -designed to measure a thermal diode like the one in a Pentium 4 -processor in a socket 423 or socket 478 package. They can also -measure temperature using a transistor like the 2N3904. - -A sophisticated control system for the PWM outputs is designed into -the LM85 that allows fan speed to be adjusted automatically based on -any of the three temperature sensors. Each PWM output is individually -adjustable and programmable. Once configured, the LM85 will adjust -the PWM outputs in response to the measured temperatures without -further host intervention. This feature can also be disabled for -manual control of the PWM's. - -Each of the measured inputs (voltage, temperature, fan speed) has -corresponding high/low limit values. The LM85 will signal an ALARM if -any measured value exceeds either limit. - -The LM85 samples all inputs continuously. The lm85 driver will not -read the registers more often than once a second. Further, configuration -data is only read once each 5 minutes. There is twice as much config -data as measurements, so this would seem to be a worthwhile -optimization. - -Special Features - -The LM85 has four fan speed monitoring modes. The ADM1027 has only -two. Both have special circuitry to compensate for PWM interactions -with the TACH signal from the fans. The ADM1027 can be configured to -measure the speed of a two wire fan, but the input conditioning -circuitry is different for 3-wire and 2-wire mode. For this reason, -the 2-wire fan modes are not exposed to user control. The BIOS should -initialize them to the correct mode. If you've designed your own -ADM1027, you'll have to modify the init_client function and add an -insmod parameter to set this up. - -To smooth the response of fans to changes in temperature, the LM85 has -an optional filter for smoothing temperatures. The ADM1027 has the -same config option but uses it to rate limit the changes to fan speed -instead. In libsensors, we associate the smoothing feature with a -zone in the LM85 and with a PWM in the ADM1027. - -The ADM1027 and ADT7463 have a 10-bit ADC and can therefore measure -temperatures with 0.25 degC resolution. They also provide an offset to -the temperature readings that is automatically applied during -measurement. This offset can be used to zero out any errors due to -traces and placement. The documentation says that the offset is in -0.25 degC steps, but in initial testing of the ADM1027 it was 1.00 -degC steps. Analog Devices has confirmed this "bug". The ADT7463 is -reported to work as described in the documentation. Accordingly, the -driver currently reports 1.00 degC steps for the ADM1027 and 0.25 degC -steps for the ADT7463. If you have an ADT7463, please confirm to the -LM85 maintainer that the temperature offset works as implemented. - -The ADT7463 has a THERM asserted counter. This counter has a 22.76ms -resolution and a range of 5.8 seconds. The driver implements a 31-bit -accumulator of the counter value to extend the range to over a year. -The counter will stay at it's max value until read. If you want to -insure no counts get lost, you need to trigger the driver to read the -counter every 5 seconds. You can do this by reading just the -therm_signal value. The driver implements reads of 'therm_signal' -without reading the other values for speed. A background shell script -like: - - #!/bin/bash - while [ 1 ] ; do - cat /proc/sys/dev/sensors/adt7463-*/therm_signal > /dev/null - sleep 5 - done - -Or if you want to record the values: - - #!/bin/bash - last=0 - while [ 1 ] ; do - read tlim total ovfl < /proc/sys/dev/sensors/adt7463-*/therm_signal - if [ $total -gt $last ]; then - echo $(date) - $tlim $total $ovfl - last=$total - fi - sleep 5; - done - -Either script should insure no counts are lost. - -See the vendor datasheets for more information. There is application -note from National (AN-1260) with some additional information about -the LM85. The Analog Devices datasheet is very detailed and describes -a procedure for determining an optimal configuration for the automatic -PWM control. - -Hardware Configurations ------------------------ - -The LM85 can be jumpered for 3 different SMBus addresses. There are -no other hardware configuration options for the LM85. - -The lm85 driver detects both LM85B and LM85C revisions of the chip. -See the datasheet for a complete description of the differences. -Other than identifying the chip, the driver behaves no differently -with regard to these two chips. The LM85B is recommended for new -designs. - -The ADM1027 and ADT7463 chips have an optional SMBALERT output that -can be used to signal the chipset in case a limit is exceeded or the -temperature sensors fail. Individual sensor interrupts can be masked -with 'alarm_mask' so they won't trigger SMBALERT. The SMBALERT output -if configured replaces one of the other functions (PWM2 or IN0). The -driver will print a message if the BIOS has configured this option -when the chip is detected. - -The ADT7463 also has an optional THERM output/input which can be -connected to the processor PROC_HOT output. If available, the autofan -control dynamic Tmin feature can be enabled to keep the system -temperature within spec (just?!) with the least possible fan noise. - -Configuration Notes -------------------- - -The voltage, temperature and fan inputs are available in libsensors -and the sensors executable. In addition, the automatic control of the -PWM outputs can also be configured via sensors.conf. This -configuration is described below: - -* Temperatures and Zones - -Each temperature sensor is associated with a Zone. There are three -sensors and therefore three zones. Each zone has the following -temperature configuration points: - - Limit temp -- Temperature at which the fan will turn on - [ absolute deg C from 0.0 to 127.0 ] - [ sensors.conf: zone#_limit ] - Hysteresis -- Degrees below the limit that fan will remain - on before turning off. - [ relative C from 0.0 to -15.0 ] - [ sensors.conf: zone#_hyst ] - Range -- Degrees above the limit over which the fan - PWM will be adjusted (from PWM_MIN to 100%) - [ relative deg C from 2.0 to 80.0 ] - [ sensors.conf: zone#_range ] - Critical temp -- Temperature above which other fans will be - forced to 100% PWM - [ absolute deg C from 0.0 to 127.0 ] - [ sensors.conf: zone#_critical ] - -** Temperature Range for a Zone - -The RANGE value for a given zone can have one of 16 different values -in an approximately logrithmic spacing: -Selecting a RANGE not in this list will cause the next larger range to -be used. - - Temperature ranges: 2.0, 2.5, 3.3, 4.0, 5.0, 6.6, 8.0, 10.0, - (in deg C) 13.3, 16.0, 20.0, 26.6, 32.0, 40.0, 53.3, - 80.0 - -* Temperature Smoothing or Acoustic Enhancement - -The LM85 and ADM1027 use this value in different ways. In the LM85 -it's used to filter the temperature input of a zone. In this way, it -affects all PWM's controlled by that zone temperature. In the -ADM1027, it limits the rate of change in fan speed. Thus it is part -of the PWM control algorithm. - - Smooth filter -- Optional filter constant to smooth the system - response to temperature spikes. It either - filters the measured temperatures or limits the - rate of change of fan speed. This improves - the system by limiting rapid changes in fan - speed. - [ seconds from 0.8 to 35.0 or 0.0 for OFF ] - [ sensors.conf: zone#_smooth or pwm#_smooth ] - -The smoothing can be disabled, or enabled and set to one of the values -listed below. Selecting a filter time constant not on this list will -cause the next smaller value to be used. Setting the time constant to -0 will disable the filtering. - - Filter time constant: 35.0, 17.6, 11.8, 7.0, 4.4, 3.0, 1.6, 0.8 - (in seconds) - -* PWM Control - -There are three PWM outputs. The LM85 datasheet suggests that the -pwm3 output control both fan3 and fan4. Each PWM can be individually -configured and assigned to a zone for it's control value. Each PWM can be -configured individually according to the following options. - - Spinup time -- When turning on a fan that was off, the PWM will - temporarily be set to 100% for this length of - time to insure the fan starts spinning. - [ seconds from 0.0 to 4.0 ] - [ sensors.conf: pwm#_spinup ] - Minimum PWM -- This is the PWM value at the limit temp of the - referenced zone. - [ PWM value from 0.0 to 255.0 ] - [ sensors.conf: pwm#_min ] - Frequency -- This is the base frequency of the PWM output. - [ Hz from 10.0 to 98.0 ] - [ sensors.conf: pwm#_freq ] - Min/Off flag -- This flag determines if the PWM will be off or - "min PWM" below the limit temperature. - [ 0.0 means PWM off (0%) below limit ] - [ sensors.conf: pwm#_min_ctl ] - Invert flag -- This flag causes the PWM output to be inverted. - If inverted, a PWM setting of 0 will be full on - and 100 will be off. - [ 0.0 means PWM is "normal" ] - [ sensors.conf: pwm#_invert ] - -** Spinup Time - -Spinup time can be one of eight (8) values. Selecting a spinup time -not on this list will result in the next larger spinup time being -selected. Note, the value 0.2 actually results in a setting of 0.250 -seconds. - - Spinup Time 0.0, 0.1, 0.2, 0.4, 0.7, 1.0, 2.0, 4.0 - (in seconds) - -** PWM Frequency - -The base frequency of the PWM can be controlled. The frequency can be -set to one of the following 8 values. Setting the frequency to a -value not on this list, will result in the next higher frequency being -selected. The actual device frequency may vary slightly from this -specification as designed by the manufacturer. Consult the datasheet -for more details. - - PWM Frequency 10.0, 15.0, 23.0, 30.0, 38.0, 47.0, 62.0, 98.0 - (in Hz) - -** Min/Off Flag - -Below the temperature "Limit - Hysteresis" from the controlling zone, -the PWM can turn off (set to 0) or it can stay at the minimum PWM -value. Setting this flag to 1 will cause the PWM value to be the -"Minimum PWM" value below this limit. Setting it to 0 will set the -PWM to 0 (off) below that limit. - -NOTE: It has been reported that there is a bug in the LM85 that causes -the Min/Off flag to be associated with the zones not the PWMs. This -contradicts all the published documentation. Setting pwm#_min_ctl in -this case actually affects all PWMs controlled by zone '#'. - -** Invert Flag - -The PWM output can be inverted. This may be useful if the fan power -circuitry is inverted. (A low output turns on power and a high output -turns off power to the fan). Alternatively, if a slower fan speed is -needed for higher temperatures, this could be set. - -Setting this flag to 1 will invert the PWM output. A value of 0 -does not invert the PWM output. - -* PWM Controlling Zone selection - -PWM's can be controlled by zones according to the following -configuration choices: - - Value Meaning - ------ ------------------------------------------------ - 1 Controlled by Zone 1 - 2 Controlled by Zone 2 - 3 Controlled by Zone 3 - 23 Controlled by higher temp of Zone 2 or 3 - 123 Controlled by highest temp of Zone 1, 2 or 3 - 0 PWM alwasy 0% (off) - -1 PWM always 100% (full on) - -2 Manual control (write to 'pwm#' to set) - -These are specified in sensors.conf using 'pwm#_zone' - -* /proc Interface - -These values can also be set using the /proc interface. The following -files contain the above settings in the order listed below: - - Name Values - ---------- ---------------------------------------------------- - zone# Limit, Hysteresis, Range, Critical - pwm#_cfg Spinup, PWM at low limit, Frequency, Min/Off, Invert - pwm#_zone Control Zone choice - smooth# Filtering - -The National LM85's have two vendor specific configuration -features. Tach. mode and Spinup Control. For more details on these, -see the LM85 datasheet or Application Note AN-1260. - - Name Values - ------------ -------------------------------------------------- - tach_mode For best fan speed measurement when PWM's are in use, - the Tach Mode should be set to 2 for all three (Fan's - 3 and 4 share a config setting) config values. If - PWM's are not in use or not wired to control fan - speed, mode 0 or 1 may be better. - [ sensors.conf: fan#_tach_mode ] - spinup_ctl Setting spinup_ctl to 1 will modify the fan spinup - algorithm. Instead of setting the PWM to 100% for - the configured period of time, it will be set to 100% - until the measured RPM is greater than the RPM limit - register or the time period elapses. - [ sensors.conf: pwm#_spinup_ctl ] - -The Analog Devices ADM1027 has several vendor specific enhancements. -The number of pulses-per-rev of the fans can be set, Tach monitoring -can be optimized for PWM operation, and an offset can be applied to -the temperatures to compensate for systemic errors in the -measurements. - - Name Values - ------------ -------------------------------------------------- - tach_mode For best fan speed measurement when PWM's are in use, - the Tach Mode should be set to 0. If PWM's are not - in use or not wired to control fan speed, a mode of 1 - can be selected. This will also increase the rate - of fan speed measurement from 1 per second to 4 per - second. - [ sensors.conf: fan#_tach_mode ] - fan_ppr You can set the pulses per rev to 1, 2, 3 or 4 so - that fan speeds don't have to be scaled. - [ sensors.conf: fan#_ppr ] - temp#_offset This is the value to be added or subtracted from the - measured temperature before reporting it. This also - affects the PWM control algorithms. - [ sensors.conf: temp#_offset ] - -In addition to the ADM1027 features, the ADT7463 also has Tmin control -and THERM asserted counts. Automatic Tmin control acts to adjust the -Tmin value to maintain the measured temperature sensor at a specified -temperature. There isn't much documentation on this feature in the -ADT7463 data sheet. The following values control this feature. -(These are not available via sensors.conf) - - Enable Flag -- When set to 1, the Tmin control is enabled. When - set to 0, Tmin will remain unchanged. - [ 1 means Tmin control is enabled ] - [ sensors.conf: none ] - Control Loop -- This value sets the cycle time of the control - loop which adjusts the Tmin value. The mapping - from raw value to loop period is non-linear. - [ Raw value from 0 to 7 (4sec) ] - [ sensors.conf: none ] - Set on THERM -- If enabled, this causes the operating point to be - set from the current temperature when THERM is - asserted. If THERM is connected to a PROC_HOT - signal, this can automatically set the operating - point to the highest value that is within spec. - allowing the lowest/quietest fan speed possible. - [ 1 means set op-point on THERM asserted ] - [ sensors.conf: none ] - Target Temp -- This is the target temperature. Tmin will be - adjusted to keep the measured temperature at this - value. - [ degC -127 to 127 degC ] - [ sensors.conf: none ] - -The THERM signal monitoring has three parameters: - - THERM Limit -- How long THERM can be asserted before an ALARM is - triggered. - [ 22.7 ms counts ] - [ sensors.conf: none ] - THERM Total -- How long THERM has been asserted since the driver - was loaded. - [ 22.7 ms counts ] - [ sensors.conf: none ] - Overflows -- How many times the THERM counter was read with a - max value indicating it overflowed. - [ count ] - [ sensors.conf: none ] - -These values are available via /proc under the following names in the -listed order. - - Name Values - ------------ -------------------------------------------------- - tmin_ctl# Enable, Control Period, Set on THREM, Target - therm_signal Limit, Total, Overflows - - -* Sample sensors.conf Config File - -Here is a sample LM85 chip config for sensors.conf - ---------- cut here --------- -chip "lm85c-*" "adm1027-*" "adt7463-*" "lm85-*" "lm85b-*" - -# Voltage inputs - label in0 "V1.5" # AGP on Intel S845WD1-E - label in1 "VCore" - label in2 "V3.3" - label in3 "V5" - label in4 "V12" - -# Temperature inputs - label temp1 "CPU" - label temp2 "Board" - label temp3 "Remote" - -# Fan inputs - label fan1 "CPU_Fan" - label fan2 "Fan2" - label fan3 "Fan3" - label fan4 "Fan4" - -# PWM Outputs - label pwm1 "CPU_PWM" - label pwm2 "Fan2_PWM" - label pwm3 "Fan3_PWM" - -# Voltage scaling is done on-chip. No 'compute' directive -# should be necessary. If in0 has external scaling set -# it here. - -# compute in0 @ * 2.5, @ / 2.5 - -# Adjust fans speeds for actual pulses per rev - compute fan1 @ * 2, @ / 2 # 1 pulse per rev -# set fan1_ppr 1 # ADM1027 or ADT7463 - compute fan2 @ / 2, @ * 2 # 4 pulse per rev -# set fan2_ppr 4 # ADM1027 or ADT7463 - -# Set VRM version - set vrm 9.1 # Pentium 4 - -# Set voltage limits - set in0_min 1.5 * 0.95 - set in0_max 1.5 * 1.05 - set in1_min vid * 0.95 - set in1_max vid * 1.05 - set in2_min 3.3 * 0.95 - set in2_max 3.3 * 1.05 - set in3_min 5.0 * 0.95 - set in3_max 5.0 * 1.05 - set in4_min 12 * 0.95 - set in4_max 12 * 1.05 - -# Set Fan limits - set fan1_min 3000 - set fan2_min 3000 - set fan3_min 3000 - set fan4_min 3000 - diff --git a/doc/chips/lm87 b/doc/chips/lm87 deleted file mode 100644 index b791244f..00000000 --- a/doc/chips/lm87 +++ /dev/null @@ -1,150 +0,0 @@ -Kernel driver `lm87.o' -====================== - -Status: Complete and somewhat tested - -Supported chips: - * National Semiconductor LM87 - Prefix: 'lm87' - Addresses scanned: I2C 0x2c - 0x2e - Datasheet: http://www.national.com/pf/LM/LM87.html - -Authors: Frodo Looijaard , - Philip Edelbrock , - Mark Studebaker , - and Stephen Rousset - - -Module Parameters ------------------ - -* force: short array (min = 1, max = 48) - List of adapter,address pairs to boldly assume to be present -* force_lm87: short array (min = 1, max = 48) - List of adapter,address pairs which are unquestionably assumed to contain - a `lm87' chip -* ignore: short array (min = 1, max = 48) - List of adapter,address pairs not to scan -* ignore_range: short array (min = 1, max = 48) - List of adapter,start-addr,end-addr triples not to scan -* probe: short array (min = 1, max = 48) - List of adapter,address pairs to scan additionally -* probe_range: short array (min = 1, max = 48) - List of adapter,start-addr,end-addr triples to scan additionally - - -Description ------------ - -This driver implements support for the National Semiconductor LM87. - -The LM87 implements up to three temperature sensors, up to two fan -rotation speed sensors, up to seven voltage sensors, alarms, and some -miscellaneous stuff. - -Temperatures are measured in degrees Celsius. Each input has a high -and low alarm settings. A high limit produces an alarm when the value -goes above it, and an alarm is also produced when the value goes below -the low limit. - -Fan rotation speeds are reported in RPM (rotations per minute). An alarm is -triggered if the rotation speed has dropped below a programmable limit. Fan -readings can be divided by a programmable divider (1, 2, 4 or 8) to give -the readings more range or accuracy. Not all RPM values can accurately be -represented, so some rounding is done. With a divider of 2, the lowest -representable value is around 2600 RPM. - -Voltage sensors (also known as IN sensors) report their values in -volts. An alarm is triggered if the voltage has crossed a programmable -minimum or maximum limit. Note that minimum in this case always means -'closest to zero'; this is important for negative voltage -measurements. - -If an alarm triggers, it will remain triggered until the hardware register -is read at least once. This means that the cause for the alarm may -already have disappeared! Note that in the current implementation, all -hardware registers are read whenever any data is read (unless it is less -than 1.0 second since the last update). This means that you can easily -miss once-only alarms. - -The lm87 driver only updates its values each 1.0 seconds; reading it more -often will do no harm, but will return 'old' values. - - -Hardware Configurations ------------------------ - -The LM87 has four pins which can serve one of two possible functions, -depending on the hardware configuration. These pins are: - -Vccp2/D2- (pin 17) -+2.5V(IN0)/D2+ (pin 18) -FAN1/AIN1 (pin 5) -FAN2/AIN2 (pin 6) - -The most common configuration is to use the values shown here on the -left (Vccp2, 2.5V, FAN1, and FAN2). However, for a third temperature -sensor, it is possible to do away with Vccp2 and 2.5V (IN0) for the -second external temp diode inputs. Strangely, it seems that you can -monitor the core voltage of the second processor or its temperature, -but never both at the same time. Also, either/both FAN1 and FAN2 -inputs can be substituted for aux analog inputs AIN1 and/or AIN2, -respectively. - -To adjust the driver for a hardware configuration other than the -default, simply uncomment the appropriate #defines in the -kernel/chips/lm87.c driver header, and then recompile/reinstall. -Here is a copy (as of this writing) of the header: - - ---snip-- -/* Chip configuration settings. These should be set to reflect the -HARDWARE configuration of your chip. By default (read: when all of -these are left commented out), this driver assumes that the -configuration is the same as National's defaults for the Channel Mode -register. - - Set to '1' the appropriate defines, as nessesary: - - - External temp sensors 2 (possible second CPU temp) - This will disable the 2.5V and Vccp2 readings. - Strangely, National decided that you can read the - temperature of a second CPU or its core voltage, - but not both! Comment out if FAULT is reported. */ - -/* #define LM87_EXT2 1 */ - -/* Aux analog input. When enabled, the Fan 1 reading - will be disabled */ - -/* #define LM87_AIN1 1 */ - -/* Aux analog input 2. When enabled, the Fan 2 reading - will be disabled */ - -/* #define LM87_AIN2 1 */ - -/* Internal Vcc is 5V instead of 3.3V */ - -/* #define LM87_5V_VCC 1 */ - -/* That's the end of the hardware config defines. I would have made - them insmod params, but it would be too much work. ;') */ ---snip-- - -Please note: Only adjust the #defines to reflect your HARDWARE -configuration. Otherwise some, if not all, the readings will be -wrong. Simply enabling different driver configurations does not -provide the desired readings. You must make hardware changes (which -is hard) if you really wish to get a different set of readings!! - -If you may suspect that your configuration may be different than the -default, try enabling the different #defines. If you get a 'FAULT' -when using D2, it is most likely that you don't have a second external -diode, so recomment-out the #define. If you get strange readings for -some/all of the other values when enabling a AIN, then recomment-out -that #define. - -Unfortunately, it's tough to 'detect' all hardware config's -automaticly. And, I needed to resort to using #defines instead of -insmod params to make life easier on myself. diff --git a/doc/chips/lm90 b/doc/chips/lm90 deleted file mode 100644 index a45410a0..00000000 --- a/doc/chips/lm90 +++ /dev/null @@ -1,223 +0,0 @@ -Kernel driver `lm90.o' -====================== - -Status: Complete and well tested - -Supported chips: - * National Semiconductor LM90 - Prefix: 'lm90' - Addresses scanned: I2C 0x4c - Datasheet: Publicly available at the National Semiconductor website - http://www.national.com/pf/LM/LM90.html - * National Semiconductor LM89 - Prefix: 'lm99' - Addresses scanned: I2C 0x4c and 0x4d - Datasheet: Publicly available at the National Semiconductor website - http://www.national.com/mpf/LM/LM89.html - * National Semiconductor LM99 - Prefix: 'lm99' - Addresses scanned: I2C 0x4c and 0x4d - Datasheet: Publicly available at the National Semiconductor website - http://www.national.com/pf/LM/LM99.html - * National Semiconductor LM86 - Prefix: 'lm86' - Addresses scanned: I2C 0x4c - Datasheet: Publicly available at the National Semiconductor website - http://www.national.com/mpf/LM/LM86.html - * Analog Devices ADM1032 - Prefix: 'adm1032' - Addresses scanned: I2C 0x4c and 0x4d - Datasheet: Publicly available at the ON Semiconductor website - http://www.onsemi.com/PowerSolutions/product.do?id=ADM1032 - * Analog Devices ADT7461 - Prefix: 'adt7461' - Addresses scanned: I2C 0x4c and 0x4d - Datasheet: Publicly available at the ON Semiconductor website - http://www.onsemi.com/PowerSolutions/product.do?id=ADT7461 - Note: Only if in ADM1032 compatibility mode - * Maxim MAX6657 - Prefix: 'max6657' - Addresses scanned: I2C 0x4c - Datasheet: Publicly available at the Maxim website - http://www.maxim-ic.com/quick_view2.cfm/qv_pk/2578 - * Maxim MAX6658 - Prefix: 'max6657' - Addresses scanned: I2C 0x4c - Datasheet: Publicly available at the Maxim website - http://www.maxim-ic.com/quick_view2.cfm/qv_pk/2578 - * Maxim MAX6659 - Prefix: 'max6657' - Addresses scanned: I2C 0x4c and 0x4d - Datasheet: Publicly available at the Maxim website - http://www.maxim-ic.com/quick_view2.cfm/qv_pk/2578 - - -Author: Jean Delvare - -License: GPL - - -Module Parameters ------------------ - -* force: short array (min = 1, max = 48) - List of adapter,address pairs to boldly assume to be present -* force_lm90: short array (min = 1, max = 48) - List of adapter,address pairs which are unquestionably assumed to contain - a `lm90' chip -* force_adm1032: short array (min = 1, max = 48) - List of adapter,address pairs which are unquestionably assumed to contain - a `adm1032' chip -* force_lm99: short array (min = 1, max = 48) - List of adapter,address pairs which are unquestionably assumed to contain - a `lm99' chip -* force_lm86: short array (min = 1, max = 48) - List of adapter,address pairs which are unquestionably assumed to contain - a `lm86' chip -* force_max6657: short array (min = 1, max = 48) - List of adapter,address pairs which are unquestionably assumed to contain - a `max6657' chip -* force_adt7461: short array (min = 1, max = 48) - List of adapter,address pairs which are unquestionably assumed to contain - a `adt7461' chip -* probe: short array (min = 1, max = 48) - List of adapter,address pairs to scan additionally -* probe_range: short array (min = 1, max = 48) - List of adapter,start-addr,end-addr triples to scan additionally -* ignore: short array (min = 1, max = 48) - List of adapter,address pairs not to scan -* ignore_range: short array (min = 1, max = 48) - List of adapter,start-addr,end-addr triples not to scan - - -Description ------------ - -The LM90 is a digital temperature sensor. It senses its own temperature as -well as the temperature of up to one external diode. It is compatible -with many other devices such as the LM86, the LM89, the LM99, the ADM1032, -the MAX6657, the MAX6658, and the MAX6659, all of which are supported by -this driver. Additionally, the ADT7461 is supported if found in ADM1032 -compatibility mode. - -The specificity of this family of chipsets over the ADM1021/LM84 -family is that it features critical limits with hysteresis, and an -increased resolution of the remote temperature measurement. - -The different chipsets of the family are not strictly identical, although -very similar. This driver doesn't handle any specific feature for now, -with the exception of SMBus PEC. For reference, here comes a non-exhaustive -list of specific features: - -LM90: - * Filter and alert configuration register at 0xBF. - * ALERT is triggered by temperatures over critical limits. - -LM86 and LM89: - * Same as LM90 - * Better external channel accuracy - -LM99: - * Same as LM89 - * External temperature shifted by 16 degrees down - -ADM1032: - * Consecutive alert register at 0x22. - * Conversion averaging. - * Up to 64 conversions/s. - * ALERT is triggered by open remote sensor. - * SMBus PEC support for Write Byte and Receive Byte transactions. - -ADT7461 - * Extended temperature range (breaks compatibility) - * Lower resolution for remote temperature - -MAX6657 and MAX6658: - * Remote sensor type selecion - -MAX6659 - * Selectable address - * Second critical temperature limit - -All temperature values are given in degrees Celsius. Resolution -is 1.0 degree for the local temperature, 0.125 degree for the remote -temperature. - -Each sensor has its own high and low limits, plus a critical limit. -Additionally, there is a relative hysteresis value common to both critical -values. To make life easier to user-space applications, two absolute values -are exported, one for each channel, but these values are of course linked. -Only the local hysteresis can be set from user-space, and the same delta -applies to the remote hysteresis. - -The lm90 driver will not update its values more frequently than every -other second; reading them more often will do no harm, but will return -'old' values. - - -PEC Support ------------ - -The ADM1032 is the only chip of the family which supports PEC. It does -not support PEC on all transactions though, so some care must be taken. - -When reading a register value, the PEC byte is computed and sent by the -ADM1032 chip. However, in the case of a combined transaction (SMBus Read -Byte), the ADM1032 computes the CRC value over only the second half of -the message rather than its entirety, because it thinks the first half -of the message belongs to a different transaction. As a result, the CRC -value differs from what the SMBus master expects, and all reads fail. - -For this reason, the lm90 driver will enable PEC for the ADM1032 only if -the bus supports the SMBus Send Byte and Receive Byte transaction types. -These transactions will be used to read register values, instead of -SMBus Read Byte, and PEC will work properly. - -Additionally, the ADM1032 doesn't support SMBus Send Byte with PEC. -Instead, it will try to write the PEC value to the register (because the -SMBus Send Byte transaction with PEC is similar to a Write Byte transaction -without PEC), which is not what we want. Thus, PEC is explicitly disabled -on SMBus Send Byte transactions in the lm90 driver. - -PEC on byte data transactions represents a significant increase in bandwidth -usage (+33% for writes, +25% for reads) in normal conditions. With the need -to use two SMBus transaction for reads, this overhead jumps to +50%. Worse, -two transactions will typically mean twice as much delay waiting for -transaction completion, effectively doubling the register cache refresh time. -I guess reliability comes at a price, but it's quite expensive this time. - -So, as not everyone might enjoy the slowdown, PEC can be disabled through -procfs. Just write 0 to the "pec" file and PEC will be disabled. Write 1 -to that file to enable PEC again. - - -Chip Features -------------- - -Chips 'lm90', adm1032', 'lm99', 'lm86', 'max6657' and 'adt7461' - -LABEL LABEL CLASS COMPUTE CLASS MODE MAGN -temp1 - - R- 0 -temp1_high temp1 temp1 RW 0 -temp1_low temp1 temp1 RW 0 -temp2 - - R- 1 -temp2_high temp2 temp2 RW 1 -temp2_low temp2 temp2 RW 1 -tcrit1 temp1 temp1 RW 0 -tcrit2 temp2 temp2 RW 0 -hyst1 temp1 temp1 RW 0 -hyst2 temp2 temp2 R- 0 -alarms - - R- 0 - -LABEL FEATURE SYMBOL SYSCTL FILE:N -temp1 SENSORS_LM90_LOCAL_TEMP temp1:3 -temp1_high SENSORS_LM90_LOCAL_HIGH temp1:1 -temp1_low SENSORS_LM90_LOCAL_LOW temp1:2 -temp2 SENSORS_LM90_REMOTE_TEMP temp2:3 -temp2_high SENSORS_LM90_REMOTE_HIGH temp2:1 -temp2_low SENSORS_LM90_REMOTE_LOW temp2:2 -tcrit1 SENSORS_LM90_LOCAL_TCRIT tcrit1:1 -tcrit2 SENSORS_LM90_REMOTE_TCRIT tcrit2:1 -hyst1 SENSORS_LM90_LOCAL_TCRIT_HYST hyst1:1 -hyst2 SENSORS_LM90_REMOTE_TCRIT_HYST hyst2:1 -alarms SENSORS_LM90_ALARMS alarms:1 diff --git a/doc/chips/lm92 b/doc/chips/lm92 deleted file mode 100644 index d59803c8..00000000 --- a/doc/chips/lm92 +++ /dev/null @@ -1,89 +0,0 @@ -Kernel driver `lm92.o' -====================== - -Status: Complete and somewhat tested - -Supported chips: - * National Semiconductor LM92 - Prefix: 'lm92' - Addresses scanned: I2C 0x48 - 0x4b - * National Semiconductor LM76 - Prefix: 'lm92' - Addresses scanned: none, force parameter needed - * Maxim MAX6633/MAX6634/MAX6635 - Prefix: 'lm92' - Addresses scanned: I2C 0x48 - 0x4f - MAX6633 with address in 0x40 - 0x47 needs force parameter - -Author: Abraham van der Merwe - -License: GPL - - -Module Parameters ------------------ - -* force: short array (min = 1, max = 48) - List of adapter,address pairs to boldly assume to be present -* force_lm92: short array (min = 1, max = 48) - List of adapter,address pairs which are unquestionably assumed to contain - a `lm92' chip -* probe: short array (min = 1, max = 48) - List of adapter,address pairs to scan additionally -* probe_range: short array (min = 1, max = 48) - List of adapter,start-addr,end-addr triples to scan additionally -* ignore: short array (min = 1, max = 48) - List of adapter,address pairs not to scan -* ignore_range: short array (min = 1, max = 48) - List of adapter,start-addr,end-addr triples not to scan - - -Description ------------ - -This driver implements support for the National Semiconductor LM92 -temperature sensor. - -Each LM92 temperature sensor supports a single temperature sensor. -Temperatures are exported to proc in degrees Celsius * 10000 (in other -words temperatures are accurate to 4 decimal places). There are alarms -for high, low, and critical thresholds. There's also an hysteresis to -control the thresholds for resetting alarms. - -At the moment the driver controls these sensors in comparator mode and the -interrupt pins (INT, T_CRIT_A) are ignored. - -Support was added later for the LM76 and Maxim MAX6633/MAX6634/MAX6635, -which are mostly compatible. They have not all been tested, so you -may need to use the force parameter. - - -Hardware Configurations ------------------------ - -The only thing that can be changed is enabling of the fault queue. Doing so -ensures that alarms will only be triggered if 4 consecutive readings all -cross the alarm thresholds. You can enable this behaviour by uncommenting -the #define in the driver source, and then recompile/reinstall. - - -Chip Features -------------- - -Chip 'lm92' - -LABEL LABEL CLASS COMPUTE CLASS MODE MAGN -temp - - R- 4 -temp_high temp temp RW 4 -temp_low temp temp RW 4 -temp_crit temp temp RW 4 -temp_hyst temp temp RW 4 -alarms - - R- 0 - -LABEL FEATURE SYMBOL SYSCTL FILE:N -temp SENSORS_LM92_TEMP temp:1 -temp_high SENSORS_LM92_TEMP_HIGH temp:2 -temp_low SENSORS_LM92_TEMP_LOW temp:3 -temp_crit SENSORS_LM92_TEMP_CRIT temp:4 -temp_hyst SENSORS_LM92_TEMP_HYST temp:5 -alarms SENSORS_LM92_ALARMS alarms:1 diff --git a/doc/chips/lm93 b/doc/chips/lm93 deleted file mode 100644 index ae3e5c68..00000000 --- a/doc/chips/lm93 +++ /dev/null @@ -1,386 +0,0 @@ -Kernel driver 'lm93.o' -====================== - -Status: In progress - -Supported chips: - * National Semiconductor LM93 - Prefix: 'lm93' - Addresses scanned: I2C 0x2c-0x2e - -Author: - Mark M. Hoffman - - -Module Parameters ------------------ - -(specific to LM93) -* init: integer - Set to zero to disable some initializations (default is 1) -* disable_block: integer - A "0" allows SMBus block data transactions if the host supports them. A "1" - disables SMBus block data transactions. The default is 0. -* vccp_limit_type: integer array (2) - Configures in7 and in8 limit type, where 0 means absolute and non-zero - means relative. "Relative" here refers to "Dynamic Vccp Monitoring using - VID" from the datasheet. It greatly simplifies the interface to allow - only one set of limits (absolute or relative) to be in operation at a - time (even though the hardware is capable of enabling both). There's - not a compelling use case for enabling both at once, anyway. The default - is "0,0". -* vid_agtl: integer - A "0" configures the VID pins for V(ih) = 2.1V min, V(il) = 0.8V max. - A "1" configures the VID pins for V(ih) = 0.8V min, V(il) = 0.4V max. - (The latter setting is referred to as AGTL+ Compatible in the datasheet.) - I.e. this parameter controls the VID pin input thresholds; if your VID - inputs are not working, trying changing this. The default value is "0". - -(common among sensor drivers) -* force: short array (min = 1, max = 48) - List of adapter,address pairs to assume to be present. Autodetection - of the target device will still be attempted. Use one of the more - specific force directives below if this doesn't detect the device. -* force_lm93: short array (min = 1, max = 48) - List of adapter,address pairs which are unquestionably assumed to contain - a 'lm93' chip -* ignore: short array (min = 1, max = 48) - List of adapter,address pairs not to scan -* ignore_range: short array (min = 1, max = 48) - List of adapter,start-addr,end-addr triples not to scan -* probe: short array (min = 1, max = 48) - List of adapter,address pairs to scan additionally -* probe_range: short array (min = 1, max = 48) - List of adapter,start-addr,end-addr triples to scan additionally - - -Hardware Description --------------------- - -(from the datasheet) - -The LM93, hardware monitor, has a two wire digital interface compatible with -SMBus 2.0. Using an 8-bit ADC, the LM93 measures the temperature of two remote -diode connected transistors as well as its own die and 16 power supply -voltages. To set fan speed, the LM93 has two PWM outputs that are each -controlled by up to four temperature zones. The fancontrol algorithm is lookup -table based. The LM93 includes a digital filter that can be invoked to smooth -temperature readings for better control of fan speed. The LM93 has four -tachometer inputs to measure fan speed. Limit and status registers for all -measured values are included. The LM93 builds upon the functionality of -previous motherboard management ASICs and uses some of the LM85's features -(i.e. smart tachometer mode). It also adds measurement and control support -for dynamic Vccp monitoring and PROCHOT. It is designed to monitor a dual -processor Xeon class motherboard with a minimum of external components. - - -User Interface --------------- - -#PROCHOT: - -The LM93 can monitor two #PROCHOT signals. The results are found in the -/proc files prochot1 and prochot2. There are three values per file: the first -value is the user limit. The second value is the current reading for the -most recent complete time interval. The third value is something like a -2 period exponential moving average (but not quite - check the datasheet). -Note that this third value is calculated by the chip itself. All values -range from 0-255 where 0 indicates no throttling, and 255 indicates > 99.6%. - -The monitoring intervals for the two #PROCHOT signals is also configurable. -These intervals can be found in the /proc file prochot_interval. There are -two values in this file: one each for #P1_PROCHOT and #P2_PROCHOT, res- -pectively. Selecting a value not in this list will cause the driver to -use the next largest interval. The available intervals are (in seconds): - -#PROCHOT intervals: 0.73, 1.46, 2.9, 5.8, 11.7, 23.3, 46.6, 93.2, 186, 372 - -It is possible to configure the LM93 to logically short the two #PROCHOT -signals. I.e. when #P1_PROCHOT is asserted, the LM93 will automatically -assert #P2_PROCHOT, and vice-versa. This mode is enabled by writing a -non-zero integer to the /proc file prochot_short. - -The LM93 can also override the #PROCHOT pins by driving a PWM signal onto -one or both of them. When overridden, the signal has a period of 3.56 ms, -a minimum pulse width of 5 clocks (at 22.5kHz => 6.25% duty cycle), and -a maximum pulse width of 80 clocks (at 22.5kHz => 99.88% duty cycle). - -The /proc file prochot_override has three values. The first two are boolean -integers which enable/disable the override funtion for #P1_PROCHOT and -#P2_PROCHOT, the third value is 0-15 where 0 indicates minimum duty cycle -and 15 indicates maximum. - -#VRD_HOT: - -The LM93 can monitor two #VRD_HOT signals. The results are found in the -/proc files vrdhot1 and vrdhot2. There is one value per file: a boolean for -which 1 indicates #VRD_HOT is asserted and 0 indicates it is negated. These -files are read-only. - -Smart Tach Mode: - -(from the datasheet) - - If a fan is driven using a low-side drive PWM, the tachometer - output of the fan is corrupted. The LM93 includes smart tachometer - circuitry that allows an accurate tachometer reading to be - achieved despite the signal corruption. In smart tach mode all - four signals are measured within 4 seconds. - -Smart tach mode is enabled by the driver by writing 1 or 2 (associating the -the fan tachometer with a pwm) to the /proc file fan_smart_tach. A zero -will disable the function for that fan. Note that Smart tach mode cannot be -enabled if the PWM output frequency is 22500 Hz (see below). - -Manual PWM: - -The LM93 has a fixed or override mode for the two PWM outputs (although, there -are still some conditions that will override even this mode - see section -15.10.6 of the datasheet for details.) The /proc files pwm1 and pwm2 are -used to enable and control this mode. The first value of the file is an -integer (0-255) where 0 is 0% duty cycle, and 255 is 100%. The second value -is a boolean integer where 0 disables and 1 enables the manual control mode. -Note that the duty cycle values are constrained by the hardware. Selecting -a value which is not available will cause the driver to use the next largest -value. Also note: when manual PWM mode is disabled, the first value of the -/proc files indicates the current duty cycle chosen by the h/w. - -PWM Output Frequency: - -The LM93 supports several different frequencies for the PWM output channels. -The /proc files pwm1_freq and pwm2_freq are used to select the frequency. The -frequency values are constrained by the hardware. Selecting a value which is -not available will cause the driver to use the next largest value. Also note -that this parameter has implications for the Smart Tach Mode (see above). - -PWM Output Frequencies: 12, 36, 48, 60, 72, 84, 96, 22500 Hz (h/w default) - -Automatic PWM: - -The LM93 is capable of complex automatic fan control, with many different -points of configuration. To start, each PWM output can be bound to any -combination of eight control sources. The final PWM is the largest of all -individual control sources to which the PWM output is bound. - -The eight control sources are: temp1-temp4 (aka "zones" in the datasheet), -#PROCHOT 1 & 2, and #VRDHOT 1 & 2. The bindings are expressed as a bitmask -in the /proc files pwm_auto_channels, where a "1" enables the binding, and -a "0" disables it. The h/w default is 0x0f (all temperatures bound). - - 0x01 - Temp 1 - 0x02 - Temp 2 - 0x04 - Temp 3 - 0x08 - Temp 4 - 0x10 - #PROCHOT 1 - 0x20 - #PROCHOT 2 - 0x40 - #VRDHOT 1 - 0x80 - #VRDHOT 2 - -The function y = f(x) takes a source temperature x to a PWM output y. This -function of the LM93 is derived from a base temperature and a table of 12 -temperature offsets. The base temperature is expressed in degrees C in the -/proc files temp_auto_base. The offsets are expressed in cumulative -degrees C, with all 12 values in the files temp_auto_offsets. E.g. if the -base temperature is 40C: - - offset # temp_auto_offsets range pwm - 1 0 - 25.00% - 2 0 - 28.57% - 3 1 40C - 41C 32.14% - 4 1 41C - 42C 35.71% - 5 2 42C - 44C 39.29% - 6 2 44C - 46C 42.86% - 7 2 48C - 50C 46.43% - 8 2 50C - 52C 50.00% - 9 2 52C - 54C 53.57% - 10 2 54C - 56C 57.14% - 11 2 56C - 58C 71.43% - 12 2 58C - 60C 85.71% - > 60C 100.00% - -Valid offsets are in the range 0C <= x <= 7.5C in 0.5C increments. - -There is an independent base temperature for each temperature channel. Note, -however, there are only two tables of offsets: one each for temp[12] and -temp[34]. Therefore, any change to e.g. temp1_auto_offsets will also affect -temp2_auto_offsets. - -The LM93 can also apply hysteresis to the offset table, to prevent unwanted -oscillation between two steps in the offsets table. These values are found in -the /proc files temp_auto_offset_hyst. There is just one value; it has the -same representation as in temp_auto_offsets. - -If a temperature reading falls below the base value for that channel, the LM93 -will use the minimum PWM value. These values are found in the /proc files -temp_auto_pwm_min. Note, there are only two minimums: one each for temp[12] -and temp[34]. Therefore, any change to e.g. temp1_auto_pwm_min will also -affect temp2_auto_pwm_min. - -PWM Spin-Up Cycle: - -A spin-up cycle occurs when a PWM output is commanded from 0% duty cycle to -some value > 0%. The LM93 supports a minimum duty cycle during spin-up. These -values are found in the /proc files pwm_auto_spinup_min. There is one value -per file; it has the same representation as other PWM duty cycle values. The -duration of the spin-up cycle is also configurable. These values are found in -the /proc files pwm_auto_spinup_time. There is one value per file; it is -the spin-up time in seconds. The available spin-up times are constrained by -the hardware. Selecting a value which is not available will cause the driver -to use the next largest value. - -Spin-up Durations: 0 (disabled, h/w default), 0.1, 0.25, 0.4, 0.7, 1.0, 2.0, 4.0 - -#PROCHOT and #VRDHOT PWM Ramping: - -If the #PROCHOT or #VRDHOT signals are asserted while bound to a PWM output -channel, the LM93 will ramp the PWM output up to 100% duty cycle in discrete -steps. The duration of each step is configurable. There are two files, with -one value each in seconds: pwm_auto_prochot_ramp and pwm_auto_vrdhot_ramp. -The available ramp times are constrained by the hardware. Selecting a value -which is not available will cause the driver to use the next largest value. - -Ramp Times: 0 (disabled, h/w default) to 0.75 in 0.05 second intervals - -Fan Boost: - -For each temperature channel, there is a boost temperature: if the channel -exceeds this limit, the LM93 will immediately drive both PWM outputs to 100%. -This limit is expressed in degrees C in the /proc files temp_auto_boost. -There is also a hysteresis temperature for this function: after the boost -limit is reached, the temperature channel must drop below this value before -the boost function is disabled. This temperature is also expressed in degrees -C in the /proc files temp_auto_boost_hyst. - -GPIO Pins: - -The LM93 can monitor the logic level of four dedicated GPIO pins as well as the -four tach input pins. GPIO0-GPIO3 correspond to (fan) tach 1-4, respectively. -All eight GPIOs are read by reading the bitmask in the /proc file gpio. The -LSB is GPIO0, and the MSB is GPIO7. - - -LM93 Unique /proc Files ------------------------ - - file description - ------------------------------------------------------------- - - prochot limit, current, and moving average #PROCHOT % - - prochot_short enable or disable logical #PROCHOT pin short - - prochot_override force #PROCHOT assertion as PWM - - prochot_interval #PROCHOT PWM sampling interval - - vrdhot 0 means negated, 1 means asserted - - fan_smart_tach enable or disable smart tach mode - - pwm_auto_spinup_min minimum duty cycle during spin-up - - pwm_auto_spinup_time duration of spin-up - - pwm_auto_prochot_ramp ramp time per step when #PROCHOT asserted - - pwm_auto_vrdhot_ramp ramp time per step when #VRDHOT asserted - - temp_auto_base temperature channel base - - temp_auto_offsets temperature channel offsets - - temp_auto_offset_hyst - temperature channel offset hysteresis - - temp_auto_boost temperature channel boost (PWMs to 100%) limit - - temp_auto_boost_hyst temperature channel boost hysteresis - - gpio input state of 8 GPIO pins; read-only - - -Sample Configuration File -------------------------- - -Here is a sample LM93 chip config for sensors.conf: - ----------- cut here ---------- -chip "lm93-*" - -# VOLTAGE INPUTS - - # labels and scaling based on datasheet recommendations - label in1 "+12V1" - compute in1 @ * 12.945, @ / 12.945 - set in1_min 12 * 0.90 - set in1_max 12 * 1.10 - - label in2 "+12V2" - compute in2 @ * 12.945, @ / 12.945 - set in2_min 12 * 0.90 - set in2_max 12 * 1.10 - - label in3 "+12V3" - compute in3 @ * 12.945, @ / 12.945 - set in3_min 12 * 0.90 - set in3_max 12 * 1.10 - - label in4 "FSB_Vtt" - - label in5 "3GIO" - - label in6 "ICH_Core" - - label in7 "Vccp1" - - label in8 "Vccp2" - - label in9 "+3.3V" - set in9_min 3.3 * 0.90 - set in9_max 3.3 * 1.10 - - label in10 "+5V" - set in10_min 5.0 * 0.90 - set in10_max 5.0 * 1.10 - - label in11 "SCSI_Core" - - label in12 "Mem_Core" - - label in13 "Mem_Vtt" - - label in14 "Gbit_Core" - - # Assuming R1/R2 = 4.1143, and 3.3V reference - # -12V = (4.1143 + 1) * (@ - 3.3) + 3.3 - label in15 "-12V" - compute in15 @ * 5.1143 - 13.57719, (@ + 13.57719) / 5.1143 - set in15_min -12 * 0.90 - set in15_max -12 * 1.10 - - label in16 "+3.3VSB" - set in16_min 3.3 * 0.90 - set in16_max 3.3 * 1.10 - -# TEMPERATURE INPUTS - - label temp1 "CPU1" - label temp2 "CPU2" - label temp3 "LM93" - -# TACHOMETER INPUTS - - label fan1 "Fan1" - set fan1_min 3000 - label fan2 "Fan2" - set fan2_min 3000 - label fan3 "Fan3" - set fan3_min 3000 - label fan4 "Fan4" - set fan4_min 3000 - -# PWM OUTPUTS - - label pwm1 "CPU1" - label pwm2 "CPU2" - diff --git a/doc/chips/ltc1710 b/doc/chips/ltc1710 deleted file mode 100644 index 7d1b5897..00000000 --- a/doc/chips/ltc1710 +++ /dev/null @@ -1,67 +0,0 @@ -Kernel driver `ltc1710.o' -========================= - -Status: Complete and well-tested - -Supported chips: - * Linear Technologies LTC1710 - Prefix: 'ltc1710' - Addresses scanned: I2C 0x58 - 0x5a - Datasheet: Publicly available at the Linear Technologies website - -Author: Frodo Looijaard and Philip Edelbrock - - - -Module Parameters ------------------ - -* force: short array (min = 1, max = 48) - List of adapter,address pairs to boldly assume to be present -* force_ltc1710: short array (min = 1, max = 48) - List of adapter,address pairs which are unquestionably assumed to contain - a `ltc1710' chip -* ignore: short array (min = 1, max = 48) - List of adapter,address pairs not to scan -* ignore_range: short array (min = 1, max = 48) - List of adapter,start-addr,end-addr triples not to scan -* probe: short array (min = 1, max = 48) - List of adapter,address pairs to scan additionally -* probe_range: short array (min = 1, max = 48) - List of adapter,start-addr,end-addr triples to scan additionally - - -Description ------------ - -This is some documenation for the ltc1710 driver for the Linear -Technologies LTC1710. - -The LTC1710 is a simple dual switch device with a SMBus interface. It can -switch a supply voltage to either of its two output pins independantly -from the built-in SMBus interface. - -For each sensed LTC1710 there is a directory which looks something like: -ltc1710-i2c-1-59 - -For each directory there are the following files: - -* switch1 (LTC1710_SYSCTL_SWITCH_1) - Simply contains either a 1 or 0 depending on whether the switch is - currently turned on or off. -* switch2 (LTC1710_SYSCTL_SWITCH_2) - Works the same way as switch1, but is for the second switch. - -Some notes: The LTC1710 is a *very* simple I2C/SMBus device. It does not -support reads, so the status of the switches isn't polled, but rather -remembered. The LTC1710 has enough 'umph' to drive 300mA with only 0.4 Ohm -impedence (in an 'on' state). This works well for LEDs, or to drive other -devices (MOSFETs and such) which can multiply the switching effect. The -LTC1710 also contains an emergency over-temperature shut-off in the case -of too much current flow. Switch 2 switches the Vcc voltage on/off, but -Switch 1 switches the voltage present on pin 1 (0V to Vcc). - -This driver was written and maintained by Philip Edelbrock -. Please send comments/suggestions/corrections to him. -For more technical information on the LTC1710, please get the Acrobat PDF -from http://www.linear-tech.com/ diff --git a/doc/chips/matorb b/doc/chips/matorb deleted file mode 100644 index 8de73fcd..00000000 --- a/doc/chips/matorb +++ /dev/null @@ -1,97 +0,0 @@ -Kernel driver `matorb.o' -======================= - -Status: 'Beta', but it's so simple that it may be in its final state - -Supported devices: - * Matrix-Orbital (www.matrix-orbital.com) displays. Developed and - tested on the LCD2041V, but should work with all their displays. - Prefix: 'matorb' - Addresses scanned: I2C 0x2E - Datasheet: Publicly available at the Matrix-Orbital web site - (www.matrix-orbital.com) - -Author: Frodo Looijaard , and Philip Edelbrock - - -Main Contact: Philip Edelbrock - -Module Parameters ------------------ -(I'm not positive about these, so don't take this as granite) -* force: short array (min = 1, max = 48) - List of adapter,address pairs to boldly assume to be present -* force_matorb: short array (min = 1, max = 48) - List of adapter,address pairs which are unquestionably assumed to contain - a `bt869' chip -* ignore: short array (min = 1, max = 48) - List of adapter,address pairs not to scan -* ignore_range: short array (min = 1, max = 48) - List of adapter,start-addr,end-addr triples not to scan -* probe: short array (min = 1, max = 48) - List of adapter,address pairs to scan additionally -* probe_range: short array (min = 1, max = 48) - List of adapter,start-addr,end-addr triples to scan additionally - - -Description ------------ -This driver provides access to the Matrix-Orbital display devices. These -devices are usually in the form of a small LCD (20x4 is typical) screen -which is mounted in a carrier which is then mounted into a 5.25" drive bay -of a computer. - -This driver allows the user to send any data to the display to control or -display anything which the display supports. - -For more information on the displays or of particular features/command sets -go to: - -http://www.matrix-orbital.com - - -Use ---- -To use, just redirect the base-10 ordinal value of bytes (or chars) to the -display. For example, to clear the screen and write a simple message, you -could do this: - -# To clear the screen, send byte 0xFE and the char 'X' (ordinal 88) -echo "254 88" > /proc/sys/dev/sensors/matorb*/disp - -# To display "hi there" -echo "hi there" \ - | perl -e '$_=; while (/(.)/gc) { print ord($1)," "; }' \ - > /proc/sys/dev/sensors/matorb*/disp - -I've written a simple sample program (in Perl) to display a full screen -of text (which is fed in on standard-input) to the display. It is in the -prog/matorb folder of this project. - -I think the displays are very attractive and add a neat sort of 'status' -display to things like servers. It would be very simple to either -make a script daemon (or modify the healthd provided in this project) -to display a current status of health info (voltages, fans, temps, etc.) -on the display. Let's see Windoze do *THAT*! :') - - -Issues ------- -Redirecting too long of a string (32 ordinals seem to be the max) to 'disp' -seems to cause problems. Keep things in small chunks (like lines). - -Built in functions (screen clearing, etc.) were initially planned to be -added as other device files (other than just 'disp'), but these functions -are just as easily done by sending the command sequences to disp (as shown -above when clearing the screen). This also ensures that the driver will -be compatible with all the displays. - -Detection is very poor (as of this writing, anyway). It looks for a device -at 0x2E and asumes it is a display. Unfortunately, the 'beta' firmware -the Matrix-Orbital people gave me doesn't have good detection abilities to -it (it ignores reads... it used to lock up the bus on reads, so at least -it doesn't do that any more! :'). If they provide an easy way to 'sense' -that it is a display (and what kind it is?) then I will add support for it. - -Let me know if you have problems which you can't figure out -(phil@netroedge.com). diff --git a/doc/chips/max1619 b/doc/chips/max1619 deleted file mode 100644 index 83bf5756..00000000 --- a/doc/chips/max1619 +++ /dev/null @@ -1,73 +0,0 @@ -Kernel driver `max1619.o' -========================= - -Status: New - -Supported chips: - * Maxim MAX1619 - Prefix: 'max1619' - Addresses scanned: I2C 0x18-0x1a, 0x29-0x2b, 0x4c-0x4e - Datasheet: Publicly available at the Maxim website - http://pdfserv.maxim-ic.com/en/ds/MAX1619.pdf - -Author: Alexey Fisher - -License: GPL - - -Module Parameters ------------------ - -* force: short array (min = 1, max = 48) - List of adapter,address pairs to boldly assume to be present -* force_max1619: short array (min = 1, max = 48) - List of adapter,address pairs which are unquestionably assumed to contain - a `max1619' chip -* probe: short array (min = 1, max = 48) - List of adapter,address pairs to scan additionally -* probe_range: short array (min = 1, max = 48) - List of adapter,start-addr,end-addr triples to scan additionally -* ignore: short array (min = 1, max = 48) - List of adapter,address pairs not to scan -* ignore_range: short array (min = 1, max = 48) - List of adapter,start-addr,end-addr triples not to scan - - -Description ------------ - -The MAX1619 is a digital temperature sensor. It senses its own temperature as -well as the temperature of up to one external diode. - -All temperature values are given in degrees Celsius. Resolution -is 1.0 degree for the local temperature and for the remote temperature. - -Only the external sensor has high and low limits. - -The max1619 driver will not update its values more frequently than every -other second; reading them more often will do no harm, but will return -'old' values. - - -Chip Features -------------- - -Chips 'max1619' - -LABEL LABEL CLASS COMPUTE CLASS MODE MAGN -temp1 - - R- 0 -temp2 - - R- 0 -temp2_max temp2 temp2 RW 0 -temp2_min temp2 temp2 RW 0 -temp2_crit temp2 temp2 RW 0 -temp2_hyst temp2 temp2 RW 0 -alarms - - R- 0 - -LABEL FEATURE SYMBOL SYSCTL FILE:N -temp1 SENSORS_MAX1619_LOCAL_TEMP temp1:1 -temp2 SENSORS_MAX1619_REMOTE_TEMP temp2:3 -temp2_max SENSORS_MAX1619_REMOTE_HIGH temp2:1 -temp2_min SENSORS_MAX1619_REMOTE_LOW temp2:2 -temp2_crit SENSORS_MAX1619_REMOTE_HYST temp2_crit:1 -temp2_hyst SENSORS_MAX1619_REMOTE_MAX temp2_crit:2 -alarms SENSORS_MAX1619_ALARMS alarms:1 diff --git a/doc/chips/max6650 b/doc/chips/max6650 deleted file mode 100644 index bbd63d6c..00000000 --- a/doc/chips/max6650 +++ /dev/null @@ -1,125 +0,0 @@ -Sensors chip driver for MAXIM MAX6650 / MAX6651 fan controllers -=============================================================== - -Chip notes ----------- - -The MAX6651 is a fan controller. It has two distinct functions: - -1) Speed control, with feedback, for a single fan. The code can write - to a register requesting that the fan run at a certain speed, and the - chip will adjust the fan voltage until it reaches that speed. This - is called "closed loop" mode in the datasheet. - -2) Speed measurement (tachometers) for up to four fans, including the - controlled one. - -The MAX6650 is similar but only has one measurement tachometer. - -Both chips have a few general purpose i/o pins, some of which can be -configured to have special functions. At the time of writing an overview -of the chip, with links to the datasheet, can be seen at: - - http://www.maxim-ic.com/quick_view2.cfm/qv_pk/2296/ln/en - -If that has moved searching for MAX6650 from Maxim's home page should -work. - -Driver state ------------- - -Currently the driver provides the following entries in /proc/sys/ -dev/sensors/max6650-xxx/: - -fan1 through fan4 (read only): the current measured fan speeds, in -rpm. - -speed (read/write): when written, sets the chip to closed loop mode and -sets the configured speed, in rpm, to the value written. When read returns -the configured speed, again in rpm. - -xdump (read only): returns all of the chip register values, except the -tachometers. Used for debug, and should probably go away or be conditionally -compiled. - -The MAX665x uses byte wide registers with various scaling factors and -some more or less complex equations (in the datasheet) relating register -values to real world values. The driver takes care of all of this. - -Note that the measured speed ("fan1") never exactly matches the set speed -("speed") because of the coarse resolution of the underlying registers. - -Assumptions ------------ - -The driver assumes that: - - o The MAX665x is running from its internal 254 kHz clock, not an - external clock. - - o The monitored fans produce two pulses per rotation (This same - assumption is made by Maxim throughout the datasheet.) - - o The tachometer count time (register 0x16) has been configured suitably - for the fans in use, perhaps by some boot code. The driver reads this - register to compute rpm, but never writes to it. - - o The speed controller prescale (low three bits of register 0x04) has - been configured suitably for the fans in use, perhaps by some boot - code. The driver reads these bits to compute rpm, but never changes - them. - -The driver currently never reads or writes any other configuration -(gpio config, alarms, 5V/12V setting). - -Bugs ----- - - o The driver assumes too much: it should be possible to set more of the - configuration dynamically instead of assuming that some other code has - done it. - - o It does not differentiate between a MAX6650 and a MAX6651, as I can - see no obvious way to do this. It has only been tested with a MAX6651 - so if anyone gets a board with a MAX6650 to test with maybe something - will be revealed, such as the three missing tachometer registers - returning all ones or something. (OK, so maybe I should have called - this driver max6651, and ignored the max6650 totally...) - - o The /proc names don't match the standards in doc/developers/proc, - as this chip doesn't map well to other fan controllers, - -Detection notes ---------------- - -The module will autodetect the presence of a max6650 or max6651 at any -of the four possible I2C addresses for these devices. There is no ID -register, but there are several registers with all zero bits at the -high end. The driver checks that all of these are in fact zero before -declaring the chip to be a MAX6650/1. - -sensors-detect --------------- - -Support for MAX6650/1 has been added to sensors-detect. It has been -tested as correctly detecting a MAX6651 at I2C address 0x1B. Like the -driver, it cannot yet distinguish a MAX6650 and MAX6651. - -prog/sensors ------------- - -Initial read-only support has been added to the "sensors" program. - -Testing -------- - -The driver and associated programs have been tested under Linux 2.4.18 -running on an embedded Intel XScale processor (actually an IXP425 running -in big-endian mode) with a MAX6651 chip. - -Author ------- - -John Morris (john.morris@spirentcom.com) - - diff --git a/doc/chips/maxilife b/doc/chips/maxilife deleted file mode 100644 index 800ee8c0..00000000 --- a/doc/chips/maxilife +++ /dev/null @@ -1,433 +0,0 @@ -Kernel driver `maxilife.o' -========================== - -Status: Mostly done and tested - -Supported chips: - * Hewlett Packard Maxilife Revision AS 00.01 for Single Pentium II Slot 1 - Prefix: 'maxilife-as' - Addresses scanned: I2C 0x10 - 0x14 - Datasheet: Only available under NDA - * Hewlett Packard Maxilife Revision CO 00.03 for Dual Xeon Slot 2 - Prefix: 'maxilife-co' - Addresses scanned: I2C 0x10 - 0x14 - Datasheet: Only available under NDA - * Hewlett Packard Maxilife Revision CG 00.04 for Dual Pentium II Slot 1 - Prefix: 'maxilife-cg' - Addresses scanned: I2C 0x10 - 0x14 - Datasheet: Only available under NDA - * Hewlett Packard NBA (New BIOS Architecture) for newer machines, - for example Kayak XU800 and XM600. - Prefix: 'maxilife-nba' - Addresses scanned: I2C 0x10 - 0x14 - Datasheet: Only available under NDA - -Author: Fons Rademakers - -License: GPL - - -Module Parameters ------------------ - -* force: short array (min = 1, max = 48) - List of adapter,address pairs to boldly assume to be present -* force_maxilife: short array (min = 1, max = 48) - List of adapter,address pairs which are unquestionably assumed to contain - a `maxilife' chip -* probe: short array (min = 1, max = 48) - List of adapter,address pairs to scan additionally -* probe_range: short array (min = 1, max = 48) - List of adapter,start-addr,end-addr triples to scan additionally -* ignore: short array (min = 1, max = 48) - List of adapter,address pairs not to scan -* ignore_range: short array (min = 1, max = 48) - List of adapter,start-addr,end-addr triples not to scan -* maxi_version: int - MaxiLife firmware version - - -Description ------------ - -The is the driver for the HP MaxiLife Health monitoring system -as used in the line of HP Kayak Workstation PC's. - -The driver supports the following MaxiLife firmware versions: - -0) HP KAYAK XU/XAs (Dual Pentium II Slot 1, Deschutes/Klamath) -1) HP KAYAK XU (Dual Xeon [Slot 2] 400/450 Mhz) -2) HP KAYAK XA (Pentium II Slot 1, monoprocessor) - -Currently firmware auto detection is not implemented. To use the -driver load it with the correct option for you Kayak. For example: - -insmod maxilife.o maxi_version=0 | 1 | 2 - -maxi_version=0 is the default - - -The lm75's are indeed accessable in the regular way via the lm75 module. -They worked out of the box. However, I don't use the "raw" lm75 info. -MaxiLife takes care of reading out the lm75's and converts the values to -temperatures. Compared to some of the other monitoring controllers MaxiLife -is quite advanced. It takes care of a lot of issues, like setting ranges, -raising alarms, etc. Machines with MaxiLife also have a little LCD display -on their front (lcd is at address 0x54). The idea is that later versions -of the driver will write health info on the lcd (a bit like lcdproc). - - -Note ----- -sensors-detect does not support recognition of the maxilife chips. - - -Chip Features -------------- - -Chip 'maxilife-as' - -LABEL LABEL CLASS COMPUTE CLASS MODE MAGN -fan1 - - R- 0 -fan2 - - R- 0 -fan3 - - R- 0 -fan1_min fan1 fan1 RW 0 -fan2_min fan2 fan2 RW 0 -fan3_min fan3 fan3 RW 0 -fan1_div fan1 - R- 0 -fan2_div fan2 - R- 0 -fan3_div fan3 - R- 0 -temp1 - - R- 1 -temp2 - - R- 1 -temp3 - - R- 1 -temp4 - - R- 1 -temp5 - - R- 1 -temp1_max temp1 temp1 R- 1 -temp2_max temp2 temp2 R- 1 -temp3_max temp3 temp3 R- 1 -temp4_max temp4 temp4 R- 1 -temp5_max temp5 temp5 R- 1 -temp1_hyst temp1 temp1 R- 1 -temp2_hyst temp2 temp2 R- 1 -temp3_hyst temp3 temp3 R- 1 -temp4_hyst temp4 temp4 R- 1 -temp5_hyst temp5 temp5 R- 1 -pll - - R- 2 -pll_min pll pll RW 2 -pll_max pll pll RW 2 -vid1 - - R- 4 -vid2 - - R- 4 -vid3 - - R- 4 -vid4 - - R- 4 -vid1_min vid1 vid1 RW 4 -vid2_min vid2 vid2 RW 4 -vid3_min vid3 vid3 RW 4 -vid4_min vid4 vid4 RW 4 -vid1_max vid1 vid1 RW 4 -vid2_max vid2 vid2 RW 4 -vid3_max vid3 vid3 RW 4 -vid4_max vid4 vid4 RW 4 -alarms - - R- 0 - -LABEL FEATURE SYMBOL SYSCTL FILE:N -fan1 SENSORS_MAXI_AS_FAN1 fan1:3 -fan2 SENSORS_MAXI_AS_FAN2 fan2:3 -fan3 SENSORS_MAXI_AS_FAN3 fan3:3 -fan1_min SENSORS_MAXI_AS_FAN1_MIN fan1:1 -fan2_min SENSORS_MAXI_AS_FAN2_MIN fan2:1 -fan3_min SENSORS_MAXI_AS_FAN3_MIN fan3:1 -fan1_div SENSORS_MAXI_AS_FAN1_DIV fan1:2 -fan2_div SENSORS_MAXI_AS_FAN2_DIV fan2:2 -fan3_div SENSORS_MAXI_AS_FAN3_DIV fan3:2 -temp1 SENSORS_MAXI_AS_TEMP1 temp1:3 -temp2 SENSORS_MAXI_AS_TEMP2 temp2:3 -temp3 SENSORS_MAXI_AS_TEMP3 temp3:3 -temp4 SENSORS_MAXI_AS_TEMP4 temp4:3 -temp5 SENSORS_MAXI_AS_TEMP5 temp5:3 -temp1_max SENSORS_MAXI_AS_TEMP1_MAX temp1:1 -temp2_max SENSORS_MAXI_AS_TEMP2_MAX temp2:1 -temp3_max SENSORS_MAXI_AS_TEMP3_MAX temp3:1 -temp4_max SENSORS_MAXI_AS_TEMP4_MAX temp4:1 -temp5_max SENSORS_MAXI_AS_TEMP5_MAX temp5:1 -temp1_hyst SENSORS_MAXI_AS_TEMP1_HYST temp1:2 -temp2_hyst SENSORS_MAXI_AS_TEMP2_HYST temp2:2 -temp3_hyst SENSORS_MAXI_AS_TEMP3_HYST temp3:2 -temp4_hyst SENSORS_MAXI_AS_TEMP4_HYST temp4:2 -temp5_hyst SENSORS_MAXI_AS_TEMP5_HYST temp5:2 -pll SENSORS_MAXI_AS_PLL pll:3 -pll_min SENSORS_MAXI_AS_PLL_MIN pll:1 -pll_max SENSORS_MAXI_AS_PLL_MAX pll:2 -vid1 SENSORS_MAXI_AS_VID1 vid1:3 -vid2 SENSORS_MAXI_AS_VID2 vid2:3 -vid3 SENSORS_MAXI_AS_VID3 vid3:3 -vid4 SENSORS_MAXI_AS_VID4 vid4:3 -vid1_min SENSORS_MAXI_AS_VID1_MIN vid1:1 -vid2_min SENSORS_MAXI_AS_VID2_MIN vid2:1 -vid3_min SENSORS_MAXI_AS_VID3_MIN vid3:1 -vid4_min SENSORS_MAXI_AS_VID4_MIN vid4:1 -vid1_max SENSORS_MAXI_AS_VID1_MAX vid1:2 -vid2_max SENSORS_MAXI_AS_VID2_MAX vid2:2 -vid3_max SENSORS_MAXI_AS_VID3_MAX vid3:2 -vid4_max SENSORS_MAXI_AS_VID4_MAX vid4:2 -alarms SENSORS_MAXI_AS_ALARMS alarms:1 - - -Chip 'maxilife-cg' - -LABEL LABEL CLASS COMPUTE CLASS MODE MAGN -fan1 - - R- 0 -fan2 - - R- 0 -fan3 - - R- 0 -fan1_min fan1 fan1 RW 0 -fan2_min fan2 fan2 RW 0 -fan3_min fan3 fan3 RW 0 -fan1_div fan1 - R- 0 -fan2_div fan2 - R- 0 -fan3_div fan3 - R- 0 -temp1 - - R- 1 -temp2 - - R- 1 -temp3 - - R- 1 -temp4 - - R- 1 -temp5 - - R- 1 -temp1_max temp1 temp1 R- 1 -temp2_max temp2 temp2 R- 1 -temp3_max temp3 temp3 R- 1 -temp4_max temp4 temp4 R- 1 -temp5_max temp5 temp5 R- 1 -temp1_hyst temp1 temp1 R- 1 -temp2_hyst temp2 temp2 R- 1 -temp3_hyst temp3 temp3 R- 1 -temp4_hyst temp4 temp4 R- 1 -temp5_hyst temp5 temp5 R- 1 -pll - - R- 2 -pll_min pll pll RW 2 -pll_max pll pll RW 2 -vid1 - - R- 4 -vid2 - - R- 4 -vid3 - - R- 4 -vid4 - - R- 4 -vid1_min vid1 vid1 RW 4 -vid2_min vid2 vid2 RW 4 -vid3_min vid3 vid3 RW 4 -vid4_min vid4 vid4 RW 4 -vid1_max vid1 vid1 RW 4 -vid2_max vid2 vid2 RW 4 -vid3_max vid3 vid3 RW 4 -vid4_max vid4 vid4 RW 4 -alarms - - R- 0 - -LABEL FEATURE SYMBOL SYSCTL FILE:N -fan1 SENSORS_MAXI_CG_FAN1 fan1:3 -fan2 SENSORS_MAXI_CG_FAN2 fan2:3 -fan3 SENSORS_MAXI_CG_FAN3 fan3:3 -fan1_min SENSORS_MAXI_CG_FAN1_MIN fan1:1 -fan2_min SENSORS_MAXI_CG_FAN2_MIN fan2:1 -fan3_min SENSORS_MAXI_CG_FAN3_MIN fan3:1 -fan1_div SENSORS_MAXI_CG_FAN1_DIV fan1:2 -fan2_div SENSORS_MAXI_CG_FAN2_DIV fan2:2 -fan3_div SENSORS_MAXI_CG_FAN3_DIV fan3:2 -temp1 SENSORS_MAXI_CG_TEMP1 temp1:3 -temp2 SENSORS_MAXI_CG_TEMP2 temp2:3 -temp3 SENSORS_MAXI_CG_TEMP3 temp3:3 -temp4 SENSORS_MAXI_CG_TEMP4 temp4:3 -temp5 SENSORS_MAXI_CG_TEMP5 temp5:3 -temp1_max SENSORS_MAXI_CG_TEMP1_MAX temp1:1 -temp2_max SENSORS_MAXI_CG_TEMP2_MAX temp2:1 -temp3_max SENSORS_MAXI_CG_TEMP3_MAX temp3:1 -temp4_max SENSORS_MAXI_CG_TEMP4_MAX temp4:1 -temp5_max SENSORS_MAXI_CG_TEMP5_MAX temp5:1 -temp1_hyst SENSORS_MAXI_CG_TEMP1_HYST temp1:2 -temp2_hyst SENSORS_MAXI_CG_TEMP2_HYST temp2:2 -temp3_hyst SENSORS_MAXI_CG_TEMP3_HYST temp3:2 -temp4_hyst SENSORS_MAXI_CG_TEMP4_HYST temp4:2 -temp5_hyst SENSORS_MAXI_CG_TEMP5_HYST temp5:2 -pll SENSORS_MAXI_CG_PLL pll:3 -pll_min SENSORS_MAXI_CG_PLL_MIN pll:1 -pll_max SENSORS_MAXI_CG_PLL_MAX pll:2 -vid1 SENSORS_MAXI_CG_VID1 vid1:3 -vid2 SENSORS_MAXI_CG_VID2 vid2:3 -vid3 SENSORS_MAXI_CG_VID3 vid3:3 -vid4 SENSORS_MAXI_CG_VID4 vid4:3 -vid1_min SENSORS_MAXI_CG_VID1_MIN vid1:1 -vid2_min SENSORS_MAXI_CG_VID2_MIN vid2:1 -vid3_min SENSORS_MAXI_CG_VID3_MIN vid3:1 -vid4_min SENSORS_MAXI_CG_VID4_MIN vid4:1 -vid1_max SENSORS_MAXI_CG_VID1_MAX vid1:2 -vid2_max SENSORS_MAXI_CG_VID2_MAX vid2:2 -vid3_max SENSORS_MAXI_CG_VID3_MAX vid3:2 -vid4_max SENSORS_MAXI_CG_VID4_MAX vid4:2 -alarms SENSORS_MAXI_CG_ALARMS alarms:1 - - -Chip 'maxilife-co' - -LABEL LABEL CLASS COMPUTE CLASS MODE MAGN -fan1 - - R- 0 -fan2 - - R- 0 -fan3 - - R- 0 -fan1_min fan1 fan1 RW 0 -fan2_min fan2 fan2 RW 0 -fan3_min fan3 fan3 RW 0 -fan1_div fan1 - R- 0 -fan2_div fan2 - R- 0 -fan3_div fan3 - R- 0 -temp1 - - R- 1 -temp2 - - R- 1 -temp3 - - R- 1 -temp4 - - R- 1 -temp5 - - R- 1 -temp1_max temp1 temp1 R- 1 -temp2_max temp2 temp2 R- 1 -temp3_max temp3 temp3 R- 1 -temp4_max temp4 temp4 R- 1 -temp5_max temp5 temp5 R- 1 -temp1_hyst temp1 temp1 R- 1 -temp2_hyst temp2 temp2 R- 1 -temp3_hyst temp3 temp3 R- 1 -temp4_hyst temp4 temp4 R- 1 -temp5_hyst temp5 temp5 R- 1 -pll - - R- 2 -pll_min pll pll RW 2 -pll_max pll pll RW 2 -vid1 - - R- 4 -vid2 - - R- 4 -vid3 - - R- 4 -vid4 - - R- 4 -vid1_min vid1 vid1 RW 4 -vid2_min vid2 vid2 RW 4 -vid3_min vid3 vid3 RW 4 -vid4_min vid4 vid4 RW 4 -vid1_max vid1 vid1 RW 4 -vid2_max vid2 vid2 RW 4 -vid3_max vid3 vid3 RW 4 -vid4_max vid4 vid4 RW 4 -alarms - - R- 0 - -LABEL FEATURE SYMBOL SYSCTL FILE:N -fan1 SENSORS_MAXI_CO_FAN1 fan1:3 -fan2 SENSORS_MAXI_CO_FAN2 fan2:3 -fan3 SENSORS_MAXI_CO_FAN3 fan3:3 -fan1_min SENSORS_MAXI_CO_FAN1_MIN fan1:1 -fan2_min SENSORS_MAXI_CO_FAN2_MIN fan2:1 -fan3_min SENSORS_MAXI_CO_FAN3_MIN fan3:1 -fan1_div SENSORS_MAXI_CO_FAN1_DIV fan1:2 -fan2_div SENSORS_MAXI_CO_FAN2_DIV fan2:2 -fan3_div SENSORS_MAXI_CO_FAN3_DIV fan3:2 -temp1 SENSORS_MAXI_CO_TEMP1 temp1:3 -temp2 SENSORS_MAXI_CO_TEMP2 temp2:3 -temp3 SENSORS_MAXI_CO_TEMP3 temp3:3 -temp4 SENSORS_MAXI_CO_TEMP4 temp4:3 -temp5 SENSORS_MAXI_CO_TEMP5 temp5:3 -temp1_max SENSORS_MAXI_CO_TEMP1_MAX temp1:1 -temp2_max SENSORS_MAXI_CO_TEMP2_MAX temp2:1 -temp3_max SENSORS_MAXI_CO_TEMP3_MAX temp3:1 -temp4_max SENSORS_MAXI_CO_TEMP4_MAX temp4:1 -temp5_max SENSORS_MAXI_CO_TEMP5_MAX temp5:1 -temp1_hyst SENSORS_MAXI_CO_TEMP1_HYST temp1:2 -temp2_hyst SENSORS_MAXI_CO_TEMP2_HYST temp2:2 -temp3_hyst SENSORS_MAXI_CO_TEMP3_HYST temp3:2 -temp4_hyst SENSORS_MAXI_CO_TEMP4_HYST temp4:2 -temp5_hyst SENSORS_MAXI_CO_TEMP5_HYST temp5:2 -pll SENSORS_MAXI_CO_PLL pll:3 -pll_min SENSORS_MAXI_CO_PLL_MIN pll:1 -pll_max SENSORS_MAXI_CO_PLL_MAX pll:2 -vid1 SENSORS_MAXI_CO_VID1 vid1:3 -vid2 SENSORS_MAXI_CO_VID2 vid2:3 -vid3 SENSORS_MAXI_CO_VID3 vid3:3 -vid4 SENSORS_MAXI_CO_VID4 vid4:3 -vid1_min SENSORS_MAXI_CO_VID1_MIN vid1:1 -vid2_min SENSORS_MAXI_CO_VID2_MIN vid2:1 -vid3_min SENSORS_MAXI_CO_VID3_MIN vid3:1 -vid4_min SENSORS_MAXI_CO_VID4_MIN vid4:1 -vid1_max SENSORS_MAXI_CO_VID1_MAX vid1:2 -vid2_max SENSORS_MAXI_CO_VID2_MAX vid2:2 -vid3_max SENSORS_MAXI_CG_VID3_MAX vid3:2 -vid4_max SENSORS_MAXI_CO_VID4_MAX vid4:2 -alarms SENSORS_MAXI_CO_ALARMS alarms:1 - - -Chip 'maxilife-nba' - -LABEL LABEL CLASS COMPUTE CLASS MODE MAGN -fan1 - - R- 0 -fan2 - - R- 0 -fan3 - - R- 0 -fan1_min fan1 fan1 RW 0 -fan2_min fan2 fan2 RW 0 -fan3_min fan3 fan3 RW 0 -fan1_div fan1 - R- 0 -fan2_div fan2 - R- 0 -fan3_div fan3 - R- 0 -temp1 - - R- 1 -temp2 - - R- 1 -temp3 - - R- 1 -temp4 - - R- 1 -temp5 - - R- 1 -temp1_max temp1 temp1 R- 1 -temp2_max temp2 temp2 R- 1 -temp3_max temp3 temp3 R- 1 -temp4_max temp4 temp4 R- 1 -temp5_max temp5 temp5 R- 1 -temp1_hyst temp1 temp1 R- 1 -temp2_hyst temp2 temp2 R- 1 -temp3_hyst temp3 temp3 R- 1 -temp4_hyst temp4 temp4 R- 1 -temp5_hyst temp5 temp5 R- 1 -pll - - R- 2 -pll_min pll pll RW 2 -pll_max pll pll RW 2 -vid1 - - R- 4 -vid2 - - R- 4 -vid3 - - R- 4 -vid4 - - R- 4 -vid1_min vid1 vid1 RW 4 -vid2_min vid2 vid2 RW 4 -vid3_min vid3 vid3 RW 4 -vid4_min vid4 vid4 RW 4 -vid1_max vid1 vid1 RW 4 -vid2_max vid2 vid2 RW 4 -vid3_max vid3 vid3 RW 4 -vid4_max vid4 vid4 RW 4 -alarms - - R- 0 - -LABEL FEATURE SYMBOL SYSCTL FILE:N -fan1 SENSORS_MAXI_AS_FAN1 fan1:3 -fan2 SENSORS_MAXI_AS_FAN2 fan2:3 -fan3 SENSORS_MAXI_AS_FAN3 fan3:3 -fan1_min SENSORS_MAXI_AS_FAN1_MIN fan1:1 -fan2_min SENSORS_MAXI_AS_FAN2_MIN fan2:1 -fan3_min SENSORS_MAXI_AS_FAN3_MIN fan3:1 -fan1_div SENSORS_MAXI_AS_FAN1_DIV fan1:2 -fan2_div SENSORS_MAXI_AS_FAN2_DIV fan2:2 -fan3_div SENSORS_MAXI_AS_FAN3_DIV fan3:2 -temp1 SENSORS_MAXI_AS_TEMP1 temp1:3 -temp2 SENSORS_MAXI_AS_TEMP2 temp2:3 -temp3 SENSORS_MAXI_AS_TEMP3 temp3:3 -temp4 SENSORS_MAXI_AS_TEMP4 temp4:3 -temp5 SENSORS_MAXI_AS_TEMP5 temp5:3 -temp1_max SENSORS_MAXI_AS_TEMP1_MAX temp1:1 -temp2_max SENSORS_MAXI_AS_TEMP2_MAX temp2:1 -temp3_max SENSORS_MAXI_AS_TEMP3_MAX temp3:1 -temp4_max SENSORS_MAXI_AS_TEMP4_MAX temp4:1 -temp5_max SENSORS_MAXI_AS_TEMP5_MAX temp5:1 -temp1_hyst SENSORS_MAXI_AS_TEMP1_HYST temp1:2 -temp2_hyst SENSORS_MAXI_AS_TEMP2_HYST temp2:2 -temp3_hyst SENSORS_MAXI_AS_TEMP3_HYST temp3:2 -temp4_hyst SENSORS_MAXI_AS_TEMP4_HYST temp4:2 -temp5_hyst SENSORS_MAXI_AS_TEMP5_HYST temp5:2 -pll SENSORS_MAXI_AS_PLL pll:3 -pll_min SENSORS_MAXI_AS_PLL_MIN pll:1 -pll_max SENSORS_MAXI_AS_PLL_MAX pll:2 -vid1 SENSORS_MAXI_AS_VID1 vid1:3 -vid2 SENSORS_MAXI_AS_VID2 vid2:3 -vid3 SENSORS_MAXI_AS_VID3 vid3:3 -vid4 SENSORS_MAXI_AS_VID4 vid4:3 -vid1_min SENSORS_MAXI_AS_VID1_MIN vid1:1 -vid2_min SENSORS_MAXI_AS_VID2_MIN vid2:1 -vid3_min SENSORS_MAXI_AS_VID3_MIN vid3:1 -vid4_min SENSORS_MAXI_AS_VID4_MIN vid4:1 -vid1_max SENSORS_MAXI_AS_VID1_MAX vid1:2 -vid2_max SENSORS_MAXI_AS_VID2_MAX vid2:2 -vid3_max SENSORS_MAXI_AS_VID3_MAX vid3:2 -vid4_max SENSORS_MAXI_AS_VID4_MAX vid4:2 -alarms SENSORS_MAXI_AS_ALARMS alarms:1 diff --git a/doc/chips/mic74 b/doc/chips/mic74 deleted file mode 100644 index e115d385..00000000 --- a/doc/chips/mic74 +++ /dev/null @@ -1,57 +0,0 @@ -Kernel driver `mic74.o' -========================= - -Status: Beta - -Supported chips: - * Micrel MIC74 - Prefix: 'mic74' - Addresses scanned: I2C 0x20 - 0x27 - Datasheet: Publicly available at the Micrel website - http://www.micrel.com/ - -Authors: zebo25 - mds (cleanups and this doc) - -Module Parameters ------------------ - - -Description ------------ -The MIC74 is an 8-bit I/O expander for the I2C bus. -Semiconductors. It is designed to provide a byte I2C interface to up to 8 -separate devices. - -This device consists of a quasi-bidirectionnal port. Each of the eight I/Os -can be independently used as an input or output. - -The driver does not initialize the ports, they will be at their -power-up defaults, or however the BIOS programmed them. - -For more information see the datasheet. - - -Accessing MIC74 via /proc interface -------------------------------------- - -! Be careful ! -The chip is plainly impossible to detect ! Stupid chip. -So every chip with adress in the interval [20..27] could be -detected as an MIC74 or a PCF8574. Don't load both drivers. -If you have other chips in this address -range, the workaround is to load this module after the one -for your others chips. - -On detection, directories are created for each detected chip: - - /proc/sys/dev/sensors/mic74-<0>-<1>/ - where <0> is the bus the chip was detected on (e. g. i2c-0) - and <1> the chip address [20..27]: - ./mic74-i2c-0-27/ - -Inside these directories, there are seven files each, -one for each of the seven registers in the device. - -At this point you really need the datasheet. -It should be self-explanatory which file is for which register. diff --git a/doc/chips/mtp008 b/doc/chips/mtp008 deleted file mode 100644 index bf20c2c0..00000000 --- a/doc/chips/mtp008 +++ /dev/null @@ -1,73 +0,0 @@ -Kernel driver `mtp008.o' -========================= - -Status: Complete; Beta. - This chip is quite configurable and many settings cannot - be done through the driver. Hopefully the BIOS settings will - be correct for most motherboards. - -Supported chips: - * Myson MTP008 - Prefix: 'mtp008' - Addresses scanned: I2C 0x2c - 0x2e - Datasheet: Publicly available at the Myson website - -Author: Kris Van Hees - - -Description ------------ - -The Myson MTP008 is similar in function to the Winbond W83781D and the -National Semi LM78. See documentation for those chips for an overview. - - -The MTP008 chip has several pins that are configurable. - -The three temperature sensors are configurable via the driver -using either the /proc entries or 'set sensorx y' statements in -/etc/sensors.conf. -One temperature input is always temp1, and the sensor type is configured -with the sensor1 entry in /proc. -One input is either in4 or temp2, and is configured with the sensor2 entry. -One input is either in5 or temp3, and is configured with the sensor3 entry. - -For example, on the Tyan S1824D motherboard, -AIN4 is configured as PII temp sensor 2 and -AIN5 is hooked up to the -12V sensing circuit. - -Other Tyan motherboards (the 2510 Thunder and the Tiger 200) appear to -have different configurations. - -For the 2510, which has two MTP008 chips, each with a different -configuration, follow the instructions in the mtp008 section of -etc/sensors.conf.eg to configure 'sensors' correctly. - -The PWM outputs are configurable via the driver. -PWM values are from 0 to 255. The first value in the /proc entry is -the pwm value; the second is the enable (0 or 1). - -The fan3 and pwm1 functions share a pin. -If pwm1 is enabled than fan3 will read as 0. - -The Fan input types (2 wire or 3 wire) are configurable but -not via the driver. - -The driver now preserves pin settings that the BIOS configures. -If your BIOS did it right then the driver should work great. - -The MTP008 has sensor type selection in /proc like the Winbond W83782D. -However, the appropriate values used to make the selection are different. - -To select a sensor type, echo the value to the /proc entry, for example: - echo 1 > /proc/sys/dev/sensors/mtp008-i2c-0-2d/sensor1 -Or, use /etc/sensors.conf and add a line 'set sensor1 1', for example. -Hopefully the BIOS has set these already. - -Sensor selection is as follows: - - Value Function Valid on sensors - ----- -------- ---------------- - 1 Analog input (not for temperature sensing) 2,3 - 2 Thermistor 1,2,3 - 3 Pentium diode 1,2 diff --git a/doc/chips/pc87360 b/doc/chips/pc87360 deleted file mode 100644 index 5cf0e4cf..00000000 --- a/doc/chips/pc87360 +++ /dev/null @@ -1,179 +0,0 @@ -Kernel driver `pc87360.o' -========================= - -Status: Beta, PC87366 well tested, other chips untested. - -Supported chips: - * National Semiconductor PC87360, PC87363, PC87364, PC87365 and PC87366 - Addresses scanned: none, address read from Super I/O config space - Prefixes: 'pc87360', 'pc87363', 'pc87364', 'pc87365', 'pc87366' - Datasheets: No longer available - -Authors: Jean Delvare - -Thanks to Sandeep Mehta, Tonko de Rooy and Daniel Ceregatti for testing. -Thanks to Rudolf Marek for helping me investigate conversion issues. - - -Module Parameters ------------------ - -init (int): - Chip initialization level: - 0: None - *1: Forcibly enable internal voltage and temperature channels, except in9 - 2: Forcibly enable all voltage and temperature channels, except in9 - 3: Forcibly enable all voltage and temperature channels, including in9 - -Note that this parameter has no effect for the PC87360, PC87363 and PC87364 -chips. - -Also note that for the PC87366, initialization levels 2 and 3 don't enable -all temperature channels, because some of them share pins with each other, -so they can't be used at the same time. - - -Description ------------ - -The National Semiconductor PC87360 Super I/O chip contains monitoring and -PWM control circuitry for two fans. The PC87363 chip is similar, and the -PC87364 chip has monitoring and PWM control for a third fan. - -The National Semiconductor PC87365 and PC87366 Super I/O chips are complete -hardware monitoring chipsets, not only controling and monitoring three fans, -but also monitoring eleven voltage inputs and two (PC87365) or up to four -(PC87366) temperatures. - -The driver assumes that no more than one chip is present, and one of the -standard Super I/O addresses is used (0x2E/0x2F or 0x4E/0x4F). - - -Fan Monitoring --------------- - -Fan rotation speeds are reported in RPM (revolutions per minute). An alarm -is triggered if the rotation speed has dropped below a programmable limit. -A different alarm is triggered if the fan speed is too low to be measured. - -Fan readings are affected by a programmable clock divider, giving the -readings more range or accuracy. Usually, users have to learn how it works, -but this driver implements dynamic clock divider selection, so you don't -have to care no more. - -For reference, here are a few values about clock dividers: - - slowest accuracy highest - measurable around 3000 accurate - divider speed (RPM) RPM (RPM) speed (RPM) - 1 1882 18 6928 - 2 941 37 4898 - 4 470 74 3464 - 8 235 150 2449 - -For the curious, here is how the values above were computed: - * slowest measurable speed: clock/(255*divider) - * accuracy around 3000 RPM: 3000^2/clock - * highest accurate speed: sqrt(clock*100) -The clock speed for the PC87360 family is 480 kHz. I arbitrarily chose 100 -RPM as the lowest acceptable accuracy. - -As mentioned above, you don't have to care about this no more. - -Note that not all RPM values can be represented, even when the best clock -divider is selected. This is not only true for the measured speeds, but -also for the programmable low limits, so don't be surprised if you try to -set, say, fan1_min to 2900 and it finaly reads 2909. - - -Fan Control ------------ - -PWM (pulse width modulation) values range from 0 to 255, with 0 meaning -that the fan is stopped, and 255 meaning that the fan goes at full speed. - -Be extremely careful when changing PWM values. Low PWM values, even -non-zero, can stop the fan, which may cause irreversible damage to your -hardware if temperature increases too much. When changing PWM values, go -step by step and keep an eye on temperatures. - -One user reported problems with PWM. Changing PWM values would break fan -speed readings. No explanation nor fix could be found. - - -Temperature Monitoring ----------------------- - -Temperatures are reported in degrees Celsius. Each temperature measured has -associated low, high and overtemperature limits, each of which triggers an -alarm when crossed. - -The first two temperature channels are external. The third one (PC87366 -only) is internal. - -The PC87366 has three additional temperature channels, based on -thermistors (as opposed to thermal diodes for the first three temperature -channels). For technical reasons, these channels are held by the VLM -(voltage level monitor) logical device, not the TMS (temperature -measurement) one. As a consequence, these temperatures are exported as -voltages, and converted into temperatures in user-space. - -Note that these three additional channels share their pins with the -external thermal diode channels, so you (physically) can't use them all at -the same time. Although it should be possible to mix the two sensor types, -the documents from National Semiconductor suggest that motherboard -manufacturers should choose one type and stick to it. So you will more -likely have either channels 1 to 3 (thermal diodes) or 3 to 6 (internal -thermal diode, and thermistors). - - -Voltage Monitoring ------------------- - -Voltages are reported relatively to a reference voltage, either internal or -external. Some of them (in7:Vsb, in8:Vdd and in10:AVdd) are divided by two -internally, you will have to compensate in sensors.conf. Others (in0 to in6) -are likely to be divided externally. The meaning of each of these inputs as -well as the values of the resistors used for division is left to the -motherboard manufacturers, so you will have to document yourself and edit -sensors.conf accordingly. National Semiconductor has a document with -recommended resistor values for some voltages, but this still leaves much -room for per motherboard specificities, unfortunately. Even worse, -motherboard manufacturers don't seem to care about National Semiconductor's -recommendations. - -Each voltage measured has associated low and high limits, each of which -triggers an alarm when crossed. - -When available, VID inputs are used to provide the nominal CPU Core voltage. -The driver will default to VRM 9.0, but this can be changed from user-space. -The chipsets can handle two sets of VID inputs (on dual-CPU systems), but -the driver will only export one for now. This may change later if there is -a need. - - -General Remarks ---------------- - -If an alarm triggers, it will remain triggered until the hardware register -is read at least once. This means that the cause for the alarm may already -have disappeared! Note that all hardware registers are read whenever any -data is read (unless it is less than 2 seconds since the last update, in -which case cached values are returned instead). As a consequence, when -a once-only alarm triggers, it may take 2 seconds for it to show, and 2 -more seconds for it to disappear. - -Monitoring of in9 isn't enabled at lower init levels (<3) because that -channel measures the battery voltage (Vbat). It is a known fact that -repeatedly sampling the battery voltage reduces its lifetime. National -Semiconductor smartly designed their chipset so that in9 is sampled only -once every 1024 sampling cycles (that is every 34 minutes at the default -sampling rate), so the effect is attenuated, but still present. - - -Limitations ------------ - -The datasheets suggests that some values (fan mins, fan dividers) -shouldn't be changed once the monitoring has started, but we ignore that -recommendation. We'll reconsider if it actually causes trouble. diff --git a/doc/chips/pca9540 b/doc/chips/pca9540 deleted file mode 100644 index d810dbc5..00000000 --- a/doc/chips/pca9540 +++ /dev/null @@ -1,76 +0,0 @@ -Kernel driver `pca9540.o' -========================= - -Status: Complete but untested - -Supported chips: - * Philips PCA9540 - Prefix: 'pca9540' - Addresses scanned: I2C 0x70 - Datasheet: Publicly available at the Philips Semiconductors website - http://www.semiconductors.philips.com/pip/PCA9540.html - -Authors: Jean Delvare - - -Module Parameters ------------------ - -* force: short array (min = 1, max = 48) - List of adapter,address pairs to boldly assume to be present -* force_pca9540: short array (min = 1, max = 48) - List of adapter,address pairs which are unquestionably assumed to - contain a `pca9540' chip -* ignore: short array (min = 1, max = 48) - List of adapter,address pairs not to scan -* ignore_range: short array (min = 1, max = 48) - List of adapter,start-addr,end-addr triples not to scan -* probe: short array (min = 1, max = 48) - List of adapter,address pairs to scan additionally -* probe_range: short array (min = 1, max = 48) - List of adapter,start-addr,end-addr triples to scan additionally - -Note that the force and force_pca9540 parameters are equivalent here. - - -Description (from the Philips web site) ---------------------------------------- - -The PCA9540 is a 1-of-2 bi-directional translating multiplexer, controlled -via the I2C bus. The SCL/SDA upstream pair fans out to two SCL/SDA downstream -pairs, or channels. Only one SCL/SDA channel is selected at a time, -determined by the contents of the programmable control register. - - -Accessing the PCA9540 ---------------------- - -The PCA9540 is almost impossible to detect. We are lucky that no other -known chip lives at address 0x70. - -Beware that the PCA9540 has a single internal register. It does work with -READ BYTE and WRITE BYTE commands, contrary to regular chips which use -READ BYTE DATA and WRITE BYTE DATA. Using i2cdump on the PCA9540 will -actually *write* to it and leave its internal register to value 0x07 (i.e. -no downstream channel selected). - - -/proc Interface ---------------- - -There is a single read/write file, named "channel". - - 0 = no downstream channel selected - 1 = first downstream channel selected - 2 = second downstream channel selected - - -Chip Features -------------- - -Chip `pca9540' - LABEL LABEL CLASS COMPUTE CLASS ACCESS MAGNITUDE - channel NONE NONE RW 0 - - LABEL FEATURE SYMBOL SYSCTL FILE:OFFSET - channel SENSORS_PCA9540_CHANNEL channel:1 diff --git a/doc/chips/pcf8574 b/doc/chips/pcf8574 deleted file mode 100644 index 744beebf..00000000 --- a/doc/chips/pcf8574 +++ /dev/null @@ -1,100 +0,0 @@ -Kernel driver `pcf8574.o' -========================= - -Status: Complete - -Supported chips: - * Philips PCF8574 - Prefix: 'pcf8574' - Addresses scanned: I2C 0x20 - 0x27 - Datasheet: Publicly available at the Philips Semiconductors website - http://www.semiconductors.philips.com/pip/PCF8574P.html - - * Philips PCF8574A - Prefix: 'pcf8574a' - Addresses scanned: I2C 0x38 - 0x3f - Datasheet: Publicly available at the Philips Semiconductors website - http://www.semiconductors.philips.com/pip/PCF8574P.html - -Authors: Frodo Looijaard , - Philip Edelbrock , - and Dan Eaton - -Module Parameters ------------------ - -* force: short array (min = 1, max = 48) - List of adapter,address pairs to boldly assume to be present -* force_pcf8574: short array (min = 1, max = 48) - List of adapter,address pairs which are unquestionably assumed to - contain a `pcf8574' chip -* force_pcf8574a: short array (min = 1, max = 48) - List of adapter,address pairs which are unquestionably assumed to - contain a `pcf8574a' chip -* ignore: short array (min = 1, max = 48) - List of adapter,address pairs not to scan -* ignore_range: short array (min = 1, max = 48) - List of adapter,start-addr,end-addr triples not to scan -* probe: short array (min = 1, max = 48) - List of adapter,address pairs to scan additionally -* probe_range: short array (min = 1, max = 48) - List of adapter,start-addr,end-addr triples to scan additionally - - -Description ------------ -The PCF8574(A) is an 8-bit I/O expander for the I2C bus produced by Philips -Semiconductors. It is designed to provide a byte I2C interface to up to 16 -separate devices (8 x PCF8574 and 8 x PCF8574A). - -This device consists of a quasi-bidirectionnal port. Each of the eight I/Os -can be independently used as an input or output. To setup an I/O as an -input, you have to write a 1 to the corresponding output. - -For more informations see the datasheet. - - -Accessing PCF8574(A) via /proc interface -------------------------------------- - -! Be careful ! -The PCF8574(A) is plainly impossible to detect ! Stupid chip. -So every chip with adress in the interval [20..27] and [38..3f] is -detected as PCF8574(A). If you have other chips in this address -range, the workaround is to load this module after the one -for your others chips. - -On detection (i.e. insmod, modprobe et al.), directories are being -created for each detected PCF8574(A): - -/proc/sys/dev/sensors/pcf8574-<0>-<1>/ -where <0> is the bus the chip was detected on (e. g. i2c-0) -and <1> the chip address ([20..27] or [38..3f]): -./pcf8574-i2c-0-27/ - -Inside these directories, there are two files each: -read and write. - -The read file is read-only. Reading gives you the current I/O input -if the corresponding output is set as 1, otherwise the current output -value, that is to say 0. - -The write file is read/write. Writing a value outputs it on the I/O -port. Reading return the last written value. - -On module initialization the chip is configured as eight inputs (all -outputs to 1), so you can connect any circuit to the PCF8574(A) without -being afraid of short-circuit. - - -Chip Features -------------- - -Chip `pcf8574' - LABEL LABEL CLASS COMPUTE CLASS ACCESS MAGNITUDE - read NONE NONE R 0 - write NONE NONE RW 0 - - LABEL FEATURE SYMBOL SYSCTL FILE:OFFSET - read SENSORS_PCF8591_READ read:1 - write SENSORS_PCF8591_WRITE write:1 diff --git a/doc/chips/pcf8591 b/doc/chips/pcf8591 deleted file mode 100644 index 71123adb..00000000 --- a/doc/chips/pcf8591 +++ /dev/null @@ -1,127 +0,0 @@ -Kernel driver `pcf8591.o' -======================== - -Status: Status: Complete; Beta. - -Supported chips: - * Philips PCF8591 - Prefix: 'pcf8591' - Addresses scanned: I2C 0x48 - 0x4f - Datasheet: Publicly available at the Philips Semiconductors website - http://www.semiconductors.philips.com/pip/PCF8591P.html - -Author: Aurelien Jarno -valuable contributions by Jan M. Sendler - -Module Parameters ------------------ - -* force: short array (min = 1, max = 48) - List of adapter,address pairs to boldly assume to be present -* force_pcf8591: short array (min = 1, max = 48) - List of adapter,address pairs which are unquestionably assumed to - contain a `pcf8591' chip -* ignore: short array (min = 1, max = 48) - List of adapter,address pairs not to scan -* ignore_range: short array (min = 1, max = 48) - List of adapter,start-addr,end-addr triples not to scan -* probe: short array (min = 1, max = 48) - List of adapter,address pairs to scan additionally -* probe_range: short array (min = 1, max = 48) - List of adapter,start-addr,end-addr triples to scan additionally - - -Description ------------ -The PCF8591 is an 8-bit A/D and D/A converter (4 analog inputs and one -analog ouput) for the I2C bus produced by Philips Semiconductors. It -is designed to provide a byte I2C interface to up to 4 separate devices. - -The PCF8591 has 4 analog inputs programmable as single-ended or -differential inputs : -- mode 0 : four single ended inputs - Pins AIN0 to AIN3 are single ended inputs for channels 0 to 3 - -- mode 1 : three differential inputs - Pins AIN3 is the common negative differential input - Pins AIN0 to AIN2 are positive differential inputs for channels 0 to 2 - -- mode 2 : single ended and differential mixed - Pins AIN0 and AIN1 are single ended inputs for channels 0 and 1 - Pins AIN2 is the positive differential input for channel 3 - Pins AIN3 is the negative differential input for channel 3 - -- mode 3 : two differential inputs - Pins AIN0 is the positive differential input for channel 0 - Pins AIN1 is the negative differential input for channel 0 - Pins AIN2 is the positive differential input for channel 1 - Pins AIN3 is the negative differential input for channel 1 - -For more informations see the datasheet. - - -Accessing PCF8591 via /proc interface -------------------------------------- - -! Be careful ! -The PCF8591 is plainly impossible to detect ! Stupid chip. -So every chip with adress in the interval [48..4f] is -detected as PCF8591. If you have other chips in this address -range, the workaround is to load this module after the one -for your others chips. - -On detection (i.e. insmod, modprobe et al.), directories are being -created for each detected PCF8591: - -/proc/sys/dev/sensors/pcf8591-<0>-<1>/ -where <0> is the bus the chip was detected on (e. g. i2c-0) -and <1> the chip address ([48..4f]): ./pcf8591-i2c-0-48/ - -Inside these directories, there are five files each: -ain_conf, ch0, ch1, ch2, ch3, aout_enable, aout. - -The ain_conf file is rw. Reading gives you the current analog inputs -configuration, and writing configure the analog inputs. It must be -a number between 0 and 3., other values are ignored. For the different -modes, see above in the description. - -The ch0, ch1, ch2 and ch3 files are ro. Reading gives the value -of the corresponding channel. Depending on the current analog inputs -configuration, channel ch2 and/or ch3 may are not used by the chip -and so read as 0. Values range are from 0 to 255 for single -ended inputs and -128 to +127 for differential inputs (8-bit ADC). - -The aout_enable is rw. Reading gives "1" for analog output enabled and -"0" for analog output disabled. Writing accepts "0" and "1" accordingly. - -The aout is rw. Writing a number between 0 and 255 (8-bit DAC), send -the value to the digital-to-analog converter. Note that a voltage will -only appears on AOUT pin if aout_enable equals 1. Reading returns the last -value written. - -On module initialization the chip is configured as followed : -- four single ended differential inputs -- analog output set to 0 and enabled - - -Chip Features -------------- - -Chip `pcf8591' - LABEL LABEL CLASS COMPUTE CLASS ACCESS MAGNITUDE - ain_conf NONE NONE RW 0 - ch0 NONE NONE R 0 - ch1 NONE NONE R 0 - ch2 NONE NONE R 0 - ch3 NONE NONE R 0 - aout_enable NONE NONE RW 0 - aout NONE NONE RW 0 - - LABEL FEATURE SYMBOL SYSCTL FILE:OFFSET - ain_conf SENSORS_PCF8591_AIN_CONF ain_conf:1 - ch0 SENSORS_PCF8591_CH0 ain_ch0:1 - ch1 SENSORS_PCF8591_CH1 ain_ch1:1 - ch2 SENSORS_PCF8591_CH2 ain_ch2:1 - ch3 SENSORS_PCF8591_CH3 ain_ch3:1 - aout_enable SENSORS_PCF8591_AOUT_ENABLE aout_enable:1 - aout SENSORS_PCF8591_AOUT aout:1 diff --git a/doc/chips/saa1064 b/doc/chips/saa1064 deleted file mode 100644 index bc246eab..00000000 --- a/doc/chips/saa1064 +++ /dev/null @@ -1,81 +0,0 @@ -Kernel driver `saa1064.o' -======================== - -Status: Testing; - -Supported chips: - * Philips SAA1064 - Prefix: 'saa1064' - Addresses scanned: I2C 0x38 - 0x3b - Datasheet: Publicly available at the Philips Semiconductors website - http://www.semiconductors.philips.com/ - http://www.philipslogic.com/products/i2c/pdf/saa1064.pdf - - -Author: Sascha Volkenandt - -Module Parameters ------------------ - -* force: short array (min = 1, max = 48) - List of adapter,address pairs to boldly assume to be present -* force_saa1064: short array (min = 1, max = 48) - List of adapter,address pairs which are unquestionably assumed to - contain a `saa1064' chip -* ignore: short array (min = 1, max = 48) - List of adapter,address pairs not to scan -* ignore_range: short array (min = 1, max = 48) - List of adapter,start-addr,end-addr triples not to scan -* probe: short array (min = 1, max = 48) - List of adapter,address pairs to scan additionally -* probe_range: short array (min = 1, max = 48) - List of adapter,start-addr,end-addr triples to scan additionally - - -Description ------------ -The SAA1064 is a 4-digit LED driver chip for the I2C bus produced by Philips -Semiconductors. It is designed to provide a byte I2C interface to up to 4 -separate 4-digit displays (16 digits). - -This device has eight write-only registers, five are used for a control byte -and the four digit values. - -For more informations see the datasheet. - - -Accessing SAA1064 via /proc interface -------------------------------------- - -On detection (i.e. insmod, modprobe et al.), directories are being -created for each detected SAA1064: - -/proc/sys/dev/sensors/saa1064-<0>-<1>/ -where <0> is the bus the chip was detected on (e. g. i2c-0) -and <1> the chip address ([38..3b]): -./saa1064-i2c-0-38/ - -Inside these directories, there are four files each: -bright, test, disp and refresh - -The bright, test and disp files are read-write. - -Writing bright sets the output current to the LEDs connected to the -chip and thus the brightness. Range is from 0 to 7. Reading -gives you the last known value. - -Writing test sets the segment test mode (all LEDs lit regardless of -the digit values) on/off (values 0/1). Reading gives you the last -known value. - -Writing up to four values to disp sets the digits. Each value represents -one segment, while each bit represents one LED of the segment (seven bars -and one dot usually). Reading gives you the last known value. - -The refresh file is read-only. You can't read anything from it, but -reading it will trigger a refresh in case a power-loss has occurred since -the last refresh. - -On module initialization the chip is configured for segment test (test=1), -full brightness (bright=7), all digit values zeroed. - diff --git a/doc/chips/sis5595 b/doc/chips/sis5595 deleted file mode 100644 index a6f4f02b..00000000 --- a/doc/chips/sis5595 +++ /dev/null @@ -1,165 +0,0 @@ -Kernel driver `sis5595.o' -========================= - -Status: Complete and tested - -Supported chips: - * Silicon Integrated Systems Corp. SiS5595 Southbridge Hardware Monitor - Prefix: sis5595 - Addresses scanned: ISA in PCI-space encoded address - Datasheet: Publicly available at the Silicon Integrated Systems Corp. site. - - Supports following revisions: - Version PCI ID PCI Revision - 1 1039/0008 01 - 2 1039/0008 C0 - -Author: Kyösti Mälkki - - Note: The chips below contain a 0008 device which is incompatible with the - 5595. We recognize these by the presence of the listed - "blacklist" PCI ID and refuse to load. - - NOT SUPPORTED PCI ID BLACKLIST PCI ID - 540 0008 0540 - 550 0008 0550 - 5513 0008 5511 - 5581 0008 5597 - 5582 0008 5597 - 5597 0008 5597 - 5598 0008 5597/5598 - 630 0008 0630 - 645 0008 0645 - 730 0008 0730 - 735 0008 0735 - -Module Parameters ------------------ -force_addr=0xaddr Set the I/O base address. Useful for boards - that don't set the address in the BIOS. Does not do a - PCI force; the device must still be present in lspci. - Don't use this unless the driver complains that the - base address is not set. - Example: 'modprobe sis5595 force_addr=0x290' - - -Description ------------ - -The Sis5595 southbridge has integrated hardware monitor functions. -It also has an I2C bus, but this driver only supports the hardware monitor. -For the I2C bus driver see i2c-sis5595. - -The SiS5595 implements zero or one temperature sensor, two fan speed -sensors, four or five voltage sensors, and alarms. - -On the first version of the chip, there are four voltage -sensors and one temperature sensor. - -On the second version of the chip, -the temperature sensor (temp) and the fifth voltage sensor (in4) share a pin -which is configurable, but not through the driver. Sorry. -The driver senses the configuration of the pin, which was hopefully -set by the BIOS. -If the temperature function is enabled, in4 will return 0. -If the in4 function is enabled, temp will return 0. - -Temperatures are measured in degrees Celsius. An alarm is triggered once -when the max is crossed; it is also triggered -when it drops below the min value. -Measurements are guaranteed -between -55 and +125 degrees, with a resolution of 1 degree. - -Fan rotation speeds are reported in RPM (rotations per minute). An alarm is -triggered if the rotation speed has dropped below a programmable limit. Fan -readings can be divided by a programmable divider (1, 2, 4 or 8) to give -the readings more range or accuracy. Not all RPM values can accurately be -represented, so some rounding is done. With a divider of 2, the lowest -representable value is around 2600 RPM. - -Voltage sensors (also known as IN sensors) report their values in volts. -An alarm is triggered if the voltage has crossed a programmable minimum -or maximum limit. Note that minimum in this case always means 'closest to -zero'; this is important for negative voltage measurements. All voltage -inputs can measure voltages between 0 and 4.08 volts, with a resolution -of 0.016 volt. - -In addition to the alarms described above, there is a BTI alarm, which gets -triggered when an external chip has crossed its limits. Usually, this is -connected to some LM75-like chip; if at least one crosses its limits, this -bit gets set. - -If an alarm triggers, it will remain triggered until the hardware register -is read at least once. This means that the cause for the alarm may -already have disappeared! Note that in the current implementation, all -hardware registers are read whenever any data is read (unless it is less -than 1.5 seconds since the last update). This means that you can easily -miss once-only alarms. - -The Sis5595 only updates its values each 1.5 seconds; reading it more often -will do no harm, but will return 'old' values. - -Problems --------- -Some chips refuse to be enabled. We don't know why. -The driver will recognize this and print a message in dmesg. - -Chip Features -------------- - -Chip `sis5595' - LABEL LABEL CLASS COMPUTE CLASS ACCESS MAGNITUDE - in0 NONE NONE R 2 - in1 NONE NONE R 2 - in2 NONE NONE R 2 - in3 NONE NONE R 2 - in4 NONE NONE R 2 - in0_min in0 in0 RW 2 - in1_min in1 in1 RW 2 - in2_min in2 in2 RW 2 - in3_min in3 in3 RW 2 - in4_min in4 in4 RW 2 - in0_max in0 in0 RW 2 - in1_max in1 in1 RW 2 - in2_max in2 in2 RW 2 - in3_max in3 in3 RW 2 - in4_max in4 in4 RW 2 - fan1 NONE NONE R 0 - fan2 NONE NONE R 0 - fan1_min fan1 fan1 RW 0 - fan2_min fan2 fan2 RW 0 - temp NONE NONE R 1 - temp_hyst temp temp RW 1 - temp_over temp temp RW 1 - fan1_div fan1 NONE RW 0 - fan2_div fan2 NONE RW 0 - alarms NONE NONE R 0 - - LABEL FEATURE SYMBOL SYSCTL FILE:NR - in0 SENSORS_SIS5595_IN0 in0:3 - in1 SENSORS_SIS5595_IN1 in1:3 - in2 SENSORS_SIS5595_IN2 in2:3 - in3 SENSORS_SIS5595_IN3 in3:3 - in4 SENSORS_SIS5595_IN4 in3:3 - in0_min SENSORS_SIS5595_IN0_MIN in0:1 - in1_min SENSORS_SIS5595_IN1_MIN in1:1 - in2_min SENSORS_SIS5595_IN2_MIN in2:1 - in3_min SENSORS_SIS5595_IN3_MIN in3:1 - in4_min SENSORS_SIS5595_IN4_MIN in4:1 - in0_max SENSORS_SIS5595_IN0_MAX in0:2 - in1_max SENSORS_SIS5595_IN1_MAX in1:2 - in2_max SENSORS_SIS5595_IN2_MAX in2:2 - in3_max SENSORS_SIS5595_IN3_MAX in3:2 - in4_max SENSORS_SIS5595_IN4_MAX in4:2 - fan1 SENSORS_SIS5595_FAN1 fan1:2 - fan2 SENSORS_SIS5595_FAN2 fan2:2 - fan1_min SENSORS_SIS5595_FAN1_MIN fan1:1 - fan2_min SENSORS_SIS5595_FAN2_MIN fan2:1 - temp SENSORS_SIS5595_TEMP temp:3 - temp_hyst SENSORS_SIS5595_TEMP_HYST temp:2 - temp_over SENSORS_SIS5595_TEMP_OVER temp:1 - fan1_div SENSORS_SIS5595_FAN1_DIV fan_div:1 - fan2_div SENSORS_SIS5595_FAN2_DIV fan_div:2 - alarms SENSORS_SIS5595_ALARMS alarms:1 - - diff --git a/doc/chips/smartbatt b/doc/chips/smartbatt deleted file mode 100644 index 14e2b14d..00000000 --- a/doc/chips/smartbatt +++ /dev/null @@ -1,66 +0,0 @@ -Kernel driver `smartbatt.o' -========================== - -Status: Alpha - -Supported chips: - * Smart batteries - Prefix: 'smartbatt' - Address scanned: 0x0b - Datasheet: Smart Battery Data Specification Revision 1.1 - http://www.sbs-forum.org/ - -Author: M. Studebaker - -License: GPL - - -Module Parameters ------------------ - -* force: short array (min = 1, max = 48) - List of adapter,address pairs to boldly assume to be present -* force_smartbatt: short array (min = 1, max = 48) - List of adapter,address pairs which are unquestionably assumed to contain - a `smartbatt' chip -* probe: short array (min = 1, max = 48) - List of adapter,address pairs to scan additionally -* probe_range: short array (min = 1, max = 48) - List of adapter,start-addr,end-addr triples to scan additionally -* ignore: short array (min = 1, max = 48) - List of adapter,address pairs not to scan -* ignore_range: short array (min = 1, max = 48) - List of adapter,start-addr,end-addr triples not to scan - - -Detection ---------- - -Very poor. Just looks for the presence of some registers. - - -Uses ----- - -Provides read-only access to battery voltage, current, temperature, -charge status, time remaining, and alarms. - - -/proc entries -------------- - -Average readings are one minute rolling averages. - - alarms bitmask - charge relative charge, absolute charge (%) - i average current, instantaneous current (A) - temp temperature (deg. C) - time avg. time to empty, avg. time to full, - instantaneous time to full (min) - v max voltage, current voltage (V) - - -To do ------ - -More features. diff --git a/doc/chips/smbus-arp b/doc/chips/smbus-arp deleted file mode 100644 index e04fc0a4..00000000 --- a/doc/chips/smbus-arp +++ /dev/null @@ -1,66 +0,0 @@ -SMBUS_ARP Driver -------------- -This is a demonstration driver which provides SMBus 2.0 -ARP services. It isn't much use except for testing SMBus 2.0 -ARP and PEC support in the i2c layer. -It is NOT a normal 'chip' driver for a particular sensor device. -If you don't know what SMBus ARP is you don't need this driver. - - -Stability ---------- -Beta. - - -DETECTION -------------- -This driver requires SMBus 2.0 support in i2c-2.6.4 or higher. -If your kernel does not have i2c-2.6.4 or higher the module -will refuse to load. - -This driver will register itself on each i2c bus which -supports SMBus Block Data transactions. - - -USES ----- -The module ARPs each supported bus when it is inserted -(or after that when a i2c bus driver is inserted). -It does not periodically re-ARP, and the i2c stack does not -currently support SMBus Host Notify, so it will not detect -hot-plugged devices. - -The smbus-arp module should be inserted before any chip modules -so that it has an opportunity to assign addresses. - - -/PROC ENTRIES -------------- -There are 8 entries in /proc, 0-7. Each is a 'slot'. -If a chip has responded to ARP, it will appear in a 'slot' -as follows. See the SMBus 2.0 Specification for details. - - value function - 1 SMBus address - 2 UDID Device Capabilities - 3 UDID Version / Revision - 4 UDID Vendor ID - 5 UDID Device ID - 6 UDID Interface - 7 UDID Subsystem Vendor ID - 8 UDID Subsystem Device ID - 9 UDID Vendor Specific ID - -To reassign a device to a different address, write -that address to the slot. For example, 'echo 13 > 0' -to reassign the device in slot 0 to address 13 (0x0d). - - -TO DO ------ -lots - -Author/Maintainer ------------------ -Mark D. Studebaker (mdsxyz123@yahoo.com) - diff --git a/doc/chips/smsc47m1 b/doc/chips/smsc47m1 deleted file mode 100644 index 6c1c35ae..00000000 --- a/doc/chips/smsc47m1 +++ /dev/null @@ -1,75 +0,0 @@ -Kernel driver `smsc47m1.o' -========================== - -Status: Beta. - -Supported chips: - * SMSC LPC47B27x, LPC47M112, LPC47M10x, LPC47M13x, LPC47M14x, - LPC47M15x and LPC47M192 - Prefix: 'smsc47m1' - Addresses scanned: none, address read from Super I/O config space - Datasheets: - http://www.smsc.com/main/datasheets/47b27x.pdf - http://www.smsc.com/main/datasheets/47m10x.pdf - http://www.smsc.com/main/datasheets/47m112.pdf - http://www.smsc.com/main/tools/discontinued/47m13x.pdf - http://www.smsc.com/main/datasheets/47m14x.pdf - http://www.smsc.com/main/tools/discontinued/47m15x.pdf - http://www.smsc.com/main/datasheets/47m192.pdf - * SMSC LPC47M292 - Prefix: 'smsc47m2' - Addresses scanned: none, address read from Super I/O config space - Datasheet: Not public - * SMSC LPC47M997 - Addresses scanned: none, address read from Super I/O config space - Prefix: 'smsc47m1' - Datasheet: none - -Authors: Mark D. Studebaker - With assistance from Bruce Allen and his - fan.c program: http://www.lsc-group.phys.uwm.edu/%7Eballen/driver/ - -Module Parameters ------------------ - -force_addr=0xaddr Set the I/O base address. Useful for boards - that don't set the address in the BIOS. - Don't use this unless the driver complains that the - base address is not set. - Example: 'modprobe smsc47m1 force_addr=0x680' - - -Description ------------ - -The Standard Microsystems Corporation (SMSC) 47M1xx Super I/O chips -contain monitoring and PWM control circuitry for two fans. - -The LPC47M15x, LPC47M192 and LPC47M292 chips contain a full 'hardware -monitoring block' in addition to the fan monitoring and control. The -hardware monitoring block is not supported by the driver. - -No documentation is available for the 47M997, but it has the same device -ID as the 47M15x and 47M192 chips and seems to be compatible therewith. - -Fan rotation speeds are reported in RPM (rotations per minute). An alarm is -triggered if the rotation speed has dropped below a programmable limit. Fan -readings can be divided by a programmable divider (1, 2, 4 or 8) to give -the readings more range or accuracy. Not all RPM values can accurately be -represented, so some rounding is done. With a divider of 2, the lowest -representable value is around 2600 RPM. - -PWM values are from 0 to 255. The first value in the /proc entry is -the pwm value; the second is the enable (0 or 1). - -If an alarm triggers, it will remain triggered until the hardware register -is read at least once. This means that the cause for the alarm may -already have disappeared! Note that in the current implementation, all -hardware registers are read whenever any data is read (unless it is less -than 1.5 seconds since the last update). This means that you can easily -miss once-only alarms. - - -********************** -The lm_sensors project gratefully acknowledges the support of -Intel in the development of this driver. diff --git a/doc/chips/thmc50 b/doc/chips/thmc50 deleted file mode 100644 index dc4323c5..00000000 --- a/doc/chips/thmc50 +++ /dev/null @@ -1,96 +0,0 @@ -Kernel driver `thmc50.o' -===================== - -Status: Complete and some-what tested - -Supported chips: - * Analog Devices ADM1022 - Prefix: 'adm1022' - Addresses scanned: I2C 0x2C - 0x2E - Datasheet: http://www.analog.com/en/prod/0,2877,ADM1022,00.html - * Texas Instruments THMC50 - Prefix: 'thmc50' - Addresses scanned: I2C 0x2C - 0x2E - Datasheet: http://focus.ti.com/docs/prod/folders/print/thmc50.html - -Authors: Frodo Looijaard and - Philip Edelbrock - - -Module Parameters ------------------ - -* force: short array (min = 1, max = 48) - List of adapter,address pairs to boldly assume to be present -* force_thmc50: short array (min = 1, max = 48) - List of adapter,address pairs which are unquestionably assumed to contain - a `thmc50' chip -* ignore: short array (min = 1, max = 48) - List of adapter,address pairs not to scan -* ignore_range: short array (min = 1, max = 48) - List of adapter,start-addr,end-addr triples not to scan -* probe: short array (min = 1, max = 48) - List of adapter,address pairs to scan additionally -* probe_range: short array (min = 1, max = 48) - List of adapter,start-addr,end-addr triples to scan additionally - - -Description ------------ - -The THMC50 implements: an internal temperature sensor, support for an -external diode-type temperature sensor (compatible w/ the diode sensor inside -many processors), and a controllable fan/analog_out DAC. For the temperature -sensors, limits can be set through the appropriate Overtemperature Shutdown -register and Hysteresis register. Each value can be set and read to half-degree -accuracy. An alarm is issued (usually to a connected LM78) when the -temperature gets higher then the Overtemperature Shutdown value; it stays on -until the temperature falls below the Hysteresis value. All temperatures are in -degrees Celsius, and are guaranteed within a range of -55 to +125 degrees. - -The THMC50 only updates its values each 1.5 seconds; reading it more often -will do no harm, but will return 'old' values. - -The THMC50 is usually used in combination with LM78-like chips, to measure -the temperature of the processor(s). - - -Driver Features ---------------- - -These are the files which are provided by the driver (ro=read-only, -rw=read and writeable): - -temp1 (internal) -- Three fields: [temp-os,rw] [temp-hyst,rw] [temp,ro] -temp2 (remote) -- Three fields: [temp-os,rw] [temp-hyst,rw] [temp,ro] - -temp-os, temp-hyst, and temp are whole degree integers representing degrees -Celsius. - -analog_out -- One field: [output-value,rw] - -output-value is a number from 0 to 255 representing the voltage output -provided by the DAC from 0 to 2.5, respectively. Note: the max *current* -supplied is actually quite low. Some type of current amplification is needed -in order to control a fan or other current demanding device (see the -datasheet for more info). - -die_code -- One field: [die-code,ro] - -die-code is an integer representation of the die_code byte register. -According to the docs, the high nibble is the die version, and the lower -nibble is the stepping. (Don't ask me why or what this means! ;') - -inter -- One field: [interrupts,rw] - -interrupts is an integer representation of the interrupts byte. See the data -sheet for what bits mean what. - -inter_mask -- One field: [inter-mask,rw] - -inter-mask is an integer repressentation of the interrupt mask which is a -determination of which conditions can cause the /INT pin on the chip to -become asserted. - - - diff --git a/doc/chips/via686a b/doc/chips/via686a deleted file mode 100644 index 6db475fa..00000000 --- a/doc/chips/via686a +++ /dev/null @@ -1,155 +0,0 @@ -Kernel driver `via686a.o' -========================= - -Status: Stable. - -Supported chips: - * Via VT82C686A, VT82C686B Southbridge Integrated Hardware Monitor - Prefix: 'via686a' - Addresses scanned: ISA in PCI-space encoded address - Datasheet: On request through web form - (http://www.via.com.tw/en/support/datasheets/) - -Authors: Kyösti Mälkki , - Mark D. Studebaker - Bob Dougherty - (Some conversion-factor data were contributed by - Jonathan Teh Soon Yew - and Alex van Kaam .) - -Module Parameters ------------------ - -force_addr=0xaddr Set the I/O base address. Useful for boards that - don't set the address in the BIOS. Look for a BIOS - upgrade before resorting to this. Does not do a - PCI force; the via686a must still be present in lspci. - Don't use this unless the driver complains that the - base address is not set. - Example: 'modprobe via686a force_addr=0x6000' - - -Description ------------ - -The driver does not distinguish between the chips and reports -all as a 686A. - -The Via 686a southbridge has integrated hardware monitor functionality. -It also has an I2C bus, but this driver only supports the hardware monitor. -For the I2C bus driver, see ../busses/i2c-viapro. - -The Via 686a implements three temperature sensors, two fan rotation speed -sensors, five voltage sensors and alarms. - -Temperatures are measured in degrees Celsius. An alarm is triggered once -when the Overtemperature Shutdown limit is crossed; it is triggered again -as soon as it drops below the hysteresis value. - -Fan rotation speeds are reported in RPM (rotations per minute). An alarm is -triggered if the rotation speed has dropped below a programmable limit. Fan -readings can be divided by a programmable divider (1, 2, 4 or 8) to give -the readings more range or accuracy. Not all RPM values can accurately be -represented, so some rounding is done. With a divider of 2, the lowest -representable value is around 2600 RPM. - -Voltage sensors (also known as IN sensors) report their values in volts. -An alarm is triggered if the voltage has crossed a programmable minimum -or maximum limit. Voltages are internally scalled, so each voltage channel -has a different resolution and range. - -If an alarm triggers, it will remain triggered until the hardware register -is read at least once. This means that the cause for the alarm may -already have disappeared! Note that in the current implementation, all -hardware registers are read whenever any data is read (unless it is less -than 1.5 seconds since the last update). This means that you can easily -miss once-only alarms. - -The driver only updates its values each 1.5 seconds; reading it more often -will do no harm, but will return 'old' values. - - -Known Issues ------------- - -This driver handles sensors integrated in some VIA south bridges. It is -possible that a motherboard maker used a VT82C686A/B chip as part of a -product design but was not interested in its hardware monitoring features, -in which case the sensor inputs will not be wired. This is the case of -the Asus K7V, A7V and A7V133 motherboards, to name only a few of them. -So, if you need the force_addr parameter, and end up with values which -don't seem to make any sense, don't look any further: your chip is simply -not wired for hardware monitoring. - - -Chip Features -------------- - -Chip `via686a' - LABEL LABEL CLASS COMPUTE CLASS ACCESS MAGNITUDE - in0 NONE NONE R 2 - in1 NONE NONE R 2 - in2 NONE NONE R 2 - in3 NONE NONE R 2 - in4 NONE NONE R 2 - in0_min in0 in0 RW 2 - in1_min in1 in1 RW 2 - in2_min in2 in2 RW 2 - in3_min in3 in3 RW 2 - in4_min in3 in3 RW 2 - in0_max in0 in0 RW 2 - in1_max in1 in1 RW 2 - in2_max in2 in2 RW 2 - in3_max in3 in3 RW 2 - in4_max in3 in3 RW 2 - fan1 NONE NONE R 0 - fan2 NONE NONE R 0 - fan1_min fan1 fan1 RW 0 - fan2_min fan2 fan2 RW 0 - temp NONE NONE R 1 - temp_hyst temp temp RW 1 - temp_over temp temp RW 1 - temp2 NONE NONE R 1 - temp2_hyst temp temp RW 1 - temp2_over temp temp RW 1 - temp3 NONE NONE R 1 - temp3_hyst temp temp RW 1 - temp3_over temp temp RW 1 - fan1_div fan1 NONE RW 0 - fan2_div fan2 NONE RW 0 - alarms NONE NONE R 0 - - LABEL FEATURE SYMBOL SYSCTL FILE:NR - in0 SENSORS_VIA686A_IN0 in0:3 - in1 SENSORS_VIA686A_IN1 in1:3 - in2 SENSORS_VIA686A_IN2 in2:3 - in3 SENSORS_VIA686A_IN3 in3:3 - in4 SENSORS_VIA686A_IN4 in4:3 - in0_min SENSORS_VIA686A_IN0_MIN in0:1 - in1_min SENSORS_VIA686A_IN1_MIN in1:1 - in2_min SENSORS_VIA686A_IN2_MIN in2:1 - in3_min SENSORS_VIA686A_IN3_MIN in3:1 - in4_min SENSORS_VIA686A_IN4_MIN in4:1 - in0_max SENSORS_VIA686A_IN0_MAX in0:2 - in1_max SENSORS_VIA686A_IN1_MAX in1:2 - in2_max SENSORS_VIA686A_IN2_MAX in2:2 - in3_max SENSORS_VIA686A_IN3_MAX in3:2 - in4_max SENSORS_VIA686A_IN4_MAX in4:2 - fan1 SENSORS_VIA686A_FAN1 fan1:2 - fan2 SENSORS_VIA686A_FAN2 fan2:2 - fan1_min SENSORS_VIA686A_FAN1_MIN fan1:1 - fan2_min SENSORS_VIA686A_FAN2_MIN fan2:1 - temp SENSORS_VIA686A_TEMP temp:3 - temp_hyst SENSORS_VIA686A_TEMP_HYST temp:2 - temp_over SENSORS_VIA686A_TEMP_OVER temp:1 - temp2 SENSORS_VIA686A_TEMP2 temp2:3 - temp2_hyst SENSORS_VIA686A_TEMP2_HYST temp2:2 - temp2_over SENSORS_VIA686A_TEMP2_OVER temp2:1 - temp3 SENSORS_VIA686A_TEMP3 temp3:3 - temp3_hyst SENSORS_VIA686A_TEMP3_HYST temp3:2 - temp3_over SENSORS_VIA686A_TEMP3_OVER temp3:1 - fan1_div SENSORS_VIA686A_FAN1_DIV fan_div:1 - fan2_div SENSORS_VIA686A_FAN2_DIV fan_div:2 - alarms SENSORS_VIA686A_ALARMS alarms:1 - - diff --git a/doc/chips/vt1211 b/doc/chips/vt1211 deleted file mode 100644 index a6156687..00000000 --- a/doc/chips/vt1211 +++ /dev/null @@ -1,70 +0,0 @@ -Kernel driver `vt1211.o' -========================= - -Status: Beta. - -Supported chips: - * Via VT1211 Super I/O Controller - Addresses scanned: none, address read from Super I/O config space - -Authors: Mark D. Studebaker - - -Module Parameters ------------------ - -force_addr=0xaddr Set the I/O base address. Useful for boards - that don't set the address in the BIOS. - Don't use this unless the driver complains that the - base address is not set. - Example: 'modprobe vt1211 force_addr=0x680' - - -Description ------------ - -The Via VT1211 Super I/O chip -contains voltage/temperature monitoring and -PWM control circuitry for two fans. - -We define the sensors as follows. Somewhat convoluted to minimize -changes from via686a. - - Sensor Voltage Mode Temp Mode uch_config bit - -------- ------------ --------- -------------- - Reading 1 temp3 - Reading 3 temp1 - UCH1/Reading2 in0 temp2 0x04 (4) - UCH2 in1 temp4 0x08 (8) - UCH3 in2 temp5 0x10 (16) - UCH4 in3 temp6 0x20 (32) - UCH5 in4 temp7 0x40 (64) - 3.3V in5 - -As noted above, 5 of the sensors are "universal channels" and can -be set for either voltage or temperature. -Set the uch_config bit (in /proc) to 0 for voltage and 1 for temperature. -Voltages will read 0 if set for temperature. -Temperatures will read a really low number if set for voltage. - -Fan rotation speeds are reported in RPM (rotations per minute). An alarm is -triggered if the rotation speed has dropped below a programmable limit. Fan -readings can be divided by a programmable divider (1, 2, 4 or 8) to give -the readings more range or accuracy. Not all RPM values can accurately be -represented, so some rounding is done. With a divider of 2, the lowest -representable value is around 2600 RPM. - -PWM values are from 0 to 255. The first value in the /proc entry is -the pwm value; the second is the enable (0 or 1). - -If an alarm triggers, it will remain triggered until the hardware register -is read at least once. This means that the cause for the alarm may -already have disappeared! Note that in the current implementation, all -hardware registers are read whenever any data is read (unless it is less -than 1.5 seconds since the last update). This means that you can easily -miss once-only alarms. - - -********************** -The lm_sensors project gratefully acknowledges the support of -Via in the development of this driver. diff --git a/doc/chips/vt8231 b/doc/chips/vt8231 deleted file mode 100644 index fdf7c989..00000000 --- a/doc/chips/vt8231 +++ /dev/null @@ -1,184 +0,0 @@ -Kernel driver `vt8231.o' -======================== - -Status: Beta - -Supported chips: - * VIA VT8231 South Bridge - Prefix: 'vt8231' - Addresses scanned: none, address read from PCI space - -Author: Mark D. Studebaker - -License: GPL - - -Module Parameters ------------------ - -* force_addr: int - Initialize the base address of the sensors -* force: short array (min = 1, max = 48) - List of adapter,address pairs to boldly assume to be present -* force_vt8231: short array (min = 1, max = 48) - List of adapter,address pairs which are unquestionably assumed to contain - a `vt8231' chip -* probe: short array (min = 1, max = 48) - List of adapter,address pairs to scan additionally -* probe_range: short array (min = 1, max = 48) - List of adapter,start-addr,end-addr triples to scan additionally -* ignore: short array (min = 1, max = 48) - List of adapter,address pairs not to scan -* ignore_range: short array (min = 1, max = 48) - List of adapter,start-addr,end-addr triples not to scan - - -Description ------------ - -The VIA VT8231 South Bridge contains voltage/temperature monitoring and -PWM control circuitry for two fans. - -We define the sensors as follows. - - Sensor Voltage Mode Temp Mode uch_config bit - ------ ------------ --------- -------------- - Reading 1 temp1 - UCH1 in0 temp2 0x04 (4) - UCH2 in1 temp3 0x08 (8) - UCH3 in2 temp4 0x10 (16) - UCH4 in3 temp5 0x20 (32) - UCH5 in4 temp6 0x40 (64) - 3.3V in5 - -As noted above, 5 of the sensors are "universal channels" and can -be set for either voltage or temperature. -Set the uch_config bit (in /proc) to 0 for voltage and 1 for temperature. -Voltages will read 0 if set for temperature. -Temperatures will read a really low number if set for voltage. - -Fan rotation speeds are reported in RPM (rotations per minute). An alarm is -triggered if the rotation speed has dropped below a programmable limit. Fan -readings can be divided by a programmable divider (1, 2, 4 or 8) to give -the readings more range or accuracy. Not all RPM values can accurately be -represented, so some rounding is done. With a divider of 2, the lowest -representable value is around 2600 RPM. - -PWM values are from 0 to 255. The first value in the /proc entry is -the pwm value; the second is the enable (0 or 1). - -If an alarm triggers, it will remain triggered until the hardware register -is read at least once. This means that the cause for the alarm may -already have disappeared! Note that in the current implementation, all -hardware registers are read whenever any data is read (unless it is less -than 1.5 seconds since the last update). This means that you can easily -miss once-only alarms. - - -Chip Features -------------- - -Chip 'vt8231' - -LABEL LABEL CLASS COMPUTE CLASS MODE MAGN -in0 - - R- 2 -in1 - - R- 2 -in2 - - R- 2 -in3 - - R- 2 -in4 - - R- 2 -in5 - - R- 2 -in0_min in0 in0 RW 2 -in1_min in1 in1 RW 2 -in2_min in2 in2 RW 2 -in3_min in3 in3 RW 2 -in4_min in4 in4 RW 2 -in5_min in5 in5 RW 2 -in0_max in0 in0 RW 2 -in1_max in1 in1 RW 2 -in2_max in2 in2 RW 2 -in3_max in3 in3 RW 2 -in4_max in4 in4 RW 2 -in5_max in5 in5 RW 2 -fan1 - - R- 0 -fan2 - - R- 0 -fan1_min fan1 fan1 RW 0 -fan2_min fan2 fan2 RW 0 -temp1 - - R- 1 -temp1_hyst temp1 temp1 RW 1 -temp1_over temp1 temp1 RW 1 -temp2 - - R- 2 -temp2_hyst temp2 temp2 RW 2 -temp2_over temp2 temp2 RW 2 -temp3 - - R- 2 -temp3_hyst temp3 temp3 RW 2 -temp3_over temp3 temp3 RW 2 -temp4 - - R- 2 -temp4_hyst temp4 temp4 RW 2 -temp4_over temp4 temp4 RW 2 -temp5 - - R- 2 -temp5_hyst temp5 temp5 RW 2 -temp5_over temp5 temp5 RW 2 -temp6 - - R- 2 -temp6_hyst temp6 temp6 RW 2 -temp6_over temp6 temp6 RW 2 -fan1_div fan1 - RW 0 -fan2_div fan2 - RW 0 -alarms - - R- 0 -vid - - R- 3 -vrm - - RW 1 -config - - R- 0 - -LABEL FEATURE SYMBOL SYSCTL FILE:N -in0 SENSORS_VT8231_IN0 in0:3 -in1 SENSORS_VT8231_IN1 in1:3 -in2 SENSORS_VT8231_IN2 in2:3 -in3 SENSORS_VT8231_IN3 in3:3 -in4 SENSORS_VT8231_IN4 in4:3 -in5 SENSORS_VT8231_IN5 in5:3 -in0_min SENSORS_VT8231_IN0_MIN in0:1 -in1_min SENSORS_VT8231_IN1_MIN in1:1 -in2_min SENSORS_VT8231_IN2_MIN in2:1 -in3_min SENSORS_VT8231_IN3_MIN in3:1 -in4_min SENSORS_VT8231_IN4_MIN in4:1 -in5_min SENSORS_VT8231_IN5_MIN in5:1 -in0_max SENSORS_VT8231_IN0_MAX in0:2 -in1_max SENSORS_VT8231_IN1_MAX in1:2 -in2_max SENSORS_VT8231_IN2_MAX in2:2 -in3_max SENSORS_VT8231_IN3_MAX in3:2 -in4_max SENSORS_VT8231_IN4_MAX in4:2 -in5_max SENSORS_VT8231_IN5_MAX in5:2 -fan1 SENSORS_VT8231_FAN1 fan1:2 -fan2 SENSORS_VT8231_FAN2 fan2:2 -fan1_min SENSORS_VT8231_FAN1_MIN fan1:1 -fan2_min SENSORS_VT8231_FAN2_MIN fan2:1 -temp1 SENSORS_VT8231_TEMP temp1:3 -temp1_hyst SENSORS_VT8231_TEMP_HYST temp1:2 -temp1_over SENSORS_VT8231_TEMP_OVER temp1:1 -temp2 SENSORS_VT8231_TEMP2 temp2:3 -temp2_hyst SENSORS_VT8231_TEMP2_HYST temp2:2 -temp2_over SENSORS_VT8231_TEMP2_OVER temp2:1 -temp3 SENSORS_VT8231_TEMP3 temp3:3 -temp3_hyst SENSORS_VT8231_TEMP3_HYST temp3:2 -temp3_over SENSORS_VT8231_TEMP3_OVER temp3:1 -temp4 SENSORS_VT8231_TEMP4 temp4:3 -temp4_hyst SENSORS_VT8231_TEMP4_HYST temp4:2 -temp4_over SENSORS_VT8231_TEMP4_OVER temp4:1 -temp5 SENSORS_VT8231_TEMP5 temp5:3 -temp5_hyst SENSORS_VT8231_TEMP5_HYST temp5:2 -temp5_over SENSORS_VT8231_TEMP5_OVER temp5:1 -temp6 SENSORS_VT8231_TEMP6 temp6:3 -temp6_hyst SENSORS_VT8231_TEMP6_HYST temp6:2 -temp6_over SENSORS_VT8231_TEMP6_OVER temp6:1 -fan1_div SENSORS_VT8231_FAN1_DIV fan_div:1 -fan2_div SENSORS_VT8231_FAN2_DIV fan_div:2 -alarms SENSORS_VT8231_ALARMS alarms:1 -vid SENSORS_VT8231_VID vid:1 -vrm SENSORS_VT8231_VRM vrm:1 -config SENSORS_VT8231_UCH uch_config:1 - - -Notes ------ - -The lm_sensors project gratefully acknowledges the support of VIA in the -development of this driver. diff --git a/doc/chips/w83627ehf b/doc/chips/w83627ehf deleted file mode 100644 index 248f392c..00000000 --- a/doc/chips/w83627ehf +++ /dev/null @@ -1,67 +0,0 @@ -Kernel driver `w83627ehf.o' -=========================== - -Status: Stable; some missing features. - -Supported chips: - * Winbond W83627EHF/EHG (ISA access ONLY) - Prefix: 'w83627ehf' - Addresses scanned: ISA address retrieved from Super I/O registers - Datasheet: http://www.winbond-usa.com/products/winbond_products/pdfs/PCIC/W83627EHF_%20W83627EHGb.pdf - -Authors: - Jean Delvare - Yuan Mu (Winbond) - Rudolf Marek - David Hubbard - -Thanks to Observit and Bernardo Motta for providing a motherboard, CPU -and memory that made it possible to backport the w83627ehf driver from -Linux 2.6 to Linux 2.4. - - -Description ------------ - -This driver implements support for the Winbond W83627EHF and W83627EHG -super I/O chips. Support for the W83627DHG isn't included, but could be -easily added if needed. - -The chips implement three temperature sensors, five fan rotation speed -sensors, ten analog voltage sensors, alarms with beep warnings (control -unimplemented), some automatic fan regulation strategies (unimplemented) -and manual fan speed control. - -Temperatures are measured in degrees Celsius and measurement resolution is -1 degree Celsius for temp1 and 0.5 degee Celsius for temp2 and temp3. An -alarm is triggered when the temperature gets higher than high limit; it -stays on until the temperature falls below the hysteresis value. - -Fan rotation speeds are reported in RPM (rotations per minute). An alarm is -triggered if the rotation speed has dropped below a programmable limit. Fan -readings can be divided by a programmable divider (1, 2, 4, 8, 16, 32, 64 or -128) to give the readings more range or accuracy. The driver sets the most -suitable fan divisor itself. Some fans might not be present because they -share pins with other functions. - -Voltage sensors (also known as IN sensors) report their values in Volts. -An alarm is triggered if the voltage has crossed a programmable minimum -or maximum limit. - - -Fan speed control ------------------ - -The chips support 4 different fan speed control modes. The currently -selected mode can be read from (and written to) the second value of -files pwm[1-4]. Modes are: - - 1: Manual mode. The desired fan speed can be written to the first - value of the pwm[1-4] file, from 0 (stop) to 255 (full speed). - 2: Thermal cruise mode (unimplemented). - 3: Fan speed cuise mode (unimplemented). - 4: Smart Fan III mode (pwm2 and pwm4 only, unimplemented). - -While the automatic modes are not implemented by this driver, they can -still be selected, so they will work if (and only if) the BIOS has -programmed the chip with sensible register values. diff --git a/doc/chips/w83627hf b/doc/chips/w83627hf deleted file mode 100644 index f9836f5d..00000000 --- a/doc/chips/w83627hf +++ /dev/null @@ -1,103 +0,0 @@ -Kernel driver `w83627hf.o' -========================= - -Status: Beta. - -Supported chips: - * Winbond W83627HF (ISA accesses ONLY) - Prefix: 'w83627hf' - Addresses scanned: ISA address retrieved from Super I/O registers - Datasheet: http://www.winbond.com/PDF/sheet/w83627hf.pdf - * Winbond W83627THF - Prefix: 'w83627thf' - Addresses scanned: ISA address retrieved from Super I/O registers - Datasheet: http://www.winbond.com/PDF/sheet/w83627thf.pdf - * Winbond W83697HF - Prefix: 'w83697hf' - Addresses scanned: ISA address retrieved from Super I/O registers - Datasheet: http://www.winbond.com/PDF/sheet/w83697hf.pdf - * Winbond W83637HF - Prefix: 'w83637hf' - Addresses scanned: ISA address retrieved from Super I/O registers - Datasheet: http://www.winbond.com/PDF/sheet/w83637hf.pdf - * Winbond W83687THF - Prefix: 'w83687thf' - Addresses scanned: ISA address retrieved from Super I/O registers - Datasheet: Provided by Winbond on request - -Authors: Frodo Looijaard , Philip Edelbrock , - and Mark Studebaker - - -Module Parameters ------------------ - -* force: short array (min = 1, max = 48) - List of adapter,address pairs to boldly assume to be present -* force_addr: int - Initialize the ISA address of the sensors -* force_i2c: int - Initialize the I2C address of the sensors -* force_w83627hf: short array (min = 1, max = 48) - List of adapter,address pairs which are unquestionably assumed to contain - a `w83627hf' chip -* force_w83627thf: short array (min = 1, max = 48) - List of adapter,address pairs which are unquestionably assumed to contain - a `w83627thf' chip -* force_w83697hf: short array (min = 1, max = 48) - List of adapter,address pairs which are unquestionably assumed to contain - a `w83697hf' chip -* force_w83637hf: short array (min = 1, max = 48) - List of adapter,address pairs which are unquestionably assumed to contain - a `w83637hf' chip -* force_w83687thf: short array (min = 1, max = 48) - List of adapter,address pairs which are unquestionably assumed to contain - a `w83687thf' chip -* ignore: short array (min = 1, max = 48) - List of adapter,address pairs not to scan -* ignore_range: short array (min = 1, max = 48) - List of adapter,start-addr,end-addr triples not to scan -* probe: short array (min = 1, max = 48) - List of adapter,address pairs to scan additionally -* probe_range: short array (min = 1, max = 48) - List of adapter,start-addr,end-addr triples to scan additionally -* init=[0,1] (default 1) - Use 'init=0' to bypass initializing the chip. - Try this if your computer crashes when you load the module. - - -Description ------------ - -This driver implements support for ISA accesses *only* for -the Winbond W83627HF, W83627THF, W83697HF, W83637HF and W83687THF -Super I/O chips. We will refer to them collectively as Winbond chips. - -This driver supports ISA accesses, which should be more reliable -than i2c accesses. Also, for Tyan boards which contain both a -Super I/O chip and a second i2c-only Winbond chip (often a W83782D), -using this driver will avoid i2c address conflicts and complex -initialization that were required in the w83781d driver -(lm_sensors releases 2.7.0 and earlier). - -If you really want i2c accesses for these Super I/O chips, -use the w83781d driver. However this is not the preferred method -now that this ISA driver has been developed. - -The w83627_HF_ uses pins 110-106 as VID0-VID4. The w83627_THF_ uses the -same pins as GPIO[0:4]. Technically, the w83627_THF_ does not support a -VID reading. However the two chips have the identical 128 pin package. So, -it is possible or even likely for a w83627thf to have the VID signals routed -to these pins despite their not being labeled for that purpose. Therefore, -the w83627thf driver interprets these as VID. If the VID on your board -doesn't work, first see doc/vid. If that still doesn't help, you may just -ignore the bogus VID reading with no harm done. - -For further information on this driver, /proc values, etc. -see the w83781d driver documentation. - - -Author/Maintainer ------------------ -Mark D. Studebaker (mdsxyz123@yahoo.com). -Derived from the w83781d driver. diff --git a/doc/chips/w83781d b/doc/chips/w83781d deleted file mode 100644 index 3f490c51..00000000 --- a/doc/chips/w83781d +++ /dev/null @@ -1,833 +0,0 @@ -Kernel driver `w83781d.o' -========================= - -Status: W83781D support is complete and well-tested. - W83782D support is complete and well-tested. - W83783S support is complete but has not been well-tested. - W83791D support is BETA. - W83627HF support is complete but has not been well-tested. - AS99127F support is BETA and has known problems due to lack of a - chip datasheet. SEE BELOW. - -Supported chips: - * Winbond W83781D - Prefix: 'w83781d' - Addresses scanned: I2C 0x20 - 0x2f, ISA 0x290 (8 I/O ports) - Datasheet: http://www.winbond-usa.com/products/winbond_products/pdfs/PCIC/w83781d.pdf - * Winbond W83782D - Prefix: 'w83782d' - Addresses scanned: I2C 0x20 - 0x2f, ISA 0x290 (8 I/O ports) - Datasheet: http://www.winbond.com/PDF/sheet/w83782d.pdf - * Winbond W83783S - Prefix: 'w83783s' - Addresses scanned: I2C 0x2d - Datasheet: http://www.winbond-usa.com/products/winbond_products/pdfs/PCIC/w83783s.pdf - * Winbond W83791D - Prefix: 'w83791d' - Addresses scanned: I2C 0x2c - 0x2f - Datasheet: http://www.winbond-usa.com/products/winbond_products/pdfs/PCIC/w83791d.pdf - * Winbond W83627HF - Prefix: 'w83627hf' - Addresses scanned: I2C 0x20 - 0x2f, ISA 0x290 (8 I/O ports) - Datasheet: http://www.winbond.com/PDF/sheet/w83627hf.pdf - * Asus AS99127F - Prefix: 'as99127f' - Addresses scanned: I2C 0x28 - 0x2f - Datasheet: Unavailable from Asus - - - -Authors: Frodo Looijaard , Philip Edelbrock , - and Mark Studebaker - - -Module Parameters ------------------ - -* force: short array (min = 1, max = 48) - List of adapter,address pairs to boldly assume to be present -* force_w83781d: short array (min = 1, max = 48) - List of adapter,address pairs which are unquestionably assumed to contain - a `w83781d' chip -* force_w83782d: - Ditto -* force_w83783s: - Ditto -* force_w83791d: - Ditto -* force_w83627hf: - Ditto -* force_as99127f: - Ditto -* force_subclients=bus,caddr,saddr,saddr - This is used to force the i2c addresses for subclients of - a certain chip. Typical usage is `force_subclients=0,0x2d,0x4a,0x4b' - to force the subclients of chip 0x2d on bus 0 to i2c addresses - 0x4a and 0x4b. - This parameter is useful for certain Tyan boards. -* ignore: short array (min = 1, max = 48) - List of adapter,address pairs not to scan -* ignore_range: short array (min = 1, max = 48) - List of adapter,start-addr,end-addr triples not to scan -* probe: short array (min = 1, max = 48) - List of adapter,address pairs to scan additionally -* probe_range: short array (min = 1, max = 48) - List of adapter,start-addr,end-addr triples to scan additionally -* init=[0,1] (default 1) - Use 'init=0' to bypass initializing the chip. - Try this if your computer crashes when you load the module. - - -Description ------------ - -This driver implements support for the Winbond W83781D, W83782D, -W83783S, W83791D, W83627HF and W83698HF chips, and the Asus AS99127F chips. -We will refer to them collectively as W8378* chips. - -There is quite some difference between these chips, but they are similar -enough that it was sensible to put them together in one driver. -The W83627HF chip is assumed to be identical to the ISA W83782D. -The Asus chips are similar to an I2C-only W83782D. - -Detection of these chips can sometimes be foiled because they can be in -an internal state that allows no clean access. If you know the address -of the chip, use a 'force' parameter; this will put them into a more -well-behaved state first. - -The W8378* implements temperature sensors (three on the W83781D and W83782D, -two on the W83783S), three fan rotation speed sensors, voltage sensors -(seven on the W83781D, nine on the W83782D and six on the W83783S), VID -lines, alarms with beep warnings, and some miscellaneous stuff. - -Temperatures are measured in degrees Celsius. There is always one main -temperature sensor, and one (W83783S) or two (W83781D and W83782D) other -sensors. An alarm is triggered for the main sensor once when the -Overtemperature Shutdown limit is crossed; it is triggered again as soon as -it drops below the Hysteresis value. A more useful behaviour -can be found by setting the Hysteresis value to +127 degrees Celsius; in -this case, alarms are issued during all the time when the actual temperature -is above the Overtemperature Shutdown value. The driver sets the -hysteresis value for temp1 to 127 at initialization. - -For the other temperature sensor(s), an -alarm is triggered when the temperature gets higher then the Overtemperature -Shutdown value; it stays on until the temperature falls below the Hysteresis -value. But on the W83781D, there is only one alarm that functions for both -other sensors! Temperatures are guaranteed within a range of -55 to +125 -degrees. The main temperature sensors has a resolution of 1 degree; the other -sensor(s) of 0.5 degree. - -Fan rotation speeds are reported in RPM (rotations per minute). An alarm is -triggered if the rotation speed has dropped below a programmable limit. Fan -readings can be divided by a programmable divider (1, 2, 4 or 8 for the -W83781D; 1, 2, 4, 8, 16, 32, 64 or 128 for the others) to give -the readings more range or accuracy. Not all RPM values can accurately be -represented, so some rounding is done. With a divider of 2, the lowest -representable value is around 2600 RPM. - -Voltage sensors (also known as IN sensors) report their values in volts. -An alarm is triggered if the voltage has crossed a programmable minimum -or maximum limit. Note that minimum in this case always means 'closest to -zero'; this is important for negative voltage measurements. All voltage -inputs can measure voltages between 0 and 4.08 volts, with a resolution -of 0.016 volt. - -The VID lines encode the core voltage value: the voltage level your processor -should work with. This is hardcoded by the mainboard and/or processor itself. -It is a value in volts. When it is unconnected, you will often find the -value 3.50 V here. - -The W83782D and W83783S temperature conversion machine understands about -several kinds of temperature probes. You can program the so-called -beta value in the sensor files. '1' is the PII/Celeron diode, '2' is the -TN3904 transistor, and 3435 the default thermistor value. Other values -are (not yet) supported. You can program your own values through the -rt interface, but this is not very useful, because these tables are -under NDA. - -In addition to the alarms described above, there is a CHAS alarm on the -chips which triggers if your computer case is open. - -When an alarm goes off, you can be warned by a beeping signal through -your computer speaker. It is possible to enable all beeping globally, -or only the beeping for some alarms. - -Individual alarm and beep bits: - -0x000001: in0 -0x000002: in1 -0x000004: in2 -0x000008: in3 -0x000010: temp1 -0x000020: temp2 (+temp3 on W83781D) -0x000040: fan1 -0x000080: fan2 -0x000100: in4 -0x000200: in5 -0x000400: in6 -0x000800: fan3 -0x001000: chassis -0x002000: temp3 (W83782D and W83627HF only) -0x010000: in7 (W83782D and W83627HF only) -0x020000: in8 (W83782D and W83627HF only) - -If an alarm triggers, it will remain triggered until the hardware register -is read at least once. This means that the cause for the alarm may -already have disappeared! Note that in the current implementation, all -hardware registers are read whenever any data is read (unless it is less -than 1.5 seconds since the last update). This means that you can easily -miss once-only alarms. - -The chips only update values each 1.5 seconds; reading them more often -will do no harm, but will return 'old' values. - - -AS99127F PROBLEMS ------------------ -The as99127f support was developed without the benefit of a datasheet. -In most cases it is treated as a w83781d (although revision 2 of the -AS9917F looks more like a w83782d). -This support will be BETA until a datasheet is released. -One user has reported problems with fans stopping -occasionally. - -Note that the individual beep bits are inverted from the other chips. -The driver now takes care of this so that user-space applications -don't have to know about it. - -Known problems: - - Problems with diode/thermistor settings (supported?) - - One user reports fans stopping under high server load. - - Revision 2 seems to have 2 PWM registers but we don't know - how to handle them. More details below. - -These will not be fixed unless we get a datasheet. -If you have problems, please lobby Asus to release a datasheet. -Unfortunately several others have without success. -Please do not send mail to us asking for better as99127f support. -We have done the best we can without a datasheet. -Please do not send mail to the author or the sensors group asking for -a datasheet or ideas on how to convince Asus. We can't help. - - -Chip Features -------------- - -Chip `w83781d' - LABEL LABEL CLASS COMPUTE CLASS ACCESS MAGNITUDE - in0 NONE NONE R 2 - in1 NONE NONE R 2 - in2 NONE NONE R 2 - in3 NONE NONE R 2 - in4 NONE NONE R 2 - in5 NONE NONE R 2 - in6 NONE NONE R 2 - in0_min in0 in0 RW 2 - in1_min in1 in1 RW 2 - in2_min in2 in2 RW 2 - in3_min in3 in3 RW 2 - in4_min in4 in4 RW 2 - in5_min in5 in5 RW 2 - in6_min in6 in6 RW 2 - in0_max in0 in0 RW 2 - in1_max in1 in1 RW 2 - in2_max in2 in2 RW 2 - in3_max in3 in3 RW 2 - in4_max in4 in4 RW 2 - in5_max in5 in5 RW 2 - in6_max in6 in6 RW 2 - fan1 NONE NONE R 0 - fan2 NONE NONE R 0 - fan3 NONE NONE R 0 - fan1_min fan1 NONE RW 0 - fan2_min fan2 NONE RW 0 - fan3_min fan3 NONE RW 0 - temp1 NONE NONE R 1 - temp1_hyst temp1 temp1 RW 1 - temp1_over temp1 temp1 RW 1 - temp2 NONE NONE R 1 - temp2_hyst temp2 temp2 RW 1 - temp2_over temp2 temp2 RW 1 - temp3 NONE NONE R 1 - temp3_hyst temp3 temp3 RW 1 - temp3_over temp3 temp3 RW 1 - vid NONE NONE R 2 - fan1_div fan1 NONE RW 0 - fan2_div fan2 NONE RW 0 - fan3_div fan3 NONE R 0 - alarms NONE NONE R 0 - beep_enable alarms NONE RW 0 - beeps alarms alarms RW 0 - - LABEL FEATURE SYMBOL SYSCTL FILE:NR - in0 SENSORS_W83781D_IN0 in0:3 - in1 SENSORS_W83781D_IN1 in1:3 - in2 SENSORS_W83781D_IN2 in2:3 - in3 SENSORS_W83781D_IN3 in3:3 - in4 SENSORS_W83781D_IN4 in4:3 - in5 SENSORS_W83781D_IN5 in5:3 - in6 SENSORS_W83781D_IN6 in6:3 - in0_min SENSORS_W83781D_IN0_MIN in0:1 - in1_min SENSORS_W83781D_IN1_MIN in1:1 - in2_min SENSORS_W83781D_IN2_MIN in2:1 - in3_min SENSORS_W83781D_IN3_MIN in3:1 - in4_min SENSORS_W83781D_IN4_MIN in4:1 - in5_min SENSORS_W83781D_IN5_MIN in5:1 - in6_min SENSORS_W83781D_IN6_MIN in6:1 - in0_max SENSORS_W83781D_IN0_MAX in0:2 - in1_max SENSORS_W83781D_IN1_MAX in1:2 - in2_max SENSORS_W83781D_IN2_MAX in2:2 - in3_max SENSORS_W83781D_IN3_MAX in3:2 - in4_max SENSORS_W83781D_IN4_MAX in4:2 - in5_max SENSORS_W83781D_IN5_MAX in5:2 - in6_max SENSORS_W83781D_IN6_MAX in6:2 - fan1 SENSORS_W83781D_FAN1 fan1:2 - fan2 SENSORS_W83781D_FAN2 fan2:2 - fan3 SENSORS_W83781D_FAN3 fan3:2 - fan1_min SENSORS_W83781D_FAN1_MIN fan1:1 - fan2_min SENSORS_W83781D_FAN2_MIN fan2:1 - fan3_min SENSORS_W83781D_FAN3_MIN fan3:1 - temp1 SENSORS_W83781D_TEMP1 temp1:3 - temp1_hyst SENSORS_W83781D_TEMP1_HYST temp1:2 - temp1_over SENSORS_W83781D_TEMP1_OVER temp1:1 - temp2 SENSORS_W83781D_TEMP2 temp2:3 - temp2_hyst SENSORS_W83781D_TEMP2_HYST temp2:2 - temp2_over SENSORS_W83781D_TEMP2_OVER temp2:1 - temp3 SENSORS_W83781D_TEMP3 temp3:3 - temp3_hyst SENSORS_W83781D_TEMP3_HYST temp3:2 - temp3_over SENSORS_W83781D_TEMP3_OVER temp3:1 - vid SENSORS_W83781D_VID vid:1 - fan1_div SENSORS_W83781D_FAN1_DIV fan_div:1 - fan2_div SENSORS_W83781D_FAN2_DIV fan_div:2 - fan3_div SENSORS_W83781D_FAN3_DIV fan_div:3 - alarms SENSORS_W83781D_ALARMS alarms:1 - beep_enable SENSORS_W83781D_BEEP_ENABLE beep:1 - beeps SENSORS_W83781D_BEEPS beep:2 - - -Chip `w83782d' - LABEL LABEL CLASS COMPUTE CLASS ACCESS MAGNITUDE - in0 NONE NONE R 2 - in1 NONE NONE R 2 - in2 NONE NONE R 2 - in3 NONE NONE R 2 - in4 NONE NONE R 2 - in5 NONE NONE R 2 - in6 NONE NONE R 2 - in7 NONE NONE R 2 - in8 NONE NONE R 2 - in0_min in0 in0 RW 2 - in1_min in1 in1 RW 2 - in2_min in2 in2 RW 2 - in3_min in3 in3 RW 2 - in4_min in4 in4 RW 2 - in5_min in5 in5 RW 2 - in6_min in6 in6 RW 2 - in7_min in7 in7 RW 2 - in8_min in8 in8 RW 2 - in0_max in0 in0 RW 2 - in1_max in1 in1 RW 2 - in2_max in2 in2 RW 2 - in3_max in3 in3 RW 2 - in4_max in4 in4 RW 2 - in5_max in5 in5 RW 2 - in6_max in6 in6 RW 2 - in7_max in7 in7 RW 2 - in8_max in8 in8 RW 2 - fan1 NONE NONE R 0 - fan2 NONE NONE R 0 - fan3 NONE NONE R 0 - fan1_min fan1 NONE RW 0 - fan2_min fan2 NONE RW 0 - fan3_min fan3 NONE RW 0 - temp1 NONE NONE R 1 - temp1_hyst temp1 temp1 RW 1 - temp1_over temp1 temp1 RW 1 - temp2 NONE NONE R 1 - temp2_hyst temp2 temp2 RW 1 - temp2_over temp2 temp2 RW 1 - temp3 NONE NONE R 1 - temp3_hyst temp3 temp3 RW 1 - temp3_over temp3 temp3 RW 1 - vid NONE NONE R 2 - fan1_div fan1 NONE RW 0 - fan2_div fan2 NONE RW 0 - fan3_div fan3 NONE R 0 - alarms NONE NONE R 0 - beep_enable alarms NONE RW 0 - beeps alarms alarms RW 0 - sensor1 NONE NONE RW 0 - sensor2 NONE NONE RW 0 - sensor3 NONE NONE RW 0 - - LABEL FEATURE SYMBOL SYSCTL FILE:NR - in0 SENSORS_W83782D_IN0 in0:3 - in1 SENSORS_W83782D_IN1 in1:3 - in2 SENSORS_W83782D_IN2 in2:3 - in3 SENSORS_W83782D_IN3 in3:3 - in4 SENSORS_W83782D_IN4 in4:3 - in5 SENSORS_W83782D_IN5 in5:3 - in6 SENSORS_W83782D_IN6 in6:3 - in7 SENSORS_W83782D_IN7 in7:3 - in8 SENSORS_W83782D_IN8 in8:3 - in0_min SENSORS_W83782D_IN0_MIN in0:1 - in1_min SENSORS_W83782D_IN1_MIN in1:1 - in2_min SENSORS_W83782D_IN2_MIN in2:1 - in3_min SENSORS_W83782D_IN3_MIN in3:1 - in4_min SENSORS_W83782D_IN4_MIN in4:1 - in5_min SENSORS_W83782D_IN5_MIN in5:1 - in6_min SENSORS_W83782D_IN6_MIN in6:1 - in7_min SENSORS_W83782D_IN7_MIN in7:1 - in8_min SENSORS_W83782D_IN8_MIN in8:1 - in0_max SENSORS_W83782D_IN0_MAX in0:2 - in1_max SENSORS_W83782D_IN1_MAX in1:2 - in2_max SENSORS_W83782D_IN2_MAX in2:2 - in3_max SENSORS_W83782D_IN3_MAX in3:2 - in4_max SENSORS_W83782D_IN4_MAX in4:2 - in5_max SENSORS_W83782D_IN5_MAX in5:2 - in6_max SENSORS_W83782D_IN6_MAX in6:2 - in7_max SENSORS_W83782D_IN7_MAX in7:2 - in8_max SENSORS_W83782D_IN8_MAX in8:2 - fan1 SENSORS_W83782D_FAN1 fan1:2 - fan2 SENSORS_W83782D_FAN2 fan2:2 - fan3 SENSORS_W83781D_FAN3 fan3:2 - fan1_min SENSORS_W83782D_FAN1_MIN fan1:1 - fan2_min SENSORS_W83782D_FAN2_MIN fan2:1 - fan3_min SENSORS_W83781D_FAN3_MIN fan3:1 - temp1 SENSORS_W83782D_TEMP1 temp1:3 - temp1_hyst SENSORS_W83782D_TEMP1_HYST temp1:2 - temp1_over SENSORS_W83782D_TEMP1_OVER temp1:1 - temp2 SENSORS_W83782D_TEMP2 temp2:3 - temp2_hyst SENSORS_W83782D_TEMP2_HYST temp2:2 - temp2_over SENSORS_W83782D_TEMP2_OVER temp2:1 - temp3 SENSORS_W83782D_TEMP3 temp3:3 - temp3_hyst SENSORS_W83782D_TEMP3_HYST temp3:2 - temp3_over SENSORS_W83782D_TEMP3_OVER temp3:1 - vid SENSORS_W83782D_VID vid:1 - fan1_div SENSORS_W83782D_FAN1_DIV fan_div:1 - fan2_div SENSORS_W83782D_FAN2_DIV fan_div:2 - fan3_div SENSORS_W83781D_FAN3_DIV fan_div:3 - alarms SENSORS_W83782D_ALARMS alarms:1 - beep_enable SENSORS_W83782D_BEEP_ENABLE beep:1 - beeps SENSORS_W83782D_BEEPS beep:2 - sensor1 SENSORS_W83782D_SENS1 sensor1:1 - sensor2 SENSORS_W83782D_SENS2 sensor2:1 - sensor3 SENSORS_W83782D_SENS3 sensor3:1 - - -Chip `w83783s' - LABEL LABEL CLASS COMPUTE CLASS ACCESS MAGNITUDE - in0 NONE NONE R 2 - in1 NONE NONE R 2 - in2 NONE NONE R 2 - in3 NONE NONE R 2 - in4 NONE NONE R 2 - in5 NONE NONE R 2 - in6 NONE NONE R 2 - in0_min in0 in0 RW 2 - in1_min in1 in1 RW 2 - in2_min in2 in2 RW 2 - in3_min in3 in3 RW 2 - in4_min in4 in4 RW 2 - in5_min in5 in5 RW 2 - in6_min in6 in6 RW 2 - in0_max in0 in0 RW 2 - in1_max in1 in1 RW 2 - in2_max in2 in2 RW 2 - in3_max in3 in3 RW 2 - in4_max in4 in4 RW 2 - in5_max in5 in5 RW 2 - in6_max in6 in6 RW 2 - fan1 NONE NONE R 0 - fan2 NONE NONE R 0 - fan3 NONE NONE R 0 - fan1_min fan1 NONE RW 0 - fan2_min fan2 NONE RW 0 - fan3_min fan3 NONE RW 0 - temp1 NONE NONE R 1 - temp1_hyst temp1 temp1 RW 1 - temp1_over temp1 temp1 RW 1 - temp2 NONE NONE R 1 - temp2_hyst temp2 temp2 RW 1 - temp2_over temp2 temp2 RW 1 - vid NONE NONE R 2 - fan1_div fan1 NONE RW 0 - fan2_div fan2 NONE RW 0 - fan3_div fan3 NONE R 0 - alarms NONE NONE R 0 - beep_enable alarms NONE RW 0 - beeps alarms alarms RW 0 - sensor1 NONE NONE RW 0 - sensor2 NONE NONE RW 0 - - LABEL FEATURE SYMBOL SYSCTL FILE:NR - in0 SENSORS_W83783S_IN0 in0:3 - in1 SENSORS_W83783S_IN1 in1:3 - in2 SENSORS_W83783S_IN2 in2:3 - in3 SENSORS_W83783S_IN3 in3:3 - in4 SENSORS_W83783S_IN4 in4:3 - in5 SENSORS_W83783S_IN5 in5:3 - in6 SENSORS_W83783S_IN6 in6:3 - in0_min SENSORS_W83783S_IN0_MIN in0:1 - in1_min SENSORS_W83783S_IN1_MIN in1:1 - in2_min SENSORS_W83783S_IN2_MIN in2:1 - in3_min SENSORS_W83783S_IN3_MIN in3:1 - in4_min SENSORS_W83783S_IN4_MIN in4:1 - in5_min SENSORS_W83783S_IN5_MIN in5:1 - in6_min SENSORS_W83783S_IN6_MIN in6:1 - in0_max SENSORS_W83783S_IN0_MAX in0:2 - in1_max SENSORS_W83783S_IN1_MAX in1:2 - in2_max SENSORS_W83783S_IN2_MAX in2:2 - in3_max SENSORS_W83783S_IN3_MAX in3:2 - in4_max SENSORS_W83783S_IN4_MAX in4:2 - in5_max SENSORS_W83783S_IN5_MAX in5:2 - in6_max SENSORS_W83783S_IN6_MAX in6:2 - fan1 SENSORS_W83783S_FAN1 fan1:2 - fan2 SENSORS_W83783S_FAN2 fan2:2 - fan3 SENSORS_W83783S_FAN3 fan3:2 - fan1_min SENSORS_W83783S_FAN1_MIN fan1:1 - fan2_min SENSORS_W83783S_FAN2_MIN fan2:1 - fan3_min SENSORS_W83783S_FAN3_MIN fan3:1 - temp1 SENSORS_W83783S_TEMP1 temp1:3 - temp1_hyst SENSORS_W83783S_TEMP1_HYST temp1:2 - temp1_over SENSORS_W83783S_TEMP1_OVER temp1:1 - temp2 SENSORS_W83783S_TEMP2 temp2:3 - temp2_hyst SENSORS_W83783S_TEMP2_HYST temp2:2 - temp2_over SENSORS_W83783S_TEMP2_OVER temp2:1 - vid SENSORS_W83783S_VID vid:1 - fan1_div SENSORS_W83783S_FAN1_DIV fan_div:1 - fan2_div SENSORS_W83783S_FAN2_DIV fan_div:2 - fan3_div SENSORS_W83783S_FAN3_DIV fan_div:3 - alarms SENSORS_W83783S_ALARMS alarms:1 - beep_enable SENSORS_W83783S_BEEP_ENABLE beep:1 - beeps SENSORS_W83783S_BEEPS beep:2 - sensor1 SENSORS_W83783S_SENS1 sensor1:1 - sensor2 SENSORS_W83783S_SENS2 sensor2:1 - - - -Miscellaneous documentation -=========================== - - - -/PROC ENTRIES -------------- -Varies depending on chip type. Most are identical to the lm78 entries. -See the lm78 documentation for details. - -Additional entries not in the lm78: - - pwm[1-4]: (not on w83781d nor as99127f) - Controls the speed of the fans with PWM (Pulse Width Modulation) - Valid values: - 0 - 255. 255 = max speed. - Second value is PWM enable 0/1. - - sensor[1-3]: (not on w83781d nor as99127f) - Controls the sensor type. To change to a different - sensor type, for example, do 'echo 2 > sensor1'. - Valid values: - 1: Pentium II / Celeron diode - 2: 2N3904 Transistor in a diode configuration - 3435: Thermistor with Beta = 3435. Beta is a measure - of sensitivity to temperature. - Thermistors with other Betas could in theory be supported - after correspondence with Winbond. See below. - - rt[1-3]: (w83781d only) - 32-byte tables controlling the conversion from - resistance to temperature for thermistors. - For the curious only. Writing to these entries will - probably render temperature sensing insane. - Only set at initialization; not updated every 1.5 seconds. - - - -TO DO: ------ - 782d programmable pins - - -NOTES: ------ - 783s has no in1 so that in[2-6] are compatible with the 781d/782d. - - 783s pin is programmable for -5V or temp1; defaults to -5V, - no control in driver so temp1 doesn't work. - - 782d and 783s datasheets differ on which is pwm1 and which is pwm2. - We chose to follow 782d. - - 782d and 783s pin is programmable for fan3 input or pwm2 output; - defaults to fan3 input. - If pwm2 is enabled (with echo 255 1 > pwm2), then - fan3 will report 0. - - 782d has pwm1-2 for isa, pwm1-4 for i2c. (pwm3-4 share pins with - the isa pins) - - - -Data sheet updates: ------------------- - - PWM clock registers: - - 000: master / 512 - 001: master / 1024 - 010: master / 2048 - 011: master / 4096 - 100: master / 8192 - - -Answers from Winbond tech support ---------------------------------- -> -> 1) In the W83781D data sheet section 7.2 last paragraph, it talks about -> reprogramming the R-T table if the Beta of the thermistor is not -> 3435K. The R-T table is described briefly in section 8.20. -> What formulas do I use to program a new R-T table for a given Beta? -> - We are sorry that the calculation for R-T table value is -confidential. If you have another Beta value of thermistor, we can help -to calculate the R-T table for you. But you should give us real R-T -Table which can be gotten by thermistor vendor. Therefore we will calculate -them and obtain 32-byte data, and you can fill the 32-byte data to the -register in Bank0.CR51 of W83781D. - - -> 2) In the W83782D data sheet, it mentions that pins 38, 39, and 40 are -> programmable to be either thermistor or Pentium II diode inputs. -> How do I program them for diode inputs? I can't find any register -> to program these to be diode inputs. - --> You may program Bank0 CR[5Dh] and CR[59h] registers. - - CR[5Dh] bit 1(VTIN1) bit 2(VTIN2) bit 3(VTIN3) - - thermistor 0 0 0 - diode 1 1 1 - - -(error) CR[59h] bit 4(VTIN1) bit 2(VTIN2) bit 3(VTIN3) -(right) CR[59h] bit 4(VTIN1) bit 5(VTIN2) bit 6(VTIN3) - - PII thermal diode 1 1 1 - 2N3904 diode 0 0 0 - - -Author/Maintainer ------------------ -Original 781D support: Frodo and Phil -782D/783S support added by: Mark D. Studebaker (mdsxyz123@yahoo.com) - - -Asus Clones ------------ - -We have no datasheets for the Asus clones (AS99127F and ASB100 Bach). -Here are some very useful information that were given to us by Alex Van -Kaam about how to detect these chips, and how to read their values. He -also gives advice for another Asus chipset, the Mozart-2 (which we -don't support yet). Thanks Alex! -I reworded some parts and added personal comments. - -# Detection: - -AS99127F rev.1, AS99127F rev.2 and ASB100: -- I2C address range: 0x29 - 0x2F -- If register 0x58 holds 0x31 then we have an Asus (either ASB100 or - AS99127F) -- Which one depends on register 0x4F (manufacturer ID): - 0x06 or 0x94: ASB100 - 0x12 or 0xC3: AS99127F rev.1 - 0x5C or 0xA3: AS99127F rev.2 - Note that 0x5CA3 is Winbond's ID (WEC), which let us think Asus get their - AS99127F rev.2 direct from Winbond. The other codes mean ATT and DVC, - respectively. ATT could stand for Asustek something (although it would be - very badly chosen IMHO), I don't know what DVC could stand for. Maybe - these codes simply aren't meant to be decoded that way. - -Mozart-2: -- I2C address: 0x77 -- If register 0x58 holds 0x56 or 0x10 then we have a Mozart-2 -- Of the mozart there are 3 types: - 0x58=0x56, 0x4E=0x94, 0x4F=0x36: Asus ASM58 Mozart-2 - 0x58=0x56, 0x4E=0x94, 0x4F=0x06: Asus AS2K129R Mozart-2 - 0x58=0x10, 0x4E=0x5C, 0x4F=0xA3: Asus ??? Mozart-2 - You can handle all 3 the exact same way :) - -# Temperature sensors: - -ASB100: -- sensor 1: register 0x27 -- sensor 2 & 3 are the 2 LM75's on the SMBus -- sensor 4: register 0x17 -Remark: I noticed that on Intel boards sensor 2 is used for the CPU - and 4 is ignored/stuck, on AMD boards sensor 4 is the CPU and sensor 2 is - either ignored or a socket temperature. - -AS99127F (rev.1 and 2 alike): -- sensor 1: register 0x27 -- sensor 2 & 3 are the 2 LM75's on the SMBus -Remark: Register 0x5b is suspected to be temperature type selector. Bit 1 - would control temp1, bit 3 temp2 and bit 5 temp3. - -Mozart-2: -- sensor 1: register 0x27 -- sensor 2: register 0x13 - -# Fan sensors: - -ASB100, AS99127F (rev.1 and 2 alike): -- 3 fans, identical to the W83781D - -Mozart-2: -- 2 fans only, 1350000/rpm/div -- fan 1: register 0x28, divisor on register 0xA1 (bits 4-5) -- fan 2: register 0x29, divisor on register 0xA1 (bits 6-7) - -# Voltages: - -This is where there is a difference between AS99127F rev.1 and 2. -Remark: The difference is similar to the difference between - W83781D and W83782D. - -ASB100: -in0=r(0x20)*0.016 -in1=r(0x21)*0.016 -in2=r(0x22)*0.016 -in3=r(0x23)*0.016*1.68 -in4=r(0x24)*0.016*3.8 -in5=r(0x25)*(-0.016)*3.97 -in6=r(0x26)*(-0.016)*1.666 - -AS99127F rev.1: -in0=r(0x20)*0.016 -in1=r(0x21)*0.016 -in2=r(0x22)*0.016 -in3=r(0x23)*0.016*1.68 -in4=r(0x24)*0.016*3.8 -in5=r(0x25)*(-0.016)*3.97 -in6=r(0x26)*(-0.016)*1.503 - -AS99127F rev.2: -in0=r(0x20)*0.016 -in1=r(0x21)*0.016 -in2=r(0x22)*0.016 -in3=r(0x23)*0.016*1.68 -in4=r(0x24)*0.016*3.8 -in5=(r(0x25)*0.016-3.6)*5.14+3.6 -in6=(r(0x26)*0.016-3.6)*3.14+3.6 - -Mozart-2: -in0=r(0x20)*0.016 -in1=255 -in2=r(0x22)*0.016 -in3=r(0x23)*0.016*1.68 -in4=r(0x24)*0.016*4 -in5=255 -in6=255 - - -# PWM - -* Additional info about PWM on the AS99127F (may apply to other Asus -chips as well) by Jean Delvare as of 2004-04-09: - -AS99127F revision 2 seems to have two PWM registers at 0x59 and 0x5A, -and a temperature sensor type selector at 0x5B (which basically means -that they swapped registers 0x59 and 0x5B when you compare with Winbond -chips). -Revision 1 of the chip also has the temperature sensor type selector at -0x5B, but PWM registers have no effect. - -We don't know exactly how the temperature sensor type selection works. -Looks like bits 1-0 are for temp1, bits 3-2 for temp2 and bits 5-4 for -temp3, although it is possible that only the most significant bit matters -each time. So far, values other than 0 always broke the readings. - -PWM registers seem to be split in two parts: bit 7 is a mode selector, -while the other bits seem to define a value or threshold. - -When bit 7 is clear, bits 6-0 seem to hold a threshold value. If the value -is below a given limit, the fan runs at low speed. If the value is above -the limit, the fan runs at full speed. We have no clue as to what the limit -represents. Note that there seem to be some inertia in this mode, speed -changes may need some time to trigger. Also, an hysteresis mechanism is -suspected since walking through all the values increasingly and then -decreasingly led to slightly different limits. - -When bit 7 is set, bits 3-0 seem to hold a threshold value, while bits 6-4 -would not be significant. If the value is below a given limit, the fan runs -at full speed, while if it is above the limit it runs at low speed (so this -is the contrary of the other mode, in a way). Here again, we don't know -what the limit is supposed to represent. - -One remarkable thing is that the fans would only have two or three -different speeds (transitional states left apart), not a whole range as -you usually get with PWM. - -As a conclusion, you can write 0x00 or 0x8F to the PWM registers to make -fans run at low speed, and 0x7F or 0x80 to make them run at full speed. - -Please contact us if you can figure out how it is supposed to work. As -long as we don't know more, the w83781d driver doesn't handle PWM on -AS99127F chips at all. - -* Additional info about PWM on the AS99127F rev.1 by Hector Martin: - -I've been fiddling around with the (in)famous 0x59 register and -found out the following values do work as a form of coarse pwm: - -0x80 - seems to turn fans off after some time(1-2 minutes)... might be -some form of auto-fan-control based on temp? hmm (Qfan? this mobo is an -old ASUS, it isn't marketed as Qfan. Maybe some beta pre-attempt at Qfan -that was dropped at the BIOS) -0x81 - off -0x82 - slightly "on-ner" than off, but my fans do not get to move. I can -hear the high-pitched PWM sound that motors give off at too-low-pwm. -0x83 - now they do move. Estimate about 70% speed or so. -0x84-0x8f - full on - -Changing the high nibble doesn't seem to do much except the high bit -(0x80) must be set for PWM to work, else the current pwm doesn't seem to -change. - -My mobo is an ASUS A7V266-E. This behaviour is similar to what I got -with speedfan under Windows, where 0-15% would be off, 15-2x% (can't -remember the exact value) would be 70% and higher would be full on. - -* Additional info about PWM on the AS99127F rev.1 from lm-sensors - ticket #2350: - -I conducted some experiment on Asus P3B-F motherboard with AS99127F -(Ver. 1). - -I confirm that 0x59 register control the CPU_Fan Header on this -motherboard, and 0x5a register control PWR_Fan. - -In order to reduce the dependency of specific fan, the measurement is -conducted with a digital scope without fan connected. I found out that -P3B-F actually output variable DC voltage on fan header center pin, -looks like PWM is filtered on this motherboard. - -Here are some of measurements: - -0x80 20 mV -0x81 20 mV -0x82 232 mV -0x83 1.2 V -0x84 2.31 V -0x85 3.44 V -0x86 4.62 V -0x87 5.81 V -0x88 7.01 V -9x89 8.22 V -0x8a 9.42 V -0x8b 10.6 V -0x8c 11.9 V -0x8d 12.4 V -0x8e 12.4 V -0x8f 12.4 V - diff --git a/doc/chips/w83792d b/doc/chips/w83792d deleted file mode 100644 index 046692e8..00000000 --- a/doc/chips/w83792d +++ /dev/null @@ -1,298 +0,0 @@ -Kernel driver `w83792d.o' -========================= - -Status: W83792D support is complete and well-tested. - - -Supported chips: - * Winbond W83792D - Prefix: 'w83792d' - Addresses scanned: I2C 0x2c - 0x2f - Datasheet: http://www.winbond.com.tw/E-WINBONDHTM/partner/PDFresult.asp?Pname=1035 - -Author: Chunhao Huang -Contact: DZShen - - -Module Parameters ------------------ - -* init int - (default 1) - Use 'init=0' to bypass initializing the chip. - Try this if your computer crashes when you load the module. - -* force_subclients=bus,caddr,saddr,saddr - This is used to force the i2c addresses for subclients of - a certain chip. Example usage is `force_subclients=0,0x2f,0x4a,0x4b' - to force the subclients of chip 0x2f on bus 0 to i2c addresses - 0x4a and 0x4b. - - -Description ------------ - -This driver implements support for the Winbond W83792AD/D. - -Detection of the chip can sometimes be foiled because it can be in an -internal state that allows no clean access (Bank with ID register is not -currently selected). If you know the address of the chip, use a 'force' -parameter; this will put it into a more well-behaved state first. - -The driver implements three temperature sensors, seven fan rotation speed -sensors, nine voltage sensors, and two automatic fan regulation -strategies called: Smart Fan I (Thermal Cruise mode) and Smart Fan II. -Automatic fan control mode is possible only for fan1-fan3. Fan4-fan7 can run -synchronized with selected fan (fan1-fan3). This functionality and manual PWM -control for fan4-fan7 is not yet implemented. - -Temperatures are measured in degrees Celsius and measurement resolution is 1 -degC for temp1 and 0.5 degC for temp2 and temp3. An alarm is triggered when -the temperature gets higher than the Overtemperature Shutdown value; it stays -on until the temperature falls below the Hysteresis value. - -Fan rotation speeds are reported in RPM (rotations per minute). An alarm is -triggered if the rotation speed has dropped below a programmable limit. Fan -readings can be divided by a programmable divider (1, 2, 4, 8, 16, 32, 64 or -128) to give the readings more range or accuracy. This driver modifies the -fan divisor automatically to get the reasonable RPM rotation range. - -Voltage sensors (also known as IN sensors) report their values in volts. -An alarm is triggered if the voltage has crossed a programmable minimum -or maximum limit. - -Alarms are provided as output from "realtime status register". Following bits -are defined: - -bit - alarm on: -0 - in0 -1 - in1 -2 - temp1 -3 - temp2 -4 - temp3 -5 - fan1 -6 - fan2 -7 - fan3 -8 - in2 -9 - in3 -10 - in4 -11 - in5 -12 - in6 -13 - VID change -14 - chassis -15 - fan7 -16 - tart1 -17 - tart2 -18 - tart3 -19 - in7 -20 - in8 -21 - fan4 -22 - fan5 -23 - fan6 - -Tart will be asserted while target temperature cannot be achieved after 3 minutes -of full speed rotation of corresponding fan. - -In addition to the alarms described above, there is a CHAS alarm on the chips -which triggers if your computer case is open (This one is latched, contrary -to realtime alarms). - -The chips only update values each 3 seconds; reading them more often will -do no harm, but will return 'old' values. - - -W83792D PROBLEMS ----------------- -Known problems: - - This driver is only for Winbond W83792D C version device, there - are also some motherboards with B version W83792D device. The - calculation method to in6-in7(measured value, limits) is a little - different between C and B version. C or B version can be identified - by CR[0x49h]. - - The function of vid and vrm has not been finished, because I'm NOT - very familiar with them. Adding support is welcome. - - The function of chassis open detection needs more tests. - - If you have ASUS server board and chip was not found: Then you will - need to upgrade to latest (or beta) BIOS. If it does not help please - contact us. - - -Chip Features -------------- - -Chip `w83792d' - LABEL LABEL CLASS COMPUTE CLASS ACCESS MAGNITUDE - in0 NONE NONE R 3 - in1 NONE NONE R 3 - in2 NONE NONE R 3 - in3 NONE NONE R 3 - in4 NONE NONE R 3 - in5 NONE NONE R 3 - in6 NONE NONE R 3 - in7 NONE NONE R 3 - in8 NONE NONE R 3 - in0_min in0 in0 RW 3 - in1_min in1 in1 RW 3 - in2_min in2 in2 RW 3 - in3_min in3 in3 RW 3 - in4_min in4 in4 RW 3 - in5_min in5 in5 RW 3 - in6_min in6 in6 RW 3 - in7_min in7 in7 RW 3 - in8_min in8 in8 RW 3 - in0_max in0 in0 RW 3 - in1_max in1 in1 RW 3 - in2_max in2 in2 RW 3 - in3_max in3 in3 RW 3 - in4_max in4 in4 RW 3 - in5_max in5 in5 RW 3 - in6_max in6 in6 RW 3 - in7_max in7 in7 RW 3 - in8_max in8 in8 RW 3 - fan1 NONE NONE R 0 - fan2 NONE NONE R 0 - fan3 NONE NONE R 0 - fan4 NONE NONE R 0 - fan5 NONE NONE R 0 - fan6 NONE NONE R 0 - fan7 NONE NONE R 0 - fan1_min fan1 NONE RW 0 - fan2_min fan2 NONE RW 0 - fan3_min fan3 NONE RW 0 - fan4_min fan4 NONE RW 0 - fan5_min fan5 NONE RW 0 - fan6_min fan6 NONE RW 0 - fan7_min fan7 NONE RW 0 - temp1 NONE NONE R 1 - temp1_hyst temp1 temp1 RW 1 - temp1_over temp1 temp1 RW 1 - temp2 NONE NONE R 1 - temp2_hyst temp2 temp2 RW 1 - temp2_over temp2 temp2 RW 1 - temp3 NONE NONE R 1 - temp3_hyst temp3 temp3 RW 1 - temp3_over temp3 temp3 RW 1 - fan1_div fan1 NONE RW 0 - fan2_div fan2 NONE RW 0 - fan3_div fan3 NONE RW 0 - fan4_div fan4 NONE RW 0 - fan5_div fan5 NONE RW 0 - fan6_div fan6 NONE RW 0 - fan7_div fan7 NONE RW 0 - - LABEL FEATURE SYMBOL SYSCTL FILE:NR - in0 SENSORS_W83792D_IN0 in0:3 - in1 SENSORS_W83792D_IN1 in1:3 - in2 SENSORS_W83792D_IN2 in2:3 - in3 SENSORS_W83792D_IN3 in3:3 - in4 SENSORS_W83792D_IN4 in4:3 - in5 SENSORS_W83792D_IN5 in5:3 - in6 SENSORS_W83792D_IN6 in6:3 - in7 SENSORS_W83792D_IN7 in7:3 - in8 SENSORS_W83792D_IN8 in8:3 - in0_min SENSORS_W83792D_IN0_MIN in0:1 - in1_min SENSORS_W83792D_IN1_MIN in1:1 - in2_min SENSORS_W83792D_IN2_MIN in2:1 - in3_min SENSORS_W83792D_IN3_MIN in3:1 - in4_min SENSORS_W83792D_IN4_MIN in4:1 - in5_min SENSORS_W83792D_IN5_MIN in5:1 - in6_min SENSORS_W83792D_IN6_MIN in6:1 - in7_min SENSORS_W83792D_IN7_MIN in7:1 - in8_min SENSORS_W83792D_IN8_MIN in8:1 - in0_max SENSORS_W83792D_IN0_MAX in0:2 - in1_max SENSORS_W83792D_IN1_MAX in1:2 - in2_max SENSORS_W83792D_IN2_MAX in2:2 - in3_max SENSORS_W83792D_IN3_MAX in3:2 - in4_max SENSORS_W83792D_IN4_MAX in4:2 - in5_max SENSORS_W83792D_IN5_MAX in5:2 - in6_max SENSORS_W83792D_IN6_MAX in6:2 - in7_max SENSORS_W83792D_IN7_MAX in7:2 - in8_max SENSORS_W83792D_IN8_MAX in8:2 - fan1 SENSORS_W83792D_FAN1 fan1:2 - fan2 SENSORS_W83792D_FAN2 fan2:2 - fan3 SENSORS_W83792D_FAN3 fan3:2 - fan4 SENSORS_W83792D_FAN4 fan4:2 - fan5 SENSORS_W83792D_FAN5 fan5:2 - fan6 SENSORS_W83792D_FAN6 fan6:2 - fan7 SENSORS_W83792D_FAN7 fan7:2 - fan1_min SENSORS_W83792D_FAN1_MIN fan1:1 - fan2_min SENSORS_W83792D_FAN2_MIN fan2:1 - fan3_min SENSORS_W83792D_FAN3_MIN fan3:1 - fan4_min SENSORS_W83792D_FAN4_MIN fan4:1 - fan5_min SENSORS_W83792D_FAN5_MIN fan5:1 - fan6_min SENSORS_W83792D_FAN6_MIN fan6:1 - fan7_min SENSORS_W83792D_FAN7_MIN fan7:1 - temp1 SENSORS_W83792D_TEMP1 temp1:3 - temp1_hyst SENSORS_W83792D_TEMP1_HYST temp1:2 - temp1_over SENSORS_W83792D_TEMP1_OVER temp1:1 - temp2 SENSORS_W83792D_TEMP2 temp2:3 - temp2_hyst SENSORS_W83792D_TEMP2_HYST temp2:2 - temp2_over SENSORS_W83792D_TEMP2_OVER temp2:1 - temp3 SENSORS_W83792D_TEMP3 temp3:3 - temp3_hyst SENSORS_W83792D_TEMP3_HYST temp3:2 - temp3_over SENSORS_W83792D_TEMP3_OVER temp3:1 - fan1_div SENSORS_W83792D_FAN1_DIV fan_div:1 - fan2_div SENSORS_W83792D_FAN2_DIV fan_div:2 - fan3_div SENSORS_W83792D_FAN3_DIV fan_div:3 - fan4_div SENSORS_W83792D_FAN4_DIV fan_div:4 - fan5_div SENSORS_W83792D_FAN5_DIV fan_div:5 - fan6_div SENSORS_W83792D_FAN6_DIV fan_div:6 - fan7_div SENSORS_W83792D_FAN7_DIV fan_div:7 - - - - -/PROC ENTRIES -------------- -Most are identical to the w83781d entries. See the w83781d documentation for -details. - -Most of the additional entries not in the w83781d are Winbond Smart Fan I/II: -Please read "7.7 FAN Speed Count and FAN Speed Control" of W83792AD/D datasheet -before you read the explanation to the /proc entries below. - - fan_cfg: indicates the fan speed control mode: 0 means PWM/DC mode, - 1 means Smart Fan I(Thermal Cruise) mode, 2 or 3 means Smart Fan II - mode. There are three items in this entry, the first one is the - configuration of Fan1, the rest may be deduced by analogy. - - pwm_flag: valid under PWM/DC mode, 1 means PWM mode, 0 means DC mode. - There are three items in this entry, the first one is PWM/DC mode - of Fan1, the rest may be deduced by analogy. - - thermal_cruise: valid under Smart Fan I mode, indicates the wanted - temperature. There are three items in this entry, the first one - is setting temperature of Fan1, the rest may be deduced by analogy. - - fan_tolerance: valid under Smart Fan I or Smart Fan II mode, indicates - the interval temperature. There are also three items in this entry. - - sf2_points_fan1: valid under Smart Fan II mode, there are four items in - this entry, indicates the Temp.[1-4] in "Figure 8. Smart Fan II - behavior" to Fan1. - - sf2_points_fan2: almost same as the above one, except that this entry - is for Fan2. - - sf2_points_fan3: almost same as the above one, except that this entry - is for Fan3. - - sf2_levels_fan1: valid under Smart Fan II mode, there are four items in - this entry, indicates the "Non-Stop Duty Cycle" and "Fan Duty Cycle - Level [1-3]" in "Figure 8. Smart Fan II behavior" to Fan1. The - first item "Non-Stop Duty Cycle" is read only in this driver, while - the other three items can be modified. - - sf2_levels_fan2: almost same as the above one, except that this entry - is for Fan2. - - sf2_levels_fan3: almost same as the above one, except that this entry - is for Fan3. - - -additional entries for chassis intrusion detection: - chassis: There are two items in this entry, the first one indicats the - chassis status, 1 means chassis intrusion detected, while 1 means - normal. The second item in this entry is used to clear the - detected chassis intrusion interrupt and reset the chassis status - to normal. diff --git a/doc/chips/w83l785ts b/doc/chips/w83l785ts deleted file mode 100644 index 16972072..00000000 --- a/doc/chips/w83l785ts +++ /dev/null @@ -1,77 +0,0 @@ -Kernel driver `w83l785ts.o' -=========================== - -Status: Beta, slightly tested - -Supported chips: - * Winbond W83L785TS-S - Prefix: 'w83l785ts' - Addresses scanned: I2C 0x2e - Datasheet: Publicly available at the Winbond USA website - http://www.winbond-usa.com/products/winbond_products/pdfs/PCIC/W83L785TS-S.pdf - - -Author: Jean Delvare - -License: GPL - - -Module Parameters ------------------ - -* force: short array (min = 1, max = 48) - List of adapter,address pairs to boldly assume to be present -* force_w83l785ts: short array (min = 1, max = 48) - List of adapter,address pairs which are unquestionably assumed to contain - a `w83l785ts' chip -* probe: short array (min = 1, max = 48) - List of adapter,address pairs to scan additionally -* probe_range: short array (min = 1, max = 48) - List of adapter,start-addr,end-addr triples to scan additionally -* ignore: short array (min = 1, max = 48) - List of adapter,address pairs not to scan -* ignore_range: short array (min = 1, max = 48) - List of adapter,start-addr,end-addr triples not to scan - - -Description ------------ - -The W83L785TS-S is a digital temperature sensor. It senses the -temperature of a single external diode. The high limit is -theoretically defined as 85 or 100 degrees C through a combination -of external resistors, so the user cannot change it. Values seen so -far suggest that the two possible limits are actually 95 and 110 -degrees C. The datasheet is rather poor and obviously inaccurate -on several points including this one. - -All temperature values are given in degrees Celsius. Resolution -is 1.0 degree. See the datasheet for details. - -The w83l785ts driver will not update its values more frequently than -every other second; reading them more often will do no harm, but will -return 'old' values. - - -Known Issues ------------- - -On some systems (Asus), the BIOS is known to interfere with the driver -and cause read errors. The driver will retry a given number of times -(5 by default) and then give up, returning the old value (or 0 if -there is no old value). It seems to work well enough so that you should -not notice anything. Thanks to James Bolt for helping test this feature. - - -Chip Features -------------- - -Chip 'w83l785ts' - -LABEL LABEL CLASS COMPUTE CLASS MODE MAGN -temp - - R- 0 -temp_high temp temp R- 0 - -LABEL FEATURE SYMBOL SYSCTL FILE:N -temp SENSORS_W83L785TS_TEMP temp:2 -temp_high SENSORS_W83L785TS_TEMP_OVER temp:1 diff --git a/doc/chips/xeontemp b/doc/chips/xeontemp deleted file mode 100644 index a77a214a..00000000 --- a/doc/chips/xeontemp +++ /dev/null @@ -1,108 +0,0 @@ -Kernel driver `xeontemp.o' -========================= - -Status: Complete; tested for most devices except Xeon. - -Supported chips: - * Intel Xeon and other processors - Prefix: 'xeontemp' - Addresses scanned: I2C 0x18, 0x1a, 0x29, 0x2b, 0x4c, 0x4e - Datasheets: Publicly available at the Intel website - See the adm1021 document for additional references - -Authors: Frodo Looijaard ,Philip Edelbrock - , and Mark D. Studebaker (mdsxyz123@yahoo.com) - -License: GPL - - -Module Parameters ------------------ - -* force: short array (min = 1, max = 48) - List of adapter,address pairs to boldly assume to be present -* force_xeontemp: short array (min = 1, max = 48) - List of adapter,address pairs which are unquestionably assumed to contain - a `xeontemp' chip -* probe: short array (min = 1, max = 48) - List of adapter,address pairs to scan additionally -* probe_range: short array (min = 1, max = 48) - List of adapter,start-addr,end-addr triples to scan additionally -* ignore: short array (min = 1, max = 48) - List of adapter,address pairs not to scan -* ignore_range: short array (min = 1, max = 48) - List of adapter,start-addr,end-addr triples not to scan -* read_only: int - Don't set any values, read only mode - - -Description ------------ - -Many Xeons and other Intel processors have an embedded i2c temperature -sensor that look very similar to an adm1021 or max1617. - -Some Xeons have honest to goodness, real live, actual MAX1617 chips on -them. Others Xeons made around the same time have other ADM1021 -compatible chips on them. They are mounted on the CPU substrate along -with the processor information EEPROM that is part of that generation of -Xeon CPU's. - -So it's basically impossible to tell a Xeon TEMP sensor from a MAX1617 -since they are in fact the same chip. The Xeon Temperature sensors spec -is just a stripped down register spec for the ADM1021 that says the -"on-board" or "built-in" sensor registers are "reserved". That way -Intel could substitute whatever ADM1021 compatible chip was cheapest at -the time when they built the CPU's. - -One reason to use the xeontemp driver is if, when Intel built your -particular Xeon's, they didn't use any of the ADM1021 compatible chips -that the ADM1021 driver recognizes. In that case, using the xeontemp -driver will get you the temperatures you want without potentially -messing up something in the sensor. - -Another reason is to avoid having 'sensors' report the second -temperature. - -Unfortunately, the 533MHz FSB Xeon's, dropped the on-board sensor chip. -So these new Xeons require a sensor on the motherboard to be connected -to the thermal diode to read the temperature. But these 533MHz capable -motherboards can also accept 400MHz CPU's with the on-board sensor so it -gets confusing in a hurry for motherboard vendors and users. - -If you have 400MHz FSB P4 Xeon CPU's, you should have an on-CPU ADM1021 -compatible sensor at 0x18 or 0x19. In that case, use the ADM1021 driver -if it detects a chip at that address. The CPU DIE temperature (Tj) will -be the "REMOTE" temperature from this sensor. The "Board" or "built-in" -temperature from the ADM1021 will be the temperature of the ADM1021 -compatible itself which is one of the chips you see on the side of the CPU. - -If you have sensors at 0x18 and 0x19 that are not detected by the -ADM1021, and you have 400MHz Xeons, then you may want to try the -xeontemp driver. - -If you have 533MHZ FSB Xeons, then you do *not* have an on-board thermal -sensor and you should look for CPU temperatures from the other sensors -on your motherboard. (Winbond chip for example). - -If you have an Intel Xeon processor, and sensors-detect recommended -the adm1021 driver, and the address is one of -0x18, 0x1a, 0x29, 0x2b, 0x4c, or 0x4e, and when using the -adm1021 driver, temp1 is invalid but temp2 looks correct, then -it is likely you should use the xeontemp driver instead. - -If you have dual Xeons you may have appear to have two separate -adm1021-compatible chips, or two single-temperature sensors, -at distinct addresses. - -In summary, the xeontemp module supports one temperature and the -adm1021 module supports two. Use the module that works best for you. - -See the adm1021 documentation for more information. - - -Author/Maintainer ------------------ -Mark D. Studebaker (mdsxyz123@yahoo.com). -Derived from the adm1021 driver. -Thanks to Philip Pokorny for help with this document. diff --git a/doc/developers/applications b/doc/developers/applications index bee75f60..6cbfd731 100644 --- a/doc/developers/applications +++ b/doc/developers/applications @@ -1,146 +1,53 @@ -How to write applications which use our drivers ------------------------------------------------ +How to write applications which use the hwmon drivers +===================================================== -You have several choices in accessing sensor devices using the -drivers in our package. This document will briefly -describe these methods, their advantages and disadvantages, -and provide examples. +You have several choices in accessing sensor devices using the hwmon drivers. +This document will briefly describe these methods, their advantages and +disadvantages, and provide examples. From lowest-level to the highest-level, the access methods are: - 1) Character device access to the i2c bus driver - via /dev/i2c-x - 2) I2C bus access functions as defined in kernel/include/i2c-dev.h - 3A) /proc access to the chip device driver - 3B) sysfs access to the chip device driver - 4) libsensors library - 5) sensors program + 1. sysfs access + 2. libsensors library + 3. sensors program Details: -1. Direct /dev access using ioctls ----------------------------------- - Character device access to the i2c bus driver via ioctls on a /dev - device. This device could be i2cx, i2c-x, or i2c/x, where x is an - integer. The ioctls are defined in doc/dev-interface in the - i2c package or Documentation/i2c/dev-interface in the linux kernel - sources. - - This method does not use a chip device driver at all. - However it does require the i2c-dev module. - The driver must set an individual chip address on the bus via - an ioctl, so it must use locking if multiple devices on the - bus are being accessed. No access is provided for non-i2c - busses such as ISA. - - For good examples, see prog/detect/i2cdetect.c and - prog/detect/sensors-detect. - - -2. Direct /dev access using inline functions --------------------------------------------- - I2C bus access inline functions as defined in kernel/include/i2c-dev.h, - and in doc/dev-interface in the i2c package or - Documentation/i2c/dev-interface in the linux kernel sources. - Note that these used to be defined in in the kernel - source tree. However, userspace applications are not supposed to - include kernel headers, so the inline functions were removed from - the kernel file in recent kernels. Use the header file in this package - instead. - - This method does not use a chip device driver at all. - However it does require the i2c-dev module. - The driver must set an individual chip address on the bus via - an ioctl, so it must use locking if multiple devices on the - bus are being accessed. No access is provided for non-i2c - busses such as ISA. - - For good examples, see prog/detect/i2cdetect.c, - prog/dump/i2cdump.c, and prog/dump/i2cset.c. - - -3A. /proc access (2.4 kernels) ------------------------------ - Chip drivers using the i2c-proc module create subdirectories in - /proc/sys/dev/sensors which can be accessed directly by applications. +1. sysfs access +--------------- + Hwmon drivers create subdirectories in the sysfs filesystem (usually /sys) + which can be accessed directly by applications. Naming and content standards for the entries in these subdirectories - is documented in the file doc/developers/proc. Note that these - standards may not be strictly followed. - - If a new driver adheres to these standards then an application may - be able to support new devices on-the-fly. - - /proc access provides a method to read and write sensor values - for any driver using i2c-proc, including ISA chip drivers. - - This method also works well for shell and perl scripts - written to access a specific device. Note that i2c-proc is - standard in the kernel as of kernel 2.4.13. - - Note that most drivers provide only raw sensor readings via /proc; - many readings must be scaled or adjusted, and these adjustments - must often be changed by the user. An application using /proc must - generally provide adjustment facilities and the requirements - of the adjustments can be quite complex. If you need adjustment - facilities, consider the libsensors library, below. - - For examples of programs using /proc accesses, see - prog/eeprom/decode-dimms.pl, prog/matorb/displayit.pl, - prog/maxilife/writelcd.sh, prog/rrd/sens_update_rrd, - prog/pwm/fancontrol, and prog/pwm/pwmconfig. - Also search freshmeat for sensors applications. - - -3B. sysfs access (2.6 kernels) ------------------------------- - Chip drivers using the hwmon module create subdirectories in - the sysfs filesystem (usually /sys) which can be accessed - directly by applications. - Naming and content standards for the entries in these subdirectories - is documented in the file Documentation/hwmon/sysfs-interface in the - 2.6 kernel source tree. Note that these standards may not be - strictly followed. - - If a new driver adheres to these standards then an application may - be able to support new devices on-the-fly. - - sysfs access provides a method to read and write sensor values - for any driver, including ISA chip drivers. - - This method may also work well for shell and perl scripts - written to access a specific device. Note that sysfs is - standard in 2.6 kernels. + are documented in the file Documentation/hwmon/sysfs-interface in the 2.6 + kernel source tree. sysfs is the lowest-level access to sensor values. Note that most drivers provide only raw sensor readings via /sys; many readings must be scaled or adjusted, and these adjustments must often be changed by the user. An application using /sys must generally provide adjustment facilities and the requirements - of the adjustments can be quite complex. If you need adjustment - facilities, consider the libsensors library, below. + of the adjustments can be quite complex. For this reason, this + approach isn't recommended. Instead, consider the libsensors library, + which offers a higher-level interface on top of sysfs (see below.) - For an example of a program using /sys accesses, see gkrellm. - See also lib/proc.c and prog/dump/i2cbusses.c for examples. - The sysfsutils package may also be helpful. - Also search freshmeat for sensors and sysfs applications. + Still, this method may work well for shell and perl scripts written to + access a specific device. + For an example of a program using /sys accesses, see gkrellm (though + recent versions use libsensors instead.) See also lib/sysfs.c. -4. libsensors library +2. libsensors library --------------------- The libsensors library provides standardized access to all chip drivers. It also provides a translation layer with settings in /etc/sensors.conf so that your application sees adjusted (scaled) values using settings - provided by the user. Other facilities are sensor renaming, limit setting, - and ignoring individual sensors. - The libsensors library supports both 2.4 and 2.6 kernels. + provided by the user. Other facilities are sensor labelling, limit setting, + and ignoring individual sensors. This is the recommended way to access + the sensor chips. - Unfortunately there is little documentation for libsensors. See the - 'sensors' application in prog/sensors for an example. The source - for libsensors is in the lib/ directory. Another example - is in prog/sensord. Also search freshmeat for sensors applications. - - One other limitation of libsensors is that it is relatively - cumbersome to add support for new devices. + The library API is documented in the libsensors(3) manual page. The + configuration file format is documented in the sensors.conf(5) manual + page. Note that libsensors falls under the GPL, not the LGPL. In more human language, that means it is FORBIDDEN to link any application @@ -148,12 +55,16 @@ Details: does not fall under the GPL. This may or may not be changed in the future. Contact us if you wish to discuss your application. - For an example of a program using libsensors accesses, see - prog/sensors/sensors. Also search freshmeat for sensors applications. + For examples of programs using libsensors accesses, see prog/sensors and + prog/sensord. -5. sensors program +3. sensors program ------------------ The 'sensors' program is a text-based application that uses libsensors. The output is fairly standardized; therefore this output could be used by other applications. One simple method is 'sensors|grep ALARM'. + Note though that there is no guarantee that the output format won't change + in the future, so be careful. We might improve the command-line interface + of 'sensors' someday to make it more convenient for external programs to + use it as a back-end. diff --git a/doc/developers/design b/doc/developers/design deleted file mode 100644 index 045fb1a3..00000000 --- a/doc/developers/design +++ /dev/null @@ -1,550 +0,0 @@ -This is a design for version 2 of our smbus and lm_sensors module. This -document is Copyright (c) 1998, 1999 by Frodo Looijaard. You may freely copy and -distribute it, as long as you recognize me as the author, and mark any -changes you make as being your own, and distribute this notice with it. - -Document version 1.0, 19981101. - 1.1, 19981111. - 1.2, 19981118. - 1.3, 19981126. - -NOTE: THIS IS BY NOW SOMEWHAT OUTDATED. SORRY. - - -Object oriented approach -======================== - -The i2c module structs contain callback functions and data fields. In the -i2c module, these structures are only referenced by pointers. This makes -it easy to extend these structs to contain additional information or -callback functions. For those familiar with object oriented languages, -you can see the smbus and isa structures as an object extension of the i2c -structures. - -To make this clearer, I will show in an example how this is done. Note -that I have simplified some things here, so this example does not -correspond to an actual struct found in one of the modules. - -In the i2c module, you can find a struct somewhat like this: - -struct i2c_adapter { - char name[32]; - int (*detach_client) (struct i2c_client *); - struct i2c_adapter *next; -} - -We have a plain data field (name), a call-back function which needs one -parameter (a pointer to a i2c_client struct), and a data field which is -a pointer to the next adapter. - -Now we want to extend this structure. We need another data field, -containing a number of flags. We will call this new structure smbus_adapter. -A few other things change too: - -struct smbus_adapter { - char name[32]; - int (*detach_client) (struct smbus_client *); - struct smbus_adapter *next; - unsigned int flags; -} - -So we copy all existing fields. The next field still points to the next -adapter - but it is now of type smbus_adapter, not i2c_adapter. And the -call-back function takes now a parameter of type pointer to smbus_client. -And there is a new data field, called flags. - -Now examine this function definition: - -int fully_detach_i2c_client (struct i2c_client * client) -{ - res = 0; - struct i2c_adapter *current_adapter = first_adapter; /* a global var. */ - while (current_adapter) { - res |= (current_adapter -> detach_client) (client); - current_adapter = current_adapter -> next; - } - return res; -} - -This function detaches a client from all adapters. Nice. But now comes the -Big Trick(tm): we can still use this function for smbus_adapters! - -int fully_detach_smbus_client (struct smbus_client * client) -{ - return fully_detach_i2c_client( (struct i2c_client *) client); -} - -All we needed here was a simple typecast. Datapointers remain datapointers, -so this can safely be done. And because we use call-back functions, the -actual function called to detach a client from a single adapter might -be the same, or different, depending on what function was put in -client->detach_client! - -It gets even better. The i2c module stores internally all registered -adapters. But it stores pointers to the i2c_adapter struct, not the -structs themselves! So there is an array: - -#define I2C_ADAPTER_MAX 32 -struct i2c_adapter *adapters[I2C_ADAPTER_MAX]; -/* this is an array of pointers to structs, not vice versa! */ - -So, an element of this array might in fact point to a smbus_adapter, instead -of an i2c_adapter! If you know this for sure, you might use a typecast and -access the additional fields. In the meantime, the i2c internal -administration remains valid. - -We have to thank Simon Vogl and Gerd Knorr for the way they implemented -their i2c module. Any other way would have made this approach impossible, -and basing anything upon their module much more difficult. - -Limitations ------------ - -Extending the adapter and algorithm structures in this way is quite safe. -They are only allocated on places where the code knows that they are -'special'. Extending the driver or client structures depending on a -specific adapter/algorithm type is *very* *dangerous*. A driver/client -module would need to be aware of every special adapter/algorithm in -order to allocate itself! For the ISA bus, it has to be aware of this -anyway, so it is safe to do; on other places, think twice first! - - -Module overview -=============== - -All in all, lots of modules will be stacked on each other. Too bad, but -that is the only way to cleanly implement everything. Note that in a -specific situation, only a few modules may need to be loaded. isa.o, -for example, does not depend on smbus.o (in the sense that you can load -sensor.o without loading smbus.o). A specific bus driver, though, will -depend on many of them. - -Generally: - isa.o depends on nothing (actually, on i2c.o, to keep the code small) - smbus.o depends on nothing (actually, on i2c.o, to keep the code small) - i2c.o depends on nothing. - - A non-i2c SMBus bus driver depends only on smbus.o - A i2c bus driver depends only on i2c.o - - A sensor chip driver depends either on isa.o or smbus.o, or both. - A SMBus chip driver depends only on smbus.o - A I2C chip driver depends only on i2c.o - -We may need a sensor.o module, to act as a central point for sensor -modules. At this moment, it seems not really necessary, but this may -change. - -We will need an enhanced i2c-dev.o module, to add SMBus access to I2C -/dev entries. - - -isa.o -ISA bus handling. -Encapsulates ISA bus access within the i2c structures. -Unites I2C adapters and the ISA bus. -Defines variables isa_algorithm and isa_adapter. - -smbus.o -Main SMBus handling. -Encapsulates SMBus access within the smbus structures. -Unites I2C adapters and SMBus hosts (like the PIIX4). -Emulates SMBus access on pure I2C adapters. -Defines variable smbus_algorithm. - - piix4.o - SMBus adapter driver for the PIIX4 SMBus host. - Defines variable piix4_adapter (based on smbus_algorithm). - - FOO.o - Adapter driver for FOO SMBus host - Defines variable FOO_adapter (based on smbus_algorithm). - -i2c-core.o (From Simon Vogl) -Main i2c handling. - - ????.o - I2C adapter driver - Implementing a class of I2C busses - - -A chip driver (typically defined in its own module) can be hooked on all -these levels: - * If it is a sensor chip, it should be hooked to isa.o or smbus.o - * A pure ISA chip should be hooked to isa.o - * A pure SMBus chip should be hooked to smbus.o - * An I2C chip should be hooked to i2c.o -It can be difficult to decide whether a specific chip should be hooked to -smbus.o or i2c.o. A good deciding question is, 'could it be connected to -a PIIX4?' - - -Module i2c.o -============ - -This is Simon Vogl's i2c module (this one is different from the i2c module -included in kernels around 2.1.120!). - -A driver --------- - -struct i2c_driver { - char name[32]; - int id; - unsigned int flags; - int (* attach_adapter) (struct i2c_adapter *); - int (* detach_client) (struct i2c_client *); - int (* command) (struct i2c_client *, unsigned int cmd, void *arg); - void (* inc_use) (struct i2c_client *); - void (* dec_use) (struct i2c_client *); -} - -A driver tells us how we should handle a specific type of i2c chip. An -instance of such a chip is called a 'client'. An example would be the LM75 -module: it would contain only one driver, which tells us how to handle the -LM75; but each detected LM75 would be a separate client (which would be -dynamically allocated). - - -A description of the above struct: - name: The name of this driver - id: A unique driver identifier - flags: Flags to set certain kinds of behaviour. Most notably, DF_NOTIFY - will notify the driver when a new i2c bus is detected, so it can - try to detect chips on it. - attach_adapter: A call-back function which is called if a new adapter (bus) - is found. This allows us to do our detection stuff on the new adapter, - and register new clients. - detach_client: A call-back function which is called if a specific client - which uses this driver should be disallocated. If a specific sensor module - is removed, for instance, this function would be called for each registered - client. - command: A generic call-back function to communicate in a driver-dependent - way with a specific client. This should only be seldom needed. - inc_use: Can be called to add one to an internal 'use' counter. This can be - used to control when it is safe to remove this module, for example. - - -A client --------- - -struct i2c_client { - char name[32]; - int id; - unsigned int flags; - unsigned char addr; - struct i2c_adapter *adapter; - struct i2c_driver *driver; - void *data; -} - -A client is a specific sensor chip. Its operation is controlled by a driver -(which describes a type of sensor chip), and it is connected to an adapter -(a bus). - -A description of the above struct: - name: The name of this client - id: A unique client id - flags: Flags to set certain kinds of behaviour (not very important) - addr: The client address. 10-bit addresses are a bit of a kludge right now. - adapter: A pointer to the adapter this client is on. - driver: A pointer to the driver this client uses. - data: Additional, client-dependent data - - -An algorithm ------------- - -struct i2c_algorithm { - char name[32]; - unsigned int id; - int (* master_xfer) (struct i2c_adapter *adap, struct i2c_msg msgs[], - int num); - int (* slave_send) (struct i2c_adapter *,char *, int); - int (* slave_recv) (struct i2c_adapter *,char *, int); - int (* algo_control) (struct i2c_adapter *, unsigned int, unsigned long); - int (* client_register) (struct i2c_client *); - int (* client_unregister) (struct i2c_client *); -} - -An algorithm describes how a certain class of i2c busses can be accessed. - -A description of the above struct: - name: The name of this algorithm - id: A unique algorithm id - master_xfer: Transfer a bunch of messages through a specific i2c bus. - slave_send: Send a message as if we are a slave device - slave_recv: Receive a message as if we are a slave device - client_register: Register a new client - client_unregister: Unregister a client - - -An adapter ----------- - -struct i2c_adapter { - char name[32]; - unsigned int id; - struct i2c_algorithm *algo; - void *data; -#ifdef SPINLOCK - spinlock_t lock; - unsigned long lockflags; -#else - struct semaphore lock; -#endif - unsigned int flags; - struct i2c_client *clients[I2C_CLIENT_MAX]; - int client_count; - int timeout; - int retries; -} - -An adapter is a specific i2c bus. How to access it is defined in the -algorithm associated with it. - -A description of the above struct: - name: The name of this adapter - id: A unique adapter id - algo: The algorithm through which this bus must be accessed - data: Adapter specific data - lock, lockflags: To lock out simultaneous adapter access - flags: Modifiers for adapter operation - clients: All currently connected clients - client_count: The number of currently connected clients - timeout, retries: Internal variables (unimportant here). - - -Access functions ----------------- - -All these functions are defined extern. - -int i2c_master_send(struct i2c_client *,const char *, int); -int i2c_master_recv(struct i2c_client *,char *, int); -int i2c_transfer(struct i2c_adapter *,struct i2c_msg [], int num); - -These function respectively send one message to a client, receive one message -from a client, or transmit a bunch of messages. struct i2c_msg contains -an i2c address to communicate with, and can both read from and write to this -address. - - -int i2c_slave_send(struct i2c_client *, char *, int); -int i2c_slave_recv(struct i2c_client *, char *, int); - -Communicate with another master as if the normal master is a common slave -device. - - -Administration functions ------------------------- - -int i2c_add_algorithm(struct i2c_algorithm *); -int i2c_del_algorithm(struct i2c_algorithm *); - -The i2c_{add,del}_algorithm functions must be called whenever a new module -is inserted with this driver in it, by the module initialization function. - - -int i2c_add_adapter(struct i2c_adapter *); -int i2c_del_adapter(struct i2c_adapter *); - -The i2c_{add,del}_adapter functions must be called if you have detected -a specific bus. It triggers driver->attach_adapter (add, for each driver -present) or driver->detach_client (del, for each registered client on -this adapter). - - -int i2c_add_driver(struct i2c_driver *); -int i2c_del_driver(struct i2c_driver *); - -The i2c_{add,del}_driver functions must be called whenever a new module is -inserted with a chip driver in it, by the module initialization function. - - -int i2c_attach_client(struct i2c_client *); -int i2c_detach_client(struct i2c_client *); - -The i2c_{attach,detach}_client functions must be called if you have detected -a single chip. - - -Module smbus.o -============== - -This module offers support for SMBus operation. An SMBus adapter can either -accept SMBus commands (like the PIIX4), or be in fact an I2C driver. In -the last case, all SMBus commands will be expressed through I2C primitives. -This means that any I2C adapter driver will automatically be a SMBus -driver. - -At this point, it should be noted that there can only be one System -Management Bus in a given system (is this really true, by the way?). This -means there must be some way of selecting which of the many possible adapters -is in fact *the* SMBus. For now, I will ignore this problem. Later on, -we can add a hook somewhere in the i2c module to help us decide this. - -This module consists in fact of three separate parts: first of all, it extends -all i2c structs to accomodate the new smbus fields. Second, it defines a -new algorithm (smbus_algorithm), that will be used by all non-i2c adapters. -Finally, it implements a new access function that sends or receives SMBus -commands; these are either translated into I2C commands or sent to the -SMBus driver. - - -A driver, client and algorithm ------------------------------- - -We will not need to extend i2c_driver, i2c_client or i2c_adapter. This means -that struct smbus_driver is exactly the same as struct i2c_driver, and -struct smbus_client is the same as struct i2c_client, and smbus_adapter is -the same as struct i2c_adapter. We *will* define the smbus_* variants, and -use them within this module, so it should be easy to extend them after all. - -Note that at this moment, 10 bit SMBus addresses seem to be only -partially supported by the i2c module. We will ignore this issue for -now. - - -An adapter ------------- - -struct smbus_adapter { - char name[32]; - unsigned int id; - struct smbus_algorithm *algo; - void *data; -#ifdef SPINLOCK - spinlock_t lock; - unsigned long lockflags; -#else - struct semaphore lock; -#endif - unsigned int flags; - struct smbus_client *clients[I2C_CLIENT_MAX]; - int client_count; - int timeout; - int retries; - - /* Here ended i2c_adapter */ - s32 (* smbus_access) (__u8 addr, char read_write, - __u8 command, int size, union smbus_data * data); -} - -A description of the above struct: - smbus_access: A function to access the SMBus. It is only used for non-i2c - smbus adapters. - - -Access functions ----------------- - -All these functions are defined extern. - -The i2c access function should not be used within SMBus chip drivers, as -they might not be defined (for the PIIX4, for example). Instead, use the -following general access function, or one of the easier functions based -on it: - -int smbus_access (struct i2c_adapter *, __u8 addr, char read_write, - __u8 command, int size, union smbus_data * data); - -There are specific SMBus registration functions too, like the i2c ones. -They are fully compatiable with each other; just substitute 'smbus' for -'i2c' everywhere in the i2c description. - -int i2c_is_smbus_client(struct i2c_client *); -int i2c_is_smbus_adapter(struct i2c_adapter *); - -Decide whether this client, or adapter, is (on) a non-I2C SMBus. Usually -not needed, but it is nice anyway to be able to decide this. - - -Module isa.o -============ - -This module implements a new algorithm and a specific adapter for the -(single) ISA bus in your computer. This makes writing drivers for chips -that can be both on ISA and SMBus much easier. - -Note that this module does *not* in any way depend on smbus.o (previous -versions of this document still assumed it would be build upon it; this -is no longer true). - - -A driver, adapter or algorithm ------------------------------- - -We will not need to extend i2c_driver, i2c_adapter or i2c_algorithm. This -means that struct isa_driver is exactly the same as struct i2c_driver, -struct isa_adapter is the same as struct i2c_adapter and struct isa_algorithm -is the same as struct isa_driver. We *will* define the isa_* variants, and -use them within this module, so it should be easy to extend them after all. - - -A client --------- - -struct isa_client { - char name[32]; - int id; - unsigned int flags; - unsigned char addr; - struct isa_adapter *adapter; - struct isa_driver *driver; - void *data; - - unsigned int isa_addr; -} - -A client is a specific sensor chip. Its operation is controlled by a driver -(which describes a type of sensor chip), and it is connected to an adapter -(a bus, the (single) ISA bus here). - -A description of the above struct: - isa_addr: ISA addresses do not fit in the i2c-compatible addr field, so - we needed a new field. - - -Access functions ----------------- - -All these functions are defined extern. - -In case of the ISA bus, the master_xfer, slave_send and slave_recv hooks -will be NULL, because these functions make no sense. It is regrettably -not easy to create an access abstraction in which both ISA bus access -and SMBus access are united. See below for examples how you can solve -this problem. - -The most imporant additional access function: - -int i2c_is_isa_client(struct i2c_client *); -int i2c_is_isa_adapter(struct i2c_adapter *); - -Decide whether this client, or adapter, is (on) the ISA bus. This is -important, because it determines whether we can use the SMBus access -routines. - -As an example, I will here implement our old LM78 access function: - -/* The SMBus locks itself, but ISA access must be locked explicitly! - We ignore the LM78 BUSY flag at this moment - it could lead to deadlocks, - would slow down the LM78 access and should not be necessary. - There are some ugly typecasts here, but the good new is - they should - nowhere else be necessary! */ -int lm78_read_value(struct i2c_client *client, u8 reg) -{ - int res; - if (i2c_is_isa_client(client)) { - down((struct semaphore *) (client->data)); - outb_p(reg,(((struct isa_client *) client)->isa_addr) + - LM78_ADDR_REG_OFFSET); - res = inb_p((((struct isa_client *) client)->isa_addr) + - LM78_DATA_REG_OFFSET); - up((struct semaphore *) (client->data)); - return res; - } else - return smbus_read_byte_data(client->adapter,client->addr, reg); -} diff --git a/doc/developers/lm_sensors.lsm b/doc/developers/lm_sensors.lsm new file mode 100644 index 00000000..1b934689 --- /dev/null +++ b/doc/developers/lm_sensors.lsm @@ -0,0 +1,18 @@ +Begin4 +Title: lm_sensors +Version: 3.0.3 +Entered-date: 2008-09-28 +Description: Hardware health monitoring package for Linux. It consists of + a library to allow applications to read sensors data more + easily, and of an example program to pretty print this data. + Also included is a fan speed control script. + http://www.lm-sensors.org/ +Keywords: sensors health hardware-monitoring fan-speed +Author: khali@linux-fr.org (Jean Delvare) +Maintained-by: khali@linux-fr.org (Jean Delvare) +Primary-site: http://dl.lm-sensors.org /lm-sensors/releases/ + lm_sensors-3.0.3.tar.bz2 + lm_sensors-3.0.3.tar.bz2.sig +Alternate-site: ftp.netroedge.com /pub/lm-sensors/ +Copying-policy: GPL +End diff --git a/doc/developers/makefiles b/doc/developers/makefiles index 8d285fdc..29d3795a 100644 --- a/doc/developers/makefiles +++ b/doc/developers/makefiles @@ -9,24 +9,15 @@ included files are called 'Module.mk'. There are several interesting targets defined through this Makefile: * all Create everything in all directories. - * user - Build only user-space tools. * install Install everything from all directories. - * user_install - Install only user-space tools. - * user_uninstall - Uninstall user-space tools. + * uninstall + Uninstall everything. * clean Remove anything which can be regenerated from all directories. A call of 'make clean' (without any other targets) will ignore any .d files; this is useful when they are out of date (and prevent the calling of any other target). - * version - Regenerate version.h, using the current date for the date-stamp, and - a user-supplied version number. - * package - Create a .tar.gz file containing everything except the SVN directories. The best way to understand the Module.mk subfiles is to examine one of them, for example lib/Module.mk. They are not too difficult to understand. @@ -43,25 +34,21 @@ ones for developers: only output more information, and never make the code mis-behave. Several files are generated by Makefiles: - * .d - Dependency files for modules. Automatically generated. * .rd Dependency files for executables. Automatically generated. * .ad Dependency files for static libraries. Automatically generated. * .ld Dependency files for shared libraries. Automatically generated. - * .o - Generated modules * .ro Object files for executables. They will be linked together to create - the executable. This extension is used to distinguish them from - modules (which end on .o). Also, using a different extensions makes - the Makefile fragments much simpler. + the executable. * .ao Object files for static libraries * .lo Object files for shared libraries +The reason for using different extensions is to make the Makefile much +simpler. There are lots of comments within the main Makefile. Please read them if you want to know more. diff --git a/doc/developers/new_drivers b/doc/developers/new_drivers deleted file mode 100644 index 014b5447..00000000 --- a/doc/developers/new_drivers +++ /dev/null @@ -1,191 +0,0 @@ -These are the steps you should follow to write a new driver and -submit it to us so that it will be applied cleanly to our package. -See at the bottom for adding new chip support to an existing driver. - -Don't be intimidated by the list, it's just here so we don't -forget anything. -We are more than happy to help you with any part of the process. - -There are two types of drivers, chip and bus. -Steps which apply to only one type of driver are noted. - -These instructions are for 2.4-kernel-compatible drivers. -If you wish to write a driver for 2.6 only, not all of the following -steps apply. - ---------------------------------------------------------------------- - -* Check our "New Drivers" page for status!! - -* Contact us. - You are of course free to write your own drivers, but it is smart to - check first nobody else is already working on it, in case the - New Drivers page is out of date. - Tell us it's OK to put your name on the "New Drivers" page. - -* Consider subscribing to the mailing list. - -* Check out our latest code from SVN. - You should use this as a base for your development. - See instructions on our download page. - -* Write the new driver. - If you write a driver for a device that is similar to one we already - support, use the other device driver as a template. If you don't know - which one to use, either ask us or use the following defaults. - For a chip driver, use lm78.c as template. For an SMBus-only adapter, - use i2c-piix4.c. Use i2c-via.c for an I2C-level adapter ('bit banger'). - Usually, we make all prefixes start with the driver name. This is not - really necessary, as these symbols will not be exported anyway. But by - doing this, you are sure you do not shadow any global kernel names. - -* A quick note about conversions. The conversions which are specified - in the sensor chip datasheet and which *cannot* vary from one board to - the next are performed by the driver. If other conversions are - necessary, they are performed in user-space. - -* Meet Kernel coding standards. - See Documentation/CodingStyle in the kernel source. - Be sure and use 8 column tabs. - Also, please do not use // comments. - Also, please do not go past column 80. - Also, please use C99 struct initializers {.foo = blat} - Please do this _before_ you check in your driver. - -* Meet /proc naming standards in the ctl_table (for chip drivers only). - See doc/developers/proc for information. Please do not deviate from - this without discussion. - -* Add the driver to the Module.mk (the makefile). - Usually, you can just add it to KERNEL{CHIPS,DRIVERS}TARGETS in the - Module.mk file in the directory itself. Put it at the beginning, - where the comment says to put drivers NOT included in mkpatch. - -* Make sure it compiles cleanly. - Check compilation with 'make DEBUG=1' if you use debugging - information. Remember, things put between #ifdef DEBUG #endif may never - stop the driver from functioning; they should just output additional - information. - -* Check for external symbols. - 'nm --extern --defined' should only output symbols starting with __module, - cleanup_module, init_module and some kernel versioning symbols. Mark all - other symbols as static in your source file. - -* Test the module. - Test with a recent 2.4 kernel. - For bus drivers, use i2cdetect and i2cdump. For i2cdump, test all supported - bus access modes (see i2cdump man page). - For chip drivers, cat all files in applicable /proc or /sys directory - and check for problems. Write all supported settings. - Check ALARM indications. - -* Add detection information to prog/detect/sensors-detect. - This is a perl script that automatically detects what chips and adapters - are present. Contact us if you need help. - -* Add chip information to lib/chips.{c,h} (for chip drivers only). - Until you have done this, the chip will be invisible for user-level - programs which use libsensors. Use standard names in lib/chips.c; - see also the comments in etc/sensors.conf.eg for help. - Contact us if you need more assistance. - -* Be sure that SYSCTL and ALARM definitions in the driver are bracketed - by the special comments so that the kernel/include/sensors.h - file, which is generated automatically, contains your definitions. - (for chip drivers only) - -* Add a procedure to prog/sensors/chips.[ch] (for chip drivers only). - This is a function specific for your driver that - makes the included 'sensors' program pretty-print your chip information. - -* Add an line for the procedure in the matches[] table in - prog/sensors/main.c (for chip drivers only). - This tells sensors to call your new procedure when the chip name matches. - -* Add entries to etc/sensors.conf.eg (for chip drivers only). - If needed, you can set defaults here. - -* Test the userspace apps (sensors-detect and sensors). - Test setting limits with sensors -s. - -* Add the name of the device to the README file. - -* Add your name to the CONTRIBUTORS file. - -* Add entries to the CHANGES file. Please keep in alphabetical order. - -* Write a doc/chips/xxx or doc/busses/xxx file. - -* Add entry to doc/chips/SUMMARY (for chip drivers only). - -* Clearly specify licensing and copyright. - Make sure the GPL boilerplate and your name - (or if applicable your company's name) is at the top of the - new driver so we know you are giving it to us under the GPL. - -* Submit the changes to us. - Do a 'svn update' to get in sync (things will have changed since - you started), then submit the changes to us as a patch against SVN. - -* If you want to have your driver integrated to Linux 2.6, you have to - port your driver to the new sysfs interface. Once done and preferably - after testing, submit a patch to our mailing list: see - http://www.lm-sensors.org/wiki/AuthorsAndContributors - Make sure to check the current status for your driver first: - http://www.lm-sensors.org/wiki/Kernel2.6 - http://www.lm-sensors.org/wiki/Devices - ---------------------------------------------------------------------- -Checklist for us to do on the webpage: - -* Add entry to 'supported drivers' page - -* Update entry on 'new drivers' page - ---------------------------------------------------------------------- -Checklist for mkpatch support, after the driver is tested and stable: - -* Add .c file to mkpatch/FILES. - -* Add makefile entry in mkpatch/mkpatch.pl (2 places - old and new formats). - (don't bother with old format, obsolete) - -* Add config help to mkpatch/mkpatch.pl. - -* Add config entry to mkpatch/Config.in (chip drivers only) - -* Add config entry in mkpatch/mkpatch.pl (bus drivers only) - -* Move .o reference in kernel/[chips,busses]/Module.mk - from first to second section. - - ---------------------------------------------------------------------- -Checklist for _adding_ support for a chip to an _existing_ driver: - -* Make the changes to the driver itself. - -* Add detection information to prog/detect/sensors-detect. - -* Add a strncmp() call for the new prefix in prog/sensors/main.c - (chip drivers only). - -* Add entries for the new prefix to etc/sensors.conf.eg (chip drivers only). - -* Update config help in mkpatch/mkpatch.pl. - -* Update config entry in mkpatch/Config.in (chip drivers only) - -* Update config entry in mkpatch/mkpatch.pl (bus drivers only) - -* Update doc/[chips,busses]/xxx file - -* Update doc/chips/SUMMARY file (chip drivers only) - -* Update list in README - -* Submit the changes as a patch or check them in - -* Update entry on 'new drivers' page - diff --git a/doc/developers/proc b/doc/developers/proc deleted file mode 100644 index 9286febb..00000000 --- a/doc/developers/proc +++ /dev/null @@ -1,145 +0,0 @@ -Naming and data format standards under /proc --------------------------------------------- - -The libsensors library offers an interface to the raw sensors data -through the sysctl interface. See the doc/developers/sysctl -and the libsensors source for further information. - -An alternative method that some programs use is to access the /proc -files directly. This document briefly describes the standards that -the drivers follow, so that an application program can scan for -entries and access this data in a simple and consistent way. - -Note that not all chip drivers adhere to this standard. -We will attempt to migrate older drivers to this standard, -and ensure that new drivers follow this standard wherever possible. -If you are developing a userspace application please send us -feedback on this standard. - -Note that motherboards vary widely in the connections to sensor chips. -There is no standard that ensures, for example, that the second -temperature sensor is connected to the CPU, or that the second -fan is on the CPU. Therefore, programs must provide a facility -for the user to label or bind /proc entries for display. -Sensor chips often have unused inputs that should be ignored -by user programs. - -Each chip gets its own directory under /proc/sys/dev/sensors. -The format is either chip-i2c-bus-hexaddress or chip-isa-hexaddress. -(Exception - chip lm78-j has a '-' in it - should this be changed??) -New dummy drivers may present chips as chip-busname-hexaddress. - -All /proc values are integers or floating point numbers. -There is no facility in the lm_sensors package for drivers -to output general strings via /proc. This facility may be added -in the future. - -Alarms are direct indications read from the chips. The drivers do NOT make -comparisons of readings to thresholds. This allows violations -between readings to be caught and alarmed. The exact definition of -an alarm (for example, whether a threshold must be met or must be -exceeded to cause an alarm) is chip-dependent. - -Guidelines for new entries: - - If there are multiple values, some r/w and some r/o, - put the r/w ones first. - - Additional non-standard values should be after the standard values. - - - -------------------------------------------------------------------------- - -/proc entries are as follows: - - -Entry Values Function ------ ------ -------- -alarms 1 Alarm bitmask. - Read only. - Integer representation of one to four bytes. - A '1' bit means an alarm. - Chips should be programmed for 'comparator' mode so that - the alarm will 'come back' after you read the register - if it is still valid. - Generally a direct representation of a chip's internal - alarm registers; there is no standard for the position - of individual bits. - Bits are defined in kernel/include/sensors.h. - -beep 2 Beep/interrupt enable and bitmask. - The first value is 0 or 1 to globally disable - or enable the beeps. - The second value is a bitmask, with the - same format as 'alarms' with same bit locations. - -curr[1-n] 3 Current max, min or hysteresis, and input value. - Floating point values XX.X or XX.XX in Amps. - The second value is preferably a hysteresis value, - reported as a absolute current, NOT a delta from - the max value. - First two values are read/write and third is read only. - -fan[1-3] 2 Fan minimum and input value. - Two integers indicating RPM. - First value is read/write and second is read only. - -fan_div 3 Fan divisor. - Integers in powers of two (1,2,4,8,16,32,64,128). - Some chips only support values 1,2,4,8. - Entries correspond to the fans[1-3]. - See doc/fan-divisors for details. - -in[0-8] 3 Voltage min, max, and input value. - Floating point values X.XX in volts from 0 to 4.01 volts. - Actual voltage depends on the scaling resistors on the - motherboard, as recommended in the chip datasheet. - This varies by chip and by motherboard. - Because of this variation, values are generally NOT scaled - by the chip driver, and must be done by the application. - However, some drivers (notably lm87 and via686a) - do scale, with various degrees of success. - These drivers will output the actual voltage. - First two values are read/write and third is read only. - Typical usage: - in0 CPU #1 voltage (not scaled) - in1 CPU #1 voltage (not scaled) - in2 3.3V nominal (not scaled) - in3 5.0V nominal (scaled) - in4 12.0V nominal (scaled) - in5 -12.0V nominal (scaled) - in6 -5.0V nominal (scaled) - in7 varies - in8 varies - -pwm[1-3] 1-2 Pulse width modulation fan control. - Integer 0 - 255, read/write. - 255 is max or 100%. - Corresponds to the fans 1-3. - Second value, if present, is an enable (0 or 1) - -sensor[1-3] 1 Sensor type selection. - Integers 1,2,3, or thermistor Beta value (3435); read/write. - -temp, -temp[1-4] 3 Temperature max, min or hysteresis, and input value. - Floating point values XXX.X or XXX.XX in degrees Celsius. - 'temp' is used if there is only one temperature sensor on the - chip; for multiple temps. start with 'temp1'. - Temp1 is generally the sensor inside the chip itself, - generally reported as "motherboard temperature". - Temp2 to temp4 are generally sensors external to the chip - itself, for example the thermal diode inside the CPU or a - termistor nearby. The second value is preferably a hysteresis - value, reported as a absolute temperature, NOT a delta from - the max value. - First two values are read/write and third is read only. - -vid 1 CPU core voltage. - Read only. - Floating point X.XX or X.XXX corresponding to CPU core voltage - as told to the sensor chip. Not always correct. - -vrm 1 Voltage Regulator Module version number. - "Floating point" X.X. Default 8.2. - Affects the way the driver calculates the core voltage from - the vid pins. See doc/vid for details. diff --git a/doc/developers/release_checklist b/doc/developers/release_checklist index be670a84..d6ba431e 100644 --- a/doc/developers/release_checklist +++ b/doc/developers/release_checklist @@ -2,35 +2,46 @@ CHECKLIST FOR NEW RELEASES ========================== Release steps: -- Check out i2c and lm-sensors +- Check out lm-sensors - Update if necessary, the version number of libsensors (edit lib/Module.mk and change LIBMAINVER and/or LIBMINORVER) Remember: update main number when interface changes, minor if new functionality is added, and patch if only bugs are fixed. `svn diff -r Vx-y-z lib' is your friend. -- Update both CHANGES files (add the release date) -- Verify i2c dependency instructions in README, QUICKSTART, and INSTALL, - update if necessary -- Update lm_sensors2/version.h and i2c/kernel/i2c.h +- Update the CHANGES file (set version and release date) +- Update lm_sensors.lsm (Version, Entered-date and Primary-site) +- Update libsensors-API.txt +- Update version.h - Commit - Tag the release using SVN: - svn copy http://lm-sensors.org/svn/lm-sensors/trunk \ - http://lm-sensors.org/svn/lm-sensors/tags/V2-x-x \ - -m "Create tag 'V2-x-x'." -- Remove 'SVN' related files/directories (e.g. rm -fR `find . -name .svn`) -- Rename i2c and lm_sensors2 to i2c-#.#.# and lm_sensors-#.#.# -- Tar it up and post it (sign it) -- Make sure the file permissions on both the archives and the signatures - are correct (664) + svn copy http://lm-sensors.org/svn/lm-sensors/branches/lm-sensors-3.0.0 \ + http://lm-sensors.org/svn/lm-sensors/tags/V3-x-x \ + -m "3.x.x release" + +- Move to a temporary directory and get a copy of the freshly tagged code: + svn export http://lm-sensors.org/svn/lm-sensors/tags/V3-x-x lm_sensors-3.x.x +- Tar it up: + tar jcf lm_sensors-3.x.x.tar.bz2 lm_sensors-3.x.x +- Sign it: + gpg -b lm_sensors-3.x.x.tar.bz2 +- Post it: + scp lm_sensors-3.x.x.tar.bz2* \ + devel.atrpms.net:/srv/lm-sensors.org/dl/lm-sensors/releases +- Set correct permissions: + ssh devel.atrpms.net chmod 664 \ + '/srv/lm-sensors.org/dl/lm-sensors/releases/lm_sensors-3.x.x.tar.bz2*' After release, remember to: - Copy to mirrors +- Update the Download page on lm-sensors.org, then add a news item +- Announce on the lm-sensors mailing list - Announce on Freshmeat -- Put back ???? for dates -- Prep CHANGES files for next release +- Add "+SVN" to version.h and commit - Mark the corresponding release milestone as complete using trac-admin - e.g. 'trac-admin /srv/lm-sensors.org/trac milestone completed 2.10.2 2006-12-31' + e.g. 'trac-admin /srv/lm-sensors.org/trac milestone completed 3.0.0 now' - Create a new version for the bug tracking system using trac-admin - e.g. 'trac-admin /srv/lm-sensors.org/trac version add 2.10.2 2006-12-31' + e.g. 'trac-admin /srv/lm-sensors.org/trac version add 3.0.0 now' - Create a new release milestone using trac-admin - e.g. 'trac-admin /srv/lm-sensors.org/trac milestone add 2.10.3 2007-03-31' + e.g. 'trac-admin /srv/lm-sensors.org/trac milestone add 3.0.1 2008-02-15' +- Send lm_sensors.lsm to the LSM by mailing it to lsm@qqx.org with the + subject `add' (no quotes) diff --git a/doc/developers/sysctl b/doc/developers/sysctl deleted file mode 100644 index 4c6532f2..00000000 --- a/doc/developers/sysctl +++ /dev/null @@ -1,16 +0,0 @@ -You can access everything under /proc/sys through the sysctl interface. This -is mostly useful for C programs, which can use the sysctl function. Try -'man 2 sysctl' for more information. - -As each chip gets its own directory under /proc/sys/dev/sensors, you must -somehow know the sysctl id of these directories to access the sensor data. -This is done through the file /proc/sys/dev/sensors/chips (see sensors.h -for the corresponding SYSCTL ids). You can only read this file; it -returns an array of struct sensors_chips_data, as defined in sensors.h. -Each chip will have its own entry here, with both its sysctl id and -the corresponding /proc name. - -Generally, it is a better idea to use the new libsensors to access this -data. If you feel you need more than the library offers, please mail us, -so we can either add the new functionality to the library, or explain how -you can work around it. diff --git a/doc/developers/sysfs-interface b/doc/developers/sysfs-interface deleted file mode 100644 index 00196f2e..00000000 --- a/doc/developers/sysfs-interface +++ /dev/null @@ -1,10 +0,0 @@ -sysfs access (2.6 kernels) --------------------------- - -In the 2.6 kernel, sensor chip drivers create subdirectories in -the sysfs filesystem (usually /sys) which can be accessed -directly by applications, or through libsensors as before. - -Naming and content standards for the entries in these subdirectories -is documented in the file Documentation/hwmon/sysfs-interface in the -2.6 kernel source tree. diff --git a/doc/fan-divisors b/doc/fan-divisors index 4694cc14..4da50a4b 100644 --- a/doc/fan-divisors +++ b/doc/fan-divisors @@ -47,7 +47,7 @@ How to change fan divisors -------------------------- Put an entry "set fanN_div X" in the appropriate section of -/etc/sensors.conf and run 'sensors -s' +/etc/sensors3.conf and run 'sensors -s' (N is the number of the fan, and X is the divisor you want). @@ -87,7 +87,7 @@ outputs 4 pulses by revolution, instead of the standard 2. As we learned above, you can _not_ fix this by changing the fan divisor. You must add entries into the appropriate -section of /etc/sensors.conf: +section of /etc/sensors3.conf: compute fanN @/2, 2*@ diff --git a/doc/fancontrol.txt b/doc/fancontrol.txt index eee5bf49..e37f9e0b 100644 --- a/doc/fancontrol.txt +++ b/doc/fancontrol.txt @@ -7,8 +7,7 @@ Introduction fancontrol is a shellscript for use with lm_sensors. It reads its configuration from a file, then calculates fan speeds from temperatures and sets the corresponding pwm outputs to the computed values. It is included in -lm_sensors since 2.8.0, the latest version is always available through SVN or -at http://www.hdev.de/fancontrol/ For easy configuration, there's a script +lm_sensors since version 2.8.0. For easy configuration, there's a script named pwmconfig which lets you interactively write your configuration file for fancontrol. Alternatively you can write this file yourself using the information from the configuration section of this document. diff --git a/doc/kernel/file_operations b/doc/kernel/file_operations deleted file mode 100644 index cfd9445b..00000000 --- a/doc/kernel/file_operations +++ /dev/null @@ -1,91 +0,0 @@ -This file documents the changes in struct file_operations throughout the 2.1 -kernel series. - -Kernels 2.0.x: - -struct file_operations { - int (*lseek) (struct inode *, struct file *, off_t, int); - int (*read) (struct inode *, struct file *, char *, int); - int (*write) (struct inode *, struct file *, const char *, int); - int (*readdir) (struct inode *, struct file *, void *, filldir_t); - int (*select) (struct inode *, struct file *, int, select_table *); - int (*ioctl) (struct inode *, struct file *, unsigned int, - unsigned long); - int (*mmap) (struct inode *, struct file *, struct vm_area_struct *); - int (*open) (struct inode *, struct file *); - void (*release) (struct inode *, struct file *); - int (*fsync) (struct inode *, struct file *); - int (*fasync) (struct inode *, struct file *, int); - int (*check_media_change) (kdev_t dev); - int (*revalidate) (kdev_t dev); -}; - - -Kernel 2.1.0: - -- int (*lseek) (struct inode *, struct file *, off_t, int); -+ long long (*llseek) (struct inode *, struct file *, long long, int); -- int (*read) (struct inode *, struct file *, char *, int); -+ long (*read) (struct inode *, struct file *, char *, unsigned long); -- int (*write) (struct inode *, struct file *, const char *, int); -+ long (*write) (struct inode *, struct file *, const char *, unsigned lon - - -Kernel 2.1.23: - -- int (*select) (struct inode *, struct file *, int, select_table *); -+ unsigned int (*poll) (struct file *, poll_table *); -[The lock field is added behind the revalidate field] -+ int (*lock) (struct inode *, struct file *, int, struct file_lock *); - - -Kernel 2.1.31: - -- void (*release) (struct inode *, struct file *); -+ int (*release) (struct inode *, struct file *); - - -Kernel 2.1.55: - -- int (*readdir) (struct inode *, struct file *, void *, filldir_t); -+ int (*readdir) (struct file *, void *, filldir_t); - - -Kernel 2.1.56: - -- long long (*llseek) (struct inode *, struct file *, long long, int); -+ long long (*llseek) (struct file *, long long, int); -- int (*mmap) (struct inode *, struct file *, struct vm_area_struct *); -+ int (*mmap) (struct file *, struct vm_area_struct *); -- int (*fsync) (struct inode *, struct file *); -+ int (*fsync) (struct file *, struct dentry *); -- int (*fasync) (struct inode *, struct file *, int); -+ int (*fasync) (struct file *, int); -- int (*lock) (struct inode *, struct file *, int, struct file_lock *); -+ int (*lock) (struct file *, int, struct file_lock *); - - -Kernel 2.1.70: - -- long long (*llseek) (struct file *, long long, int); -+ loff_t (*llseek) (struct file *, loff_t, int); -- long (*read) (struct inode *, struct file *, char *, unsigned long); -+ ssize_t (*read) (struct file *, char *, size_t, loff_t *); -- long (*write) (struct inode *, struct file *, const char *, - unsigned long); -+ ssize_t (*write) (struct file *, const char *, size_t, loff_t *); - - -Kernel 2.1.72: - -- unsigned int (*poll) (struct file *, poll_table *); -+ unsigned int (*poll) (struct file *, struct poll_table_struct *); - - -Kernel 2.1.118: - -[The flush field is added behind the open field -- stupid...] -+ int (*flush) (struct file *); - - -Last kernel checked: 2.2.0-pre4. diff --git a/doc/kernel/proc_dir_entry b/doc/kernel/proc_dir_entry deleted file mode 100644 index 9763d15e..00000000 --- a/doc/kernel/proc_dir_entry +++ /dev/null @@ -1,145 +0,0 @@ -This file documents how to handle the callback function that returns the -information displayed in a (non-/proc/sys) /proc file. - -For kernels before 2.1.29, you have to declare a proc_dir_entry, with -in the get_info field the procedure handler. For kernels 2.1.29 and later, -you can use the create_proc_entry function and assign a new value (the -procedure handler address) to the read_proc field: - - - -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,29) - static int read_bus_i2c(char *buf, char **start, off_t offset, int len, - int unused); - static struct proc_dir_entry proc_bus_i2c_dir = - { - /* low_ino */ 0, /* Set by proc_register_dynamic */ - /* namelen */ 3, /* The length of the name field */ - /* name */ "i2c", - /* mode */ S_IRUGO | S_IFREG, - /* nlink */ 1, - /* uid */ 0, - /* gid */ 0, - /* size */ 0, - /* ops */ NULL, - /* get_info */ &read_bus_i2c - }; - -#else /* LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,29) - static int read_bus_i2c(char *buf, char **start, off_t offset, int len, - int *eof , void *private); -#endif - - - /* This code fragment is part of the initialization code. You should do - several safety checks, like whether create_proc_entry does not return - NULL. */ -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,29) - proc_register_dynamic(&proc_root, &proc_bus_i2c_dir); -#else /* LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,29) - proc_bus_i2c = create_proc_entry("i2c",0,proc_root); - proc_bus_i2c->read_proc = &read_bus_i2c; -#endif - - - -Now for the function itself. - - LINUX KERNEL 2.0.x, and 2.1.x upto 2.1.28 - ========================================= - This function is known as the get_info function. - - int get_info(char *buf, char **start, off_t offset, int len, int unused); - - (INPUT) - buf: A kernel-space buffer where we can put the information. - len: The buffer length (we have a bit of slack here: if we write - 'a little' beyond this, things will still work out) - (OUTPUT) - *buf: The complete contents of the /proc file, starting at the - beginning. - return value: the number of chars written to buf. - - This is all you have to do if all information fits in the buffer (it is - about 3K in length). You can safely ignore offset and start in this case. - - If your /proc entry gets larger, you have to do a bit more work. - - (INPUT) - buf: See above - len: see above - offset: The offset from the beginning of the /proc file where the user - wants to start reading - (OUTPUT) - *buf: A part of the /proc file. The requested information does not - have to start at the beginning. - start: this is the place within buf where the information starts (ie. - you must use offset to compute this!). - return value: The number of valid characters written to buf. Begin - counting at start, not at buf! - - You do not have to worry about not the whole information being in buf. - Another call will be done (with a higher offset value) if more is - needed. - - - LINUX KERNEL 2.1.x, from 2.1.29 upwards - ======================================= - - This function is known as the read_proc function. - - int read_proc(char *buf, char **start, off_t offset, int len, int *eof, - void *private); - (INPUT) - buf: A kernel-space buffer where we can put the information. - len: The buffer length (we have a bit of slack here: if we write - 'a little' beyond this, things will still work out) - (OUTPUT) - *buf: The complete contents of the /proc file, starting at the - beginning. - eof: You can set this to true (anything but 0) to indicate we have - reached the end of the file with this read. Not strictly - necessary, but it is more efficient (else this function may be - called again). - return value: The number of valid characters written to buf. Begin - counting at start, not at buf! - - If your /proc entry gets larger, you have to do a bit more work. - - (INPUT) - buf: See above - len: See above - offset: The offset from the beginning of the /proc file where the user - wants to start reading - (OUTPUT) - *buf: A part of the /proc file. The requested information does not - have to start at the beginning. - eof: See above - start: this is the place within buf where the information starts (ie. - you must use offset to compute this!). - return value: The number of valid characters written to buf. - - You do not have to worry about not the whole information being in buf. - Another call will be done (with a higher offset value) if more is - needed. Ignore private. - - A third way to do this: - - (INPUT) - buf: See above - len: See above - offset: The offset from the beginning of the /proc file where the user - wants to start reading - (OUTPUT) - *buf: A part of the /proc file, with the requested information starting - at the beginning. - eof: See above - start: (long)start is added to the offset pointer after reading. This - allows you to play tricks with the file offset, independent of - the number of read bytes. - return value: the number of chars written to buf. - - -This document was written by Frodo Looijaard . I do not -accept any responsibility for omissions or errors, but you are free to -drop me a note if something is wrong or if you miss something. diff --git a/doc/libsensors-API.txt b/doc/libsensors-API.txt new file mode 100644 index 00000000..329d5461 --- /dev/null +++ b/doc/libsensors-API.txt @@ -0,0 +1,41 @@ +libsensors API history +====================== + +SENSORS_API_VERSION tracks the evolutions made to the libsensors API +over time. This document summarizes these evolutions so that application +authors can quickly figure out how to test for the availability of a +given new feature. + +0x402 lm-sensors SVN +* Added bus type "acpi": + #define SENSORS_BUS_TYPE_ACPI +* Added support for instantaneous power sensors + enum sensors_subfeature_type SENSORS_SUBFEATURE_POWER_INPUT + enum sensors_subfeature_type SENSORS_SUBFEATURE_POWER_INPUT_HIGHEST + enum sensors_subfeature_type SENSORS_SUBFEATURE_POWER_INPUT_LOWEST +* Added support for current sensors + enum sensors_feature_type SENSORS_FEATURE_CURR + enum sensors_subfeature_type SENSORS_SUBFEATURE_CURR_INPUT + enum sensors_subfeature_type SENSORS_SUBFEATURE_CURR_MIN + enum sensors_subfeature_type SENSORS_SUBFEATURE_CURR_MAX + enum sensors_subfeature_type SENSORS_SUBFEATURE_CURR_ALARM + enum sensors_subfeature_type SENSORS_SUBFEATURE_CURR_MIN_ALARM + enum sensors_subfeature_type SENSORS_SUBFEATURE_CURR_MAX_ALARM + enum sensors_subfeature_type SENSORS_SUBFEATURE_CURR_BEEP +* Added error value for excessive recursion depth + #define SENSORS_ERR_RECURSION 11 + +0x401 lm-sensors 3.0.2 to 3.0.3 +* Added bus type "virtual": + #define SENSORS_BUS_TYPE_VIRTUAL +* Added support for power and energy sensors + enum sensors_feature_type SENSORS_FEATURE_POWER + enum sensors_feature_type SENSORS_FEATURE_ENERGY + enum sensors_subfeature_type SENSORS_SUBFEATURE_POWER_AVERAGE + enum sensors_subfeature_type SENSORS_SUBFEATURE_POWER_AVERAGE_HIGHEST + enum sensors_subfeature_type SENSORS_SUBFEATURE_POWER_AVERAGE_LOWEST + enum sensors_subfeature_type SENSORS_SUBFEATURE_POWER_AVERAGE_INTERVAL + enum sensors_subfeature_type SENSORS_SUBFEATURE_ENERGY_INPUT + +0x400 lm-sensors 3.0.0 to 3.0.1 +* Initial API. diff --git a/doc/lm_sensors-FAQ.html b/doc/lm_sensors-FAQ.html deleted file mode 100644 index 5527e455..00000000 --- a/doc/lm_sensors-FAQ.html +++ /dev/null @@ -1,2365 +0,0 @@ - - -Sensors FAQ for lm_sensors version 2.18 - - - - - - - - - -

Sensors FAQ for lm_sensors version 2.18

-Copyright (C) 1998 - 2005
-Frodo Looijaard,
-Philip Edelbrock,
-Mark D. Studebaker
-and
-Jean Delvare
- - - -
-

Table of Contents

- -
- -
-


- -Next: , -Up: (dir) - -
- -

lm_sensors

- -

The lm_sensors package includes a collection of modules for general SMBus -access and hardware monitoring. NOTE: this requires special support which -is not in standard 2.2-vintage kernels. - -

- -
-


- -Next: , -Previous: Top, -Up: Top - -
- -

1 PC and Sensor Overview

- - - -
-


- - -Next: , -Up: Overview - -
- -

1.1 What sensors are available on my PC?

- -

Most PC's built since late 1997 now come with a -hardware health monitoring chip. This chip may be accessed via the -ISA bus or the SMBus, depending on the motherboard. - -

Some motherboard chipsets, notably the Via 686 and the SiS 5595, -contain hardware monitor functions. - -

This FAQ frequently refers to the "LM78". This chip has been -obsoleted by National Semiconductor. Most motherboards today contain -a chip with similar functions. - -

-


- - -Next: , -Previous: Section 1.1, -Up: Overview - -
- -

1.2 What can a sensor chip like the "LM78" do?

- -

The LM78 is a chip made by National Semiconductor which can monitor 7 -voltages (5 positive, 2 negative) from 0 to 4.08V. The inputs are usually in -series with voltage dividers which lower the +/- 12V and +/- 5V supplies to -measurable range. Therefore, the readings for such inputs need to be -re-scaled appropriately by software. - -

The LM78 also has 3 fan speed monitoring inputs, an internal -temperature sensor, a chassis intrusion sensor, and a couple maskable interrupt -inputs. The LM78 can also relay the processor's (P6 or Pent II) VID lines -which are hardwired and used to indicate to the power regulator (usually on -the mainboard close to the processor socket/slot) what voltage to supply to -the processor. - -

The LM78 can be interfaced to a system via the ISA bus and/or the -SMBus. - -

Most other sensor chips have comparable functionality. Each supported -chip is documented in the doc/chips directory. - -

-


- - -Previous: Section 1.2, -Up: Overview - -
- -

1.3 Where do I find out more about any of these chips?

- -

Most semiconductor companies have comprehensive documentation, -including complete datasheets, on their websites. Analog Devices, -Dallas Semiconductor, Maxim, and National Semiconductor have the widest selection -of sensor chips. Their websites are: - -

- -

Please see the file http://www.lm-sensors.org/wiki/UsefulLinks -for links to other companies' websites. - -

-


- -Next: , -Previous: Overview, -Up: Top - -
- -

2 Sensor and Bus Basics

- - - -
-


- - -Next: , -Up: Basics - -
- -

2.1 How are these sensors read?

- -

Sensor chips reside on either the ISA bus, the SMBus, or both. -See the file doc/chips/SUMMARY in our package for a list. - -

To communicate with chips on the ISA bus, the software uses -simple I/O reads and writes. - -

To communicate with chips on the SMBus, the software must -use an SMBus interface device, explained below. - -

-


- - -Next: , -Previous: Section 2.1, -Up: Basics - -
- -

2.2 What is the SMBus? And the I2C bus?

- -

The SMBus is the "System Management Bus". More specifically, it is a -2-wire, low-speed serial communication bus used for basic health monitoring -and hardware management. It is a specific implementation of the more -general I2C (pronunciation: I-squared-C) bus. In fact, both I2C devices -and SMBus devices may be connected to the same (I2C) bus. - -

The SMBus (or I2C bus) starts at the host controller, used for -starting transactions on the SMBus. From the host interface, the -devices communicated with are the slave devices. Each slave device has a -unique 7-bit address which the host uses to refer to that device. - -

For each supported SMBus host, there is a separate kernel module -which implements the communication protocol with the host. Some SMBus hosts -really operate on the SMBus level; these hosts can not cope with pure I2C -devices. Other hosts are in fact I2C hosts: in this case, we implement -the SMBus protocol in terms of I2C operations. But these hosts can also -talk to pure I2C devices. - -

-


- - -Next: , -Previous: Section 2.2, -Up: Basics - -
- -

2.3 I don't have an ISA bus!

- -

We promise, you do, even if you don't have any old ISA slots. -The "ISA Bus" exists in your computer even if you don't have ISA slots; -it is simply a memory-mapped area, 64KB in size (0x0000 - 0xFFFF) -where many "legacy" functions, such as keyboard and interrupt controllers, -are found. It isn't necessarily a separate physical bus. -See the file /proc/ioports for a list of devices living on -the "ISA Bus" in your system. If you don't like the term "ISA Bus" -think "I/O Space". - -

-


- - -Next: , -Previous: Section 2.3, -Up: Basics - -
- -

2.4 What sensors do processors have?

- -

Most new processors contain a thermal diode on the die itself. -The electical properties of all diodes and transistors vary -slightly with temperature. The thermal diode is exceptionally accurate -because it is directly on the die. Newer temperature sensor chips, -like the Analog Devices ADM1021 and clones, and the Winbond chips, -have circuitry for measuring the the electrical properties of -an external diode and converting this data to a temperature. -Any sensor chip listed in doc/chips/SUMMARY in our package which -has support for more than one temperature supports external temperature sensing. - -

Older motherboards and processors without this feature generally use -an LM75 placed close to the processor. This is much less accurate. - -

The Pentium 2 'boxed' processor usually has an LM75 very close to the -base of the box. It can be read through the SMBus to report the approximate -temperature of the processor. The processor also contains an internal -temperature sensor (of low accuracy) used as a fail-safe to disable the -processor in case it gets much too hot (usually around 130 degrees C). And, -the Pentium 2 also has a hard-wired signal (VID lines) on it's SEC (single -edge connector) which indicates what power supply is required to operate the -processor. - -

The P6 (Pentium-Pro) may have an LM75 in or just under the socket. -P6's also have VID lines. - -

Pentiums and Pentium w/ MMX do not have VID lines, and sometimes have -LM75's under the sockets (depends on the mainboard, and how 'modern' the -mainboard is). - -

The P2 Xeon was the first Intel processor to include the SMBus -interface on the P2 Xeon SEC. - -

-


- - -Next: , -Previous: Section 2.4, -Up: Basics - -
- -

2.5 How often are the sensor values updated?

- -

The LM78, and most other sensor chips like it, reads its sensors one -by one. A complete scanning sweep will take about 1.5 seconds. The LM78 stops -readings sensors if you try to access it, so if you access it very often -(by reading sensor values; writing new limits is safe) it will not find the -time to update its sensor values at all! Fortunately, the kernel module takes -care not to do this, and only reads new values each 1.5 seconds. If you -read the values again, you will get the 'old' values again. - -

-


- - -Previous: Section 2.5, -Up: Basics - -
- -

2.6 How are alarms triggered?

- -

It is possible to monitor each sensor and have an alarm go off if -it crosses some pre-determined limits. There are two sorts of interrupts -which can be generated by sensor chips if this happens (it depends a bit on -the actual chip if both are supported; the LM80, for example, has only -IRQ interrupts): IRQ interrupts and SMI interrupts. IRQ stands for -Interrupt Request and are the interrupt lines you can find in /proc/interrupts. -SMI stands for System Management Interrupt, and is a special interrupt which -puts the processor in a secure environment independent of any other things -running. SMI is currently not supported by the Linux kernel. IRQs are -supported, of course. - -

Even if no interrupt is generated, some bits in a status register -will be set until the register is read the next time. If the alarm condition -persists after that, the bits will be set on the next scanning sweep, etc. - -

Most drivers in our package do not support interrupts at this time. - -

-


- -Next: , -Previous: Basics, -Up: Top - -
- -

3 Installation and Management

- - - -
-


- - -Next: , -Up: Installation - -
- -

3.1 Why so many modules, and how do I cope with them?

- -

We tried to make this package as modular as possible. This makes it -easy to add new drivers, and unused drivers will take no precious kernel -space. On the other hand, it can be a bit confusing at first. - -

Here are two simple guidelines: -

    -
  • Run sensors-detect and do what it tells you. -
  • Always use modprobe, not insmod. -
- -

Further information is in doc/modules. - -

-


- - -Next: , -Previous: Section 3.1, -Up: Installation - -
- -

3.2 How do I know which chips I own?

- -

We have an excellent program that scans all your hardware. -It is called sensors-detect and is installed in /usr/local/sbin -by make install. Just execute this script, and it will tell you. - -

Chip detection in the drivers is fairly good. That means that it is -usually harmless to insert more chip drivers than you need. However, this -can still lead to problems, so we do not recommend it. - -

If sensors-detect didn't find any sensors, either you don't have -any, or the ones you have, we don't support. (Look at your motherboard -for candidates, then see Help) - -

- -

3.2.1 What chips are on motherboard XYZ?

- -

!!!!!!!!! YES THIS IS THE MOST FREQUENT QUESTION WE GET !!!!!!!!! - -

We have no idea. Here is what you should do: -

    -
  1. Run sensors-detect. -
- -

If that doesn't work: -

    -
  1. Look at your motherboard. -
  2. Check the manufacturer's website or ask their support -
  3. Check the -"links" -page on our website some good cross-references. -
- -

- -

3.2.2 Do you support motherboard XYZ?

- -

We don't support boards, we support chips. See What chips are on motherboard XYZ. - -

- -

3.2.3 Do you support chip XYZ?

- -

This we have good answers for. -

- -

- -

3.2.4 Anybody working on a driver for chip XYZ?

- -

Newest Driver Status: http://www.lm-sensors.org/wiki/Devices - -

-


- - -Next: , -Previous: Section 3.2, -Up: Installation - -
- -

3.3 Which modules should I insert?

- -

sensors-detect will tell you. Take the modprobe lines it -recommends and paste them into the appropriate /etc/rc.d/xxxx file -to be executed at startup. - -

You need one module for each sensor chip and bus adapter you own; -if there are sensor chips on the ISA bus, you also need i2c-isa.o. -for each type of chip you own. That's all. On my computer, I could use the -following lines: -

    -
  • modprobe i2c-isa -
  • modprobe i2c-piix4 -
  • modprobe lm78 -
  • modprobe lm75 -
  • modprobe i2c-dev -
  • sensors -s -
- -
-


- - -Next: , -Previous: Section 3.3, -Up: Installation - -
- -

3.4 Do I need the configuration file /etc/sensors.conf?

- -

Yes, for any applications that use libsensors, including the -sensors application included in our package. -It tells libsensors how to translate the values the chip -measures to real-world values. This is especially important for voltage -inputs. The default configuration file should usually do the trick. -It is automatically installed as /etc/sensors.conf, but it will not -overwrite any existing file with that name. - -

- -

3.4.1 The labels for the voltage and temperature readings in sensors are incorrect!

- -

Every motherboard is different. You can customize the labels -in the file /etc/sensors.conf. That's why it exists! -The default labelling (in lib/chips.c and /etc/sensors.conf) is just -a template. - -

- -

3.4.2 The min and max for the readings in sensors are incorrect!

- -

You can customize them in the file /etc/sensors.conf. See above. - -

- -

3.4.3 The min and max settings in /etc/sensors.conf didn't take effect!

- -

You forgot to run sensors -s. See above. - -

- -

3.4.4 One sensor isn't hooked up on my board!

- -

Use an ignore line in /etc/sensors.conf so it isn't -displayed in sensors. - -

- -

3.4.5 I need help with sensors.conf!

- -

There is detailed help at the top of that file. - -

- -

3.4.6 Do you have a database of sensors.conf entries for specific boards?

- -

No. Good idea though. If you would like to set one up on your website -send us mail and we will set up a link to it. - -

-


- - -Next: , -Previous: Section 3.4, -Up: Installation - -
- -

3.5 What about the ‘No such file or directory’ warnings when I compile?

- -

Don't worry about them. The dependency files (which tell which -files should be recompiled when certain files change) are created -dynamically. They are not distributed with the package. The make program -notices they are not there, and warns about that - and the first thing -it will do is generate them. So all is well. - -

-


- - -Next: , -Previous: Section 3.5, -Up: Installation - -
- -

3.6 I get all kinds of weird compilation errors?

- -

Check that the correct i2c header files are used. Depending on -how you installed, they should be under either /usr/local/include or -/usr/src/linux*/include. Try to edit the Makefile for the other setting. - -

- -

3.6.1 ‘No rule to make target xxxx needed by xxxx’ - how to fix?

- -
    -
  • See I get all kinds of weird compilation errors, also try make clean in lm_sensors. -
  • If that doesn't work, try make clean in i2c. -
  • If that doesn't work, try make clean in the kernel. -
  • Also make sure /usr/include/linux points to /usr/src/linux/include/linux. -
- -
-


- - -Next: , -Previous: Section 3.6, -Up: Installation - -
- -

3.7 It still does not compile or patch!

- -

Have you installed the matching version of the i2c package? Remember, -compilation is not enough, you also need to install it for the header -files to be found! - -

If you want to patch the kernel, you will have to apply the i2c -patches first! - -

-


- - -Next: , -Previous: Section 3.7, -Up: Installation - -
- -

3.8 make install fails on Mandrake kernels

- -

Mandrake uses a non-standard version.h file which confuses our Makefile. -Edit our Makefile on the MODDIR := line to hard-code the module directory. - -

-


- - -Next: , -Previous: Section 3.8, -Up: Installation - -
- -

3.9 I get unresolved symbols when I modprobe modules (Red Hat especially)

- -

Example: -

     *** Unresolved symbols in /lib/modules/2.4.5/kernel/drivers/i2c/i2c-i810.o
-     i2c_bit_add_bus_R8c3bc60e
-     i2c_bit_del_bus_R92b18f49
-
-

You can also run depmod -a -e to see all unresolved symbols. - -

These are module versioning problems. Generally you did not compile -against the kernel you are running. Sometimes the Red Hat source you -have is not for the kernel you are running. -You must compile our package against the source for the kernel you -are running with something like make LINUX=/usr/src/linux-2.4.14. - -

Try the following to be sure: - -

    -
  • nm --extern MODULE.o -Filter out the kernel symbols, like kmalloc, printk etc. and note the -number code behind them, like printk_R1b7d4074. If there is no numeric -code after them, note this too. -
  • grep SYMBOL /proc/ksyms -Substitute SYMBOL by the basename of the symbols above, like kmalloc, -printk etc. Note the number code behind them, or the lack thereof. -
  • Compare both sets of symbols. Are they the same? If so, the problem -lies somewhere else. Are they different? If so, you have a module -versioning problem. -
- -
-


- - -Previous: Section 3.9, -Up: Installation - -
- -

3.10 I2C_DRIVERID_ADM1024 undefined (Red Hat especially)

- -

In some versions of Redhat, an RPM is included to provide i2c support. -However, this RPM does not place the header files in the kernel directory -structure. When you update kernels, they may persist. To get rid of -these obsolete header files, at a command prompt: - -

    -
  1. rpm -qa | grep i2c -
  2. Look for kernel-i2c, or a similar rpm in the output -
  3. <as root> -rpm -ev kernel-i2c (or the name of the similar package) -If this complains about dependencies, you can try adding ---nodeps, but this *MAY* break something else. Not likely, -as you have upgraded kernels, and nothing should be using the -old i2c stuff anymore anyway. Just don't use it with abandon. -
  4. Try (in the build directory of lm_sensors) -
              make clean
    -          make
    -
    -
  5. If you still have problems, you may have to replace the include -paths in the .c/.h files with absolute paths to the header files. -More of a workaround than a real fix, but at least you can get it -to work. -
- -
-


- -Next: , -Previous: Installation, -Up: Top - -
- -

4 Problems

- - - -
-


- - -Next: , -Up: Problems - -
- -

4.1 My fans report exactly half/double their values compared to the BIOS?

- -

The problem with much of the sensor data is that it is impossible to -properly interpret some of the readings without knowing what the hardware -configuration is. Some fans report one 'tick' each rotation, some report -two 'ticks' each rotation. It is easy to resolve this through the -configuration file /etc/sensors.conf: - -

     chip lm78-*             # Or whatever chip this relates to
-     compute fan1 2*@,@/2    # This will double the fan1 reading
-                             # -- or --
-     compute fan1 @/2,2*@    # This will halve the fan1 reading
-
-

See doc/fan-divisors in our package for further information. - -

- -

4.1.1 Fans sometimes/always read 0!!

- -

You may not have a three-wire fan, which is required. - -

You may need to increase the 'fan divisor'. See doc/fan-divisors -in our package for further information. - -

- -

4.1.2 I doubled the fan divisor and the fan still reads 7000!

- -

Believe it or not, doubling the 'fan divisor' will not halve -the fan reading. You have to add a compute line in /etc/sensors.conf. -See My fans report exactly half/double their values compared to the BIOS, -and see doc/fan-divisors in our package for further information. - -

-


- - -Next: , -Previous: Section 4.1, -Up: Problems - -
- -

4.2 Why do my two LM75's report "-48 degrees"?

- -

For starters, those aren't LM75's. Your mainboard actually has the -Winbond W83781D which emulates two LM75's, but many systems which use the -Winbond chip (such as the Asus P2B) don't have the thermo-resisters connected -to the chip resulting in these strange -48 degree readings. - -

In upcoming versions, you will be able to disable non-interesting -readings. - -

-


- - -Next: , -Previous: Section 4.2, -Up: Problems - -
- -

4.3 Why do I have two Vcore readings, I have only one processor!

- -

The LM78 has seven voltage sensors. The default way of -connecting them is used in the configuration file. This includes a VCore2, -even if you do not have one. You can easily edit the configuration file -to give it another name, or make this reading disappear using -an ignore line. - -

Note that Vcore2 is often the same as Vcore on motherboards which -only support one processor. Another possibility is that Vcore2 is not -connected at all and will not have a valid reading at all. -A third possibility, is that Vcore2 monitors something -else, so you should not be too surprised if the values are completely -different. - -

-


- - -Next: , -Previous: Section 4.3, -Up: Problems - -
- -

4.4 How do those ALARMS work? The current value is within range but there is still an ALARM warning!

- -

The ALARM indications in sensors are those reported by the -sensor chip itself. They are NOT calculated by sensors. sensors -simply reads the ALARM bits and reports them. - -

An ALARM will go off when a minimum or maximum limit is crossed. -The ALARM is then latched - that is, it will stay there until the -chip's registers are next accessed - which will be the next time -you read these values, but not within (usually) 1.5 seconds since the last -update. - -

Reading the registers clears the ALARMS, unless the current -value is still out of range. - -

The purpose of this scheme is to tell you if there has been -a problem and report it to the user. Voltage or temperature spikes -get detected without having to read the sensor chip hundreds of times -a second. The implemetation details depend a bit on the kind of chip. -See the specific chip documentation in doc/chips and the -chip datasheet for more information. - -

-


- - -Next: , -Previous: Section 4.4, -Up: Problems - -
- -

4.5 My voltage readings seem to drift a bit. Is something wrong?

- -

No, probably not. If your motherboard heats up a bit, the sensed -voltages will drift a bit. If your power supply is loaded (because a disk -gets going, for example), the voltages may get a bit lower. Heavy -processor activity, in particular, dramatically increases core voltage -supply load which will often cause variation in the other supplies. -As long as they stay within a sensible range (say 5% of the nominal value -for CPU core voltages, and 10% for other voltages), there is no -reason to worry. - -

-


- - -Next: , -Previous: Section 4.5, -Up: Problems - -
- -

4.6 Some measurements are way out of range. What happened?

- -

Each module tries to set limits to sensible values on initialization, -but a module does not know how a chip is actually connected. This is -described in the configuration file, which is not read by kernel modules. -So limits can be strange, if the chip is connected in a non-standard way. - -

Readings can also be strange; there are several reasons for this. -Temperature sensors, for example, can simply not be present, even though -the chip supports them. Also, it can be that the input is used in a -non-standard way. You can use the configuration file to describe how this -measurement should be interpreted; see the comments the example file for -more information. - -

- -

4.6.1 -5V and -12V readings are way out of range!

- -

It's very frequent that negative voltage lines are not wired because -motherboard manufacturers don't think they're worth monitoring -(they are mostly unused these days). You can just add -ignore inN lines to /etc/sensors.conf to hide them. - -

Another possibility is that these lines are used to monitor different -voltages. Only the motherboard manufacturer can tell for sure. Taking -a look at what voltage values the BIOS displays may provide valuable -hints though. - -

-


- - -Next: , -Previous: Section 4.6, -Up: Problems - -
- -

4.7 What are VID lines? Why is the VID reading wrong?

- -

These describe the core voltage for your processor. They are -supported for most processors, however they are not always -correctly connected to the sensor chip, so the readings may be invalid. -A reading of 0V, +3.5V or +2.05V is especially suspect. -If this is the case, add a line ignore vid to /etc/sensors.conf, -and change the min and max settings for the Processor Core voltage -(often in0_min and in0_max) in that file so that they don't depend on vid. - -

The CPU nominal voltage is computed from VID lines according to a formula -that depends on the CPU type. Most chips that report a VID value can be -configured to use either VRM 8.2 (for Pentium III) or VRM 9.0 (for Pentium 4 -and Athlon). You chose which one you want through /etc/sensors.conf. -See doc/vid for more information. - -

-


- - -Next: , -Previous: Section 4.7, -Up: Problems - -
- -

4.8 I read sensor values several times a second, but they are only updated only each second or so. Why?

- -

If we would read the registers more often, it would not find the -time to update them. So we only update our readings once each 1.5 seconds -(the actual delay is chip-specific; for some chips, it may not be needed -at all). - -

-


- - -Next: , -Previous: Section 4.8, -Up: Problems - -
- -

4.9 It sometimes seems to take almost a second before I see the sensor reading results. Why?

- -

ISA bus access is fast, but SMBus access is really slow. If you have -a lot of sensors, it just takes a lot of time to access them. Fortunately, -this has almost no impact on the system as a whole, as another job can run -while we are waiting for the transaction to finish. - -

-


- - -Next: , -Previous: Section 4.9, -Up: Problems - -
- -

4.10 Can I be alerted when an ALARM occurs?

- -

No, you can't; and it may well be never supported. - -

Almost no mainboard we have encountered have actually connected the -IRQ-out pin of sensor chips. That means that we could enable IRQ reporting, but -nothing would happen. Also, even if a motherboard has it connected, it is -unclear what interrupt number would be triggered. And IRQ lines are a scarce -facility, which means that almost nobody would be able to use it anyway. - -

The SMI interrupt is only available on a few types of chips. It is -really a very obscure way to handle interrupts, and supporting it under Linux -might be quite hard to do. - -

Your best bet would be to poll the alarm file with a user-land daemon -which alerts you if an alarm is raised. I am not aware of any program which -does the job, though you might want to examine one of the graphical monitor -programs under X, see http://www.lm-sensors.org/wiki/UsefulLinks for addresses. - -

-


- - -Next: , -Previous: Section 4.10, -Up: Problems - -
- -

4.11 SMBus transactions on my PIIX4 simply don't work (timeouts happen). Why?

- -

Some chips which mainboard makers connect to the SMBus are not SMBus -devices. An example is the 91xx clock generator chips. When read, these -devices can lock up the SMBus until the next hard reboot. This is because -they have a similar serial interface (like the I2C), but don't conform to -Intel's SMBus standard. - -

Why did they connect these devices to the SMBus if they aren't -compatible? Good question! :') Actually, these devices may support being -written to, but lock things up when they are read. - -

-


- - -Next: , -Previous: Section 4.11, -Up: Problems - -
- -

4.12 My BIOS reports a much higher CPU temperature than your modules!

- -

We display the actual temperature of the sensor. This may not be the -temperature you are interested in, though. If a sensor should measure -the CPU temperature, it must be in thermal contact with it. In practice, -it may be just somewhere nearby. Your BIOS may correct for this (by adding, -for example, thirty degrees to the measured temperature). The correction -factor is regrettably different for each mainboard, so we can not do this -in the module itself. You can do it through the configuration file, though: - -

     chip lm75-*-49                      # Or whatever chip this relates to
-     label temp "Processor"
-     compute temp @*1.2+13,(@-13)/1.2    # Or whatever formula
-
-

However, the offset you are introducing might not be necessary. If you -tried to have Linux idle temperature and BIOS "idle" temperature match, -you may be misguided. -We have a Supermicro (370DLE) motherboard and we know -that its BIOS has a closed, almost undelayed while(1) loop that -keeps the CPU busy all the time. Linux reads 26 degrees idle, BIOS reads -38 degrees. Linux at full load is in the 35-40 degrees range so this -makes sense. - -

-


- - -Next: , -Previous: Section 4.12, -Up: Problems - -
- -

4.13 I try to read the raw /proc files, but the values are strange?!?

- -

Remember, these values do not take the configuration file -compute lines in account. This is especially obvious for voltage readings -(usually called in? or vin?). Use a program linked to libsensors (like -the provided sensors program) instead. - -

-


- - -Next: , -Previous: Section 4.13, -Up: Problems - -
- -

4.14 How do I set new limits?

- -

Change the limit values in /etc/sensors.conf and then run -sensors -s. - -

- -

4.14.1 I set new limits and it didn't work?

- -

You forgot to run sensors -s. Put it in a /etc/rc.d/... file -after the modprobe lines to run at startup. - -

-


- - -Next: , -Previous: Section 4.14, -Up: Problems - -
- -

4.15 Some sensors are doubly detected?

- -

Yes, this is still a problem. It is partially solved by alias detection -and confidence values in sensors-detect, but it is really tough. - -

Double detections can be caused by two things: -sensors can be detected to both the ISA and the SMBus (and if you have -loaded the approprate adapter drivers, it will be detected on both), and -some chips simulate other chips (the Winbond W83781D simulates LM75 chips -on the SMBus, for example). Remove the offending adapter or chip driver, or -run sensors-detect and add the ignore= modprobe parameters it suggests. - -

-


- - -Next: , -Previous: Section 4.15, -Up: Problems - -
- -

4.16 I ran sensors-detect, but now I get very strange readings?!?

- -

Your SMBus (PIIX4?) is probably crashed or hung. There are some mainboards -which connect a clock chip to the SMBus. Unfortunately, this clock chip -hangs the PIIX4 if it is read (it is an I2C device, but not SMBus compatible). -We have found no way of solving this, except for rebooting your computer. -Next time when you run sensors-detect, you may want to exclude addresses -0x69 and/or 0x6a, by entering s when you are asked whether you want to -scan the PIIX4. - -

-


- - -Next: , -Previous: Section 4.16, -Up: Problems - -
- -

4.17 Bad readings from particular chips

- -

See below for some particularly troublesome chips. -Also be sure and check doc/chips/xxxxx for the particular driver. - -

- -

4.17.1 Bad readings from the AS99127F!

- -

The Asus AS99127F is a modified version of the Winbond W83781D. -Asus will not release a datasheet. The driver was developed by tedious -experimentation. We've done the best we can. If you want to make adjustments -to the readings please edit /etc/sensors.conf. Please don't ask us to -fix the driver. Ask Asus to release a datasheet. - -

- -

4.17.2 Bad readings from the VIA 686A!

- -

The Via 686A datasheet is incomplete. -Via will not release details. The driver was developed by tedious -experimentation. We've done the best we can. If you want to make adjustments -to the readings please edit /etc/sensors.conf. Please don't ask us to -fix the driver. Ask Via to release a better datasheet. -Also, don't forget to modprobe i2c-isa. - -

- -

4.17.3 Bad readings from the MTP008!

- -

The MTP008 has programmable temperature sensor types. -If your sensor type does not match the default, you will have to change it. -See doc/chips/mtp008 for details. -Also, MTP008 chips seem to randomly refuse to respond, for -unknown reasons. You can see this as 'XX' entries in i2cdump. - -

- -

4.17.4 Bad temperature readings from the SIS5595!

- -

This chip can use multiple thermistor types and there are also -two different versions of the chip. We are trying to get the driver -working better and develop formulas for different thermistors -but we aren't there yet. Sorry. -Also, many times the chip isn't really a sis5595 but it was -misidentified. We are working on improving that too. - -

- -

4.17.5 Bad readings from a w8378[12]d!

- -

Do you own an ASUS motherboard? Perhaps your chip is being -misidentified. Look on the motherboard for a 'Winbond' or Asus chip. -Often the real device is an Asus as99127f. If so, the driver can be -forced to recognize the as99127f with -force_as99127f=BUS,0x2d where BUS is your i2c bus number. -Cat /proc/bus/i2c to see a list of bus numbers. -Read the w83781d module documentation (doc/chips/w83781d) -for more details. - -

- -

4.17.6 Bus hangs on Ali 1543 on Asus P5A boards!

- -

The SMBus tends to hang on this board and it seems to get worse -at higher temperatures. Use ISA accesses to reliably use the w83781d -monitor chip on this board and use the ignore=1,0x2d or similar option -to the w83781d module to prevent i2c accesses. - -

- -

4.17.7 Bad readings from LM75!

- -

The LM75 detection is poor and other hardware is often misdetected -as an LM75. Figure out what you really have See What chips are on motherboard XYZ. - -

- -

4.17.8 Bad readings from LM78!

- -

The LM78 is no longer manufactured by National Semiconductor. -You probably don't have a real LM78 but something similar that we -do not recogize or support. Figure out what you really have See What chips are on motherboard XYZ. - -

- -

4.17.9 Bad readings from LM80!

- -

The LM80 detection is poor and other hardware is often misdetected -as an LM80. Figure out what you really have See What chips are on motherboard XYZ. - -

-


- - -Next: , -Previous: Section 4.17, -Up: Problems - -
- -

4.18 How do I configure two chips (LM87) differently?

- -

There is a SuperMicro board with two LM87's on it that are -not hooked up in the same way, so they need different defaults. -For example, both CPU temperatures go to one LM87. - -

Make two different sections in /etc/sensors.conf as follows: -

     chip "lm87-i2c-*-2c"
-         put configuration for the chip at 0x2c here
-     chip "lm87-i2c-*-2d"
-         put configuration for the chip at 0x2d here
-
-

There is a commented example in sensors.conf.eg which should -be helpful. - -

-


- - -Next: , -Previous: Section 4.18, -Up: Problems - -
- -

4.19 Dmesg says ‘Upgrade BIOS’! I don't want to!

- -

If the problem is a PCI device is not present in lspci, the solution -is complex. For the ALI M7101 device, there is a solution which uses the -2.4 kernel's hotplug facility. See prog/hotplug in our package. -For other PCI devices, you can try to modify -the m7101 solution in prog/hotplug. - -

If dmesg says ‘try force_addr’, see below. Other drivers generally do not -support the force_addr parameter. Sorry. Check the documentation -for your driver in doc/[chips,busses] and if we don't support it -you can send us your request. - -

- -

4.19.1 Dmesg says ‘use force_addr=0xaddr’! What address do I use?

- -

If the problem is a PCI device whose base address is not set, -you may be able to set the address with a force parameter. The via686a -and sis5595 chip drivers, and some bus drivers, support the command line -modprobe via686a force_addr=0xADDRESS where ADDRESS -is the I/O address. You must select an address that is not in use. -cat /proc/ioports to check (carefully) for conflicts. A high number like -0xf000 is generally safe. - -

-


- - -Next: , -Previous: Section 4.19, -Up: Problems - -
- -

4.20 Sensors says ‘Can't access procfs/sysfs file’

- -
    -
  • Linux 2.6 -
      -
    • Did you modprobe i2c_sensor? Check lsmod. -
    • Do you have sysfs support in your kernel and /sys mounted (is /sys there and populated)? -Create /sys with mkdir /sys if needed. Then add the following line to /etc/fstab: -
                     sys              /sys             sysfs       default          0   0
      -

      and mount /sys. -

    -
  • Linux 2.4 -
      -
    • Did you modprobe i2c-proc? Check lsmod. -
    • Do you have procfs support in your kernel and /proc mounted (is /proc there and populated)? -Create /proc with mkdir /proc if needed. Then add the following line to /etc/fstab: -
                     proc             /proc            proc        defaults         0   0
      -

      and mount /proc. -

    -
  • If you did sensors -s, did you run it as root? -
- -
-


- - -Next: , -Previous: Section 4.20, -Up: Problems - -
- -

4.21 Sensors says ‘No sensors found!’

- -
    -
  • Did sensors-detect find sensors? (If not see Sensors-detect doesnt find any sensors) -
  • Did you do what sensors-detect said? -
  • Did you modprobe your sensor modules? -
  • Did you modprobe your I2C adapter modules? -
  • Did you modprobe i2c-isa if you have ISA sensor chips? -
  • Check lsmod. -
- -
-


- - -Next: , -Previous: Section 4.21, -Up: Problems - -
- -

4.22 Sensors output is not correct!

- -

What specifically is the trouble? -

- -
-


- - -Next: , -Previous: Section 4.22, -Up: Problems - -
- -

4.23 What is at I2C address XXX?

- -

In general, we don't know. Start by running sensors-detect. -If it doesn't recognize it, try running i2cdump. A partial list -of manufacturers' IDs are at the bottom of doc/chips/SUMMARY. - -

- -

4.23.1 What is at I2C address 0x69?

- -

A clock chip. Often, accessing these clock chips in the wrong -way will instantly crash your computer. Sensors-detect carefully -avoids these chips, and you should do too. You have been warned. - -

- -

4.23.2 What is at I2C addresses 0x50 - 0x57?

- -

EEPROMs on your SDRAM DIMMs. Load the eeprom module to -look at some basic data in sensors or use the program -prog/eeprom/decode-dimms.pl to get more information than you ever wanted. - -

- -

4.23.3 What is at I2C addresses 0x30 - 0x37?

- -

These are often 'shadows' of your EEPROMs on your SDRAM DIMMs -at addresses 0x50 - 0x57. They are the 'software write-protect' -registers of the SDRAM Serial Presence Detect EEPROMs. -If you try and -do a i2cdump on them to read the location, you won't get anything, -because they contain a single write-only register. -This register can be used to permanently -write-protect the contents of the eeprom. - -

-


- - -Next: , -Previous: Section 4.23, -Up: Problems - -
- -

4.24 Sensors-detect doesn't work at all

- -

It could be many things. What was the problem? See Problems on particular motherboards. - -

- -

4.24.1 Sensors-detect says "Couldn't open /proc/bus/i2c?!?"

- -

You don't have i2c support in your kernel, or the i2c-core module -was not loaded and you did not run sensors-detect as root. - -

- -

4.24.2 Sensors-detect says "Can't open /dev/i2c[-/]0"

- -

Your /dev/i2c-0, /dev/i2c0, or /dev/i2c/0 files do not exist -or you did not run sensors-detect as root. -Run the script prog/mkdev/mkdev.sh to create the /dev/i2c-x files. -Run devfs in the kernel to get the /dev/i2c/x files. - -

- -

4.24.3 Sensors-detect doesn't find any sensors!

- -

Either -

    -
  1. The board doesn't have any sensors. -
  2. We don't support the sensors on the board. -
  3. The sensors it has are on an I2C bus connected to an I2C bus adapter that we don't support. -
  4. You don't have the latest version of lm_sensors. -
- -

But in any case you should figure out what is on the board: -

    -
  1. Look at your motherboard. -
  2. Check the manufacturer's website. -
- -

When you know what chips you have, check the -Driver Status web page to -see if support has been added for your chip in a later release or in SVN. - -

-


- - -Next: , -Previous: Section 4.24, -Up: Problems - -
- -

4.25 Sensors says ‘Error: Line xxx: zzzzzzz’

- -

These are errors from the libsensors library in -reading the /etc/sensors.conf configuration file. Go to that line -number and fix it. If you have a parse error, perhaps you have -to put the feature name in double quotes. - -

-


- - -Next: , -Previous: Section 4.25, -Up: Problems - -
- -

4.26 Sensors only gives the name, adapter, and algorithm for my chip

- -

If sensors only says this, for example, and doesn't -provide any actual data at all: - -

     it87-isa-0290
-     Adapter: ISA adapter
-     Algorithm: ISA algorithm
-
-

Your chip is not currently supported by sensors and so all it -does is print out that information. Get the latest release -and be sure you are running the sensors program it installed -and not some older sensors. - -

-


- - -Next: , -Previous: Section 4.26, -Up: Problems - -
- -

4.27 Sensors says ‘ERROR: Can't get xxxxx data!’

- -
    -
  • (Linux 2.6) Make sure you are using one of the -recommended kernel/lm_sensors combination. -
  • You have a libsensors/sensors mismatch. -sensors is unable to -get a data entry from libsensors. You probably have an -old libsensors in your /etc/ld.so.conf path. -Make sure you did (as root) a make install (Linux 2.4) or -make user_install (Linux 2.6) followed by a ldconfig. -Then check the output of ldconfig -v | grep libsensors to -verify that there is only ONE libsensors entry and that it matches -the libsensors that was built in the lib/ directory in lm_sensors2. -
- -
-


- - -Next: , -Previous: Section 4.27, -Up: Problems - -
- -

4.28 Sensors doesn't find any sensors, just eeproms.

- -

See Sensors-detect doesnt work at all, if sensors-detect failed to find any sensors. - -

If sensors-detect did find sensors, did you insert your modules? For chips on the ISA -bus, did you insert i2c-isa? - -

See What to do if a module wont insert, if the modules didn't insert, -also Sensors says No sensors found. - -

-


- - -Next: , -Previous: Section 4.28, -Up: Problems - -
- -

4.29 Inserting modules hangs my board

- -

There are several possible causes: -

    -
  1. Bus driver problems. Insert the bus driver first, before you have inserted any chip drivers, to verify. -
  2. Wrong chip driver. Verify that you have a chip supported by the chip driver, see What chips are on motherboard XYZ. -
  3. The chip driver is reinitializing the chip, which undoes critical initialization done by the BIOS. Try the parameter init=0 for the w83781d driver; this is the only driver supporting this parameter. -
  4. Some chips on the bus don't like to be probed at all. After inserting the bus driver (but not the chip drivers), run i2cdetect on the bus, then i2cdump on each address responding to i2cdetect. This may find the culprit. Do not i2cdump address 0x69, the clock chip. -
  5. The chip driver is incorrectly finding a second chip on the bus and is accessing it. For example, with the Tyan 2688 with a w83781d at 0x29, use modprobe ignore_range=0,0x00,0x28,0,0x2a,0x7f to prevent access to other addresses. (init=0 also req'd for the Tyan 2688). -
- -
-


- - -Next: , -Previous: Section 4.29, -Up: Problems - -
- -

4.30 Inserting modules slows down my board

- -

Generally this is caused by an overtemperature alarm output from -the sensor chip. This triggers hardware on the board which -automatically slows down the CPU clock. Be sure that your -temperature limits are above the temperature reading. Put -the new limits in /etc/sensors.conf and run sensors -s. - -

-


- - -Next: , -Previous: Section 4.30, -Up: Problems - -
- -

4.31 Problems on particular motherboards

- -

The following boards have unique problems and solutions. - -

- -

4.31.1 Asus P4B

- -

See prog/hotplug/README.p4b if your SMBus master is not found. - -

- -

4.31.2 Tyan 2460, 2462

- -

See support tickets 805, 765, 781, 812, 813, and 867 for information. - -

- -

4.31.3 Tyan 2466

- -

See support tickets 941, 840, and 841 for information. - -

- -

4.31.4 Tyan 2688

- -

For board hangs, see support ticket 721 for information. -Also Inserting modules hangs my board. - -

-


- - -Next: , -Previous: Section 4.31, -Up: Problems - -
- -

4.32 Problems on particular systems

- -

For IBM systems, see README.thinkpad. - -

-


- - -Previous: Section 4.32, -Up: Problems - -
- -

4.33 Problems on 2.6 kernels

- -

Not all drivers have been ported to 2.6. If your favorite driver is not -in 2.6, the reason is that nobody has ported it, or the ported code did -not get a proper review yet. -If you would like to port the driver, see the file -Documentation/i2c/porting-clients in the 2.6 kernel tree for help, -then send us the ported driver when you are done. - -

4.33.1 i2c-viapro and via686a

- -

Until kernel 2.6.11, there was a PCI resource conflict between -i2c-viapro (the SMBus driver for VIA bridges) and via686a (the integrated -sensors driver for VIA bridges). This caused the second loaded driver to -silently fail working. So do not load both i2c-viapro and via686a together -unless you have a recent kernel. - -

4.33.2 Where are my EEPROMs?

- -

The 2.6.14-rc1 kernel introduced the hwmon class, which groups all -hardware monitoring drivers in a logical way. The goal was to help -libsensors grab the relevant sensors information in /sys. In particular: -

    -
  • libsensors will no more need to know about the underlying bus types -(I2C/SMBus, ISA or other); -
  • libsensors will no more list non-hardware monitoring chips. -
- This explains why EEPROMs are no more displayed by sensors: -they are no hardware monitoring chips. The medium term plan is to drop -eeprom support for all Linux 2.6 kernels, as it didn't fit well in -the library code in the first place. - -

Note that you can still obtain information about your EEPROMs by using -the dedicated perl scripts in prog/eeprom: ddcmon, -decode-dimms.pl, decode-edid.pl and -decode-vaio.pl. - -

-


- -Next: , -Previous: Problems, -Up: Top - -
- -

5 How to Ask for Help

- - - -
-


- - -Next: , -Up: Help - -
- -

5.1 What to send us when asking for help

- -

We are always willing to answer questions if things don't work out. -Post your question to our discussion list, -and not the individual authors, -unless you have something private to say. - -

Instead of using email, you can also use the web-based support -area, at http://www.lm-sensors.org/wiki/FeedbackAndSupport. You will be helped -just as fast, and others may profit from the answer too. You will be -emailed automatically when your question has been answered. - -

Here's what you should send us: - -

    -
  • The dmesg or syslog output if applicable -
  • The output of (as root) prog/detect/sensors-detect -
  • The output of lsmod -
  • If a PCI chip problem: -
      -
    • The output of lspci -n -
    -
  • If an I2C sensor chip problem: -
      -
    • The output of (as root) prog/detect/i2cdetect X -where X = the bus number (run i2cdetect with no arguments to list the busses) -(please send this only if it's not all ‘XX’) -
    -
  • If an ISA sensor chip problem: -
      -
    • The output of (as root) prog/dump/isadump 0x295 0x296 (only if it's not all ‘XX’) -
    -
  • Part numbers of chips on your motherboard you think are the sensor chips (look at your motherboard) -
  • Motherboard type -
  • Sensors version -
  • Kernel version -
- -
-


- - -Next: , -Previous: Section 5.1, -Up: Help - -
- -

5.2 What to do if a module won't insert?

- -

Did you use modprobe instead of insmod??? Don't use insmod. - -

Were there unresolved symbols? Did you run depmod -a? Run -depmod -a -e to see where the symbol problem is. - -

ALWAYS inspect the output of dmesg. That's where the error -messages come out!!! Don't rely on the generic message from modprobe. -If you still can't figure it out, send us the information -listed above. - -

-


- - -Next: , -Previous: Section 5.2, -Up: Help - -
- -

5.3 What to do if it inserts, but nothing happens?

- -

For an ISA sensor chip, did you also modprobe i2c-isa? It must be inserted. - -

For an I2C sensor chip, did you also modprobe i2c-xxx where xxx is your -I2C bus adapter? It must be inserted. - -

Always inspect the output of dmesg. That's where the error -messages come out. If you still can't figure it out, send us the information -listed above. - -

-


- - -Next: , -Previous: Section 5.3, -Up: Help - -
- -

5.4 What to do if I read only bogus information?

- -

It may be that this was a mis-detection: the chip may not be -present. If you are convinced there is something wrong, verify that you -indeed have the devices on your motherboard that you think you do. -Look at the motherboard and make sure. If you are still stuck, -please send us the usual information (see Help) - -

-


- - -Next: , -Previous: Section 5.4, -Up: Help - -
- -

5.5 What to do if you have other problems?

- -

Again, send the output listed above. - -

-


- - -Next: , -Previous: Section 5.5, -Up: Help - -
- -

5.6 What if it just works like a charm?

- -

Drop us a mail if you feel like it, mentioning the mainboard and -detected chip type. That way, we have some positive feedback, too! - -

-


- - -Next: , -Previous: Section 5.6, -Up: Help - -
- -

5.7 How do I update a ticket?

- -

You can't. Only developers can. Follow up by emailing us -and reference your ticket number -in the subject. Please don't enter a new ticket with -follow-up information, email us instead. Thanks. - -

-


- - -Next: , -Previous: Section 5.7, -Up: Help - -
- -

5.8 How do I follow up on a ticket?

- -

Follow up by emailing us -and reference your ticket number in the subject. - -

-


- - -Previous: Section 5.8, -Up: Help - -
- -

5.9 Why did you decide not to support undocumented chips?

- -

There are several reasons why we are generally not interested in writing -drivers for undocumented chips: - -

    -
  • Writing a driver without a datasheet is much harder, as you have to -guess most things. Remember that, most of the time, we write drivers for fun -and for free, so there is no reason we would write a driver in conditions -that promise more pain than fun. -
  • If we hit a problem, we are certain never to get any support from the -chip manufacturer. This means that we may spend days on code which will -finally never work. -
  • There are several chips out there which are fully documented and lack -a driver. This is natural for us to give these the priority when we -finally have some spare time to spend on driver coding. -
  • Hardware monitoring chips are not toys. Misprogramming them can -result in data loss or hardware breakage. This is obviously more likely -to happen with undocumented chips. This is a responsability we do not -want to endorse (the GPL is pretty clear than we are not legally -liable, but still). -
- -

There are also several reasons why we do not want to support such drivers, -even if they were written by other people: - -

    -
  • Problems are much more likely to happen with such drivers. -This means increased needs of support. User support if very -time-consuming and we are usually short of time. -
  • Support should be done by the driver author (as only him/her knows -the driver and chip) but in the reality of facts, people will always ask -us for help if the driver is part of our package. Redirecting all user -requests to the driver's author manually is boring. -
  • The lack of datasheet usually results in an original driver which -works relatively fine for its author, but will happen not to work -completely for other users. This means that the driver will need many -more additions and fixes than other drivers do, resulting in an increased -maitainance workload, which we can hardly afford. Of course this too should -be handled by the original driver author, but we never know whether he/she -will actually do the work. -
- -

Lastly, there are other considerations, some of which are deliberately -political: - -

    -
  • We do not want to trick hardware buyers into thinking that a chip is -fully supported under Linux when in fact it is only partly supported by a -driver which was written without a datasheet. Clearly stating that such -chips are not supported makes it much easier for anyone who really needs -fully working hardware monitoring under Linux to avoid motherboards with -these partly supported chips. -
  • Drivers written without a datasheet are a pain for developers and -users, but are a complete win for the manufacturers of these chips: -they don't have to write the driver, they don't have to help us, -they don't have to support the users, and they still sell their -hardware. We do not want to encourage such a selfish behavior. -
- -

That being said, authors of such drivers can still submit their code to -the Linux kernel folks for inclusion into Linux 2.6. Their driver may be -accepted there, under conditions. - -

If such a driver is ever accepted into the Linux 2.6 tree, and someone -provides a patch to libsensors and/or sensors to add support for this -driver, we will apply it. This generic code is unlikely to cause trouble. - -

-


- -Next: , -Previous: Help, -Up: Top - -
- -

6 How to Contribute

- - - -
-


- - -Next: , -Up: Contribute - -
- -

6.1 How to write a driver

- -

See doc/developers/new_drivers in our package for instructions. - -

-


- - -Next: , -Previous: Section 6.1, -Up: Contribute - -
- -

6.2 How to get SVN access

- -

For anonymous SVN read access, see the instructions on our -download page. - -

For write access, please contact us. - -

-


- - -Next: , -Previous: Section 6.2, -Up: Contribute - -
- -

6.3 How to donate hardware to the project

- -

Contact us. - -

-


- - -Next: , -Previous: Section 6.3, -Up: Contribute - -
- -

6.4 How to join the project mailing lists

- -

There are two lists you can subscribe to: - -

    -
  • A general discussion list, -meant for both development and user support. You do not need to be subscribed to post. -
  • A CVS commits list, -for watching the changes made to the CVS repositories. This list is read-only. -
- -
-


- - -Next: , -Previous: Section 6.4, -Up: Contribute - -
- -

6.5 How to access mailing list archives

- -

The primary mailing list archive is at: -http://lists.lm-sensors.org/pipermail/lm-sensors/. -It contains messages since October 28, 2001. - -

There is another mailing list archive at: -http://news.gmane.org/gmane.linux.drivers.sensors. -It contains messages since December 31, 2004. -This archive may also be accessed via a news reader: -nntp://news.gmane.org/gmane.linux.drivers.sensors -and RSS: -http://rss.gmane.org/gmane.linux.drivers.sensors. - -

And last there is a legacy archive at: -http://archives.andrew.net.au/lm-sensors. -It contains messages from October 28, 2001 through May 16, 2005. - -

-


- - -Next: , -Previous: Section 6.5, -Up: Contribute - -
- -

6.6 How to submit a patch

- -

Check out the latest from CVS, then copy the directory to another -directory, and make your changes. Generate the diff with -diff -u2 -r DIR1 DIR2. Or you can generate the diff in CVS with -cvs diff -u2. Send us the patch in an email and tell us what it does. - -

-


- - -Next: , -Previous: Section 6.6, -Up: Contribute - -
- -

6.7 How to REALLY help

- -

Believe it or not, what we really need help with are: -

    -
  • Answering email -
  • Answering support tickets -
  • Porting drivers to Linux 2.6 -
  • Creating a sensors.conf database -
  • Reviewing patches -
- -

If you are willing to help, simply join our -discussion list, -and we'll help you help us. - -

-


- - -Previous: Section 6.7, -Up: Contribute - -
- -

6.8 How to get release announcements

- -

We don't have a separate release announcement mailing list; -however, we put all our releases on freshmeat: http://freshmeat.net -and you can register on our freshmeat project page http://freshmeat.net/projects/lm_sensors -to 'subscribe to new releases' and then freshmeat -will email you announcement. - -

-


- -Previous: Contribute, -Up: Top - -
- -

Appendix A Revision History of This Document

- -
    -
  • Rev 2.18 (JD) Removed version 1 specifics part, 2005-12-17 -
  • Rev 2.17 (JD) Added 5.9 (why we don't support undocumented chips), - removed 6.9 (doesn't apply to the new mailing list), 2005-10-05 -
  • Rev 2.16 (JD) Added 4.33.2, 2005-09-06 -
  • Rev 2.15 (JD) Updates, including mailing-list change, 2005-05-21 -
  • Rev 2.14 (MDS) Updated 4.12, 2004-11-26 -
  • Rev 2.13 (JD) Added 4.6.1, updated 4.7, 2004-06-23 -
  • Rev 2.12 (JD) Updated 4.27, 2004-04-11 -
  • Rev 2.11 (JD) Various updates, 2004-01-18 -
  • Rev 2.10 (MDS) Various updates, 2004-01-03 -
  • Rev 2.9 (CP) Converted to Gnu texinfo format, 2002-09-10 -
  • Rev 2.8 (MDS) Minor updates 2002-07-10, released with lm_sensors 2.6.4 -
  • Rev 2.7 (MDS) Minor updates 2002-04-25 -
  • Rev 2.6 (MDS) Minor updates 2002-01-15, released with lm_sensors 2.6.3 -
  • Rev 2.5 (MDS) Minor updates 2001-11-11, released with lm_sensors 2.6.2 -
  • Rev 2.4 (MDS) Minor updates 2001-07-22 -
  • Rev 2.3 (MDS) General update, 2001-02-24, released with lm_sensors 2.6.0. -
  • Rev 2.2 (Frodo) Corrections for lm_sensors 2.4, 1999-09-20 -
  • Rev 2.1 (Frodo) Corrections for lm_sensors 2.2, 1999-01-12 -
  • Rev 2.0 (Frodo) Major revision for lm_sensors 2.1, 1998-12-29 -
  • Rev 1.10 (Frodo) Modified 3.8, updated some other things, 1998-09-24 -
  • Rev 1.9 (Frodo) Added 3.15, 1998-09-06 -
  • Rev 1.8 (Frodo) Added 3.14, 1998-09-05 -
  • Rev 1.7 (Phil) Added 3.13 and some other minor changes, 1998-09-01 -
  • Rev 1.6 (Frodo) Added 4, 4.1, 4.2, 4.3, 4.4, 4.5, 1998-09-01 -
  • Rev 1.5 (Frodo) Added 2.3, 2.4, 3.9, 3.10, 3.11, 1998-08-26 -
  • Rev 1.4 (Frodo) Added some more Winbond information, and 3.5-3.8, 1998-08-17 -
  • Rev 1.3 (Phil) Added info on the Winbond chip, 1998-08-16 -
  • Rev 1.2 (Frodo) Adapation, 1998-08-10 -
  • Rev 1.1 (Phil) Modifications, 1998-08-09 -
  • Rev 1.0 (Phil) First version, 1998-08-03 -
- - - diff --git a/doc/lm_sensors-FAQ.texi b/doc/lm_sensors-FAQ.texi deleted file mode 100644 index e74f2a00..00000000 --- a/doc/lm_sensors-FAQ.texi +++ /dev/null @@ -1,1621 +0,0 @@ -\input texinfo.tex @c -*-texinfo-*- - -@c %**start of header -@setfilename lm_sensors-FAQ.info -@include version.texi -@settitle Sensors FAQ for lm_sensors version @value{VERSION} -@comment %**end of header - -@titlepage -@center @titlefont{This is the FAQ for the @command{lm_sensors} program, @value{VERSION}} -@sp 3 -@center Copyright (C) 1998 - 2005 -@sp 1 -@center Frodo Looijaard, -@center Philip Edelbrock, -@center Mark D. Studebaker, -@center and -@center Jean Delvare -@end titlepage - -@ifhtml -Copyright (C) 1998 - 2005@* -Frodo Looijaard,@* -Philip Edelbrock,@* -Mark D. Studebaker@* -and@* -Jean Delvare@* -@end ifhtml - -@dircategory Utilities -@direntry -* lm_sensors-FAQ: (lm_sensors-FAQ) The lm_sensors FAQ -@end direntry - -@summarycontents -@contents - -@ifnottex -@node Top -@top lm_sensors - -The lm_sensors package includes a collection of modules for general SMBus -access and hardware monitoring. NOTE: this requires special support which -is not in standard 2.2-vintage kernels. - -@end ifnottex - -@menu -* Overview:: PC and Sensor Overview -* Basics:: Sensor and Bus Basics -* Installation:: Installation and Management -* Problems:: Problems -* Help:: How to Ask for Help -* Contribute:: How to Contribute -* Document Revisions:: Revision History of This Document -@end menu - - -@node Overview, Basics, Top, Top -@chapter PC and Sensor Overview - -@menu -* Section 1.1:: What sensors are available on my PC? -* Section 1.2:: What can a sensor chip like the "LM78" do? -* Section 1.3:: Where do I find out more about any of these chips? -@end menu - -@node Section 1.1, Section 1.2, , Overview -@section What sensors are available on my PC? - -Most PC's built since late 1997 now come with a -hardware health monitoring chip. This chip may be accessed via the -ISA bus or the SMBus, depending on the motherboard. - -Some motherboard chipsets, notably the Via 686 and the SiS 5595, -contain hardware monitor functions. - -This FAQ frequently refers to the "LM78". This chip has been -obsoleted by National Semiconductor. Most motherboards today contain -a chip with similar functions. - - -@node Section 1.2, Section 1.3, Section 1.1, Overview -@section What can a sensor chip like the "LM78" do? - -The LM78 is a chip made by National Semiconductor which can monitor 7 -voltages (5 positive, 2 negative) from 0 to 4.08V. The inputs are usually in -series with voltage dividers which lower the +/- 12V and +/- 5V supplies to -measurable range. Therefore, the readings for such inputs need to be -re-scaled appropriately by software. - -The LM78 also has 3 fan speed monitoring inputs, an internal -temperature sensor, a chassis intrusion sensor, and a couple maskable interrupt -inputs. The LM78 can also relay the processor's (P6 or Pent II) VID lines -which are hardwired and used to indicate to the power regulator (usually on -the mainboard close to the processor socket/slot) what voltage to supply to -the processor. - -The LM78 can be interfaced to a system via the ISA bus and/or the -SMBus. - -Most other sensor chips have comparable functionality. Each supported -chip is documented in the @file{doc/chips} directory. - - -@node Section 1.3, , Section 1.2, Overview -@section Where do I find out more about any of these chips? - -Most semiconductor companies have comprehensive documentation, -including complete datasheets, on their websites. Analog Devices, -Dallas Semiconductor, Maxim, and National Semiconductor have the widest selection -of sensor chips. Their websites are: - -@itemize @bullet - @item @uref{http://www.analog.com} - @item @uref{http://www.dalsemi.com} - @item @uref{http://www.maxim-ic.com} - @item @uref{http://www.national.com} -@end itemize - -Please see the file @uref{http://www.lm-sensors.org/wiki/UsefulLinks} -for links to other companies' websites. - - - -@node Basics, Installation, Overview, Top -@chapter Sensor and Bus Basics - -@menu -* Section 2.1:: What sensors are available on my PC? -* Section 2.2:: What can a sensor chip like the "LM78" do? -* Section 2.3:: Where do I find out more about any of these chips? -* Section 2.4:: What sensors are available on my PC? -* Section 2.5:: What can a sensor chip like the "LM78" do? -* Section 2.6:: Where do I find out more about any of these chips? -@end menu - - -@node Section 2.1, Section 2.2, , Basics -@section How are these sensors read? - -Sensor chips reside on either the ISA bus, the SMBus, or both. -See the file @file{doc/chips/SUMMARY} in our package for a list. - -To communicate with chips on the ISA bus, the software uses -simple I/O reads and writes. - -To communicate with chips on the SMBus, the software must -use an SMBus interface device, explained below. - - -@node Section 2.2, Section 2.3, Section 2.1, Basics -@section What is the SMBus? And the I2C bus? - -The SMBus is the "System Management Bus". More specifically, it is a -2-wire, low-speed serial communication bus used for basic health monitoring -and hardware management. It is a specific implementation of the more -general I2C (pronunciation: I-squared-C) bus. In fact, both I2C devices -and SMBus devices may be connected to the same (I2C) bus. - -The SMBus (or I2C bus) starts at the host controller, used for -starting transactions on the SMBus. From the host interface, the -devices communicated with are the @dfn{slave} devices. Each slave device has a -unique 7-bit address which the host uses to refer to that device. - -For each supported SMBus host, there is a separate kernel module -which implements the communication protocol with the host. Some SMBus hosts -really operate on the SMBus level; these hosts can not cope with pure I2C -devices. Other hosts are in fact I2C hosts: in this case, we implement -the SMBus protocol in terms of I2C operations. But these hosts can also -talk to pure I2C devices. - - -@node Section 2.3, Section 2.4, Section 2.2, Basics -@section I don't have an ISA bus! - -We promise, you do, even if you don't have any old ISA slots. -The "ISA Bus" exists in your computer even if you don't have ISA slots; -it is simply a memory-mapped area, 64KB in size (0x0000 - 0xFFFF) -where many "legacy" functions, such as keyboard and interrupt controllers, -are found. It isn't necessarily a separate physical bus. -See the file @file{/proc/ioports} for a list of devices living on -the "ISA Bus" in your system. If you don't like the term "ISA Bus" -think "I/O Space". - - -@node Section 2.4, Section 2.5, Section 2.3, Basics -@section What sensors do processors have? - -Most new processors contain a thermal diode on the die itself. -The electical properties of all diodes and transistors vary -slightly with temperature. The thermal diode is exceptionally accurate -because it is directly on the die. Newer temperature sensor chips, -like the Analog Devices ADM1021 and clones, and the Winbond chips, -have circuitry for measuring the the electrical properties of -an external diode and converting this data to a temperature. -Any sensor chip listed in @file{doc/chips/SUMMARY} in our package which -has support for more than one temperature supports external temperature sensing. - -Older motherboards and processors without this feature generally use -an LM75 placed close to the processor. This is much less accurate. - -The Pentium 2 'boxed' processor usually has an LM75 very close to the -base of the box. It can be read through the SMBus to report the approximate -temperature of the processor. The processor also contains an internal -temperature sensor (of low accuracy) used as a fail-safe to disable the -processor in case it gets much too hot (usually around 130 degrees C). And, -the Pentium 2 also has a hard-wired signal (VID lines) on it's SEC (single -edge connector) which indicates what power supply is required to operate the -processor. - -The P6 (Pentium-Pro) may have an LM75 in or just under the socket. -P6's also have VID lines. - -Pentiums and Pentium w/ MMX do not have VID lines, and sometimes have -LM75's under the sockets (depends on the mainboard, and how 'modern' the -mainboard is). - -The P2 Xeon was the first Intel processor to include the SMBus -interface on the P2 Xeon SEC. - - -@node Section 2.5, Section 2.6, Section 2.4, Basics -@section How often are the sensor values updated? - -The LM78, and most other sensor chips like it, reads its sensors one -by one. A complete scanning sweep will take about 1.5 seconds. The LM78 stops -readings sensors if you try to access it, so if you access it very often -(by reading sensor values; writing new limits is safe) it will not find the -time to update its sensor values at all! Fortunately, the kernel module takes -care not to do this, and only reads new values each 1.5 seconds. If you -read the values again, you will get the 'old' values again. - - -@node Section 2.6, , Section 2.5, Basics -@section How are alarms triggered? - -It is possible to monitor each sensor and have an alarm go off if -it crosses some pre-determined limits. There are two sorts of interrupts -which can be generated by sensor chips if this happens (it depends a bit on -the actual chip if both are supported; the LM80, for example, has only -IRQ interrupts): IRQ interrupts and SMI interrupts. IRQ stands for -Interrupt Request and are the interrupt lines you can find in @file{/proc/interrupts}. -SMI stands for System Management Interrupt, and is a special interrupt which -puts the processor in a secure environment independent of any other things -running. SMI is currently not supported by the Linux kernel. IRQs are -supported, of course. - -Even if no interrupt is generated, some bits in a status register -will be set until the register is read the next time. If the alarm condition -persists after that, the bits will be set on the next scanning sweep, etc. - -Most drivers in our package do not support interrupts at this time. - - - -@node Installation, Problems, Basics, Top -@chapter Installation and Management - -@menu -* Section 3.1:: Why so many modules, and how do I cope with them? -* Section 3.2:: How do I know which chips I own? -* Section 3.3:: Which modules should I insert? -* Section 3.4:: Do I need the configuration file @file{/etc/sensors.conf}? -* Section 3.5:: What about the @samp{No such file or directory} warnings -* Section 3.6:: I get all kinds of weird compilation errors? -* Section 3.7:: It still does not compile or patch! -* Section 3.8:: @command{make install} fails on Mandrake kernels -* Section 3.9:: I get unresolved symbols when I @command{modprobe} modules -* Section 3.10:: I2C_DRIVERID_ADM1024 undefined (Red Hat especially) -@end menu - -@node Section 3.1, Section 3.2, , Installation -@section Why so many modules, and how do I cope with them? - -We tried to make this package as modular as possible. This makes it -easy to add new drivers, and unused drivers will take no precious kernel -space. On the other hand, it can be a bit confusing at first. - -Here are two simple guidelines: -@itemize - @item Run @command{sensors-detect} and do what it tells you. - @item Always use @command{modprobe}, not @command{insmod}. -@end itemize - -Further information is in @file{doc/modules}. - - -@anchor{How do I know which chips I own} -@node Section 3.2, Section 3.3, Section 3.1, Installation -@section How do I know which chips I own? - -We have an excellent program that scans all your hardware. -It is called @file{sensors-detect} and is installed in @file{/usr/local/sbin} -by @command{make install}. Just execute this script, and it will tell you. - -Chip detection in the drivers is fairly good. That means that it is -usually harmless to insert more chip drivers than you need. However, this -can still lead to problems, so we do not recommend it. - -If sensors-detect didn't find any sensors, either you don't have -any, or the ones you have, we don't support. (Look at your motherboard -for candidates, then @pxref{Help}) - - -@anchor{Section 3.2.1} -@subsection What chips are on motherboard XYZ? - - @strong{!!!!!!!!! YES THIS IS THE MOST FREQUENT QUESTION WE GET !!!!!!!!!} - -We have no idea. Here is what you should do: -@enumerate - @item Run sensors-detect. -@end enumerate - -If that doesn't work: -@enumerate 2 -@item Look at your motherboard. -@item Check the manufacturer's website or ask their support -@item Check the -@uref{http://www.lm-sensors.org/wiki/UsefulLinks, "links"} -page on @uref{http://www.lm-sensors.org, our website} some good cross-references. -@end enumerate - - -@anchor{Section 3.2.2} -@subsection Do you support motherboard XYZ? - -We don't support boards, we support chips. @xref{Section 3.2.1, What chips are on motherboard XYZ}. - - -@anchor{Section 3.2.3} -@subsection Do you support chip XYZ? - -This we have good answers for. -@itemize -@item Sorted by Manufacturer: @file{README} -@item Sorted by Manufacturer: @uref{http://www.lm-sensors.org/wiki/Devices} -@item Sorted by Sensor Driver: @file{doc/chips/SUMMARY} -@end itemize - - -@anchor{Section 3.2.4} -@subsection Anybody working on a driver for chip XYZ? - -Newest Driver Status: @uref{http://www.lm-sensors.org/wiki/Devices} - - -@node Section 3.3, Section 3.4, Section 3.2, Installation -@section Which modules should I insert? - -@command{sensors-detect} will tell you. Take the @command{modprobe} lines it -recommends and paste them into the appropriate @file{/etc/rc.d/xxxx} file -to be executed at startup. - -You need one module for each sensor chip and bus adapter you own; -if there are sensor chips on the ISA bus, you also need @file{i2c-isa.o}. -for each type of chip you own. That's all. On my computer, I could use the -following lines: -@itemize -@item @command{modprobe i2c-isa} -@item @command{modprobe i2c-piix4} -@item @command{modprobe lm78} -@item @command{modprobe lm75} -@item @command{modprobe i2c-dev} -@item @command{sensors -s} -@end itemize - - -@node Section 3.4, Section 3.5, Section 3.3, Installation -@section Do I need the configuration file @file{/etc/sensors.conf}? - -Yes, for any applications that use @file{libsensors,} including the -@command{sensors} application included in our package. -It tells libsensors how to translate the values the chip -measures to real-world values. This is especially important for voltage -inputs. The default configuration file should usually do the trick. -It is automatically installed as @file{/etc/sensors.conf}, but it will not -overwrite any existing file with that name. - - -@anchor{Section 3.4.1} -@subsection The labels for the voltage and temperature readings in @command{sensors} are incorrect! - -Every motherboard is different. You can customize the labels -in the file @file{/etc/sensors.conf}. That's why it exists! -The default labelling (in @file{lib/chips.c} and @file{/etc/sensors.conf}) is just -a template. - - -@anchor{Section 3.4.2} -@subsection The min and max for the readings in @command{sensors} are incorrect! - -You can customize them in the file @file{/etc/sensors.conf}. See above. - - -@anchor{Section 3.4.3} -@subsection The min and max settings in @file{/etc/sensors.conf} didn't take effect! - -You forgot to run @command{sensors -s}. See above. - - -@anchor{Section 3.4.4} -@subsection One sensor isn't hooked up on my board! - -Use an @command{ignore} line in @file{/etc/sensors.conf} so it isn't -displayed in @command{sensors}. - - -@anchor{Section 3.4.5} -@subsection I need help with @file{sensors.conf}! - -There is detailed help at the top of that file. - - -@anchor{Section 3.4.6} -@subsection Do you have a database of @file{sensors.conf} entries for specific boards? - -No. Good idea though. If you would like to set one up on your website -send us mail and we will set up a link to it. - - -@node Section 3.5, Section 3.6, Section 3.4, Installation -@section What about the @samp{No such file or directory} warnings when I compile? - -Don't worry about them. The dependency files (which tell which -files should be recompiled when certain files change) are created -dynamically. They are not distributed with the package. The @command{make} program -notices they are not there, and warns about that - and the first thing -it will do is generate them. So all is well. - - -@node Section 3.6, Section 3.7, Section 3.5, Installation -@section I get all kinds of weird compilation errors? - -Check that the correct i2c header files are used. Depending on -how you installed, they should be under either @file{/usr/local/include} or -@file{/usr/src/linux*/include}. Try to edit the @file{Makefile} for the other setting. - - -@anchor{Section 3.6.1} -@subsection @samp{No rule to make target xxxx needed by xxxx} - how to fix? - -@itemize -@item @xref{Section 3.6, I get all kinds of weird compilation errors}, also try @command{make clean} in @file{lm_sensors}. -@item If that doesn't work, try @command{make clean} in @file{i2c}. -@item If that doesn't work, try @command{make clean} in the kernel. -@item Also make sure @file{/usr/include/linux} points to @file{/usr/src/linux/include/linux}. -@end itemize - - -@node Section 3.7, Section 3.8, Section 3.6, Installation -@section It still does not compile or patch! - -Have you installed the matching version of the i2c package? Remember, -compilation is not enough, you also need to install it for the header -files to be found! - -If you want to patch the kernel, you will have to apply the i2c -patches first! - - -@node Section 3.8, Section 3.9, Section 3.7, Installation -@section @command{make install} fails on Mandrake kernels - -Mandrake uses a non-standard @file{version.h} file which confuses our @file{Makefile}. -Edit our @file{Makefile} on the @code{MODDIR :=} line to hard-code the module directory. - - -@node Section 3.9, Section 3.10, Section 3.8, Installation -@section I get unresolved symbols when I @command{modprobe} modules (Red Hat especially) - -Example: -@example -*** Unresolved symbols in /lib/modules/2.4.5/kernel/drivers/i2c/i2c-i810.o -i2c_bit_add_bus_R8c3bc60e -i2c_bit_del_bus_R92b18f49 -@end example - -You can also run @command{depmod -a -e} to see all unresolved symbols. - - -These are module versioning problems. Generally you did not compile -against the kernel you are running. Sometimes the Red Hat source you -have is not for the kernel you are running. -You must compile our package against the source for the kernel you -are running with something like @command{make LINUX=/usr/src/linux-2.4.14}. - - -Try the following to be sure: - -@itemize -@item @command{nm --extern MODULE.o} -Filter out the kernel symbols, like @code{kmalloc}, @code{printk} etc. and note the -number code behind them, like @code{printk_R1b7d4074}. If there is no numeric -code after them, note this too. -@item @command{grep SYMBOL /proc/ksyms} -Substitute SYMBOL by the basename of the symbols above, like @code{kmalloc}, -@code{printk} etc. Note the number code behind them, or the lack thereof. -@item Compare both sets of symbols. Are they the same? If so, the problem -lies somewhere else. Are they different? If so, you have a module -versioning problem. -@end itemize - - -@node Section 3.10, , Section 3.9, Installation -@section I2C_DRIVERID_ADM1024 undefined (Red Hat especially) - -In some versions of Redhat, an RPM is included to provide i2c support. -However, this RPM does not place the header files in the kernel directory -structure. When you update kernels, they may persist. To get rid of -these obsolete header files, at a command prompt: - -@enumerate -@item @command{rpm -qa | grep i2c} -@item Look for @file{kernel-i2c,} or a similar rpm in the output -@item -@command{rpm -ev kernel-i2c} (or the name of the similar package) -If this complains about dependencies, you can try adding -@command{--nodeps}, but this *MAY* break something else. Not likely, -as you have upgraded kernels, and nothing should be using the -old i2c stuff anymore anyway. Just don't use it with abandon. -@item Try (in the build directory of @file{lm_sensors)} -@example -@command{make clean} -@command{make} -@end example -@item @emph{If} you still have problems, you may have to replace the include -paths in the @file{.c/.h} files with absolute paths to the header files. -More of a workaround than a real fix, but at least you can get it -to work. -@end enumerate - - -@node Problems, Help, Installation, Top -@chapter Problems - -@menu -* Section 4.1:: My fans report exactly half/double their values? -* Section 4.2:: Why do my two LM75's report "-48 degrees"? -* Section 4.3:: Why do I have two Vcore readings? -* Section 4.4:: How do those ALARMS work? -* Section 4.5:: My voltage readings seem to drift a bit. What's wrong? -* Section 4.6:: Some measurements are way out of range. What happened? -* Section 4.7:: What are VID lines? Why is the VID reading wrong? -* Section 4.8:: Sensor are only updated each second or so. Why? -* Section 4.9:: It takes a second before reading sensor results. Why? -* Section 4.10:: Can I be alerted when an ALARM occurs? -* Section 4.11:: SMBus transactions on my PIIX4 simply don't work. Why? -* Section 4.12:: My BIOS reports a higher CPU temperature than you! -* Section 4.13:: I read strange values from the raw @file{/proc} files! -* Section 4.14:: How do I set new limits? -* Section 4.15:: Some sensors are doubly detected? -* Section 4.16:: I ran sensors-detect, but now I get strange readings?! -* Section 4.17:: Bad readings from particular chips -* Section 4.18:: How do I configure two chips (LM87) differently? -* Section 4.19:: Dmesg says @samp{Upgrade BIOS}! I don't want to! -* Section 4.20:: Sensors says @samp{Can't access procfs/sysfs file} -* Section 4.21:: Sensors says @samp{No sensors found!} -* Section 4.22:: Sensors output is not correct! -* Section 4.23:: What is at I2C address XXX? -* Section 4.24:: Sensors-detect doesn't work at all -* Section 4.25:: Sensors says @samp{Error: Line xxx: zzzzzzz} -* Section 4.26:: Sensors only gives the name, adapter, and algorithm! -* Section 4.27:: Sensors says @samp{ERROR: Can't get xxxxx data!} -* Section 4.28:: Sensors doesn't find any sensors, just eeproms. -* Section 4.29:: Inserting modules hangs my board -* Section 4.30:: Inserting modules slows down my board -* Section 4.31:: Problems on particular motherboards -* Section 4.32:: Problems on particular systems -* Section 4.33:: Problems on 2.6 kernels -@end menu - - -@node Section 4.1, Section 4.2, , Problems -@section My fans report exactly half/double their values compared to the BIOS? - -The problem with much of the sensor data is that it is impossible to -properly interpret some of the readings without knowing what the hardware -configuration is. Some fans report one 'tick' each rotation, some report -two 'ticks' each rotation. It is easy to resolve this through the -configuration file @file{/etc/sensors.conf}: - -@example -chip lm78-* # Or whatever chip this relates to -compute fan1 2*@@,@@/2 # This will double the fan1 reading - # -- or -- -compute fan1 @@/2,2*@@ # This will halve the fan1 reading -@end example - -See @file{doc/fan-divisors} in our package for further information. - - -@anchor{Fans sometimes/always read 0!} -@subsection Fans sometimes/always read 0!! - -You may not have a three-wire fan, which is required. - -You may need to increase the 'fan divisor'. See @file{doc/fan-divisors} -in our package for further information. - - -@anchor{I doubled the fan divisor and the fan still reads 7000} -@subsection I doubled the fan divisor and the fan still reads 7000! - -Believe it or not, doubling the 'fan divisor' will not halve -the fan reading. You have to add a compute line in @file{/etc/sensors.conf}. -@xref{Section 4.1, My fans report exactly half/double their values compared to the BIOS}, -and see @file{doc/fan-divisors} in our package for further information. - - -@node Section 4.2, Section 4.3, Section 4.1, Problems -@section Why do my two LM75's report "-48 degrees"? - -For starters, those aren't LM75's. Your mainboard actually has the -Winbond W83781D which emulates two LM75's, but many systems which use the -Winbond chip (such as the Asus P2B) don't have the thermo-resisters connected -to the chip resulting in these strange -48 degree readings. - -In upcoming versions, you will be able to disable non-interesting -readings. - - -@node Section 4.3, Section 4.4, Section 4.2, Problems -@section Why do I have two Vcore readings, I have only one processor! - -The LM78 has seven voltage sensors. The default way of -connecting them is used in the configuration file. This includes a VCore2, -even if you do not have one. You can easily edit the configuration file -to give it another name, or make this reading disappear using -an @command{ignore} line. - -Note that Vcore2 is often the same as Vcore on motherboards which -only support one processor. Another possibility is that Vcore2 is not -connected at all and will not have a valid reading at all. -A third possibility, is that Vcore2 monitors something -else, so you should not be too surprised if the values are completely -different. - - -@node Section 4.4, Section 4.5, Section 4.3, Problems -@section How do those ALARMS work? The current value is within range but there is still an ALARM warning! - -The ALARM indications in @command{sensors} are those reported by the -sensor chip itself. They are NOT calculated by @command{sensors}. @command{sensors} -simply reads the ALARM bits and reports them. - -An ALARM will go off when a minimum or maximum limit is crossed. -The ALARM is then latched - that is, it will stay there until the -chip's registers are next accessed - which will be the next time -you read these values, but not within (usually) 1.5 seconds since the last -update. - -Reading the registers clears the ALARMS, unless the current -value is still out of range. - -The purpose of this scheme is to tell you if there has been -a problem and report it to the user. Voltage or temperature spikes -get detected without having to read the sensor chip hundreds of times -a second. The implemetation details depend a bit on the kind of chip. -See the specific chip documentation in @file{doc/chips} and the -chip datasheet for more information. - - -@node Section 4.5, Section 4.6, Section 4.4, Problems -@section My voltage readings seem to drift a bit. Is something wrong? - -No, probably not. If your motherboard heats up a bit, the sensed -voltages will drift a bit. If your power supply is loaded (because a disk -gets going, for example), the voltages may get a bit lower. Heavy -processor activity, in particular, dramatically increases core voltage -supply load which will often cause variation in the other supplies. -As long as they stay within a sensible range (say 5% of the nominal value -for CPU core voltages, and 10% for other voltages), there is no -reason to worry. - - -@node Section 4.6, Section 4.7, Section 4.5, Problems -@section Some measurements are way out of range. What happened? - -Each module tries to set limits to sensible values on initialization, -but a module does not know how a chip is actually connected. This is -described in the configuration file, which is not read by kernel modules. -So limits can be strange, if the chip is connected in a non-standard way. - -Readings can also be strange; there are several reasons for this. -Temperature sensors, for example, can simply not be present, even though -the chip supports them. Also, it can be that the input is used in a -non-standard way. You can use the configuration file to describe how this -measurement should be interpreted; see the comments the example file for -more information. - -@anchor{-5V and -12V readings are way out of range!} -@subsection -5V and -12V readings are way out of range! - -It's very frequent that negative voltage lines are not wired because -motherboard manufacturers don't think they're worth monitoring -(they are mostly unused these days). You can just add -@command{ignore inN} lines to @file{/etc/sensors.conf} to hide them. - -Another possibility is that these lines are used to monitor different -voltages. Only the motherboard manufacturer can tell for sure. Taking -a look at what voltage values the BIOS displays may provide valuable -hints though. - - -@node Section 4.7, Section 4.8, Section 4.6, Problems -@section What are VID lines? Why is the VID reading wrong? - -These describe the core voltage for your processor. They are -supported for most processors, however they are not always -correctly connected to the sensor chip, so the readings may be invalid. -A reading of 0V, +3.5V or +2.05V is especially suspect. -If this is the case, add a line @command{ignore vid} to @file{/etc/sensors.conf}, -and change the min and max settings for the Processor Core voltage -(often in0_min and in0_max) in that file so that they don't depend on vid. - -The CPU nominal voltage is computed from VID lines according to a formula -that depends on the CPU type. Most chips that report a VID value can be -configured to use either VRM 8.2 (for Pentium III) or VRM 9.0 (for Pentium 4 -and Athlon). You chose which one you want through @file{/etc/sensors.conf}. -See @file{doc/vid} for more information. - - -@node Section 4.8, Section 4.9, Section 4.7, Problems -@section I read sensor values several times a second, but they are only updated only each second or so. Why? - -If we would read the registers more often, it would not find the -time to update them. So we only update our readings once each 1.5 seconds -(the actual delay is chip-specific; for some chips, it may not be needed -at all). - - -@node Section 4.9, Section 4.10, Section 4.8, Problems -@section It sometimes seems to take almost a second before I see the sensor reading results. Why? - -ISA bus access is fast, but SMBus access is really slow. If you have -a lot of sensors, it just takes a lot of time to access them. Fortunately, -this has almost no impact on the system as a whole, as another job can run -while we are waiting for the transaction to finish. - - -@node Section 4.10, Section 4.11, Section 4.9, Problems -@section Can I be alerted when an ALARM occurs? - -No, you can't; and it may well be never supported. - -Almost no mainboard we have encountered have actually connected the -IRQ-out pin of sensor chips. That means that we could enable IRQ reporting, but -nothing would happen. Also, even if a motherboard has it connected, it is -unclear what interrupt number would be triggered. And IRQ lines are a scarce -facility, which means that almost nobody would be able to use it anyway. - -The SMI interrupt is only available on a few types of chips. It is -really a very obscure way to handle interrupts, and supporting it under Linux -might be quite hard to do. - -Your best bet would be to poll the alarm file with a user-land daemon -which alerts you if an alarm is raised. I am not aware of any program which -does the job, though you might want to examine one of the graphical monitor -programs under X, see @uref{http://www.lm-sensors.org/wiki/UsefulLinks} for addresses. - - -@node Section 4.11, Section 4.12, Section 4.10, Problems -@section SMBus transactions on my PIIX4 simply don't work (timeouts happen). Why? - -Some chips which mainboard makers connect to the SMBus are not SMBus -devices. An example is the 91xx clock generator chips. When read, these -devices can lock up the SMBus until the next hard reboot. This is because -they have a similar serial interface (like the I2C), but don't conform to -Intel's SMBus standard. - -Why did they connect these devices to the SMBus if they aren't -compatible? Good question! :') Actually, these devices may support being -written to, but lock things up when they are read. - - -@node Section 4.12, Section 4.13, Section 4.11, Problems -@section My BIOS reports a much higher CPU temperature than your modules! - -We display the actual temperature of the sensor. This may not be the -temperature you are interested in, though. If a sensor should measure -the CPU temperature, it must be in thermal contact with it. In practice, -it may be just somewhere nearby. Your BIOS may correct for this (by adding, -for example, thirty degrees to the measured temperature). The correction -factor is regrettably different for each mainboard, so we can not do this -in the module itself. You can do it through the configuration file, though: - -@example -chip lm75-*-49 # Or whatever chip this relates to -label temp "Processor" -compute temp @@*1.2+13,(@@-13)/1.2 # Or whatever formula -@end example - -However, the offset you are introducing might not be necessary. If you -tried to have Linux idle temperature and BIOS "idle" temperature match, -you may be misguided. -We have a Supermicro (370DLE) motherboard and we know -that its BIOS has a closed, almost undelayed while(1) loop that -keeps the CPU busy all the time. Linux reads 26 degrees idle, BIOS reads -38 degrees. Linux at full load is in the 35-40 degrees range so this -makes sense. - -@node Section 4.13, Section 4.14, Section 4.12, Problems -@section I try to read the raw @file{/proc} files, but the values are strange?!? - -Remember, these values do not take the configuration file -@file{compute} lines in account. This is especially obvious for voltage readings -(usually called in? or vin?). Use a program linked to libsensors (like -the provided @command{sensors} program) instead. - - -@node Section 4.14, Section 4.15, Section 4.13, Problems -@section How do I set new limits? - -Change the limit values in @file{/etc/sensors.conf} and then run -@command{sensors -s}. - - -@anchor{I set new limits and it didnt work} -@subsection I set new limits and it didn't work? - -You forgot to run @command{sensors -s}. Put it in a @file{/etc/rc.d/...} file -after the modprobe lines to run at startup. - - -@node Section 4.15, Section 4.16, Section 4.14, Problems -@section Some sensors are doubly detected? - -Yes, this is still a problem. It is partially solved by alias detection -and confidence values in sensors-detect, but it is really tough. - -Double detections can be caused by two things: -sensors can be detected to both the ISA and the SMBus (and if you have -loaded the approprate adapter drivers, it will be detected on both), and -some chips simulate other chips (the Winbond W83781D simulates LM75 chips -on the SMBus, for example). Remove the offending adapter or chip driver, or -run sensors-detect and add the @command{ignore=} modprobe parameters it suggests. - - -@node Section 4.16, Section 4.17, Section 4.15, Problems -@section I ran sensors-detect, but now I get very strange readings?!? - -Your SMBus (PIIX4?) is probably crashed or hung. There are some mainboards -which connect a clock chip to the SMBus. Unfortunately, this clock chip -hangs the PIIX4 if it is read (it is an I2C device, but not SMBus compatible). -We have found no way of solving this, except for rebooting your computer. -Next time when you run sensors-detect, you may want to exclude addresses -0x69 and/or 0x6a, by entering @kbd{s} when you are asked whether you want to -scan the PIIX4. - - -@node Section 4.17, Section 4.18, Section 4.16, Problems -@section Bad readings from particular chips - -See below for some particularly troublesome chips. -Also be sure and check @file{doc/chips/xxxxx} for the particular driver. - - -@anchor{Bad readings from the AS99127F} -@subsection Bad readings from the AS99127F! - -The Asus AS99127F is a modified version of the Winbond W83781D. -Asus will not release a datasheet. The driver was developed by tedious -experimentation. We've done the best we can. If you want to make adjustments -to the readings please edit @file{/etc/sensors.conf.} Please don't ask us to -fix the driver. Ask Asus to release a datasheet. - - -@anchor{Bad readings from the VIA 686A} -@subsection Bad readings from the VIA 686A! - -The Via 686A datasheet is incomplete. -Via will not release details. The driver was developed by tedious -experimentation. We've done the best we can. If you want to make adjustments -to the readings please edit @file{/etc/sensors.conf.} Please don't ask us to -fix the driver. Ask Via to release a better datasheet. -Also, don't forget to @command{modprobe i2c-isa}. - - -@anchor{Bad readings from the MTP008} -@subsection Bad readings from the MTP008! - -The MTP008 has programmable temperature sensor types. -If your sensor type does not match the default, you will have to change it. -See @file{doc/chips/mtp008} for details. -Also, MTP008 chips seem to randomly refuse to respond, for -unknown reasons. You can see this as 'XX' entries in i2cdump. - - -@anchor{Bad temperature readings from the SIS5595} -@subsection Bad temperature readings from the SIS5595! - -This chip can use multiple thermistor types and there are also -two different versions of the chip. We are trying to get the driver -working better and develop formulas for different thermistors -but we aren't there yet. Sorry. -Also, many times the chip isn't really a sis5595 but it was -misidentified. We are working on improving that too. - - -@anchor{Bad readings from a w8378[12]d} -@subsection Bad readings from a w8378[12]d! - -Do you own an ASUS motherboard? Perhaps your chip is being -misidentified. Look on the motherboard for a 'Winbond' or Asus chip. -Often the real device is an Asus as99127f. If so, the driver can be -forced to recognize the as99127f with -@command{force_as99127f=BUS,0x2d} where @code{BUS} is your i2c bus number. -Cat /proc/bus/i2c to see a list of bus numbers. -Read the w83781d module documentation (@file{doc/chips/w83781d}) -for more details. - - -@anchor{Bus hangs on Ali 1543 on Asus P5A boards} -@subsection Bus hangs on Ali 1543 on Asus P5A boards! - -The SMBus tends to hang on this board and it seems to get worse -at higher temperatures. Use ISA accesses to reliably use the w83781d -monitor chip on this board and use the @command{ignore=1,0x2d} or similar option -to the w83781d module to prevent i2c accesses. - - -@anchor{Bad readings from LM75} -@subsection Bad readings from LM75! - -The LM75 detection is poor and other hardware is often misdetected -as an LM75. Figure out what you really have @xref{Section 3.2.1, What chips are on motherboard XYZ}. - - -@anchor{Bad readings from LM78} -@subsection Bad readings from LM78! - -The LM78 is no longer manufactured by National Semiconductor. -You probably don't have a real LM78 but something similar that we -do not recogize or support. Figure out what you really have @xref{Section 3.2.1, What chips are on motherboard XYZ}. - - -@anchor{Bad readings from LM80} -@subsection Bad readings from LM80! - -The LM80 detection is poor and other hardware is often misdetected -as an LM80. Figure out what you really have @xref{Section 3.2.1, What chips are on motherboard XYZ}. - - -@node Section 4.18, Section 4.19, Section 4.17, Problems -@section How do I configure two chips (LM87) differently? - -There is a SuperMicro board with two LM87's on it that are -not hooked up in the same way, so they need different defaults. -For example, both CPU temperatures go to one LM87. - -Make two different sections in @file{/etc/sensors.conf} as follows: -@example -chip "lm87-i2c-*-2c" - put configuration for the chip at 0x2c here -chip "lm87-i2c-*-2d" - put configuration for the chip at 0x2d here -@end example - -There is a commented example in @file{sensors.conf.eg} which should -be helpful. - - -@node Section 4.19, Section 4.20, Section 4.18, Problems -@section Dmesg says @samp{Upgrade BIOS}! I don't want to! - -If the problem is a PCI device is not present in @command{lspci}, the solution -is complex. For the ALI M7101 device, there is a solution which uses the -2.4 kernel's @command{hotplug} facility. See @file{prog/hotplug} in our package. -For other PCI devices, you can try to modify -the m7101 solution in @file{prog/hotplug}. - - -If dmesg says @samp{try force_addr}, see below. Other drivers generally do not -support the force_addr parameter. Sorry. Check the documentation -for your driver in @file{doc/[chips,busses]} and if we don't support it -you can send us your request. - - -@anchor{Dmesg says use force_addr=0xaddr! What address do I use} -@subsection Dmesg says @samp{use force_addr=0xaddr}! What address do I use? - -If the problem is a PCI device whose base address is not set, -you may be able to set the address with a force parameter. The via686a -and sis5595 chip drivers, and some bus drivers, support the command line -@command{modprobe via686a force_addr=0xADDRESS} where ADDRESS -is the I/O address. You must select an address that is not in use. -@command{cat @file{/proc/ioports}} to check (carefully) for conflicts. A high number like -0xf000 is generally safe. - - -@node Section 4.20, Section 4.21, Section 4.19, Problems -@section Sensors says @samp{Can't access procfs/sysfs file} - -@itemize -@item Linux 2.6 -@itemize -@item Did you @command{modprobe i2c_sensor}? Check @command{lsmod}. -@item Do you have sysfs support in your kernel and @file{/sys} mounted (is @file{/sys} there and populated)? -Create /sys with @command{mkdir /sys} if needed. Then add the following line to @file{/etc/fstab}: -@example -sys /sys sysfs default 0 0@end example -and @command{mount /sys}. -@end itemize -@item Linux 2.4 -@itemize -@item Did you @command{modprobe i2c-proc}? Check @command{lsmod}. -@item Do you have procfs support in your kernel and @file{/proc} mounted (is @file{/proc} there and populated)? -Create /proc with @command{mkdir /proc} if needed. Then add the following line to @file{/etc/fstab}: -@example -proc /proc proc defaults 0 0@end example -and @command{mount /proc}. -@end itemize -@item If you did @command{sensors -s}, did you run it as root? -@end itemize - - -@node Section 4.21, Section 4.22, Section 4.20, Problems -@section Sensors says @samp{No sensors found!} - -@itemize -@item Did @command{sensors-detect} find sensors? (If not @pxref{Sensors-detect doesnt find any sensors}) -@item Did you do what @command{sensors-detect} said? -@item Did you @command{modprobe} your sensor modules? -@item Did you @command{modprobe} your I2C adapter modules? -@item Did you @command{modprobe i2c-isa} if you have ISA sensor chips? -@item Check @command{lsmod}. -@end itemize - - -@node Section 4.22, Section 4.23, Section 4.21, Problems -@section Sensors output is not correct! - - What specifically is the trouble? -@itemize -@item Labels: @xref{Section 3.4.1, The labels for the voltage and temperature readings in sensors are incorrect}. -@item Min/max readings: @xref{Section 3.4.2, The min and max for the readings in sensors are incorrect}, and @xref{Section 3.4.3, The min and max settings didnt take effect}. -@item AS99127F: @xref{Section 4.16, I ran sensors-detect but now I get very strange readings?}. -@item Via 686A: @xref{Section 4.16, I ran sensors-detect but now I get very strange readings?}. -@item Other specific chips: @xref{Section 4.16, I ran sensors-detect but now I get very strange readings?}. -@item No output for a particular sensors chip: @xref{Section 5.3, What to do if it inserts but nothing happens}. -@item No output at all: @xref{Section 4.21, Sensors says No sensors found}, @xref{Section 5.3, What to do if it inserts but nothing happens}. -@item Completely bad output for a particular sensor chip: @xref{Section 5.4, What to do if I read only bogus information}. -@item One particular sensor readings: -@itemize -@item Maybe it isn't hooked up? - tell 'sensors' to ignore it. @xref{Section 3.4.4, One sensor isnt hooked up on my board}. -@item Maybe it is hooked up differently on your motherboard? - adjust @file{sensors.conf} calculation. -@end itemize -@end itemize - -@node Section 4.23, Section 4.24, Section 4.22, Problems -@section What is at I2C address XXX? - -In general, we don't know. Start by running @command{sensors-detect}. -If it doesn't recognize it, try running @command{i2cdump}. A partial list -of manufacturers' IDs are at the bottom of @file{doc/chips/SUMMARY}. - - -@anchor{What is at I2C address 0x69} -@subsection What is at I2C address 0x69? - -A clock chip. Often, accessing these clock chips in the wrong -way will instantly crash your computer. Sensors-detect carefully -avoids these chips, and you should do too. You have been warned. - - -@anchor{What is at I2C addresses 0x50 - 0x57} -@subsection What is at I2C addresses 0x50 - 0x57? - -EEPROMs on your SDRAM DIMMs. Load the eeprom module to -look at some basic data in @command{sensors} or use the program -@command{prog/eeprom/decode-dimms.pl} to get more information than you ever wanted. - - -@anchor{What is at I2C addresses 0x30 - 0x37} -@subsection What is at I2C addresses 0x30 - 0x37? - -These are often 'shadows' of your EEPROMs on your SDRAM DIMMs -at addresses 0x50 - 0x57. They are the 'software write-protect' -registers of the SDRAM Serial Presence Detect EEPROMs. -If you try and -do a @command{i2cdump} on them to read the location, you won't get anything, -because they contain a single write-only register. -This register can be used to permanently -write-protect the contents of the eeprom. - - -@node Section 4.24, Section 4.25, Section 4.23, Problems -@section Sensors-detect doesn't work at all - -It could be many things. What was the problem? @xref{Section 4.31, Problems on particular motherboards}. - - -@anchor{Sensors-detect says "Couldnt open /proc/bus/i2c?!?"} -@subsection Sensors-detect says "Couldn't open /proc/bus/i2c?!?" - -You don't have i2c support in your kernel, or the i2c-core module -was not loaded and you did not run sensors-detect as root. - - -@anchor{Sensors-detect says "Cant open /dev/i2c[-/]0"} -@subsection Sensors-detect says "Can't open /dev/i2c[-/]0" - -Your @file{/dev/i2c-0,} @file{/dev/i2c0}, or @file{/dev/i2c/0} files do not exist -or you did not run @command{sensors-detect} as root. -Run the script @command{prog/mkdev/mkdev.sh} to create the @file{/dev/i2c-x} files. -Run @command{devfs} in the kernel to get the @file{/dev/i2c/x} files. - - -@anchor{Sensors-detect doesnt find any sensors} -@subsection Sensors-detect doesn't find any sensors! - -Either -@enumerate -@item The board doesn't have any sensors. -@item We don't support the sensors on the board. -@item The sensors it has are on an I2C bus connected to an I2C bus adapter that we don't support. -@item You don't have the latest version of lm_sensors. -@end enumerate - -But in any case you should figure out what is on the board: -@enumerate -@item Look at your motherboard. -@item Check the manufacturer's website. -@end enumerate - -When you know what chips you have, check the -@uref{http://www.lm-sensors.org/wiki/Devices, Driver Status} web page to -see if support has been added for your chip in a later release or in SVN. - - -@node Section 4.25, Section 4.26, Section 4.24, Problems -@section Sensors says @samp{Error: Line xxx: zzzzzzz} - -These are errors from the libsensors library in -reading the @file{/etc/sensors.conf} configuration file. Go to that line -number and fix it. If you have a parse error, perhaps you have -to put the feature name in double quotes. - - -@node Section 4.26, Section 4.27, Section 4.25, Problems -@section Sensors only gives the name, adapter, and algorithm for my chip - -If @command{sensors} only says this, for example, and doesn't -provide any actual data at all: - -@example -it87-isa-0290 -Adapter: ISA adapter -Algorithm: ISA algorithm -@end example - -Your chip is not currently supported by @command{sensors} and so all it -does is print out that information. Get the latest release -and be sure you are running the @command{sensors} program it installed -and not some older @command{sensors}. - - -@node Section 4.27, Section 4.28, Section 4.26, Problems -@section Sensors says @samp{ERROR: Can't get xxxxx data!} - -@itemize -@item (Linux 2.6) Make sure you are using one of the -@uref{http://www.lm-sensors.org/wiki/Kernel2.6, -recommended kernel/lm_sensors combination}. -@item You have a @file{libsensors}/@command{sensors} mismatch. -@command{sensors} is unable to -get a data entry from @file{libsensors}. You probably have an -old @file{libsensors} in your @file{/etc/ld.so.conf} path. -Make sure you did (as root) a @command{make install} (Linux 2.4) or -@command{make user_install} (Linux 2.6) followed by a @command{ldconfig}. -Then check the output of @command{ldconfig -v | grep libsensors} to -verify that there is only ONE @file{libsensors} entry and that it matches -the @file{libsensors} that was built in the @file{lib/} directory in @file{lm_sensors2}. -@end itemize - - -@node Section 4.28, Section 4.29, Section 4.27, Problems -@section Sensors doesn't find any sensors, just eeproms. - -@xref{Section 4.24, Sensors-detect doesnt work at all}, if @command{sensors-detect} failed to find any sensors. - -If @command{sensors-detect} did find sensors, did you insert your modules? For chips on the ISA -bus, did you insert i2c-isa? - -@xref{Section 5.2, What to do if a module wont insert}, if the modules didn't insert, -also @ref{Section 4.21, Sensors says No sensors found}. - - -@node Section 4.29, Section 4.30, Section 4.28, Problems -@section Inserting modules hangs my board - -There are several possible causes: -@enumerate -@item Bus driver problems. Insert the bus driver first, before you have inserted any chip drivers, to verify. -@item Wrong chip driver. Verify that you have a chip supported by the chip driver, see @ref{Section 3.2.1, What chips are on motherboard XYZ}. -@item The chip driver is reinitializing the chip, which undoes critical initialization done by the BIOS. Try the parameter @command{init=0} for the w83781d driver; this is the only driver supporting this parameter. -@item Some chips on the bus don't like to be probed at all. After inserting the bus driver (but not the chip drivers), run @command{i2cdetect} on the bus, then @command{i2cdump} on each address responding to @command{i2cdetect}. This may find the culprit. Do not @command{i2cdump address 0x69}, the clock chip. -@item The chip driver is incorrectly finding a second chip on the bus and is accessing it. For example, with the Tyan 2688 with a w83781d at 0x29, use @command{modprobe ignore_range=0,0x00,0x28,0,0x2a,0x7f} to prevent access to other addresses. (@command{init=0} also req'd for the Tyan 2688). -@end enumerate - - -@node Section 4.30, Section 4.31, Section 4.29, Problems -@section Inserting modules slows down my board - -Generally this is caused by an overtemperature alarm output from -the sensor chip. This triggers hardware on the board which -automatically slows down the CPU clock. Be sure that your -temperature limits are above the temperature reading. Put -the new limits in @file{/etc/sensors.conf} and run @command{sensors -s}. - - -@node Section 4.31, Section 4.32, Section 4.30, Problems -@section Problems on particular motherboards - -The following boards have unique problems and solutions. - - -@anchor{Asus P4B} -@subsection Asus P4B - -See @file{prog/hotplug/README.p4b} if your SMBus master is not found. - - -@anchor{Tyan 2460 2462} -@subsection Tyan 2460, 2462 - -See support tickets 805, 765, 781, 812, 813, and 867 for information. - - -@anchor{Tyan 2466} -@subsection Tyan 2466 - -See support tickets 941, 840, and 841 for information. - - -@anchor{Tyan 2688} -@subsection Tyan 2688 - -For board hangs, see support ticket 721 for information. -Also @ref{Section 4.29, Inserting modules hangs my board}. - - -@node Section 4.32, Section 4.33, Section 4.31, Problems -@section Problems on particular systems - -For IBM systems, see @file{README.thinkpad}. - - -@node Section 4.33, , Section 4.32, Problems -@section Problems on 2.6 kernels - -Not all drivers have been ported to 2.6. If your favorite driver is not -in 2.6, the reason is that nobody has ported it, or the ported code did -not get a proper review yet. -If you would like to port the driver, see the file -Documentation/i2c/porting-clients in the 2.6 kernel tree for help, -then send us the ported driver when you are done. - -@subsection i2c-viapro and via686a -Until kernel 2.6.11, there was a PCI resource conflict between -i2c-viapro (the SMBus driver for VIA bridges) and via686a (the integrated -sensors driver for VIA bridges). This caused the second loaded driver to -silently fail working. So do not load both i2c-viapro and via686a together -unless you have a recent kernel. - -@subsection Where are my EEPROMs? -The 2.6.14-rc1 kernel introduced the hwmon class, which groups all -hardware monitoring drivers in a logical way. The goal was to help -libsensors grab the relevant sensors information in /sys. In particular: -@itemize -@item libsensors will no more need to know about the underlying bus types -(I2C/SMBus, ISA or other); -@item libsensors will no more list non-hardware monitoring chips. -@end itemize -This explains why EEPROMs are no more displayed by @command{sensors}: -they are no hardware monitoring chips. The medium term plan is to drop -eeprom support for all Linux 2.6 kernels, as it didn't fit well in -the library code in the first place. - -Note that you can still obtain information about your EEPROMs by using -the dedicated perl scripts in @file{prog/eeprom}: @command{ddcmon}, -@command{decode-dimms.pl}, @command{decode-edid.pl} and -@command{decode-vaio.pl}. - - -@node Help, Contribute, Problems, Top -@chapter How to Ask for Help - -@menu -* Section 5.1:: What to send us when asking for help -* Section 5.2:: What to do if a module won't insert? -* Section 5.3:: What to do if it inserts, but nothing happens? -* Section 5.4:: What to do if I read only bogus information? -* Section 5.5:: What to do if you have other problems? -* Section 5.6:: What if it just works like a charm? -* Section 5.7:: How do I update a ticket? -* Section 5.8:: How do I follow up on a ticket? -* Section 5.9:: Why did you decide not to support undocumented chips? -@end menu - - -@node Section 5.1, Section 5.2, , Help -@section What to send us when asking for help - -We are always willing to answer questions if things don't work out. -Post your question to our @uref{http://lists.lm-sensors.org/mailman/listinfo/lm-sensors, discussion list}, -and not the individual authors, -unless you have something private to say. - -Instead of using email, you can also use the web-based support -area, at @uref{http://www.lm-sensors.org/wiki/FeedbackAndSupport}. You will be helped -just as fast, and others may profit from the answer too. You will be -emailed automatically when your question has been answered. - -Here's what you should send us: - -@itemize -@item The dmesg or syslog output if applicable -@item The output of (as root) @command{prog/detect/sensors-detect} -@item The output of @command{lsmod} -@item If a PCI chip problem: -@itemize -@item The output of @command{lspci -n} -@end itemize -@item If an I2C sensor chip problem: -@itemize -@item The output of (as root) @command{prog/detect/i2cdetect X} -where X = the bus number (run @command{i2cdetect} with no arguments to list the busses) -(please send this only if it's not all @samp{XX}) -@end itemize -@item If an ISA sensor chip problem: -@itemize -@item The output of (as root) @command{prog/dump/isadump 0x295 0x296} (only if it's not all @samp{XX}) -@end itemize -@item Part numbers of chips on your motherboard you think are the sensor chips (look at your motherboard) -@item Motherboard type -@item Sensors version -@item Kernel version -@end itemize - - -@node Section 5.2, Section 5.3, Section 5.1, Help -@section What to do if a module won't insert? - -Did you use @command{modprobe} instead of @command{insmod}??? Don't use insmod. - -Were there unresolved symbols? Did you run @command{depmod -a}? Run -@command{depmod -a -e} to see where the symbol problem is. - -ALWAYS inspect the output of @command{dmesg}. That's where the error -messages come out!!! Don't rely on the generic message from @command{modprobe}. -If you still can't figure it out, send us the information -listed above. - - -@node Section 5.3, Section 5.4, Section 5.2, Help -@section What to do if it inserts, but nothing happens? - -For an ISA sensor chip, did you also @command{modprobe i2c-isa}? It must be inserted. - -For an I2C sensor chip, did you also @command{modprobe i2c-xxx} where xxx is your -I2C bus adapter? It must be inserted. - -Always inspect the output of @command{dmesg}. That's where the error -messages come out. If you still can't figure it out, send us the information -listed above. - - -@node Section 5.4, Section 5.5, Section 5.3, Help -@section What to do if I read only bogus information? - -It may be that this was a mis-detection: the chip may not be -present. If you are convinced there is something wrong, verify that you -indeed have the devices on your motherboard that you think you do. -Look at the motherboard and make sure. If you are still stuck, -please send us the usual information (@pxref{Help}) - - -@node Section 5.5, Section 5.6, Section 5.4, Help -@section What to do if you have other problems? - -Again, send the output listed above. - - -@node Section 5.6, Section 5.7, Section 5.5, Help -@section What if it just works like a charm? - -Drop us a mail if you feel like it, mentioning the mainboard and -detected chip type. That way, we have some positive feedback, too! - - -@node Section 5.7, Section 5.8, Section 5.6, Help -@section How do I update a ticket? - -You can't. Only developers can. Follow up by emailing us -and reference your ticket number -in the subject. Please don't enter a new ticket with -follow-up information, email us instead. Thanks. - - -@node Section 5.8, Section 5.9, Section 5.7, Help -@section How do I follow up on a ticket? - -Follow up by emailing us -and reference your ticket number in the subject. - - -@node Section 5.9, , Section 5.8, Help -@section Why did you decide not to support undocumented chips? - -There are several reasons why we are generally not interested in writing -drivers for undocumented chips: - -@itemize -@item Writing a driver without a datasheet is much harder, as you have to -guess most things. Remember that, most of the time, we write drivers for fun -and for free, so there is no reason we would write a driver in conditions -that promise more pain than fun. -@item If we hit a problem, we are certain never to get any support from the -chip manufacturer. This means that we may spend days on code which will -finally never work. -@item There are several chips out there which are fully documented and lack -a driver. This is natural for us to give these the priority when we -finally have some spare time to spend on driver coding. -@item Hardware monitoring chips are not toys. Misprogramming them can -result in data loss or hardware breakage. This is obviously more likely -to happen with undocumented chips. This is a responsability we do not -want to endorse (the GPL is pretty clear than we are not legally -liable, but still). -@end itemize - -There are also several reasons why we do not want to support such drivers, -even if they were written by other people: - -@itemize -@item Problems are much more likely to happen with such drivers. -This means increased needs of support. User support if very -time-consuming and we are usually short of time. -@item Support should be done by the driver author (as only him/her knows -the driver and chip) but in the reality of facts, people will always ask -us for help if the driver is part of our package. Redirecting all user -requests to the driver's author manually is boring. -@item The lack of datasheet usually results in an original driver which -works relatively fine for its author, but will happen not to work -completely for other users. This means that the driver will need many -more additions and fixes than other drivers do, resulting in an increased -maitainance workload, which we can hardly afford. Of course this too should -be handled by the original driver author, but we never know whether he/she -will actually do the work. -@end itemize - -Lastly, there are other considerations, some of which are deliberately -political: - -@itemize -@item We do not want to trick hardware buyers into thinking that a chip is -fully supported under Linux when in fact it is only partly supported by a -driver which was written without a datasheet. Clearly stating that such -chips are not supported makes it much easier for anyone who really needs -fully working hardware monitoring under Linux to avoid motherboards with -these partly supported chips. -@item Drivers written without a datasheet are a pain for developers and -users, but are a complete win for the manufacturers of these chips: -they don't have to write the driver, they don't have to help us, -they don't have to support the users, and they still sell their -hardware. We do not want to encourage such a selfish behavior. -@end itemize - -That being said, authors of such drivers can still submit their code to -the Linux kernel folks for inclusion into Linux 2.6. Their driver may be -accepted there, under conditions. - -If such a driver is ever accepted into the Linux 2.6 tree, and someone -provides a patch to libsensors and/or sensors to add support for this -driver, we will apply it. This generic code is unlikely to cause trouble. - - -@node Contribute, Document Revisions, Help, Top -@chapter How to Contribute - -@menu -* Section 6.1:: How to write a driver -* Section 6.2:: How to get SVN access -* Section 6.3:: How to donate hardware to the project -* Section 6.4:: How to join the project mailing list -* Section 6.5:: How to access mailing list archives -* Section 6.6:: How to submit a patch -* Section 6.7:: How to REALLY help -* Section 6.8:: How to get release announcements -@end menu - - -@node Section 6.1, Section 6.2, , Contribute -@section How to write a driver - -See @file{doc/developers/new_drivers} in our package for instructions. - - -@node Section 6.2, Section 6.3, Section 6.1, Contribute -@section How to get SVN access - -For anonymous SVN read access, see the instructions on our -@uref{http://www.lm-sensors.org/wiki/Download, download page}. - -For write access, please contact us. - - -@node Section 6.3, Section 6.4, Section 6.2, Contribute -@section How to donate hardware to the project - -@uref{http://www.lm-sensors.org/wiki/FeedbackAndSupport, Contact us}. - - -@node Section 6.4, Section 6.5, Section 6.3, Contribute -@section How to join the project mailing lists - -There are two lists you can subscribe to: - -@itemize -@item A @uref{http://lists.lm-sensors.org/mailman/listinfo/lm-sensors, general discussion list}, -meant for both development and user support. You do not need to be subscribed to post. -@item A @uref{http://lists.lm-sensors.org/mailman/listinfo/lm-sensors-commit, CVS commits list}, -for watching the changes made to the CVS repositories. This list is read-only. -@end itemize - - -@node Section 6.5, Section 6.6, Section 6.4, Contribute -@section How to access mailing list archives - -The primary mailing list archive is at: -@uref{http://lists.lm-sensors.org/pipermail/lm-sensors/}. -It contains messages since October 28, 2001. - -There is another mailing list archive at: -@uref{http://news.gmane.org/gmane.linux.drivers.sensors}. -It contains messages since December 31, 2004. -This archive may also be accessed via a news reader: -@uref{nntp://news.gmane.org/gmane.linux.drivers.sensors} -and RSS: -@uref{http://rss.gmane.org/gmane.linux.drivers.sensors}. - -And last there is a legacy archive at: -@uref{http://archives.andrew.net.au/lm-sensors}. -It contains messages from October 28, 2001 through May 16, 2005. - - -@node Section 6.6, Section 6.7, Section 6.5, Contribute -@section How to submit a patch - -Check out the latest from CVS, then copy the directory to another -directory, and make your changes. Generate the diff with -@command{diff -u2 -r DIR1 DIR2}. Or you can generate the diff in CVS with -@command{cvs diff -u2}. Send us the patch in an email and tell us what it does. - -@node Section 6.7, Section 6.8, Section 6.6, Contribute -@section How to REALLY help - -Believe it or not, what we really need help with are: -@itemize -@item Answering email -@item Answering support tickets -@item Porting drivers to Linux 2.6 -@item Creating a sensors.conf database -@item Reviewing patches -@end itemize - -If you are willing to help, simply join our -@uref{http://lists.lm-sensors.org/mailman/listinfo/lm-sensors, discussion list}, -and we'll help you help us. - - -@node Section 6.8, , Section 6.7, Contribute -@section How to get release announcements - -We don't have a separate release announcement mailing list; -however, we put all our releases on freshmeat: @uref{http://freshmeat.net} -and you can register on our freshmeat project page @uref{http://freshmeat.net/projects/lm_sensors} -to 'subscribe to new releases' and then freshmeat -will email you announcement. - - -@node Document Revisions, , Contribute, Top -@appendix Revision History of This Document - -@itemize -@item Rev 2.18 (JD) Removed version 1 specifics part, 2005-12-17 -@item Rev 2.17 (JD) Added 5.9 (why we don't support undocumented chips), - removed 6.9 (doesn't apply to the new mailing list), 2005-10-05 -@item Rev 2.16 (JD) Added 4.33.2, 2005-09-06 -@item Rev 2.15 (JD) Updates, including mailing-list change, 2005-05-21 -@item Rev 2.14 (MDS) Updated 4.12, 2004-11-26 -@item Rev 2.13 (JD) Added 4.6.1, updated 4.7, 2004-06-23 -@item Rev 2.12 (JD) Updated 4.27, 2004-04-11 -@item Rev 2.11 (JD) Various updates, 2004-01-18 -@item Rev 2.10 (MDS) Various updates, 2004-01-03 -@item Rev 2.9 (CP) Converted to Gnu texinfo format, 2002-09-10 -@item Rev 2.8 (MDS) Minor updates 2002-07-10, released with lm_sensors 2.6.4 -@item Rev 2.7 (MDS) Minor updates 2002-04-25 -@item Rev 2.6 (MDS) Minor updates 2002-01-15, released with lm_sensors 2.6.3 -@item Rev 2.5 (MDS) Minor updates 2001-11-11, released with lm_sensors 2.6.2 -@item Rev 2.4 (MDS) Minor updates 2001-07-22 -@item Rev 2.3 (MDS) General update, 2001-02-24, released with lm_sensors 2.6.0. -@item Rev 2.2 (Frodo) Corrections for lm_sensors 2.4, 1999-09-20 -@item Rev 2.1 (Frodo) Corrections for lm_sensors 2.2, 1999-01-12 -@item Rev 2.0 (Frodo) Major revision for lm_sensors 2.1, 1998-12-29 -@item Rev 1.10 (Frodo) Modified 3.8, updated some other things, 1998-09-24 -@item Rev 1.9 (Frodo) Added 3.15, 1998-09-06 -@item Rev 1.8 (Frodo) Added 3.14, 1998-09-05 -@item Rev 1.7 (Phil) Added 3.13 and some other minor changes, 1998-09-01 -@item Rev 1.6 (Frodo) Added 4, 4.1, 4.2, 4.3, 4.4, 4.5, 1998-09-01 -@item Rev 1.5 (Frodo) Added 2.3, 2.4, 3.9, 3.10, 3.11, 1998-08-26 -@item Rev 1.4 (Frodo) Added some more Winbond information, and 3.5-3.8, 1998-08-17 -@item Rev 1.3 (Phil) Added info on the Winbond chip, 1998-08-16 -@item Rev 1.2 (Frodo) Adapation, 1998-08-10 -@item Rev 1.1 (Phil) Modifications, 1998-08-09 -@item Rev 1.0 (Phil) First version, 1998-08-03 -@end itemize - -@bye diff --git a/doc/mkpatch b/doc/mkpatch deleted file mode 100644 index c5664e4d..00000000 --- a/doc/mkpatch +++ /dev/null @@ -1,82 +0,0 @@ -This file documents how the `mkpatch' program works. ------------------------------------------------------------- - -QUICKSTART ----------- - mkpatch/mkpatch.pl . /usr/src/linux > /tmp/patch - cd /usr/src/linux - patch -p1 < /tmp/patch - - -USAGE ------ - -mkpatch compares the newest lm_sensors sources with what is found in a kernel, -and generates a set of diffs. These diffs can be applied to that kernel, -after which the kernel is synchronized with the current lm_sensors sources. - -You should generally run mkpatch against a kernel tree that has been patched -with the newest I2C sources. Check the lm_sensors "Download" page for -information on dependencies between lm_sensors and i2c versions. - -mkpatch needs two arguments. The first is the root of the lm_sensors package, -the second is the root of Linux kernel tree. For example: - cd /tmp/lm_sensors-2.4.0 - mkpatch/mkpatch . /usr/src/linux - -The patch file is written to stdout; any errors are written to stderr. -So you will want to capture the output: - mkpatch/mkpatch . /usr/src/linux > /tmp/lm_sensors-diffs - -Later on, you will want to apply the diffs: - cd /usr/src/linux - patch -p1 -E < /tmp/lm_sensors-diffs - -Of course, this can be combined: - mkpatch/mkpatch . /usr/src/linux | patch -d /usr/src/linux -p1 -E - - -IMPLEMENTATION DETAILS ----------------------- - -mkpatch uses several files in the mkpatch subdirectory. The location of -these files is hardcoded in the program, but all other files used are -specified in these files, and can easily be changed. Used files are: - FILES - A list of files that will be considered by mkpatch. Each line contains - two filenames, separated by whitespace. The first is the name and - location (relative to the lm_sensors package root) of the lm_sensors - file, the second is the name and location (relative to the kernel root) of - the kernel file. A diff will be created between these two files. - INCLUDES - A list of include file changes. Each line contains two strings that - can be found after a `#include' statement. All occurences of the - first string will be changed to the second, for all lm_sensors files in - FILES, before the normal diff is generated. This allow us to use - `#include "sensors.h"' when compiling in the package tree, and - `#include ' in the kernel tree. - Makefile, Config.in - These files are new and will be copied to the appropriate place as - specified in FILES. - -mkpatch does several things: - * For each file pair as specified in FILES, it creates a diff between - them, but before that is done, it changes `#include' lines in the - lm_sensors file as specified in INCLUDES - * It handles several special files, that have to be scanned explicitly - to generate diffs to for them - -The generated diffs have specific headers. It will seem as if the old -kernel was contained in the `linux-old' directory, and the new patched -kernel in the `linux' directory, regardless of where the kernel was -actually located. - -Most intricate are the special files that are handled. These special -files were already present in the kernel, but had to be patched. Because -they can change between kernel versions, I had to scan them by hand to -find where the new code should be inserted. Each file has documented -what actually happens. - - ------------- -This file is Copyright (c) 1999 by Frodo Looijaard diff --git a/doc/modules b/doc/modules deleted file mode 100644 index d75a0c0d..00000000 --- a/doc/modules +++ /dev/null @@ -1,15 +0,0 @@ -Installing Modules -================== - -'make install' will install the kernel modules in the -subdirectories /lib/modules/$version/kernel/drivers/i2c and -/lib/modules/$version/kernel/drivers/sensors. This puts the modules -in the same location as a kernel 'make modules_install' does so -that there will be no duplicate modules. - -If 'make install' fails, particularly on Mandrake kernels, -see FAQ #3.8 (fix MODPREF in the Makefile) and #3.9. - -For details on options that apply to most modules, see -doc/chips/MODPARMS. For details on options specific to particular -modules, see the documentation in doc/chips/ and doc/busses/. diff --git a/doc/progs b/doc/progs index e88c387c..6560c3f2 100644 --- a/doc/progs +++ b/doc/progs @@ -9,87 +9,20 @@ For more elaborate programs (for example, GUI sensor displays), see http://www.lm-sensors.org/wiki/UsefulLinks. -* prog/config/grab_busses.sh (written in bash and awk, not installed) - This program helps you generate the `bus' statements for your configuration - file. It read /proc/bus/i2c (or the file specified on the command-line), - and prints to stdout `bus' statements reflecting the currently detected - adapters. - * prog/daemon/healthd.sh (written in bash, not installed) An example of a very simple hardware health monitoring daemon. -* prog/detect/i2cdetect (written in C, installed by 'make install') - This program scans your complete I2C or SMBus adapter for connected devices. - Syntax: - i2cdetect 0 - Here the '0' stands for the bus number (run "i2cdetect -l" - to list all installed busses). - * prog/detect/sensors-detect (written in Perl, installed by 'make install') This program tries to detect the available SMBus adapters and the chips connected to them, as well as Super-I/O and misc chips. It also generates modprobe lines and module options. This program is interactive. -* prog/doc/doc-features.pl (written in Perl, not installed) - This program is used to help us generate driver documentation; it scans - some C source programs to do this. Syntax: - ./doc-features.pl BASE [PREFIX...] - BASE is the path to the base directory of the lm_sensors tree - PREFIX is one of more prefixes of chips you want documented; if left out, - all chips are documented. - -* prog/doc/doc-insmod.pl (written in Perl, not installed) - This program is used to help us generate driver documentation; it reads - all module information and outputs insmod parameter information. Syntax: - ./doc-insmod.pl DRIVER - -* prog/dump/i2cdump (written in C, installed by 'make install') - This program dumps the registers of an I2C device. - Usual syntax: - i2cdump 0 0x4c b - Here the '0' stands for the bus number (run i2cdump with no arguments - to list all installed busses). - '0x49' is the device address, and 'b' or 'w' stands for byte - or word data. - -* prog/dump/i2cset (written in C, installed by 'make install') - prog/dump/i2cget (written in C, installed by 'make install') - These programs are used to write to or read from a register of an - I2C device. Usual syntax: - i2cset bus device address data - i2cget bus device address - * prog/dump/isadump (written in C, installed by 'make install') This program dumps the registers of ISA or Super-I/O chips. Usual syntax: isadump 0x295 0x296 isadump -k 0x55 0x2e 0x2f -* prog/eeprom/decode-dimms.pl (perl script, installed by 'make install') - This program decodes the information found in a memory module SPD EEPROM. - -* prog/eeprom/decode-vaio.pl (perl script, installed by 'make install') - This program decodes the information in a Sony Vaio laptop - identification eeprom at 0x57. - -* prog/eeprom/ddcmon (perl script, installed by 'make install') - prog/eeprom/decode-edid.pl (perl script, installed by 'make install') - These programs decode the information found in a display EEPROM. They - require a bus driver for your video adapter, for DDC access to the display. - -* prog/eepromer/eepromer (written in C, not installed) - This program reads and writes eeproms. - Danger: Do not use this to write your DRAM DIMM eeproms. - -* prog/hotplug/m7101.o (kernel module, not installed) - An experimental kernel module to enable the Acer Labs 7101 PCI device. - See prog/hotplug/README for details. - -* prog/hotplug/p4b_smbus.o (kernel module, not installed) - An experimental kernel module to enable the i801 2443 PCI device - on Asus P4B boards. - See prog/hotplug/README.p4b for details. - * prog/hotplug/unhide_ICH_SMBus (shell script, not installed) It unhides the ICH Intel SMBus for 2.6 kernels @@ -101,19 +34,6 @@ see http://www.lm-sensors.org/wiki/UsefulLinks. A SysV init script to be installed in /etc/rc.d/init.d/ It inserts the bus and chip modules and starts the sensord daemon. -* prog/matorb/displayit.pl (written in Perl, not installed) - A simple Perl script to display a 'screen' on a Matrix Orbital Display. - -* prog/maxilife/sysinfo.sh (written in shell, not installed) - Write system information to the HP Maxilife LCD display using writelcd.sh. - -* prog/maxilife/writelcd.sh (written in shell, not installed) - Write a string to the HP Maxilife LCD display. - -* prog/mkdev/mkdev.sh (written in bash, not installed) - This script creates the /dev/i2c-* files. Please check the source before - you run it, as you may need to set some variables first. - * prog/pwm/pwmconfig (shell script, installed by 'make install') Formerly pwmtest, tests the pwm (pulse width modulation) outputs of sensors for their effect on the fans and helps to setup the configfile for fancontrol. @@ -122,9 +42,6 @@ see http://www.lm-sensors.org/wiki/UsefulLinks. Controls fanspeeds responding to changes on temperature sensors. Configuration through pwmconfig. -* prog/pwm/fancontrol.pl (perl script, installed by 'make install') - Reimplementation of fancontrol in perl, with self-daemonizing. - * prog/rrd/sens_update_rrd (written in bash, not installed) This script gathers sensors data and adds it to a round robin database (RRD). RRD is then used to display the graphed data in web pages. @@ -145,6 +62,3 @@ see http://www.lm-sensors.org/wiki/UsefulLinks. * prog/tellerstats/gather.sh, tellerstats.sh (written in bash, not installed) These scripts gather sensors data and graph the data for web pages. See prog/tellerstats/README for more information. - -* prog/xeon/decode-xeon.pl (written in Perl, installed by 'make install') - ID ROM data decoding for Xeon processors. diff --git a/doc/version-2 b/doc/version-2 deleted file mode 100644 index 5da58ea3..00000000 --- a/doc/version-2 +++ /dev/null @@ -1,23 +0,0 @@ -There have been many, many changes between version 1 and version 2 of this -package. Some of the more important ones: - -* Fully modular setup. This makes it much easier to support new hardware, - and consumes less kernel memory. -* Full support for I2C busses. This includes the VIA chipset I2C bus. If it - is supported by Simon Vogl, it is supported by us. -* Many things which were done in kernel space are now done in user space. - The most obvious result is the absence of /proc/sensors. Use instead the - supplied 'sensors' program. -* No more limits on the number of chips. -* All detected chips get their own directory under /proc/sys/dev/sensors -* /proc/bus contains a list of all I2C/SMBus adapters found. -* All applications which want to use sensor data can now access it through - the new libsensors. -* A configuration file which is read by the above mentioned library, which - can (through libsensors) be used by any application, and which describes - how all sensor readings are to be interpreted. -* All code has been completely rewritten. -* Many new drivers - -By now (version 2.3.0) so many things have changed that we do not even try -to keep the above list up-to-date. Just don't use version 1 anymore. diff --git a/doc/version.texi b/doc/version.texi deleted file mode 100644 index f9ae6f78..00000000 --- a/doc/version.texi +++ /dev/null @@ -1,2 +0,0 @@ -@set UPDATED 17 December 2005 -@set VERSION 2.18 diff --git a/doc/vid b/doc/vid index 7392cf0a..565774d3 100644 --- a/doc/vid +++ b/doc/vid @@ -43,79 +43,14 @@ Document Version Voltage Range Increment Processors AMD Opteron 24x processors. Note that versions 8.1 - 8.4 are compatible. -lm_sensors versions through 2.6.3 support only the VRM 8.2 standard. - -Starting in lm_sensors 2.6.4 the VRM version is configurable. -To configure the sensor chip for the correct voltage range, -you must set the "vrm" correctly either via /proc, /sys, or sensors.conf. - -To change the vrm version to 9.0, for example, do the following -after the chip module (in this example, w83781d) is loaded: - - (kernel 2.4) - echo 9.0 > /proc/sys/dev/sensors/w83781d-isa-0290/vrm - (kernel 2.6 up to 2.6.13) - echo 90 > /sys/bus/i2c/devices/0-0290/vrm - (kernel 2.6.14 and later) - echo 90 > /sys/class/hwmon/hwmon0/device/vrm - -Alternatively, add a line in /etc/sensors.conf in the w83781d section -(you should put this line BEFORE any line that uses vid in a calculation): - - set vrm 9.0 - -and then, after the chip module is loaded, do: - - sensors -s - -After this, reading the vid either by - - (kernel 2.4) - cat /proc/sys/dev/sensors/w83781d-isa-0290/vid - (kernel 2.6 up to 2.6.13 - divide the output by 1000) - cat /sys/bus/i2c/devices/0-0290/cpu0_vid - (kernel 2.6.14 and later - divide the output by 1000) - cat /sys/class/hwmon/hwmon0/device/cpu0_vid - -or by - - sensors - -should show the new vid value. - - -The following values are legal vrm values. Other values will be -allowed but will result in using the 8.2 standard. - - 2.4, 8.1-8.5, 9.0, 9.1, 10.0 - +Since Linux 2.6.9, the correct VRM version is selected automatically +based on the CPU brand and model. Thus you shouldn't have to care about +it. If you are using a brand new CPU and even the latest kernel complains +("Unknown VRM version of your CPU"), this means that the kernel must be +taught about this new CPU model. Please report to us in this case. Remember, the VID pins on the sensor chips are inputs only. -That means they can't be changed and there shouldn't be -any problems if you experiment with the vrm values until you -get it right. You cannot manipulate the actual processor core -voltage through lm_sensors drivers. - -Not all sensor chips have VID inputs. -For those that do, the VRM support status is listed below. - -The following chip drivers support all the VRM versions via -/etc/sensors.conf and the vrm entry in /proc or /sys: - - adm1025, adm1026, asb100, lm85, lm87, pc87360, - vt1211, vt8231, w83627ehf, w83627hf, w83781d, w83792d - - -The following chip drivers support only VRM 8.2 and cannot be changed: - - adm1024, it87, mtp008, adm9240, gl520sm, lm78 - -If you have a board with one of these chips which needs advanced -VRM support please email us. - -The following chip drivers support only VRM 10.0 and cannot be changed: - - lm93 +You cannot use them to manipulate the actual processor core voltage. ------------------ Copyright (c) 2002-2004 Mark D. Studebaker diff --git a/etc/Module.mk b/etc/Module.mk index 389c30b4..78cb0b0b 100644 --- a/etc/Module.mk +++ b/etc/Module.mk @@ -13,15 +13,17 @@ # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software -# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, +# MA 02110-1301 USA. # Note that MODULE_DIR (the directory in which this file resides) is a # 'simply expanded variable'. That means that its value is substituted # verbatim in the rules, until it is redefined. MODULE_DIR := etc +ETC_DIR := $(MODULE_DIR) -ETCTARGET := $(MODULE_DIR)/sensors.conf.eg -ETCINSTALL := $(ETCDIR)/sensors.conf +ETCTARGET := $(MODULE_DIR)/sensors.conf.default +ETCINSTALL := $(ETCDIR)/sensors3.conf # No all rule @@ -31,6 +33,14 @@ install-etc: if [ ! -e $(DESTDIR)$(ETCINSTALL) ] ; then \ $(INSTALL) -m 644 $(ETCTARGET) $(DESTDIR)$(ETCINSTALL); \ fi + $(MKDIR) $(DESTDIR)$(BINDIR) + $(INSTALL) -m 755 $(ETC_DIR)/sensors-conf-convert $(DESTDIR)$(BINDIR) + user_install :: install-etc +uninstall-etc: + $(RM) $(DESTDIR)$(BINDIR)/sensors-conf-convert + +user_uninstall :: uninstall-etc + # No clean rule diff --git a/etc/config.c b/etc/config.c deleted file mode 100644 index 93800b86..00000000 --- a/etc/config.c +++ /dev/null @@ -1,14 +0,0 @@ -/* - * This is used by the top-level makefile to automagically - * get the kernel version from . - * A simple grep doesn't work for Mandrake and Red Hat distributions - * that contain multiple UTS_RELEASE definitions in version.h. - * - * Note: since kernel 2.6.17, the definition of UTS_RELEASE has - * moved to . - */ -#include -#ifndef UTS_RELEASE -#include -#endif -char *uts_release=UTS_RELEASE; diff --git a/etc/sensors-conf-convert b/etc/sensors-conf-convert new file mode 100755 index 00000000..fb21c6d4 --- /dev/null +++ b/etc/sensors-conf-convert @@ -0,0 +1,482 @@ +#!/usr/bin/perl -w -pi.old + +# Convert a sensors.conf file from the old (Linux 2.4, lm-sensors 2) +# symbol names to the new (Linux 2.6, lm-sensors 3) symbol names. +# +# Copyright (C) 2007 Jean Delvare +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, +# MA 02110-1301, USA. + +# Implemented conversions: +# * The "algorithm name" part of bus statements is removed. +# * Bus statements for the ISA bus are removed. +# * Chip names containing dashes are removed. +# * Label, ignore, set and compute statements referencing features +# which are not part of the new interface are removed. +# * Label, ignore, set and compute statements referencing features +# which have been renamed are updated. This includes both general +# feature name changes and chip-specific feature name changes. +# +# Note that we have to look at the commented out lines too, so that +# the user doesn't have a bad surprise when uncommenting them. + +use strict; +use vars qw($debug $chip %trans @delete %chip_trans %chip_delete); + +BEGIN +{ + $debug = 0; + + %trans = ( + qr/\bvid\b/ => sub { "cpu0_vid" }, + qr/\bremote_temp\b/ => sub { "temp2" }, + qr/\bremote_temp_hyst\b/ => sub { "temp2_max_hyst" }, + qr/\bremote_temp_low\b/ => sub { "temp2_min" }, + qr/\bremote_temp_over\b/ => sub { "temp2_max" }, + qr/\btemp\b/ => sub { "temp1" }, + qr/\btemp_hyst\b/ => sub { "temp1_max_hyst" }, + qr/\btemp_low\b/ => sub { "temp1_min" }, + qr/\btemp_over\b/ => sub { "temp1_max" }, + qr/\btemp_high\b/ => sub { "temp1_max" }, + qr/\btemp_crit\b/ => sub { "temp1_crit" }, + + qr/\bvin(\d+)_max\b/ => sub { "in$1_max" }, + qr/\bvin(\d+)_min\b/ => sub { "in$1_min" }, + qr/\bvin(\d+)\b/ => sub { "in$1" }, + qr/\btemp(\d+)_over\b/ => sub { "temp$1_max" }, + qr/\btemp(\d+)_hyst\b/ => sub { "temp$1_max_hyst" }, + qr/\btemp(\d+)_high\b/ => sub { "temp$1_max" }, + qr/\btemp(\d+)_low\b/ => sub { "temp$1_min" }, + qr/\bsensor(\d+)\b/ => sub { "temp$1_type" }, + ); + + @delete = ( + qr/\balarms\b/, + qr/\bbeeps\b/, + qr/\bpwm\d*\b/, + qr/\bpwm\d+_enable\b/, + qr/\b(in|temp|fan)\d+_(state|status)\b/, + qr/\banalog_out\b/, + qr/\balarms_(in|temp|fan)\b/, + ); + + %chip_trans = ( + "gl518sm" => { + qr/\bvdd\b/ => sub { "in0" }, + qr/\bvdd_min\b/ => sub { "in0_min" }, + qr/\bvdd_max\b/ => sub { "in0_max" }, + }, + "gl520sm" => { + qr/\bvdd\b/ => sub { "in0" }, + qr/\bvdd_min\b/ => sub { "in0_min" }, + qr/\bvdd_max\b/ => sub { "in0_max" }, + }, + "lm80" => { + qr/\btemp_hot_hyst\b/ => sub { "temp1_max_hyst" }, + qr/\btemp_hot_max\b/ => sub { "temp1_max" }, + qr/\btemp_os_hyst\b/ => sub { "temp1_crit_hyst" }, + qr/\btemp_os_max\b/ => sub { "temp1_crit" }, + }, + "lm83" => { + qr/\btcrit\b/ => sub { "temp3_crit" }, + }, + "lm90" => { + qr/\btcrit(\d)\b/ => sub { "temp$1_crit" }, + qr/\bhyst(\d)\b/ => sub { "temp$1_crit_hyst" }, + }, + "adm1032" => { + qr/\btcrit(\d)\b/ => sub { "temp$1_crit" }, + qr/\bhyst(\d)\b/ => sub { "temp$1_crit_hyst" }, + }, + "lm86" => { + qr/\btcrit(\d)\b/ => sub { "temp$1_crit" }, + qr/\bhyst(\d)\b/ => sub { "temp$1_crit_hyst" }, + }, + "lm99" => { + qr/\btcrit(\d)\b/ => sub { "temp$1_crit" }, + qr/\bhyst(\d)\b/ => sub { "temp$1_crit_hyst" }, + }, + "adt7461" => { + qr/\btcrit(\d)\b/ => sub { "temp$1_crit" }, + qr/\bhyst(\d)\b/ => sub { "temp$1_crit_hyst" }, + }, + "max6657" => { + qr/\btcrit(\d)\b/ => sub { "temp$1_crit" }, + qr/\bhyst(\d)\b/ => sub { "temp$1_crit_hyst" }, + }, + "max6680" => { + qr/\btcrit(\d)\b/ => sub { "temp$1_crit" }, + qr/\bhyst(\d)\b/ => sub { "temp$1_crit_hyst" }, + }, + "lm93" => { + qr/\bvid([12])\b/ => sub { "cpu".($1-1)."_vid" }, + }, + "adm9240" => { + qr/"2\.5V(|_min|_max)"/ => sub { "in0$1" }, + qr/\bVccp1(|_min|_max)\b/ => sub { "in1$1" }, + qr/"3\.3V(|_min|_max)"/ => sub { "in2$1" }, + qr/"5V(|_min|_max)"/ => sub { "in3$1" }, + qr/"12V(|_min|_max)"/ => sub { "in4$1" }, + qr/\bVccp2(|_min|_max)\b/ => sub { "in5$1" }, + }, + "lm81" => { + qr/"2\.5V(|_min|_max)"/ => sub { "in0$1" }, + qr/\bVccp1(|_min|_max)\b/ => sub { "in1$1" }, + qr/"3\.3V(|_min|_max)"/ => sub { "in2$1" }, + qr/"5V(|_min|_max)"/ => sub { "in3$1" }, + qr/"12V(|_min|_max)"/ => sub { "in4$1" }, + qr/\bVccp2(|_min|_max)\b/ => sub { "in5$1" }, + }, + "ds1780" => { + qr/"2\.5V(|_min|_max)"/ => sub { "in0$1" }, + qr/\bVccp1(|_min|_max)\b/ => sub { "in1$1" }, + qr/"3\.3V(|_min|_max)"/ => sub { "in2$1" }, + qr/"5V(|_min|_max)"/ => sub { "in3$1" }, + qr/"12V(|_min|_max)"/ => sub { "in4$1" }, + qr/\bVccp2(|_min|_max)\b/ => sub { "in5$1" }, + }, + "adm1024" => { + qr/"2\.5V(|_min|_max)"/ => sub { "in0$1" }, + qr/\bVccp1(|_min|_max)\b/ => sub { "in1$1" }, + qr/"3\.3V(|_min|_max)"/ => sub { "in2$1" }, + qr/"5V(|_min|_max)"/ => sub { "in3$1" }, + qr/"12V(|_min|_max)"/ => sub { "in4$1" }, + qr/\bVccp2(|_min|_max)\b/ => sub { "in5$1" }, + qr/\btemp_hyst\b/ => sub { "temp1_min" }, + qr/\btemp(\d)\b/ => sub { "temp".($1+1) }, + qr/\btemp(\d)_hyst\b/ => sub { "temp".($1+1)."_min" }, + qr/\btemp(\d)_over\b/ => sub { "temp".($1+1)."_max" }, + }, + "maxilife" => { + qr/\bvid(\d)(|_min|_max)\b/ => sub { "in".($1-1).$2 }, + }, + "thmc50" => { + qr/\btemp_hyst\b/ => sub { "temp1_min" }, + qr/\bremote_temp_hyst\b/ => sub { "temp2_min" }, + qr/\bremote_temp2\b/ => sub { "temp3" }, + qr/\bremote_temp2_hyst\b/ => sub { "temp3_min" }, + qr/\bremote_temp2_over\b/ => sub { "temp3_max" }, + }, + "adm1022" => { + qr/\btemp_hyst\b/ => sub { "temp1_min" }, + qr/\bremote_temp_hyst\b/ => sub { "temp2_min" }, + qr/\bremote_temp2\b/ => sub { "temp3" }, + qr/\bremote_temp2_hyst\b/ => sub { "temp3_min" }, + qr/\bremote_temp2_over\b/ => sub { "temp3_max" }, + }, + "adm1026" => { + qr/\bfan(\d)(|_div|_min)\b/ => sub { "fan".($1+1).$2 }, + qr/\btemp(\d)_therm\b/ => sub { "temp$1_crit" }, + }, + "via686a" => { + qr/"2\.0V"/ => sub { "in0" }, + qr/"2\.5V"/ => sub { "in1" }, + qr/"3\.3V"/ => sub { "in2" }, + qr/"5\.0V"/ => sub { "in3" }, + qr/"12V"/ => sub { "in4" }, + }, + "lm87" => { + qr/"2\.5V(|_min|_max)"/ => sub { "in0$1" }, + qr/\bVccp1(|_min|_max)\b/ => sub { "in1$1" }, + qr/"3\.3V(|_min|_max)"/ => sub { "in2$1" }, + qr/"5V(|_min|_max)"/ => sub { "in3$1" }, + qr/"12V(|_min|_max)"/ => sub { "in4$1" }, + qr/\bVccp2(|_min|_max)\b/ => sub { "in5$1" }, + qr/\bAIN1(|_min|_max)\b/ => sub { "in6$1" }, + qr/\bAIN2(|_min|_max)\b/ => sub { "in7$1" }, + qr/\bCPU_Temp\b/ => sub { "temp2" }, + }, + "fscpos" => { + qr/\bvolt12\b/ => sub { "in0" }, + qr/\bvolt5\b/ => sub { "in1" }, + qr/\bvoltbatt\b/ => sub { "in2" }, + }, + "fscscy" => { + qr/\bvolt12\b/ => sub { "in0" }, + qr/\bvolt5\b/ => sub { "in1" }, + qr/\bvoltbatt\b/ => sub { "in2" }, + }, + "pcf8591" => { + qr/\bch(\d)\b/ => sub { "in$1" }, + }, + "smsc47m192" => { + qr/\btemp(\d)_input_fault\b/ => sub { "temp$1_fault" }, + }, + "lm92" => { + qr/\btemp_hyst\b/ => sub { "temp1_crit_hyst" }, + }, + "max1619" => { + qr/\btemp2_hyst\b/ => sub { "temp2_crit_hyst" }, + }, + "lm78" => { + qr/\bin([56])_(min|max)\b/ => sub { "in$1_".($2 eq "max" ? "min" : "max") }, + }, + "lm79" => { + qr/\bin([56])_(min|max)\b/ => sub { "in$1_".($2 eq "max" ? "min" : "max") }, + }, + "w83781d" => { + qr/\bin([56])_(min|max)\b/ => sub { "in$1_".($2 eq "max" ? "min" : "max") }, + }, + "as99127f" => { + qr/\bin([56])_(min|max)\b/ => sub { "in$1_".($2 eq "max" ? "min" : "max") }, + }, + ); + + %chip_delete = ( + "adm1021" => [ + qr/\bdie_code\b/, + ], + "lm84" => [ + qr/\bdie_code\b/, + ], + "gl523" => [ + qr/\bdie_code\b/, + ], + "thmc10" => [ + qr/\bdie_code\b/, + ], + "gl518sm" => [ + qr/\bfan1_off\b/, + qr/\bfan1_off_pin\b/, + qr/\biterate\b/, + ], + "gl520sm" => [ + qr/\bfan1_off\b/, + qr/\btwo_temps\b/, + ], + "w83792d" => [ + qr/\bchassis\b/, + ], + "w83793" => [ + qr/\bchassis\b/, + ], + "maxilife" => [ + qr/\bpll(|_min|_max)\b/, + ], + "thmc50" => [ + qr/\banalog output\b/, + qr/\binterrupts\b/, + qr/\binterrupt mask\b/, + qr/\bdie_code\b/, + ], + "adm1022" => [ + qr/\banalog output\b/, + qr/\binterrupts\b/, + qr/\binterrupt mask\b/, + qr/\bdie_code\b/, + ], + "adm1026" => [ + qr/\balarm_mask\b/, + qr/\bgpio\b/, + qr/\bgpio_mask\b/, + qr/\bafc_pwm\b/, + qr/\bafc_analog_out\b/, + qr/\btemp\d_tmin\b/, + ], + "lm85" => [ + qr/\bpwm\d_(spinup|min|freq|min_ctl|zone|spinup_ctl)\b/, + qr/\bzone\d_(limit|hyst|range|critical|smooth)\b/, + qr/\bfan\d_(tach_mode|ppr)\b/, + ], + "lm85b" => [ + qr/\bpwm\d_(spinup|min|freq|min_ctl|zone|spinup_ctl)\b/, + qr/\bzone\d_(limit|hyst|range|critical|smooth)\b/, + qr/\bfan\d_(tach_mode|ppr)\b/, + ], + "lm85c" => [ + qr/\bpwm\d_(spinup|min|freq|min_ctl|zone|spinup_ctl)\b/, + qr/\bzone\d_(limit|hyst|range|critical|smooth)\b/, + qr/\bfan\d_(tach_mode|ppr)\b/, + ], + "emc6d100" => [ + qr/\bpwm\d_(spinup|min|freq|min_ctl|zone|spinup_ctl)\b/, + qr/\bzone\d_(limit|hyst|range|critical|smooth)\b/, + qr/\bfan\d_(tach_mode|ppr)\b/, + ], + "emc6d102" => [ + qr/\bpwm\d_(spinup|min|freq|min_ctl|zone|spinup_ctl)\b/, + qr/\bzone\d_(limit|hyst|range|critical|smooth)\b/, + qr/\bfan\d_(tach_mode|ppr)\b/, + ], + "adm1027" => [ + qr/\bpwm\d_(spinup|min|freq|min_ctl|zone|spinup_ctl)\b/, + qr/\bzone\d_(limit|hyst|range|critical|smooth)\b/, + qr/\bfan\d_(tach_mode|ppr)\b/, + ], + "adt7473" => [ + qr/\bpwm\d_(spinup|min|freq|min_ctl|zone|spinup_ctl)\b/, + qr/\bzone\d_(limit|hyst|range|critical|smooth)\b/, + qr/\bfan\d_(tach_mode|ppr)\b/, + ], + "fscpos" => [ + qr/\brev\b/, + qr/\bevent\b/, + qr/\bcontrol\b/, + qr/\bfan\d_ripple\b/, + qr/\bwdog_(preset|state|control)\b/, + ], + "fscscy" => [ + qr/\brev\b/, + qr/\bevent\b/, + qr/\bcontrol\b/, + qr/\btemp\d_lim\b/, + qr/\bfan\d_ripple\b/, + qr/\bwdog_(preset|state|control)\b/, + ], + "fscher" => [ + qr/\brev\b/, + qr/\bevent\b/, + qr/\bcontrol\b/, + qr/\bfan\d_ripple\b/, + qr/\bwdog_(preset|state|control)\b/, + ], + "pcf8591" => [ + qr/\bain_conf\b/, + qr/\baout_enable\b/, + qr/\baout\b/, + ], + "vt1211" => [ + qr/\bconfig\b/, + ], + "vt8231" => [ + qr/\bconfig\b/, + ], + "max6650" => [ + qr/\bspeed\b/, + ], + "max6651" => [ + qr/\bspeed\b/, + ], + "applesmc" => [ + qr/\bfan\d_(max|safe)\b/, + ], + ); + + if (defined $ARGV[0] && ($ARGV[0] eq '-h' || $ARGV[0] eq '--help')) { + print "Convert sensors.conf from lm-sensors 2 format to lm-sensors 3 format\n", + "Typical usage: sensors-conf-convert < /etc/sensors.conf > /etc/sensors3.conf\n"; + exit 0; + } +} + +if ($. == 1) { + print "# Converted by sensors-conf-convert on ".localtime()."\n"; +} + +sub substitute_line($$) +{ + my ($chip, $line) = @_; + + # First the chip-specific ones + if ($chip && exists $chip_trans{$chip}) { + foreach my $t (keys %{$chip_trans{$chip}}) { + $line =~ s/$t/$chip_trans{$chip}->{$t}->()/ge; + } + } + + # Then the general substitutions + foreach my $t (keys %trans) { + # Kudos to the nice folks in #perl on freenode :) + $line =~ s/$t/$trans{$t}->()/ge; + } + + return $line; +} + +sub delete_line($) +{ + my $feature = shift; + + # First the general deletions + foreach my $t (@delete) { + return 1 if $feature =~ m/$t/; + } + + # Then the chip-specific ones + if ($chip && exists $chip_delete{$chip}) { + foreach my $t (@{$chip_delete{$chip}}) { + return 1 if $feature =~ m/$t/; + } + } + + return 0; +} + +if (m/^# Converted by sensors-conf-convert/) { + print STDERR "WARNING: Converting an already converted file!\n"; + print STDERR " Result will be incorrect for some chip types.\n"; +} + +# Bus statements +if (m/^([\s#]*bus\s+"?i2c-\d+"?\s+"([^"]+)")\s+"[^"]*"/) { + print STDERR "Processing bus statement: $2\n" if $debug; + + if ($2 eq "ISA main adapter") { + $_ = ''; # Drop entirely + } else { + $_ = "$1\n"; # Drop algorithm name + } +} + +# Chip statements +elsif (m/^[\s#]*chip\s+"([\w\d*-]+)"/) { + # We only remember the first chip name, assuming that all chips + # in a given "chip" statement need the same specific processing + $chip = $1; + $chip =~ s/-.*//; + undef $chip if $chip eq "*"; + + # Remove dashes from chip names, as this is no longer allowed + s/(\s+"lm78-)j-/$1/g; + s/(\s+"maxilife-)(cg|co|as|nba)-/$1/g; + # Simplify possible duplicates + s/("lm78-\*")(\s+"lm78-\*")+/$1/g; + s/("maxilife-\*")(\s+"maxilife-\*")+/$1/g; + + # "*" is no longer a valid chip name + s/"\*"/"\*-\*"/g; + + print STDERR "Processing chip section: $chip\n" if $chip and $debug; +} + +# Drop references to lm78-j +elsif (m/^\s*#+.*lm78-?j/i) { + s/(lm78), lm78-?j/$1/gi; + s/(lm78)-?j/$1/gi; +} + +# Drop references to vrm +elsif (m/^[\s#]*set\s+vrm\s/i + || m/^\s*#+\s*adjust this if your vid is wrong/i + || m/^\s*#+\s*Also, one should set vrm prior to using vid in any formula/) { + $_ = ''; +} + +# Drop references to pwm +elsif (m/^\s*#+\s*PWM Output/i) { + $_ = ''; +} + +# Feature name substitution +elsif (m/^[\s#]*(?:label|ignore|set|compute)\s+(\S+)\s/) { + if (delete_line($1)) { + # Delete references to features that are now gone + $_ = ''; + } else { + # Substitute feature names + $_ = substitute_line($chip, $_); + } +} diff --git a/etc/sensors.conf.default b/etc/sensors.conf.default new file mode 100644 index 00000000..96db52f8 --- /dev/null +++ b/etc/sensors.conf.default @@ -0,0 +1,357 @@ +# libsensors configuration file +# ----------------------------- +# +# This default configuration file only includes statements which do not +# differ from one mainboard to the next. Only label, compute and set +# statements for internal voltage and temperature sensors are included. +# +# Better configuration files for specific mainboards can be found at +# http://www.lm-sensors.org/wiki/Configurations + +chip "lm78-*" "lm79-*" "lm80-*" + + label temp1 "M/B Temp" + + +chip "w83792d-*" + + label in0 "VcoreA" + label in1 "VcoreB" + label in6 "+5V" + label in7 "5VSB" + label in8 "Vbat" + + set in6_min 5.0 * 0.90 + set in6_max 5.0 * 1.10 + set in7_min 5.0 * 0.90 + set in7_max 5.0 * 1.10 + set in8_min 3.0 * 0.90 + set in8_max 3.0 * 1.10 + + +chip "w83793-*" + + label in0 "VcoreA" + label in1 "VcoreB" + label in7 "+5V" + label in8 "5VSB" + label in9 "Vbat" + + set in7_min 5.0 * 0.90 + set in7_max 5.0 * 1.10 + set in8_min 5.0 * 0.90 + set in8_max 5.0 * 1.10 + set in9_min 3.0 * 0.90 + set in9_max 3.0 * 1.10 + + +chip "via686a-*" + + label in0 "Vcore" + label in2 "+3.3V" + label in3 "+5V" + label in4 "+12V" + + set in2_min 3.3 * 0.90 + set in2_max 3.3 * 1.10 + set in3_min 5.0 * 0.90 + set in3_max 5.0 * 1.10 + set in4_min 12.0 * 0.90 + set in4_max 12.0 * 1.10 + + +chip "adm1025-*" "ne1619-*" + + label in1 "Vcore" + label in2 "+3.3V" + label in3 "+5V" + label in4 "+12V" + label in5 "VCC" + + set in2_min 3.3 * 0.90 + set in2_max 3.3 * 1.10 + set in3_min 5.0 * 0.90 + set in3_max 5.0 * 1.10 + set in5_min 3.3 * 0.90 + set in5_max 3.3 * 1.10 +# Depending on how your chip is hardwired, you may or may not have +# +12V readings. +# set in4_min 12.0 * 0.90 +# set in4_max 12.0 * 1.10 + + label temp1 "CPU Temp" + label temp2 "M/B Temp" + + +chip "lm87-*" "adm1024-*" + + label in1 "Vcore" + label in2 "+3.3V" + label in3 "+5V" + label in4 "+12V" + + set in2_min 3.3 * 0.90 + set in2_max 3.3 * 1.10 + set in3_min 5.0 * 0.90 + set in3_max 5.0 * 1.10 + set in4_min 12.0 * 0.90 + set in4_max 12.0 * 1.10 + + label temp1 "M/B Temp" + label temp2 "CPU Temp" + + +chip "it87-*" "it8712-*" "it8716-*" "it8718-*" "it8720-*" + + label in8 "Vbat" + + +chip "fscpos-*" "fscher-*" + + label in0 "+12V" + label in1 "+5V" + label in2 "Vbat" + + label temp1 "CPU Temp" + label temp2 "M/B Temp" + label temp3 "Aux Temp" + + +chip "fscscy-*" + + label in0 "+12V" + label in1 "+5V" + label in2 "+3.3V" + + label temp1 "CPU0 Temp" + label temp2 "CPU1 Temp" + label temp3 "M/B Temp" + label temp4 "Aux Temp" + + +chip "vt1211-*" + + label in5 "+3.3V" + + label temp2 "SIO Temp" + + +chip "vt8231-*" + + label in5 "+3.3V" + + +chip "smsc47m192-*" + + label in1 "Vcore" + label in2 "+3.3V" + label in3 "+5V" + label in4 "+12V" + label in5 "VCC" + + set in2_min 3.3 * 0.90 + set in2_max 3.3 * 1.10 + set in3_min 5.0 * 0.90 + set in3_max 5.0 * 1.10 + set in4_min 12.0 * 0.90 + set in4_max 12.0 * 1.10 + set in5_min 3.3 * 0.90 + set in5_max 3.3 * 1.10 + + label temp1 "SIO Temp" + + +chip "lm85-*" "lm85b-*" "lm85c-*" "adm1027-*" "adt7463-*" "adt7468-*" "emc6d100-*" "emc6d102-*" + + label in1 "Vcore" + label in2 "+3.3V" + label in3 "+5V" + label in4 "+12V" + + set in2_min 3.3 * 0.90 + set in2_max 3.3 * 1.10 + set in3_min 5.0 * 0.90 + set in3_max 5.0 * 1.10 +# Depending on how your chip is hardwired, you may or may not have +# +12V readings. +# set in4_min 12.0 * 0.90 +# set in4_max 12.0 * 1.10 + + label temp2 "M/B Temp" + + +chip "pc87365-*" "pc87366-*" + +# Voltage inputs + + label in7 "3VSB" + label in8 "VDD" + label in9 "Vbat" + label in10 "AVDD" + + compute in7 @*2, @/2 + compute in8 @*2, @/2 + compute in10 @*2, @/2 + +# These are the operating conditions as recommended by National +# Semiconductor + set in7_min 3.0 + set in7_max 3.6 + set in8_min 3.0 + set in8_max 3.6 + set in10_min 3.0 + set in10_max 3.6 +# Depending on the hardware setup, the battery voltage may or may not +# be monitored. +# set in9_min 2.4 +# set in9_max 3.6 + + label temp3 "SIO Temp" + + set temp3_min 0 + set temp3_max 70 + set temp3_crit 85 + + +chip "adm1030-*" "adm1031-*" + + label temp1 "M/B Temp" + + +chip "w83627ehf-*" "w83627dhg-*" + + label in0 "Vcore" + label in2 "AVCC" + label in3 "VCC" + label in7 "3VSB" + label in8 "Vbat" + + set in2_min 3.3 * 0.90 + set in2_max 3.3 * 1.10 + set in3_min 3.3 * 0.90 + set in3_max 3.3 * 1.10 + set in7_min 3.3 * 0.90 + set in7_max 3.3 * 1.10 + set in8_min 3.0 * 0.90 + set in8_max 3.0 * 1.10 + + +chip "f71805f-*" + + label in0 "+3.3V" + + set in0_min 3.3 * 0.90 + set in0_max 3.3 * 1.10 + + +chip "f71872f-*" + + label in0 "+3.3V" + label in9 "Vbat" + label in10 "3VSB" + + set in0_min 3.3 * 0.90 + set in0_max 3.3 * 1.10 + set in9_min 3.0 * 0.90 + set in9_max 3.0 * 1.10 + set in10_min 3.3 * 0.90 + set in10_max 3.3 * 1.10 + + +chip "k8temp-*" + + label temp1 "Core0 Temp" + label temp2 "Core0 Temp" + label temp3 "Core1 Temp" + label temp4 "Core1 Temp" + + +chip "dme1737-*" + + label in0 "5VSB" + label in1 "Vcore" + label in2 "+3.3V" + label in3 "+5V" + label in4 "+12V" + label in5 "3VSB" + label in6 "Vbat" + + label temp2 "SIO Temp" + + set in0_min 5.0 * 0.90 + set in0_max 5.0 * 1.10 + set in2_min 3.3 * 0.90 + set in2_max 3.3 * 1.10 + set in3_min 5.0 * 0.90 + set in3_max 5.0 * 1.10 + set in4_min 12.0 * 0.90 + set in4_max 12.0 * 1.10 + set in5_min 3.3 * 0.90 + set in5_max 3.3 * 1.10 + set in6_min 3.0 * 0.90 + set in6_max 3.0 * 1.10 + + +chip "sch311x-*" + + label in1 "Vcore" + label in2 "+3.3V" + label in3 "+5V" + label in4 "+12V" + label in5 "3VSB" + label in6 "Vbat" + + label temp2 "SIO Temp" + + set in2_min 3.3 * 0.90 + set in2_max 3.3 * 1.10 + set in3_min 5.0 * 0.90 + set in3_max 5.0 * 1.10 + set in4_min 12.0 * 0.90 + set in4_max 12.0 * 1.10 + set in5_min 3.3 * 0.90 + set in5_max 3.3 * 1.10 + set in6_min 3.0 * 0.90 + set in6_max 3.0 * 1.10 + + +chip "sch5027-*" + + label in0 "5VSB" + label in1 "Vcore" + label in2 "+3.3V" + label in5 "3VSB" + label in6 "Vbat" + + label temp2 "SIO Temp" + + set in0_min 5.0 * 0.90 + set in0_max 5.0 * 1.10 + set in2_min 3.3 * 0.90 + set in2_max 3.3 * 1.10 + set in5_min 3.3 * 0.90 + set in5_max 3.3 * 1.10 + set in6_min 3.0 * 0.90 + set in6_max 3.0 * 1.10 + + +chip "f71882fg-*" + + label in0 "+3.3V" + label in7 "3VSB" + label in8 "Vbat" + + compute in0 @*2, @/2 + compute in7 @*2, @/2 + compute in8 @*2, @/2 + + +chip "f8000-*" + + label in0 "+3.3V" + label in1 "3VSB" + label in2 "Vbat" + + compute in0 @*2, @/2 + compute in1 @*2, @/2 + compute in2 @*2, @/2 diff --git a/etc/sensors.conf.eg b/etc/sensors.conf.eg index 6494c2c5..be76317d 100644 --- a/etc/sensors.conf.eg +++ b/etc/sensors.conf.eg @@ -1,281 +1,13 @@ -# Sensors configuration file used by 'libsensors' -#------------------------------------------------ -# -########################################################################## -# # -# PLEASE READ THIS HELPFUL HINT!!! # -# # -# The 'set' lines (generally for min and max values) # -# do not take effect until you run 'sensors -s' as root !!! # -# We suggest you put 'sensors -s' in a /etc/rc.d/... file # -# to be run at boot time after the modules are inserted !!! # -# # -########################################################################## -# -# -# OVERVIEW -# -------- -# This configuration file will be used by all userspace applications -# linked to libsensors. It is NOT used by the lm_sensors drivers directly. -# -# This config file consists of two parts: the heavily commented LM78 -# example, and the real parts. Search for '####' if you want to skip -# to the real stuff. -# -# Hash marks introduce comments, which continue until the end of a line. -# -# Identifiers consisting of only digits and letters can be used -# unquoted; other identifiers must be quoted. Escape characters within -# quotes operate like those in C. -# -# -# CHIP LINES -# ---------- -# A 'chip' line specifies what the following 'label', 'compute', 'set' and -# 'ignore' lines refer to. In this case, until the -# next 'chip' line, everything refers to all lm78, lm78-j and lm79 -# chips. Other examples are *-isa-* for everything on the ISA bus, and -# lm78-j-i2c-*-4e for all lm78-j chips on address 0x4e of any I2C bus. -# -# If more chip statements match a specific chip, they are all considered. -# Later lines overrule earlier lines, so if you set the in0 label for -# lm78-* to "This", and later on the in0 label for lm78-isa-* to "That", -# "That" is used for LM78 chips on the ISA bus, and "This" for LM78 -# chips on a non-ISA bus. -# -# chip "lm78-*" "lm78-j-*" "lm79-*" -# -# -# FEATURE NAMES -# ------------- -# Feature names are used in 'label', 'compute', 'set', and 'ignore' lines. -# Example feature names are 'in0', 'temp2', 'in3_min', and 'temp3_over'. -# These features are defined for each chip in lib/chips.c. -# -# Undefined features will be silently ignored in 'label' and 'compute' lines. -# Undefined features in 'set' lines will result in 'Unknown feature name' -# when running 'sensors -s'. -# -# Unfortunately, feature names starting with a number must be in -# double quotes or you get "parse error, expecting 'NAME'". -# -# If you have trouble, verify the features in lib/chips.c!!! -# -# -# LABEL LINES -# ----------- -# A label line describes what a certain feature stands for on your -# mainboard. Programs can retrieve these names and display them. -# If no label is specified for a certain feature, the default name -# (ie. 'fan1' for fan1) is used. -# -# If you specify a label for in1, this label is also used for in1_min and -# in1_max, unless they have their own labels declared. There are several -# of these logical groups. -# -# These are as advised in the LM78 and LM79 data sheets, and used on most -# boards we have seen. -# -# label in0 "VCore 1" -# label in1 "VCore 2" -# label in2 "+3.3V" -# label in3 "+5V" -# label in4 "+12V" -# label in5 "-12V" -# label in6 "-5V" -# -# -# COMPUTE LINES -# ------------- -# A compute line describes how to scale a certain feature. There are -# two expressions in it: the first describes how the /proc value must -# be translated to a user value, the second how a user value must be -# translated to a /proc value. '@' is the value to operate on. You may -# refer to other readable features (like '2 * vid'). -# -# The following operators are valid: + - * / ( ) ^ ` -# ^ is e**x and ` is ln(x) (valid in library version 2.0.0 / -# lm_sensors 2.8.0 or higher) -# -# Like for the label statement, there are logical groups here. They are -# sometimes a bit different, though. For example, fan1_div is in the -# logical label group of fan1 (it gets the same label if none is declared -# for it), but it is not in the compute group of fan1 (as it uses a -# completely different system of values). -# -# -# VOLTAGE COMPUTATION DETAILS -# --------------------------- -# Most voltage sensors in sensor chips have a range of 0 to 4.096 Volts. -# This is generally sufficient for the 3.3 and CPU (2.5V, for example) -# supply voltages, so the sensor chip reading is the actual voltage. -# -# Other supply voltages must be scaled with an external resistor network. -# The chip driver generally reports the 'raw' value 0 - 4.09 V, and the -# userspace application must convert this raw value to an actual voltage. -# The 'compute' lines provide this facility. -# -# Unfortunately the resistor values vary among motherboard types. -# Therefore you may have to adjust the computations in this file -# to match your motherboard. -# -# For positive voltages (in3, in4), two resistors are used, with the following -# formula (R1,R2: resistor values, Vs: read voltage, Vin: pin voltage) -# R1 = R2 * (Vs/Vin - 1) -# For negative voltages (in5, in6) two resistors are used, with the following -# formula (Rin,Rf: resistor values, Vs: read voltage, Vin: pin voltage) -# Rin = (Vs * Rf) / Vin -# -# Note: Some chips use a different formula, see it87 section for example. -# -# Here are the official LM78 and LM79 data sheet values. -# Vs R1,Rin R2,Rf Vin -# in3 +5.0 6.8 10 +2.98 -# in4 +12.0 30 10 +3.00 -# in5 -12.0 240 60 +3.00 -# in6 -5.0 100 60 +3.00 -# -# These would lead to these declarations: -# compute in3 ((6.8/10)+1)*@ , @/((6.8/10)+1) -# compute in4 ((30/10)+1)*@ , @/((30/10)+1) -# compute in5 -(240/60)*@ , -@/(240/60) -# compute in6 -(100/60)*@ , -@/(100/60) -# -# On almost any mainboard we have seen, the Winbond compute values lead to -# much better results, though. -# -# Vs R1,Rin R2,Rf Vin -# in4 +12.0 28 10 +3.15 -# in5 -12.0 210 60.4 +3.45 -# in6 -5.0 90.9 60.4 +3.33 -# -# These leads to these declarations: -# compute in3 ((6.8/10)+1)*@ , @/((6.8/10)+1) -# compute in4 ((28/10)+1)*@ , @/((28/10)+1) -# compute in5 -(210/60.4)*@ , -@/(210/60.4) -# compute in6 -(90.9/60.4)*@ , -@/(90.9/60.4) -# -# NOTE: On many motherboards, the -5V and -12V sensors are not connected. -# Add ignore lines so these readings will not be displayed. For example: -# ignore in5 -# ignore in6 -# -# -# TEMPERATURE COMPUTATION EXAMPLES -# -------------------------------- -# There are two common ways to adjust temperature readings. -# One is to adjust by a constant. The other is to change the -# temperature sensor type. -# -# Add 5 degrees to temperature sensor 1: -# compute temp1 @+5,@-5 -# -# Sensor type adjustments (certain chips only): -# ...Set temp1 to processor's thermal diode: -# set sensor1 1 (Winbond chips) -# set sensor1 3 (IT87xx and MTP008 chips) -# -# ...Set temp1 sensor to 3904 transistor: -# set sensor1 2 (Winbond chips) -# -# ...Set temp1 to thermistor: -# set sensor1 3435 (Winbond chips) -# set sensor1 2 (IT87xx and MTP008 chips) -# -# Often, a temperature sensor is disconnected; disable it with an ignore line: -# ignore temp3 -# -# -# SET LINES -# --------- -# Set statements set things like limits. Complete expressions can be -# used. Not everything can sensibly be set: setting 'in0', for example, -# is impossible! These settings are put through the compute translations; -# so if we specify '12.8' for in6, '3.2' will actually be written! -# -# Important note: In the 'sensors' program, these only take effect -# after running 'sensors -s'!!! -# -# Here are some examples: -# -# set in0_max vid*1.05 -# set in0_min vid*0.95 -# set temp1_over 40 -# set temp1_hyst 37 -# -# Think of tempx_over as 'alarm set' and tempx_hyst as 'alarm clear' -# thresholds. In most cases the 'over' value should be higher than -# the 'hyst' value by several degrees. -# +# libsensors configuration file +# ----------------------------- +# NOTE: # All the set statements from this file are commented out by default. # The reason is that the proper limits are highly system-dependent, # and writing improper limits may have all sorts of weird effects, # from beeping to CPU throttling to instant reboot. If you want to -# actually set the limits, remove the comment marks. -# -# -# IGNORE LINES -# ------------ -# Ignore statements tell certain features are not wanted. User programs can -# still read them if they really want, though; this is just an advisory -# marking. 'in0' would also invalidate 'in0_max' and 'in0_min'. -# 'ignore' does not disable anything in the actual sensor chip; it -# simply advises the user program to not access that data. -# -# ignore in0 -# -# -# STATEMENT ORDER -# --------------- -# Statements can go in any order, EXCEPT that some statements depend -# on others. Dependencies could be either in the library or the driver. -# A 'compute' statement must go before a 'set' statement -# for the same feature or else the 'set' won't be computed correctly. -# This is a library dependency. -# A 'set fan1_div' statement must go before a 'set fan1_min' statement, -# because the driver uses the divisor in calculating the minimum. -# Also, one should set vrm prior to using vid in any formula. -# -# -# BUS LINES -# --------- -# There is one other feature: the 'bus' statement. An example is below. -# -# bus "i2c-0" "SMBus PIIX4 adapter at e800" "Non-I2C SMBus adapter" -# -# If we refer from now on to 'i2c-0' in 'chip' lines, this will run-time -# be matched to this bus. So even if the PIIX4 is called 'i2c-5' at that -# moment, because five other adapters were detected first, 'i2c-0' in -# the config file would always only match this physical bus. In the above -# config file, this feature is not needed; but the next lines would -# only affect the LM75 chips on the PIIX4 adapter: -# -# chip "lm75-i2c-0-*" -# -# You should really use the output of /proc/bus/chips to generate bus lines, -# because one mistyped characted will inhibit the match. Wildcards are not -# yet supported; spaces at the end are ignored, though. -# -# -# BEEPS -# ----- -# Some chips support alarms with beep warnings. When an alarm is triggered -# you can be warned by a beeping signal through your computer speaker. It -# is possible to enable beeps for all alarms on a chip using the following -# line: -# -# set beep_enable 1 -# -# or disable them using: -# -# set beep_enable 0 -# -# -########################################################################## -#### Here begins the real configuration file +# actually set the limits, remove the comment marks, then run "sensors -s". - -chip "lm78-*" "lm78-j-*" "lm79-*" "w83781d-*" +chip "lm78-*" "lm79-*" "w83781d-*" # These are as advised in the LM78 and LM79 data sheets, and used on almost # any mainboard we have seen. @@ -325,32 +57,32 @@ chip "lm78-*" "lm78-j-*" "lm79-*" "w83781d-*" # Here, we assume the VID readings are valid, and we use a max. 5% deviation -# set in0_min vid*0.95 -# set in0_max vid*1.05 -# set in1_min vid*0.95 -# set in1_max vid*1.05 +# set in0_min cpu0_vid*0.95 +# set in0_max cpu0_vid*1.05 +# set in1_min cpu0_vid*0.95 +# set in1_max cpu0_vid*1.05 # set in2_min 3.3 * 0.95 # set in2_max 3.3 * 1.05 # set in3_min 5.0 * 0.95 # set in3_max 5.0 * 1.05 # set in4_min 12 * 0.95 # set in4_max 12 * 1.05 -# set in5_max -12 * 0.95 -# set in5_min -12 * 1.05 -# set in6_max -5 * 0.95 -# set in6_min -5 * 1.05 +# set in5_min -12 * 0.95 +# set in5_max -12 * 1.05 +# set in6_min -5 * 0.95 +# set in6_max -5 * 1.05 -# Examples for lm78, lm78j, lm79 temperature limits -# set temp_over 40 -# set temp_hyst 37 +# Examples for lm78, lm79 temperature limits +# set temp1_max 40 +# set temp1_max_hyst 37 # Examples for w83781d temperature limits -# set temp1_over 40 -# set temp1_hyst 37 -# set temp2_over 52 -# set temp2_hyst 47 -# set temp3_over 52 -# set temp3_hyst 47 +# set temp1_max 40 +# set temp1_max_hyst 37 +# set temp2_max 52 +# set temp2_max_hyst 47 +# set temp3_max 52 +# set temp3_max_hyst 47 # Examples of fan low speed limits # set fan1_min 3000 @@ -365,7 +97,7 @@ chip "lm78-*" "lm78-j-*" "lm79-*" "w83781d-*" # In case a lm78 is used together with a lm75, the lm78 temp sensor will # generally show the M/B temperature while the lm75 temp sensor will show # the CPU temperature. -# label temp "M/B Temp" +# label temp1 "M/B Temp" # Uncomment the following line to enable beeps for all alarms on this chip # set beep_enable 1 @@ -375,16 +107,16 @@ chip "lm78-*" "lm78-j-*" "lm79-*" "w83781d-*" chip "lm75-*" # Most boards don't need scaling. Following is for the Asus TX97-E. -# compute temp @*2.0, @/2.0 +# compute temp1 @*2.0, @/2.0 # Examples for temperature limits -# set temp_over 70 -# set temp_hyst 65 +# set temp1_max 70 +# set temp1_max_hyst 65 # In case a lm75 is used together with a lm78, the lm78 temp sensor will # generally show the M/B temperature while the lm75 temp sensor will show # the CPU temperature. -# label temp "CPU Temp" +# label temp1 "CPU Temp" chip "sis5595-*" @@ -420,7 +152,7 @@ chip "sis5595-*" # The inverse of the driver formula is x = (1.20t - 62.77) # So the final formula is newt = (.345(1.20t - 62.77)) - 12). # Put this in the sensors.conf file as -# compute temp ((.345 * ((1.20 * @) - 62.77)) - 12), ... +# compute temp1 ((.345 * ((1.20 * @) - 62.77)) - 12), ... # where ... is the inverse function I leave to you. # # Look in your 'Vendor.ini' file to see which one is present @@ -430,18 +162,17 @@ chip "sis5595-*" # Fix up a 'compute' line to match your thermistor type. # Warning. You still don't have enough information to do this. # ThermistorType = NTC-10KC15-1608-1P (10K at 25C; Beta = 3435) -# compute temp ((X * ((1.20 * @) - 62.77)) - Y), ... +# compute temp1 ((X * ((1.20 * @) - 62.77)) - Y), ... # ThermistorType = NTC-103KC15-1608-1P (??) -# compute temp ((X * ((1.20 * @) - 62.77)) - Y), ... +# compute temp1 ((X * ((1.20 * @) - 62.77)) - Y), ... # ThermistorType = NTC-103AT-2 (10K at 25C; Beta = 3435) -# compute temp ((X * ((1.20 * @) - 62.77)) - Y), ... +# compute temp1 ((X * ((1.20 * @) - 62.77)) - Y), ... # ThermistorType = NTC-103JT (10K at 25C; Beta = 3435) -# compute temp ((X * ((1.20 * @) - 62.77)) - Y), ... +# compute temp1 ((X * ((1.20 * @) - 62.77)) - Y), ... # examples for sis5595 temperature limits; -# for sis5595, temp_hyst is really the low limit, not a hysteresis value -# set temp_over 40 -# set temp_hyst 37 +# set temp1_max 40 +# set temp1_max_hyst 37 chip "w83782d-*" "w83627hf-*" @@ -474,17 +205,14 @@ chip "w83782d-*" "w83627hf-*" compute in6 (3.14 * @) - 7.71 , (@ + 7.71) / 3.14 compute in7 ((6.8/10)+1)*@ , @/((6.8/10)+1) -# adjust this if your vid is wrong; see doc/vid -# set vrm 9.0 - # set limits to 5% for the critical voltages # set limits to 10% for the non-critical voltages # set limits to 20% for the battery voltage -# set in0_min vid*0.95 -# set in0_max vid*1.05 -# set in1_min vid*0.95 -# set in1_max vid*1.05 +# set in0_min cpu0_vid*0.95 +# set in0_max cpu0_vid*1.05 +# set in1_min cpu0_vid*0.95 +# set in1_max cpu0_vid*1.05 # set in2_min 3.3 * 0.95 # set in2_max 3.3 * 1.05 # set in3_min 5.0 * 0.95 @@ -504,17 +232,17 @@ chip "w83782d-*" "w83627hf-*" # 1 = PII/Celeron Diode; 2 = 3904 transistor; # 3435 = thermistor with Beta = 3435 # If temperature changes very little, try 1 or 2. -# set sensor1 1 -# set sensor2 2 -# set sensor3 3435 +# set temp1_type 1 +# set temp2_type 2 +# set temp3_type 3435 # examples for temperature limits -# set temp1_over 40 -# set temp1_hyst 37 -# set temp2_over 52 -# set temp2_hyst 47 -# set temp3_over 52 -# set temp3_hyst 47 +# set temp1_max 40 +# set temp1_max_hyst 37 +# set temp2_max 52 +# set temp2_max_hyst 47 +# set temp3_max 52 +# set temp3_max_hyst 47 chip "w83783s-*" @@ -537,15 +265,12 @@ chip "w83783s-*" compute in5 (5.14 * @) - 14.91 , (@ + 14.91) / 5.14 compute in6 (3.14 * @) - 7.71 , (@ + 7.71) / 3.14 -# adjust this if your vid is wrong; see doc/vid -# set vrm 9.0 - # set limits to 5% for the critical voltages # set limits to 10% for the non-critical voltages # set limits to 20% for the battery voltage -# set in0_min vid*0.95 -# set in0_max vid*1.05 +# set in0_min cpu0_vid*0.95 +# set in0_max cpu0_vid*1.05 # set in2_min 3.3 * 0.95 # set in2_max 3.3 * 1.05 # set in3_min 5.0 * 0.95 @@ -561,14 +286,14 @@ chip "w83783s-*" # 1 = PII/Celeron Diode; 2 = 3904 transistor; # 3435 = thermistor with Beta = 3435 # If temperature changes very little, try 1 or 2. -# set sensor1 1 -# set sensor2 2 +# set temp1_type 1 +# set temp2_type 2 # examples for temperature limits -# set temp1_over 40 -# set temp1_hyst 37 -# set temp2_over 52 -# set temp2_hyst 47 +# set temp1_max 40 +# set temp1_max_hyst 37 +# set temp2_max 52 +# set temp2_max_hyst 47 chip "w83697hf-*" @@ -646,15 +371,15 @@ chip "w83697hf-*" # 1 = PII/Celeron Diode; 2 = 3904 transistor; # 3435 = thermistor with Beta = 3435 # If temperature changes very little, try 1 or 2. -# set sensor1 1 -# set sensor2 2 -# set sensor3 3435 +# set temp1_type 1 +# set temp2_type 2 +# set temp3_type 3435 # examples for temperature limits -# set temp1_over 40 -# set temp1_hyst 37 -# set temp2_over 52 -# set temp2_hyst 47 +# set temp1_max 40 +# set temp1_max_hyst 37 +# set temp2_max 52 +# set temp2_max_hyst 47 chip "w83627thf-*" "w83637hf-*" @@ -667,9 +392,6 @@ chip "w83627thf-*" "w83637hf-*" # Note that in1 (+12V) is the usual in4, and in4 (-12V) is the usual in5. # Data sheet is obviously wrong for in4, the usual formula should work. # No in5 nor in6. -# sensors doesn't need the ignore lines but sensord does... - ignore in5 - ignore in6 label in0 "VCore" label in1 "+12V" @@ -687,16 +409,13 @@ chip "w83627thf-*" "w83637hf-*" compute in4 (5.14*@)-14.91, (@+14.91)/5.14 compute in7 ((6.8/10)+1)*@ , @/((6.8/10)+1) -# adjust this if your vid is wrong; see doc/vid -# set vrm 9.0 - # set limits to 5% for the critical voltages # set limits to 10% for the non-critical voltages # set limits to 20% for the battery voltage # if your vid is wrong, you'll need to adjust in0_min and in0_max -# set in0_min vid * 0.95 -# set in0_max vid * 1.05 +# set in0_min cpu0_vid * 0.95 +# set in0_max cpu0_vid * 1.05 # set in1_min 12 * 0.90 # set in1_max 12 * 1.10 # set in2_min 3.3 * 0.95 @@ -714,21 +433,21 @@ chip "w83627thf-*" "w83637hf-*" # 1 = PII/Celeron Diode; 2 = 3904 transistor; # 3435 = thermistor with Beta = 3435 # If temperature changes very little, try 1 or 2. -# set sensor1 1 -# set sensor2 2 -# set sensor3 3435 +# set temp1_type 1 +# set temp2_type 2 +# set temp3_type 3435 label temp1 "M/B Temp" label temp2 "CPU Temp" # ignore temp3 # examples for temperature limits -# set temp1_over 40 -# set temp1_hyst 37 -# set temp2_over 52 -# set temp2_hyst 47 -# set temp3_over 52 -# set temp3_hyst 47 +# set temp1_max 40 +# set temp1_max_hyst 37 +# set temp2_max 52 +# set temp2_max_hyst 47 +# set temp3_max 52 +# set temp3_max_hyst 47 # ignore fan1 label fan2 "CPU Fan" @@ -740,23 +459,9 @@ chip "w83792d-*" label in0 "VCoreA" label in1 "VCoreB" - label in2 "VIN0" - label in3 "VIN1" - label in4 "VIN2" - label in5 "VIN3" label in6 "5VCC" label in7 "5VSB" label in8 "VBAT" - label fan1 "Fan1" - label fan2 "Fan2" - label fan3 "Fan3" - label fan4 "Fan4" - label fan5 "Fan5" - label fan6 "Fan6" - label fan7 "Fan7" - label temp1 "Temp1" - label temp2 "Temp2" - label temp3 "Temp3" # set in0_min 1.4 # set in0_max 1.6 @@ -784,8 +489,8 @@ chip "w83792d-*" # temp2 limits examples -# set temp2_over 42 -# set temp2_hyst 37 +# set temp2_max 42 +# set temp2_max_hyst 37 # ignore examples @@ -809,7 +514,7 @@ chip "w83793-*" label temp1 "CPU1 Temp" label temp2 "CPU2 Temp" - + # fan1 adjustments examples # set fan1_min 1500 @@ -858,7 +563,7 @@ chip "as99127f-*" # for temp2. Quoting Artur Gawryszczak (edited to reflect subsequent fixes # to the driver): # "I guess, that the formula "(@*15/43)+25, (@-25)*43/15" is correct -# for those Asus motherboards, which get CPU temperature from internal +# for those Asus motherboards, which get CPU temperature from internal # thermal diode (Pentium Coppermine, and above), while no formula is needed # for Athlon/Duron boards, which use a thermistor in the socket." # An alternative formula was then found and reported by Victor G. Marimon. @@ -885,74 +590,61 @@ chip "as99127f-*" # label temp3 "CPU 2 Temp" # ignore temp3 -# adjust this if your vid is wrong; see doc/vid -# set vrm 9.0 - # set limits to 5% for the critical voltages # set limits to 10% for the non-critical voltages # set limits to 20% for the battery voltage -# set in0_min vid*0.95 -# set in0_max vid*1.05 -# set in1_min vid*0.95 -# set in1_max vid*1.05 +# set in0_min cpu0_vid*0.95 +# set in0_max cpu0_vid*1.05 +# set in1_min cpu0_vid*0.95 +# set in1_max cpu0_vid*1.05 # set in2_min 3.3 * 0.95 # set in2_max 3.3 * 1.05 # set in3_min 5.0 * 0.95 # set in3_max 5.0 * 1.05 # set in4_min 12 * 0.90 # set in4_max 12 * 1.10 -# set in5_max -12 * 0.90 -# set in5_min -12 * 1.10 -# set in6_max -5 * 0.95 -# set in6_min -5 * 1.05 +# set in5_min -12 * 0.90 +# set in5_max -12 * 1.10 +# set in6_min -5 * 0.95 +# set in6_max -5 * 1.05 # examples for temperature limits -# set temp1_over 40 -# set temp1_hyst 37 -# set temp2_over 52 -# set temp2_hyst 47 -# set temp3_over 52 -# set temp3_hyst 47 +# set temp1_max 40 +# set temp1_max_hyst 37 +# set temp2_max 52 +# set temp2_max_hyst 47 +# set temp3_max 52 +# set temp3_max_hyst 47 chip "gl518sm-*" # IMPORTANT: in0, in1, and in2 values (+5, +3, and +12) CANNOT be read -# unless you use the slow 'iterate' method. Limits will still -# work even when iterate=0. See doc/chips/gl518sm. -# Note that the 'iterate' method was trimmed while porting the -# driver to Linux 2.6 as we considered it too ugly for the thin -# benefit. # # Factors and labels taken from GL518SM datasheet, they seem to give # reasonable values with EISCA connected Fan78 - label vdd "+5V" - label vin1 "+3.3V" - label vin2 "+12V" - label vin3 "Vcore" + label in0 "+5V" + label in1 "+3.3V" + label in2 "+12V" + label in3 "Vcore" -# vin2 depends on external resistors (4,7k and 15k assumed here) -# vin1 and vin3 require no scaling +# in2 depends on external resistors (4,7k and 15k assumed here) +# in1 and in3 require no scaling - compute vin2 (197/47)*@ , @/(197/47) + compute in2 (197/47)*@ , @/(197/47) -# set vdd_min 4.8 -# set vdd_max 5.2 -# set vin1_min 3.20 -# set vin1_max 3.40 -# set vin2_min 11.0 -# set vin2_max 13.0 -# set vin3_min 2.10 -# set vin3_max 2.30 -# set fan1_off 0 +# set in0_min 4.8 +# set in0_max 5.2 +# set in1_min 3.20 +# set in1_max 3.40 +# set in2_min 11.0 +# set in2_max 13.0 +# set in3_min 2.10 +# set in3_max 2.30 # set fan2_min 0 -# Do NOT uncomment the following line with the Linux 2.6 kernel driver, -# as it'll raise an error. -# set iterate 2 - chip "gl520sm-*" @@ -961,46 +653,41 @@ chip "gl520sm-*" # The GL520SM has two application modes. In mode 1 it has two thermistor # inputs, in mode 2 it has only one and an extra (negative) voltage input. # The mode is supposed to be set properly by your BIOS so you should not -# need to change it. You can force it below if really needed though. -# Note that this means that you have either temp2 or vin4 but never both -# at the same time. +# need to change it. Note that you have either temp2 or in4, not both. -# set two_temps 1 + label in0 "+5V" + label in1 "+3.3V" + label in2 "+12V" + label in3 "Vcore" + label in4 "-12V" - label vdd "+5V" - label vin1 "+3.3V" - label vin2 "+12V" - label vin3 "Vcore" - label vin4 "-12V" +# in1 and in3 require no scaling +# in2 depends on external resistors (4,7k and 15k assumed) -# vin1 and vin3 require no scaling -# vin2 depends on external resistors (4,7k and 15k assumed) - -# vin4 = ((R1+R2)/R2)*@ - (R1/R2)*vdd +# in4 = ((R1+R2)/R2)*@ - (R1/R2)*vdd # # -12 --| R1 |---t---| R2 |-- +5 # | # vin4 # - compute vin2 (197/47)*@ , @/(197/47) - compute vin4 (5*@)-(4*vdd) , (@+4*vdd)/5 + compute in2 (197/47)*@ , @/(197/47) + compute in4 (5*@)-(4*in0_input) , (@+4*in0_input)/5 -# set vdd_min 4.8 -# set vdd_max 5.2 -# set vin1_min 3.20 -# set vin1_max 3.40 -# set vin2_min 11.0 -# set vin2_max 13.0 -# set vin3_min 2.10 -# set vin3_max 2.30 +# set in0_min 4.8 +# set in0_max 5.2 +# set in1_min 3.20 +# set in1_max 3.40 +# set in2_min 11.0 +# set in2_max 13.0 +# set in3_min 2.10 +# set in3_max 2.30 chip "lm80-*" # The values below should be correct if you own a qdi BX (brilliant1) -# mainboard. If not, please contact us, so we can figure out better readings. -# Many thanks go to Peter T. Breuer for helping us figure +# mainboard. Many thanks go to Peter T. Breuer for helping us figure # out how to handle the LM80. # For positive voltages (in0..in4), two resistors are used, with the following @@ -1035,8 +722,8 @@ chip "lm80-*" compute in2 (22.1/30 + 1) * @ , @ / (22.1/30 + 1) compute in3 (2.8/1.9) * @, @ * 1.9/2.8 compute in4 (160/30.1 + 1) * @, @ / (160/30.1 + 1) - compute in5 (160/35.7)*(@ - in0) + @, (@ + in0 * 160/35.7)/ (1 + 160/35.7) - compute in6 (36/16.2)*(@ - in0) + @, (@ + in0 * 36/16.2) / (1 + 36/16.2) + compute in5 (160/35.7)*(@ - in0_input) + @, (@ + in0_input * 160/35.7)/ (1 + 160/35.7) + compute in6 (36/16.2)*(@ - in0_input) + @, (@ + in0_input * 36/16.2) / (1 + 36/16.2) # set in0_min 5 * 0.95 # set in0_max 5 * 1.05 @@ -1055,91 +742,13 @@ chip "lm80-*" # set in6_min -5 * 1.05 # set in6_max -5 * 0.95 -# examples for lm80 temperature limits -# WARNING - nonstandard names and functions for the lm80!!! # All 4 of these limits apply to the single temperature sensor. -# "hot" is like the standard alarm for most chips. -# "os" is the threshold for the overtemperature shutdown output. -# "os" may or may not do anything on your motherboard but it should -# be set higher than the "hot" thresholds. -# Note that the /proc file 'temp" also has five entries instead of -# the usual three. -# set temp_hot_hyst 45 -# set temp_hot_max 52 -# set temp_os_hyst 57 -# set temp_os_max 62 - - -chip "maxilife-cg-*" "maxilife-co-*" "maxilife-as-*" - - label fan1 "HDD Fan" - label fan2 "PCI Fan" - label fan3 "CPU Fan" - ignore fan4 - - label temp2 "PCI Temp" - label temp4 "HDD Temp" - label temp5 "CPU Temp" - ignore temp6 - - label vid1 "V+12" - ignore vid5 - -# vid1 need to be scaled by 6.337 other voltages -# require no scaling - - compute vid1 6.337*@ , @/6.337 - - -chip "maxilife-cg-*" - - ignore temp1 - label temp3 "BX Temp" - - label vid2 "Vcpu1" - label vid3 "Vcpu2" - ignore vid4 - - -chip "maxilife-co-*" - - label temp1 "CPU 1 Temp" - label temp3 "CPU 2 Temp" - - label vid2 "Vcpu1" - label vid3 "Vcpu2" - label vid4 "VcacheL2" - - -chip "maxilife-as-*" - - ignore temp1 - ignore temp3 - - label vid2 "Vcpu" - ignore vid3 - ignore vid4 - - -chip "maxilife-nba-*" - - label fan1 "CPU Fan" - label fan2 "PCI Fan" - label fan3 "HDD Fan" - label fan4 "Heat Sink Fan" - - label temp1 "CPU 1 Temp" - label temp2 "CPU 2 Temp" - label temp3 "PCI/Ambient Temp" - label temp4 "HDD Temp" - label temp5 "Motherboard Temp" - label temp6 "CPU Reference Temp" - - label vid1 "V+12" - label vid2 "Vcpu1" - label vid3 "Vcpu2" - label vid4 "VcacheL2" - label vid5 "V-12" +# "crit" may or may not do anything on your motherboard but it should +# be set higher than the "max" thresholds. +# set temp1_max_hyst 45 +# set temp1_max 52 +# set temp1_crit_hyst 57 +# set temp1_crit 62 chip "via686a-*" @@ -1147,25 +756,24 @@ chip "via686a-*" # VIA is very specific about the voltage sensor inputs, and our labels # reflect what they say. Unfortunately, they are not at all specific about # how to convert any of the register values to real units. Fortunately, -# Jonathan Yew and Alex van Kaam -# came through with some data for temp conversion and formulae for voltage -# conversion. However, the conversions should be regarded as our best guess- -# YMMV. +# Jonathan Yew and Alex van Kaam came through with some data for temp +# conversion and formulae for voltage conversion. However, the conversions +# should be regarded as our best guess - YMMV. # On the Tyan S1598, the 2.5V sensor reads 0 and is not displayed in the BIOS. -# Linas Vepstas reports that this sensor shows nothing of +# Linas Vepstas reports that this sensor shows nothing of # interest on the Abit KA7 (Athlon), and is also not displayed in the BIOS. -# Likewise, Johannes Drechsel-Burkhard reports that this +# Likewise, Johannes Drechsel-Burkhard reports that this # sensor is unavailable in the BIOS of his MSI K7T Pro (Thunderbird). So, -# if you have one of these boards you may want to uncomment the 'ignore 2.5V' +# if you have one of these boards you may want to uncomment the 'ignore in1' # line below. - label "2.0V" "CPU core" - label "2.5V" "+2.5V" - #ignore "2.5V" - label "3.3V" "I/O" - label "5.0V" "+5V" - label "12V" "+12V" + label in0 "CPU core" + label in1 "+2.5V" + #ignore in1 + label in2 "I/O" + label in3 "+5V" + label in4 "+12V" label fan1 "CPU Fan" label fan2 "P/S Fan" @@ -1177,10 +785,10 @@ chip "via686a-*" # different from temp1 & temp2 (as noted above, VIA has not provided # conversion info). So, you may wish to 'ignore temp3'. -# Johannes Drechsel-Burkhard notes that on his MSI K7T Pro, +# Johannes Drechsel-Burkhard notes that on his MSI K7T Pro, # temp1 is the CPU temp and temp2 is the SYS temp. Hugo van der Merwe notes # the same for his Gigabyte GA-7DXC, Olivier Martin for his Gigabyte -# GA-7ZM and Patrick Thomson for his Chaintech CT-5ATA. +# GA-7ZM and Patrick Thomson for his Chaintech CT-5ATA. # Thomas Anglmaier notes: on Epox EP-7kxa temp2 is CPU and temp1 is SYS. label temp1 "SYS Temp" @@ -1204,9 +812,9 @@ chip "via686a-*" # set in4_min 12 * 0.9 # set in4_max 12 * 1.1 -# Set your temp limits here. Remember, 'tempX_over' is the temp at which an -# alarm is triggered, and 'tempX_hyst' is the temp at which an alarm turns off. -# Setting tempX_hyst to a few degrees below the corresponding tempX_over +# Set your temp limits here. Remember, 'tempX_max' is the temp at which an +# alarm is triggered, and 'tempX_max_hyst' is the temp at which an alarm turns off. +# Setting tempX_max_hyst to a few degrees below the corresponding tempX_max # prevents an oscillation between alarm on and off states. This kind of # oscillation is known as hyteresis, thus the name. (You typically get the # most serious and troublesome hysteresis when a sensor triggers something to @@ -1214,12 +822,12 @@ chip "via686a-*" # we would still get some oscillation when the temp hovers around the limit # due to noise.) -# set temp1_hyst 40 -# set temp1_over 45 -# set temp2_hyst 55 -# set temp2_over 60 -# set temp3_hyst 60 -# set temp3_over 65 +# set temp1_max_hyst 40 +# set temp1_max 45 +# set temp2_max_hyst 55 +# set temp2_max 60 +# set temp3_max_hyst 60 +# set temp3_max 65 # You could set your fan limits too, but the defaults should be fine. @@ -1227,101 +835,6 @@ chip "via686a-*" #set fan2_min 5000 -chip "mtp008-*" - -# The values below should be correct if you own a Tyan S1834D motherboard. -# If not, please contact us, so we can figure out better readings. -# FOR TYAN S2510 SEE END OF THIS SECTION. - -# For positive voltages outside the 0..4.09V range (in2..in4), two resistors -# are used, with the following formula (R1,R2: resistor values, Vs: read -# voltage, Vin: pin voltage) -# Vin = Vs * (R2 / (R1 + R2)) -# For negative voltages (in5) two resistors are used, with the following -# formula (R3,R4: resistor values, Vs: read voltage, Vin: pin voltage) -# Vin = ((4.096 - Vs) * (R3 / (R3 + R4))) + Vs - -# Here are the official MTP008 data sheet values: -# Vs R1,R3 R2,R4 Vin -# +12.0 28000 10000 +3.16 -# -12.0 232000 56000 +0.96 -# -5.0 120000 56000 +1.20 - - label in0 "VCore1" - label in1 "+3.3V" - label in2 "+12V" - label in3 "Vcore2" - ignore in4 - label in5 "-12V" - label in6 "Vtt" - - label fan1 "CPU1 Fan" - label fan2 "CPU2 Fan" - label fan3 "fan3" - - label temp1 "CPU1 Temp" - label temp2 "CPU2 Temp" - ignore temp3 - - compute in2 @ * 38 / 10, @ * 10 / 38 - compute in5 (@ * 36 - 118.61) / 7, (118.61 + 7 * @) / 36 - -# examples for temperature limits -# set temp1_over 40 -# set temp1_hyst 37 -# set temp2_over 52 -# set temp2_hyst 47 -# set temp3_over 52 -# set temp3_hyst 47 - -# End of standard mtp008 configuration - -# TYAN S2510 INFORMATION -# This motherboard has two mtp008's which are hooked up differently, -# so they must be configured separately. -# For this motherboard, COMMENT OUT the above mtp008 section and -# UNCOMMENT the following two sections. -# -#chip "mtp008-i2c-*-2c" -# label in0 "VCore1" -# set in0_min 1.60 -# set in0_max 1.80 -# label in1 "+3.3V" -# label in2 "+12V" -# label in3 "Vcore2" -# set in3_min 1.60 -# set in3_max 1.80 -# ignore in4 -# label in5 "-12V" -# label in6 "Vtt" -# label fan1 "CPU1 Fan" -# label fan2 "CPU2 Fan" -# label fan3 "fan3" -# label temp1 "CPU1 Temp" -# label temp2 "CPU2 Temp" -# ignore temp3 -# compute in2 @ * 38 / 10, @ * 10 / 38 -# compute in5 (@ * 36 - 118.61) / 7, (118.61 + 7 * @) / 36 -# -#chip "mtp008-i2c-*-2e" -# ignore in0 -# label in1 "+3.3V" -# ignore in2 -# label in3 "+5V" -# set in3_min 4.50 -# set in3_max 5.50 -# ignore in4 -# label in5 "+3.3V" -# ignore in6 -# label fan1 "fan4" -# label fan2 "fan5" -# label fan3 "fan6" -# ignore temp1 -# label temp2 "MB Temp" -# set temp2_over 52 -# set temp2_hyst 47 -# ignore temp3 - chip "adm1025-*" "ne1619-*" # The ADM1025 has integrated scaling resistors, rather @@ -1340,12 +853,9 @@ chip "adm1025-*" "ne1619-*" label in4 "+12V" label in5 "VCC" -# Adjust this if your vid is wrong; see doc/vid -# set vrm 9.0 - # Tolerate a 5% deviance for CPU power-supply -# set in1_min vid * 0.95 -# set in1_max vid * 1.05 +# set in1_min cpu0_vid * 0.95 +# set in1_max cpu0_vid * 1.05 # Tolerate a 10% deviance for other voltages # set in0_min 2.5 * 0.90 # set in0_max 2.5 * 1.10 @@ -1369,13 +879,13 @@ chip "adm1025-*" "ne1619-*" # Temperatures label temp1 "CPU Temp" label temp2 "M/B Temp" -# set temp1_low 10 -# set temp1_high 60 -# set temp2_low 10 -# set temp2_high 45 +# set temp1_min 10 +# set temp1_max 60 +# set temp2_min 10 +# set temp2_max 45 -chip "lm87-*" +chip "lm87-*" "adm1024-*" # # The LM87 has integrated scaling resistors, rather # than external resistors common to most sensor devices. @@ -1385,52 +895,35 @@ chip "lm87-*" # motherboard connections match these labels, and that the # driver computations are correct. Therefore they do not need to # be overridden here. -# -# Note: AIN1 (-12?), AIN2 (-5?) and temp3 require changing -# #defines in the driver and recompiling!!! -# This does not apply to the Linux 2.6 driver. -# -# This chip has non-standard entries in lib/chips.c so -# the feature names are quite different from other chips. -# For this chip, libsensors anticipates the correct labeling. -# This is great if it's correct but makes it a little more -# difficult if you want to change it. -# -# This may not have been a good idea, so it may be changed in the future. -# Here is an entry with everything commented out so you can -# uncomment the appropriate line if you want to change it. -# -# Warning - feature names starting with a number must be enclosed -# with double quotes. - label "2.5V" "+2.5V" - label Vccp1 "VCore" - label "3.3V" "+3.3V" - label "5V" "+5V" - label "12V" "+12V" -# label Vccp2 "VCore2" + label in0 "+2.5V" + label in1 "VCore" + label in2 "+3.3V" + label in3 "+5V" + label in4 "+12V" +# label in5 "VCore2" label fan1 "CPU Fan" # label fan2 "Case Fan" label temp1 "M/B Temp" - label CPU_Temp "CPU Temp" + label temp2 "CPU Temp" # label temp3 "AUX Temp" -# set Vccp1_min vid * 0.95 -# set Vccp1_max vid * 1.05 -# set "3.3V_min" 3.3 * 0.92 -# set "3.3V_max" 3.3 * 1.08 -# set "5V_min" 5 * 0.92 -# set "5V_max" 5 * 1.08 -# set "12V_min" 12 * 0.90 -# set "12V_max" 12 * 1.10 +# set in1_min cpu0_vid * 0.95 +# set in1_max cpu0_vid * 1.05 +# set in2_min 3.3 * 0.92 +# set in2_max 3.3 * 1.08 +# set in3_min 5 * 0.92 +# set in3_max 5 * 1.08 +# set in4_min 12 * 0.90 +# set in4_max 12 * 1.10 # These ones are mutually exclusive with temp3. If you have temp3, # comment out these lines as they will trigger errors on "sensors -s". -# set "2.5V_min" 2.5 * 0.92 -# set "2.5V_max" 2.5 * 1.08 -# set Vccp2_min vid * 0.95 -# set Vccp2_max vid * 1.05 +# set in0_min 2.5 * 0.92 +# set in0_max 2.5 * 1.08 +# set in5_min cpu0_vid * 0.95 +# set in5_max cpu0_vid * 1.05 # Increase fan clock dividers if your fans read 0 RPM while you know # they are connected and running. @@ -1451,86 +944,16 @@ chip "lm87-*" # set temp3_max 70 # LM87 AIN1 and AIN2 Section -# As described above, the driver must be recompiled to use either or -# both of these. -12 and -5 may be reversed on your board, this is +# -12 and -5 may be reversed on your board, this is # just a guess, the datasheet gives no guidance. -# Note that the Linux 2.6 driver needs no recompilation, it'll read the -# configuration from the chip. -# label AIN1 "-12V" -# label AIN2 "-5V" -# set AIN1_min -12 * 0.95 -# set AIN2_min -5 * 0.95 -# set AIN1_max -12 * 1.05 -# set AIN2_max -5 * 1.05 -# compute AIN1 (7.50 * @) - 21.45 , (@ + 21.45) / 7.50 -# compute AIN2 (4.05 * @) - 10.07 , (@ + 10.07) / 4.05 - -chip "adm9240-*" "ds1780-*" "lm81-*" -# -# These chips have non-standard entries in lib/chips.c so -# the feature names are quite different from other chips. -# For these chips, libsensors anticipates the correct labeling. -# This is great if it's correct but makes it a little more -# difficult if you want to change it. -# -# This may not have been a good idea, so it may be changed in the future. -# Here is an entry with everything commented out so you can -# uncomment the appropriate line if you want to change it. -# -# Warning - feature names starting with a number must be enclosed -# with double quotes. -# -# label "2.5V" "xxx" -# label Vccp1 "xxx" -# label "3.3V" "xxx" -# label "5V" "xxx" -# label "12V" "xxx" -# label Vccp2 "xxx" -# label fan1 "xxx" -# label fan2 "xxx" -# label temp "xxx" -# -# set Vccp1_min xxx -# set "2.5V_min" xxx -# set "3.3V_min" xxx -# set "5V_min" xxx -# set "12V_min" xxx -# set Vccp2_min xxx -# -# set Vccp1_max xxx -# set "2.5V_max" xxx -# set "3.3V_max" xxx -# set "5V_max" xxx -# set "12V_max" xxx -# set Vccp2_max xxx -# -# set fan1_div xxx Note: do not uncomment with kernel 2.6 driver -# set fan2_div xxx Note: do not uncomment with kernel 2.6 driver -# set fan1_min xxx -# set fan2_min xxx -# set temp1_hyst xxx -# set temp1_over xxx - -# compute "2.5V" xxx -# compute Vccp1 xxx -# compute "3.3V" xxx -# compute "5V" xxx -# compute "12V" xxx -# compute Vccp2 xxx -# compute temp xxx - -chip "adm1024-*" -# -# These settings work for me, adjust for your system -# - label fan1 "CPU1 fan" - label fan2 "CPU2 fan" - label temp "SYS Temp" - label temp1 "CPU2 Temp" - label temp2 "CPU1 Temp" - ignore "2.5V" # This register is also used for temp2 - ignore "Vccp1" - ignore "Vccp2" +# label in6 "-12V" +# label in7 "-5V" +# compute in6 (7.50 * @) - 21.45 , (@ + 21.45) / 7.50 +# compute in7 (4.05 * @) - 10.07 , (@ + 10.07) / 4.05 +# set in6_min -12 * 0.95 +# set in7_min -5 * 0.95 +# set in6_max -12 * 1.05 +# set in7_max -5 * 1.05 chip "it87-*" "it8712-*" @@ -1549,10 +972,6 @@ chip "it87-*" "it8712-*" label in7 "Stdby" label in8 "VBat" - # vid is not monitored by IT8705F - # comment out if you have IT8712 - ignore vid - # Incubus Saturnus reports that the IT87 chip on Asus A7V8X-X seems # to report the VCORE voltage approximately 0.05V higher than the board's # BIOS does. Although it doesn't make much sense physically, uncommenting @@ -1619,25 +1038,23 @@ chip "it87-*" "it8712-*" # Important - if your temperature readings are completely whacky # you probably need to change the sensor type. # Adujst and uncomment the appropriate lines below. -# The old method (modprobe it87 temp_type=0xXX) is no longer supported. # # 2 = thermistor; 3 = thermal diode; 0 = unused -# set sensor1 3 -# set sensor2 3 -# set sensor3 3 +# set temp1_type 3 +# set temp2_type 3 +# set temp3_type 3 # If a given sensor isn't used, you will probably want to ignore it # (see ignore statement right below). label temp1 "M/B Temp" -# set temp1_over 40 -# set temp1_low 15 +# set temp1_max 40 +# set temp1_min 15 label temp2 "CPU Temp" -# set temp2_over 45 -# set temp2_low 15 +# set temp2_max 45 +# set temp2_min 15 # ignore temp3 - label temp3 "Temp3" -# set temp3_over 45 -# set temp3_low 15 +# set temp3_max 45 +# set temp3_min 15 # The A7V8X-X has temperatures inverted, and needs a conversion for # CPU temp. Thanks to Preben Randhol for the formula. @@ -1657,55 +1074,6 @@ chip "it87-*" "it8712-*" # ignore fan3 # set fan3_min 3000 -# The following is for the Inside Technologies 786LCD which uses either a -# IT8705F or a SIS950 for monitoring with the SIS630. -# -# delete or comment out above it87 section and uncomment the following. -#chip "it87-*" -# label in0 "VCore 1" -# label in1 "VCore 2" -# label in2 "+3.3V" -# label in3 "+5V" -# label in4 "+12V" -# label in5 "3.3 Stdby" -# label in6 "-12V" -# label in7 "Stdby" -# label in8 "VBat" - # in0 will depend on your processor VID value, set to voltage specified in - # bios setup screen -# set in0_min 1.7 * 0.95 -# set in0_max 1.7 * 1.05 -# set in1_min 2.4 -# set in1_max 2.6 -# set in2_min 3.3 * 0.95 -# set in2_max 3.3 * 1.05 -# set in3_min 5.0 * 0.95 -# set in3_max 5.0 * 1.05 - # +- 12V are very poor tolerance on this board. Verified with voltmeter -# set in4_min 12 * 0.90 -# set in4_max 12 * 1.10 -# set in5_min 3.3 * 0.95 -# set in5_max 3.3 * 1.05 -# set in6_max -12 * 0.90 -# set in6_min -12 * 1.10 -# set in7_min 5 * 0.95 -# set in7_max 5 * 1.05 - # vid not monitored by IT8705F -# ignore vid - -# compute in3 ((6.8/10)+1)*@ , @/((6.8/10)+1) -# compute in4 ((30/10) +1)*@ , @/((30/10) +1) -# compute in6 (1+232/56)*@ - 4.096*232/56, (@ + 4.096*232/56)/(1+232/56) -# compute in7 ((6.8/10)+1)*@ , @/((6.8/10)+1) - # Temperature -# label temp1 "CPU Temp" -# ignore temp2 -# ignore temp3 - # Fans -# set fan1_min 3000 -# ignore fan2 -# ignore fan3 - chip "it8716-*" @@ -1729,8 +1097,8 @@ chip "it8716-*" # If vid (nominal CPU voltage) isn't correct, hardcode the correct value # instead. -# set in0_min vid * 0.95 -# set in0_max vid * 1.05 +# set in0_min cpu0_vid * 0.95 +# set in0_max cpu0_vid * 1.05 # set in1_min 1.8 * 0.95 # set in1_max 1.8 * 1.05 # set in2_min 3.3 * 0.95 @@ -1755,9 +1123,9 @@ chip "it8716-*" # appropriate lines below. # # 2 = thermistor; 3 = thermal diode; 0 = unused -# set sensor1 3 -# set sensor2 3 -# set sensor3 3 +# set temp1_type 3 +# set temp2_type 3 +# set temp3_type 3 # If a given sensor isn't used, you will probably want to ignore it # as well (see ignore statement right below). @@ -1768,10 +1136,10 @@ chip "it8716-*" # label temp2 "M/B Temp" # ignore temp3 -# set temp1_over 60 -# set temp1_low 10 -# set temp2_over 50 -# set temp2_low 10 +# set temp1_max 60 +# set temp1_min 10 +# set temp2_max 50 +# set temp2_min 10 # Fans @@ -1791,21 +1159,17 @@ chip "fscpos-*" # Temperature - label temp1 "Temp1/CPU" - label temp2 "Temp2/MB" - label temp3 "Temp3/AUX" + label temp1 "CPU Temp" + label temp2 "M/B Temp" + label temp3 "Aux Temp" # Fans - label fan1 "Fan1" - label fan2 "Fan2" - label fan3 "Fan3" - # Voltage - label volt12 "+12V" - label volt5 "+5V" - label voltbatt "Battery" + label in0 "+12V" + label in1 "+5V" + label in2 "Battery" chip "fscscy-*" @@ -1813,76 +1177,48 @@ chip "fscscy-*" # Temperature - label temp1 "Temp1/CPU0" - label temp2 "Temp2/CPU1" - label temp3 "Temp3/MB" - label temp4 "Temp4/AUX" + label temp1 "CPU0 Temp" + label temp2 "CPU1 Temp" + label temp3 "M/B Temp" + label temp4 "Aux Temp" # Fans - label fan1 "Fan1/CPU0" - label fan2 "Fan2/CPU0" - label fan3 "Fan3" - label fan4 "Fan4" - label fan5 "Fan5" - label fan6 "Fan6" + label fan1 "CPU Fan" + label fan2 "CPU Fan" # Voltage - label volt12 "+12V" - label volt5 "+5V" - label voltbatt "+3.3V" + label in0 "+12V" + label in1 "+5V" + label in2 "+3.3V" chip "fscher-*" # Fujitsu-Siemens Hermes chip # Temperature - label temp1 "Temp1/CPU" - label temp2 "Temp2/MB" - label temp3 "Temp3/AUX" + label temp1 "CPU Temp" + label temp2 "M/B Temp" + label temp3 "Aux Temp" # Fans - label fan1 "Fan1/PS" - label fan2 "Fan2/CPU" - label fan3 "Fan3/AUX" + label fan1 "PSU Fan" + label fan2 "CPU Fan" + label fan3 "Aux Fan" # Voltage label in0 "+12V" label in1 "+5V" label in2 "Battery" -# Note: comment the compute lines below when using the newer unified fschmd -# driver, as that driver does the scaling in the driver - -# Compute Voltages using mainboard dependant MRO-values -# (see doc/chips/fscher) -# M R O O M R - compute in0 (@ * (49 * 33) / 255) + (0 / 100), (@ - (0 / 100)) * 255 / (49 * 33) - compute in1 (@ * (20 * 33) / 255) + (0 / 100), (@ - (0 / 100)) * 255 / (20 * 33) - compute in2 (@ * (10 * 33) / 255) + (0 / 100), (@ - (0 / 100)) * 255 / (10 * 33) - -# Read documentation before enabling pwm settings (see doc/chips/fscher) -# WARNING: IMPROPER VALUES MAY DAMAGE YOUR SYSTEM DUE TO OVERHEATING! - -# Note these set statements will not work with the newer unified fschmd driver -# The functionality is still available using standard sysfs attributes for -# pwm control: pwm#_auto_point1_pwm (which are not accessible through sensors) - -# Allow fans to turn off -# set pwm1 0 -# set pwm2 0 -# set pwm3 0 - -# Min cooling -# set pwm1 2 -# set pwm2 1 -# set pwm3 1 - -# Max cooling -# set pwm1 255 -# set pwm2 255 -# set pwm3 255 +# Uncomment the computes line below when using the old fscher driver, leave +# them commented when using the newer unified fschmd driver +# +# M R O O M R +# compute in0 (@ * (49 * 33) / 255) + (0 / 100), (@ - (0 / 100)) * 255 / (49 * 33) +# compute in1 (@ * (20 * 33) / 255) + (0 / 100), (@ - (0 / 100)) * 255 / (20 * 33) +# compute in2 (@ * (10 * 33) / 255) + (0 / 100), (@ - (0 / 100)) * 255 / (10 * 33) chip "pcf8591-*" @@ -1891,44 +1227,33 @@ chip "pcf8591-*" # # Analog inputs - ignore ain_conf -# Since Linux 2.6, input configuration is set as module parameter, -# so the line below is for older kernels only. -# set ain_conf 0 - # You may discard ch2 and ch3 if you don't use them (depends on the input # configuration) -# ignore ch2 -# ignore ch3 +# ignore in2 +# ignore in3 - label ch0 "Chan. 0" - label ch1 "Chan. 1" - label ch2 "Chan. 2" - label ch3 "Chan. 3" + label in0 "Chan. 0" + label in1 "Chan. 1" + label in2 "Chan. 2" + label in3 "Chan. 3" # The driver assumes Vref = 2.56V and Agnd = 0V. If it doesn't match # your hardware, you have to use compute lines. The example below is # correct for Vref = 5.0V and Agnd = 0V. -# compute ch0 (@ * 500 / 256), (@ * 256 / 500) -# compute ch1 (@ * 500 / 256), (@ * 256 / 500) -# compute ch2 (@ * 500 / 256), (@ * 256 / 500) -# compute ch3 (@ * 500 / 256), (@ * 256 / 500) +# compute in0 (@ * 500 / 256), (@ * 256 / 500) +# compute in1 (@ * 500 / 256), (@ * 256 / 500) +# compute in2 (@ * 500 / 256), (@ * 256 / 500) +# compute in3 (@ * 500 / 256), (@ * 256 / 500) -# Analog output - - ignore aout_enable -# set aout_enable 1 - label aout "Output" -# set aout 0 chip "adm1021-*" "adm1023-*" "max1617-*" "max1617a-*" "thmc10-*" "lm84-*" "gl523sm-*" "mc1066-*" - label temp "Board Temp" - label remote_temp "CPU Temp" -# set temp_low 40 -# set temp_over 70 -# set remote_temp_low 40 -# set remote_temp_over 70 + label temp1 "Board Temp" + label temp2 "CPU Temp" +# set temp1_min 40 +# set temp1_max 70 +# set temp2_min 40 +# set temp2_max 70 chip "lm83-*" @@ -1942,15 +1267,15 @@ chip "lm83-*" # ignore temp4 # change high limits to fit your needs -# set temp1_high 55 -# set temp2_high 60 -# set temp3_high 65 -# set temp4_high 60 +# set temp1_max 55 +# set temp2_max 60 +# set temp3_max 65 +# set temp4_max 60 # change critical limit to fit your needs # only one limit for all four temperatures # should be higher than each of the high limits above -# set tcrit 85 +# set temp3_crit 85 chip "max1619-*" @@ -1963,27 +1288,25 @@ chip "max1619-*" # set temp2_max 100 # change critical limit and hysteresis to fit your needs -# set temp2_crit 50 -# set temp2_hyst 40 +# set temp2_crit 50 +# set temp2_crit_hyst 40 chip "lm90-*" "adm1032-*" "lm86-*" "max6657-*" "adt7461-*" "max6680-*" label temp1 "M/B Temp" label temp2 "CPU Temp" - label tcrit1 "M/B Crit" - label tcrit2 "CPU Crit" # change high and low limits to fit your needs -# set temp1_low 10 -# set temp1_high 55 -# set temp2_low 10 -# set temp2_high 66 +# set temp1_min 10 +# set temp1_max 55 +# set temp2_min 10 +# set temp2_max 66 # change critical limits to fit your needs # should be higher than the corresponding high limit above -# set tcrit1 75 -# set tcrit2 85 +# set temp1_crit 75 +# set temp2_crit 85 # change the hysteresis values (to critical limits) to fit your needs # note #1: hyst2 will be automatically set with the same delta @@ -1991,32 +1314,31 @@ chip "lm90-*" "adm1032-*" "lm86-*" "max6657-*" "adt7461-*" "max6680-*" # for both channels, cannot hold values greater than 31, so the delta # between critical temperatures and respective absolute hysteresis can # never exceed this value -# set hyst1 70 +# set temp1_crit_hyst 70 -chip "lm99-*" +chip "lm89-*" "lm99-*" label temp1 "G/C Temp" label temp2 "GPU Temp" - label tcrit1 "G/C Crit" - label tcrit2 "GPU Crit" -# note #1: only the LM99 needs this; for a LM89, comment the compute line -# out +# note #1: the LM99 needs the compute statement below if you're running +# a kernel <= 2.6.27; since kernel 2.6.28 the offset is handled in the +# lm90 driver directly instead # note #2: there is no way for us to differentiate between a LM89 and a -# LM99; you have to know what you have; LM99 are frequently found on -# graphics cards, most notably nVidia ones - compute temp2 @+16, @-16 +# LM99; you have to know what you have; the driver will assume a LM99, +# use the force_lm86 module parameter if you have a LM89 +# compute temp2 @+16, @-16 # change high and low limits to fit your needs -# set temp1_low 10 -# set temp1_high 90 -# set temp2_low 10 -# set temp2_high 100 +# set temp1_min 10 +# set temp1_max 90 +# set temp2_min 10 +# set temp2_max 100 # change critical limits to fit your needs # should be higher than the corresponding high limit above -# set tcrit1 100 -# set tcrit2 110 +# set temp1_crit 100 +# set temp2_crit 110 # change the hysteresis values (to critical limits) to fit your needs # note #1: hyst2 will be automatically set with the same delta @@ -2024,54 +1346,25 @@ chip "lm99-*" # for both channels, cannot hold values greater than 31, so the delta # between critical temperatures and respective absolute hysteresis can # never exceed this value -# set hyst1 105 +# set temp1_crit_hyst 105 chip "lm63-*" label temp1 "M/B Temp" label temp2 "CPU Temp" - label temp2_crit "CPU Crit" label fan1 "CPU Fan" # Change limits to fit your needs. Note that temp2_crit is read-only. -# set temp1_high 50 -# set temp2_low 10 -# set temp2_high 70 +# set temp1_max 50 +# set temp2_min 10 +# set temp2_max 70 # set temp2_crit_hyst 75 # set fan1_min 2000 chip "vt1211-*" -# 1 for temp, 0 for volt. -# Sensor Voltage Mode Temp Mode config bit -# -------- ------------ --------- -------------- -# Reading 1 temp1 -# Reading 3 temp2 -# UCH1/Reading2 in0 temp3 0x04 (4) -# UCH2 in1 temp4 0x08 (8) -# UCH3 in2 temp5 0x10 (16) -# UCH4 in3 temp6 0x20 (32) -# UCH5 in4 temp7 0x40 (64) -# 3.3V in5 - -# Set uch1-2 to temp mode, uch3-5 to voltage mode. This works only -# for the 2.4 driver. For the 2.6 driver use the uch_config module parameter. -# If the value doesn't match the hardware wiring, you'll get weird readings! -# set config 12 - -# The 2.6 driver will automatically ignore the inputs which are not -# configured, but the 2.4 driver will not so you'll need to add ignore -# statements depending on the config value above. -# ignore in0 -# ignore in1 -# ignore temp3 -# ignore temp4 - ignore temp5 - ignore temp6 - ignore temp7 - label in0 "+3.3V" label in1 "+2.5V" label in2 "VCore" @@ -2105,16 +1398,13 @@ chip "vt1211-*" compute in3 @ * (1 + 14 / 10), @ / (1 + 14 / 10) compute in4 @ * (1 + 47 / 10), @ / (1 + 47 / 10) -# Adjust this if your vid is wrong (for 2.4 only); see doc/vid -# set vrm 9.1 - # set in0_min 3.3 * 0.95 # set in0_max 3.3 * 1.05 # set in1_min 2.5 * 0.95 # set in1_max 2.5 * 1.05 # If your vid is wrong, hardcode the CPU voltage (e.g. 1.4) -# set in2_min vid * 0.97 -# set in2_max vid * 1.03 +# set in2_min cpu0_vid * 0.97 +# set in2_max cpu0_vid * 1.03 # set in3_min 5.0 * 0.95 # set in3_max 5.0 * 1.05 # set in4_min 12.0 * 0.90 @@ -2162,41 +1452,19 @@ chip "vt1211-*" compute temp7 1 / (1 / 298.15 - (` (2.2 / @ - 1)) / 3435) - 273.15, \ 2.2 / (1 + (^ (3435 / 298.15 - 3435 / (273.15 + @)))) -# set temp1_hyst 80 -# set temp1_over 85 -# set temp2_hyst 60 -# set temp2_over 65 -# set temp3_hyst 60 -# set temp3_over 65 -# set temp4_hyst 40 -# set temp4_over 45 +# set temp1_max_hyst 80 +# set temp1_max 85 +# set temp2_max_hyst 60 +# set temp2_max 65 +# set temp3_max_hyst 60 +# set temp3_max 65 +# set temp4_max_hyst 40 +# set temp4_max 45 # set fan1_min 3000 # set fan2_min 3000 chip "vt8231-*" -# -# 1 for temp, 0 for volt. -# Sensor Voltage Mode Temp Mode config bit -# -------- ------------ --------- -------------- -# Reading 1 temp1 -# UCH1 in0 temp2 0x04 (4) -# UCH2 in1 temp3 0x08 (8) -# UCH3 in2 temp4 0x10 (16) -# UCH4 in3 temp5 0x20 (32) -# UCH5 in4 temp6 0x40 (64) -# 3.3V in5 -# -# Hardware default is UCH1 in temp mode, UCH2-5 in voltage mode -# Note that the Linux 2.6 driver will not let you change the channel -# configuration. In theory, the BIOS should have done it properly. -# set config 4 - -# ignore in0 -# ignore temp3 -# ignore temp4 -# ignore temp5 -# ignore temp6 label in1 "+2.5V" label in2 "VCore" @@ -2244,7 +1512,6 @@ chip "vt8231-*" # Thermistor calculations # 3435 is the thermistor beta, 2.2 is the reference voltage. # '^' is the e**x operator; '`' is the ln(x) operator -# (valid in library version 1.4.0 / lm_sensors 2.7.1 or higher) # This assumes that the thermistor forms a resistor divider with a resistor # equal to its nominal value at 25 degrees C. @@ -2253,32 +1520,19 @@ chip "vt8231-*" compute temp3 1 / (1 / 298.15 - (` (2.2 / @ - 1)) / 3435) - 273.15, \ 2.2 / (1 + (^ (3435 / 298.15 - 3435 / (273.15 + @)))) -# set temp1_hyst 60 -# set temp1_over 65 -# set temp2_hyst 40 -# set temp2_over 45 +# set temp1_max_hyst 60 +# set temp1_max 65 +# set temp2_max_hyst 40 +# set temp2_max 45 # set fan1_min 3000 # set fan2_min 3000 -chip "bmc-*" -# -# You should not need compute lines here, the driver will -# do all the conversions. -# For label lines, copy from syslog/dmesg when the bmcsensors -# module is inserted. -# -# for example: -# label temp1 "Ambient Temp" - chip "smsc47m1-*" # SMSC LPC47M10x, LPC47M13x, LPC47M14x and LPC47B27x chips -# We don't set the fan mins by default anymore because they may not exist -# when using the Linux 2.6 driver (since we respect the original chip -# configuration). # set fan1_min 3000 # set fan2_min 3000 @@ -2293,8 +1547,8 @@ chip "smsc47m192-*" # set in0_max 2.5 * 1.05 label in1 "VCore" -# set in1_min vid * 0.95 -# set in1_max vid * 1.05 +# set in1_min cpu0_vid * 0.95 +# set in1_max cpu0_vid * 1.05 label in2 "+3.3V" # set in2_min 3.3 * 0.95 @@ -2323,7 +1577,7 @@ chip "smsc47m192-*" # Haven't yet heard from any board that has 1.8V connected, so # this might be more appropriate: # ignore in7 - + label temp1 "Chip Temp" # set temp1_min 0 # set temp1_max 60 @@ -2340,17 +1594,15 @@ chip "smsc47m192-*" # This example was tested vs. Asus P4S333 # chip "asb100-*" -# adjust this if your vid is wrong; see doc/vid - #set vrm 9.0 label in0 "VCore 1" - #set in0_min vid * 0.95 - #set in0_max vid * 1.05 + #set in0_min cpu0_vid * 0.95 + #set in0_max cpu0_vid * 1.05 label in1 "VCore 2" ignore in1 - #set in1_min vid * 0.95 - #set in1_max vid * 1.05 + #set in1_min cpu0_vid * 0.95 + #set in1_max cpu0_vid * 1.05 label in2 "+3.3V" #set in2_min 3.3 * 0.95 @@ -2379,25 +1631,25 @@ chip "asb100-*" #set in6_min -5 * 1.05 label temp1 "M/B Temp" - #set temp1_over 45 - #set temp1_hyst 40 + #set temp1_max 45 + #set temp1_max_hyst 40 label temp2 "CPU Temp (Intel)" #ignore temp2 - #set temp2_over 60 - #set temp2_hyst 50 + #set temp2_max 60 + #set temp2_max_hyst 50 # PWRTMP connector on P4S333, for external sensor label temp3 "Power Temp" #ignore temp3 - #set temp3_over 45 - #set temp3_hyst 40 + #set temp3_max 45 + #set temp3_max_hyst 40 # Used for Athlon diode, ignore for P4S333 label temp4 "CPU Temp (AMD)" - #set temp4_over 60 - #set temp4_hyst 50 + #set temp4_max 60 + #set temp4_max_hyst 50 #ignore temp4 label fan1 "CPU Fan" @@ -2416,10 +1668,10 @@ chip "asb100-*" # Sample configuration for the Intel S845WD1-E # courtesy of Marcus Schopen # -chip "lm85c-*" "adm1027-*" "adt7463-*" "lm85-*" "lm85b-*" +chip "lm85-*" "lm85b-*" "lm85c-*" "adm1027-*" "adt7463-*" "adt7468-*" "emc6d100-*" "emc6d102-*" # Voltage inputs -# Depending on the hardware setup, the ADT7463 may not have in4. +# Depending on the hardware setup, the ADT7463 and ADT7468 may not have in4. label in0 "V1.5" # AGP on Intel S845WD1-E label in1 "VCore" label in2 "V3.3" @@ -2432,15 +1684,7 @@ chip "lm85c-*" "adm1027-*" "adt7463-*" "lm85-*" "lm85b-*" label temp3 "Remote Temp" # Fan inputs - label fan1 "CPU_Fan" -# label fan2 "Fan2" -# label fan3 "Fan3" -# label fan4 "Fan4" - -# PWM Outputs - label pwm1 "CPU_PWM" - label pwm2 "Fan2_PWM" - label pwm3 "Fan3_PWM" + label fan1 "CPU Fan" # Voltage scaling is done on-chip. No 'compute' directive # should be necessary. If in0 has external scaling set @@ -2450,24 +1694,18 @@ chip "lm85c-*" "adm1027-*" "adt7463-*" "lm85-*" "lm85b-*" # Adjust fans speeds for actual pulses per rev # compute fan1 @ * 2, @ / 2 # 1 pulse per rev -# set fan1_ppr 1 # ADM1027 or ADT7463 # compute fan2 @ / 2, @ * 2 # 4 pulse per rev -# set fan2_ppr 4 # ADM1027 or ADT7463 # Ignore fans you (or your motherboard) don't have # ignore fan2 # ignore fan3 # ignore fan4 -# Set VRM version -# adjust this if your vid is wrong; see doc/vid -# set vrm 9.1 # Pentium 4 - # Set voltage limits # set in0_min 1.5 * 0.95 # set in0_max 1.5 * 1.05 -# set in1_min vid * 0.95 -# set in1_max vid * 1.05 +# set in1_min cpu0_vid * 0.95 +# set in1_max cpu0_vid * 1.05 # set in2_min 3.3 * 0.95 # set in2_max 3.3 * 1.05 # set in3_min 5.0 * 0.95 @@ -2486,13 +1724,10 @@ chip "lm85c-*" "adm1027-*" "adt7463-*" "lm85-*" "lm85b-*" # set temp3_min 10 # set temp3_max 35 -chip "pc87366-*" +chip "pc87365-*" "pc87366-*" # Voltage inputs -# Set VRM version (default 9.0) -# set vrm 9.0 - label in7 "Vsb" label in8 "Vdd" label in9 "Vbat" @@ -2516,11 +1751,8 @@ chip "pc87366-*" # Temperature inputs label temp1 "CPU0 Temp" - label temp1_crit "CPU0 Crit" label temp2 "CPU1 Temp" - label temp2_crit "CPU1 Crit" label temp3 "S-IO Temp" - label temp3_crit "S-IO Crit" # set temp1_min 0 # set temp1_max 70 @@ -2548,12 +1780,12 @@ chip "pc87366-*" # We also assume that you have a working in10 (which is forcibly enabled by # default). If not, use 3.3 instead, but you lose accuracy. - compute temp4 3435 / (` (1 / (1 - @ / in10) - 1) + 3435 / 298.15) - 273.15, \ - in10 * (1 - 1 / (1 + (^ (3435 / (273.15 + @) - 3435 / 298.15)))) - compute temp5 3435 / (` (1 / (1 - @ / in10) - 1) + 3435 / 298.15) - 273.15, \ - in10 * (1 - 1 / (1 + (^ (3435 / (273.15 + @) - 3435 / 298.15)))) - compute temp6 3435 / (` (1 / (1 - @ / in10) - 1) + 3435 / 298.15) - 273.15, \ - in10 * (1 - 1 / (1 + (^ (3435 / (273.15 + @) - 3435 / 298.15)))) + compute temp4 3435 / (` (1 / (1 - @ / in10_input) - 1) + 3435 / 298.15) - 273.15, \ + in10_input * (1 - 1 / (1 + (^ (3435 / (273.15 + @) - 3435 / 298.15)))) + compute temp5 3435 / (` (1 / (1 - @ / in10_input) - 1) + 3435 / 298.15) - 273.15, \ + in10_input * (1 - 1 / (1 + (^ (3435 / (273.15 + @) - 3435 / 298.15)))) + compute temp6 3435 / (` (1 / (1 - @ / in10_input) - 1) + 3435 / 298.15) - 273.15, \ + in10_input * (1 - 1 / (1 + (^ (3435 / (273.15 + @) - 3435 / 298.15)))) # set temp4_min 0 # set temp4_max 70 @@ -2580,8 +1812,6 @@ chip "adm1030-*" label temp1 "SYS Temp" label temp2 "CPU Temp" - label temp1_crit "SYS Crit" - label temp2_crit "CPU Crit" # set temp1_max 60 # set temp2_max 70 @@ -2598,9 +1828,6 @@ chip "adm1031-*" label temp1 "SYS Temp" label temp2 "CPU Temp" label temp3 "AUX Temp" - label temp1_crit "SYS Crit" - label temp2_crit "CPU Crit" - label temp3_crit "AUX Crit" # set temp1_max 60 # set temp2_max 70 @@ -2622,18 +1849,16 @@ chip "w83l785ts-*" chip "lm92-*" - label temp "CPU Temp" + label temp1 "CPU Temp" # Change limits as you see fit -# set temp_low 14 -# set temp_high 60 -# set temp_crit 72 -# Hysteresis is computed from critical limit for Linux 2.6, -# and from high limit for Linux 2.4. That might change in the future. -# Whatever, the same relative hysteresis is used for all of low, high +# set temp1_min 14 +# set temp1_max 60 +# set temp1_crit 72 +# Hysteresis is computed from critical limit +# The same relative hysteresis is used for all of low, high # and critical limits. -# set temp_hyst 70 # Linux 2.6 -# set temp_hyst 58 # Linux 2.4 +# set temp1_crit_hyst 70 # Winbond W83627EHF configuration originally contributed by Leon Moonen @@ -2641,15 +1866,14 @@ chip "lm92-*" chip "w83627ehf-*" "w83627dhg-*" label in0 "VCore" + label in1 "+12V" label in2 "AVCC" label in3 "3VCC" + label in6 "+5V" label in7 "VSB" label in8 "VBAT" -# The W83627DHG has no in9, uncomment the following line -# ignore in9 - -# +12V is in1 and +5V is in6 as recommended by datasheet +# +12V is in1 and +5V is in6 as recommended by datasheet compute in1 @*(1+(56/10)), @/(1+(56/10)) compute in6 @*(1+(22/10)), @/(1+(22/10)) # set in1_min 12.0*0.9 @@ -2680,19 +1904,19 @@ chip "w83627ehf-*" "w83627dhg-*" label temp1 "Sys Temp" label temp2 "CPU Temp" label temp3 "AUX Temp" - + # ignore temp3 -# set temp1_over 45 -# set temp1_hyst 40 -# set temp2_over 45 -# set temp2_hyst 40 +# set temp1_max 45 +# set temp1_max_hyst 40 +# set temp2_max 45 +# set temp2_max_hyst 40 # Fintek F71805F/FG configuration # This is the recommended wiring and resistor values from the F71805F/FG # datasheet. Your motherboard manufacturer may or may not have followed # these. -chip "f71805f-*" +chip "f71805f-*" "f71872f-*" # Voltages label in0 "+3.3V" label in1 "Vtt1.2V" @@ -2747,12 +1971,12 @@ chip "f71805f-*" label temp2 "Sys Temp" label temp3 "Aux Temp" - #set temp1_max 60 - #set temp1_hyst 58 - #set temp2_max 50 - #set temp2_hyst 48 - #set temp3_max 50 - #set temp3_hyst 48 + #set temp1_max 60 + #set temp1_max_hyst 58 + #set temp2_max 50 + #set temp2_max_hyst 48 + #set temp3_max 50 + #set temp3_max_hyst 48 # Abit Uguru sensor part configuration. @@ -2841,19 +2065,7 @@ chip "dme1737-*" label temp3 "CPU Temp" # Fan inputs - label fan1 "CPU_Fan" - label fan2 "Fan2" - label fan3 "Fan3" - label fan4 "Fan4" - label fan5 "Fan5" - label fan6 "Fan6" - -# PWM Outputs - label pwm1 "CPU_PWM" - label pwm2 "Fan2_PWM" - label pwm3 "Fan3_PWM" - label pwm5 "Fan5_PWM" - label pwm6 "Fan6_PWM" + label fan1 "CPU Fan" # Set voltage limits # set in0_min 5.0 * 0.95 @@ -2925,7 +2137,7 @@ chip "f71882fg-*" label in8 "Battery" # never change the in0, in7 and in8 compute, these are hardwired in the chip! - compute in0 (@ * 2), (@ / 2) + compute in0 (@ * 2), (@ / 2) compute in2 (@ * 2), (@ / 2) compute in3 (@ * 2), (@ / 2) compute in4 (@ * 5.25), (@ / 5.25) @@ -2937,11 +2149,23 @@ chip "f71882fg-*" chip "adm1022-*" "thmc50-*" - label temp "M/B Temp" + label temp1 "M/B Temp" # Single CPU setup - label remote_temp "CPU Temp" + label temp2 "CPU Temp" # Dual CPU setup (ADM1022 only) - #label remote_temp "CPU0 Temp" - #label remote_temp2 "CPU1 Temp" + #label temp2 "CPU0 Temp" + #label temp3 "CPU1 Temp" +# Asus/Fintek F8000 +chip "f8000-*" + + # All 3 voltages are internal, but scaling is not done by the driver + # so we do it here + compute in0 @*2, @/2 + compute in1 @*2, @/2 + compute in2 @*2, @/2 + + label in0 "+3.3V" + label in1 "3VSB" + label in2 "Vbat" diff --git a/kernel/busses/Module.mk b/kernel/busses/Module.mk deleted file mode 100644 index 39e8d139..00000000 --- a/kernel/busses/Module.mk +++ /dev/null @@ -1,129 +0,0 @@ -# Module.mk - Makefile for a Linux module for reading sensor data. -# Copyright (c) 1998, 1999 Frodo Looijaard -# -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - -# Note that MODULE_DIR (the directory in which this file resides) is a -# 'simply expanded variable'. That means that its value is substituted -# verbatim in the rules, until it is redefined. -MODULE_DIR := kernel/busses -KERNELBUSSESDIR := $(MODULE_DIR) - -# Regrettably, even 'simply expanded variables' will not put their currently -# defined value verbatim into the command-list of rules... -# These targets are NOT included in 'mkpatch' ... -KERNELBUSSESTARGETS := -ifeq ($(shell if grep -q '^CONFIG_IPMI_HANDLER=' $(LINUX)/.config; then echo 1; fi),1) -#doesn't work yet -#KERNELBUSSESTARGETS += $(MODULE_DIR)/i2c-ipmb.o -KERNELBUSSESTARGETS += $(MODULE_DIR)/i2c-ipmi.o -endif - -# These targets ARE included in 'mkpatch' ... -ifneq ($(shell if grep -q '^CONFIG_I2C_ALI1535=y' $(LINUX)/.config; then echo 1; fi),1) -KERNELBUSSESTARGETS += $(MODULE_DIR)/i2c-ali1535.o -endif -ifneq ($(shell if grep -q '^CONFIG_I2C_ALI15X3=y' $(LINUX)/.config; then echo 1; fi),1) -KERNELBUSSESTARGETS += $(MODULE_DIR)/i2c-ali15x3.o -endif -ifneq ($(shell if grep -q '^CONFIG_I2C_ALI1563=y' $(LINUX)/.config; then echo 1; fi),1) -KERNELBUSSESTARGETS += $(MODULE_DIR)/i2c-ali1563.o -endif -ifneq ($(shell if grep -q '^CONFIG_I2C_AMD756=y' $(LINUX)/.config; then echo 1; fi),1) -KERNELBUSSESTARGETS += $(MODULE_DIR)/i2c-amd756.o -endif -ifneq ($(shell if grep -q '^CONFIG_I2C_AMD756_S4882=y' $(LINUX)/.config; then echo 1; fi),1) -KERNELBUSSESTARGETS += $(MODULE_DIR)/i2c-amd756-s4882.o -endif -ifneq ($(shell if grep -q '^CONFIG_I2C_AMD8111=y' $(LINUX)/.config; then echo 1; fi),1) -KERNELBUSSESTARGETS += $(MODULE_DIR)/i2c-amd8111.o -endif -ifneq ($(shell if grep -q '^CONFIG_I2C_HYDRA=y' $(LINUX)/.config; then echo 1; fi),1) -KERNELBUSSESTARGETS += $(MODULE_DIR)/i2c-hydra.o -endif -ifneq ($(shell if grep -q '^CONFIG_I2C_I801=y' $(LINUX)/.config; then echo 1; fi),1) -KERNELBUSSESTARGETS += $(MODULE_DIR)/i2c-i801.o -endif -ifneq ($(shell if grep -q '^CONFIG_I2C_I810=y' $(LINUX)/.config; then echo 1; fi),1) -KERNELBUSSESTARGETS += $(MODULE_DIR)/i2c-i810.o -endif -ifneq ($(shell if grep -q '^CONFIG_I2C_ISA=y' $(LINUX)/.config; then echo 1; fi),1) -KERNELBUSSESTARGETS += $(MODULE_DIR)/i2c-isa.o -endif -ifneq ($(shell if grep -q '^CONFIG_I2C_NFORCE2=y' $(LINUX)/.config; then echo 1; fi),1) -KERNELBUSSESTARGETS += $(MODULE_DIR)/i2c-nforce2.o -endif -ifneq ($(shell if grep -q '^CONFIG_I2C_SIS5595=y' $(LINUX)/.config; then echo 1; fi),1) -KERNELBUSSESTARGETS += $(MODULE_DIR)/i2c-sis5595.o -endif -ifneq ($(shell if grep -q '^CONFIG_I2C_SIS630=y' $(LINUX)/.config; then echo 1; fi),1) -KERNELBUSSESTARGETS += $(MODULE_DIR)/i2c-sis630.o -endif -ifneq ($(shell if grep -q '^CONFIG_I2C_SIS645=y' $(LINUX)/.config; then echo 1; fi),1) -KERNELBUSSESTARGETS += $(MODULE_DIR)/i2c-sis645.o -endif -# don't compile dmi_scan unless x86 because it needs isa access -ifneq ($(shell if grep -q '^CONFIG_I2C_PIIX4=y' $(LINUX)/.config; then echo 1; fi),1) -KERNELBUSSESTARGETS += $(MODULE_DIR)/i2c-piix4.o -ifeq ($(shell if grep -q '^CONFIG_X86=y' $(LINUX)/.config; then echo 1; fi),1) -KERNELBUSSESTARGETS += $(MODULE_DIR)/dmi_scan.o -endif -endif -ifneq ($(shell if grep -q '^CONFIG_I2C_SAVAGE4=y' $(LINUX)/.config; then echo 1; fi),1) -KERNELBUSSESTARGETS += $(MODULE_DIR)/i2c-savage4.o -endif -# don't compile unless alpha because of kernel include-file dependencies -ifeq ($(MACHINE),alpha) -ifneq ($(shell if grep -q '^CONFIG_I2C_TSUNAMI=y' $(LINUX)/.config; then echo 1; fi),1) -KERNELBUSSESTARGETS += $(MODULE_DIR)/i2c-tsunami.o -endif -endif -ifneq ($(shell if grep -q '^CONFIG_I2C_VIA=y' $(LINUX)/.config; then echo 1; fi),1) -KERNELBUSSESTARGETS += $(MODULE_DIR)/i2c-via.o -endif -ifneq ($(shell if grep -q '^CONFIG_I2C_VIAPRO=y' $(LINUX)/.config; then echo 1; fi),1) -KERNELBUSSESTARGETS += $(MODULE_DIR)/i2c-viapro.o -endif -ifneq ($(shell if grep -q '^CONFIG_I2C_VOODOO3=y' $(LINUX)/.config; then echo 1; fi),1) -KERNELBUSSESTARGETS += $(MODULE_DIR)/i2c-voodoo3.o -endif - -# Include all dependency files -INCLUDEFILES += $(KERNELBUSSESTARGETS:.o=.d) - -all-kernel-busses: $(KERNELBUSSESTARGETS) -all :: all-kernel-busses - -# -# If $MODPREF/kernel exists, we presume the new (2.4.0) /lib/modules/x.y.z directory -# layout, so we install in kernel/drivers/i2c/busses and remove old versions in misc/ -# and kernel/drivers/i2c/ . Otherwise we install in misc/ as before. -# -install-kernel-busses: all-kernel-busses - if [ -n "$(KERNELBUSSESTARGETS)" ] ; then \ - $(MKDIR) $(DESTDIR)$(MODPREF)/kernel/drivers/i2c/busses ; \ - $(INSTALL) -m 644 $(KERNELBUSSESTARGETS) $(DESTDIR)$(MODPREF)/kernel/drivers/i2c/busses ; \ - for i in $(KERNELBUSSESTARGETS) ; do \ - $(RM) $(DESTDIR)$(MODPREF)/misc/`basename $$i` $(DESTDIR)$(MODPREF)/kernel/drivers/i2c/`basename $$i` \ - $(DESTDIR)$(MODPREF)/kernel/drivers/i2c/`basename $$i`.gz $(DESTDIR)$(MODPREF)/kernel/drivers/i2c/busses/`basename $$i`.gz ; \ - done ; \ - $(RMDIR) $(DESTDIR)$(MODPREF)/misc 2> /dev/null || true ; \ - fi - -install :: install-kernel-busses - -clean-kernel-busses: - $(RM) $(KERNELBUSSESDIR)/*.o $(KERNELBUSSESDIR)/*.d -clean :: clean-kernel-busses diff --git a/kernel/busses/dmi_scan.c b/kernel/busses/dmi_scan.c deleted file mode 100644 index 7d2748c7..00000000 --- a/kernel/busses/dmi_scan.c +++ /dev/null @@ -1,249 +0,0 @@ -/* - Taken from arch/i386/kernel/dmi_scan.c. - Changes dmi_ident to be non-static so we can access. -*/ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "version.h" - -int is_unsafe_smbus; -EXPORT_SYMBOL(is_unsafe_smbus); - -struct dmi_header -{ - u8 type; - u8 length; - u16 handle; -}; - -enum -{ - DMI_BIOS_VENDOR, - DMI_BIOS_VERSION, - DMI_BIOS_DATE, - DMI_SYS_VENDOR, - DMI_PRODUCT_NAME, - DMI_PRODUCT_VERSION, - DMI_BOARD_VENDOR, - DMI_BOARD_NAME, - DMI_BOARD_VERSION, - DMI_STRING_MAX -}; - -#define dmi_printk(x) -//#define dmi_printk(x) printk x - -static char * __init dmi_string(struct dmi_header *dm, u8 s) -{ - u8 *bp=(u8 *)dm; - bp+=dm->length; - if(!s) - return ""; - s--; - while(s>0 && *bp) - { - bp+=strlen(bp); - bp++; - s--; - } - return bp; -} - -/* - * We have to be cautious here. We have seen BIOSes with DMI pointers - * pointing to completely the wrong place for example - */ - -static int __init dmi_table(u32 base, int len, int num, void (*decode)(struct dmi_header *)) -{ - u8 *buf; - struct dmi_header *dm; - u8 *data; - int i=0; - - buf = ioremap(base, len); - if(buf==NULL) - return -1; - - data = buf; - - /* - * Stop when we see all the items the table claimed to have - * OR we run off the end of the table (also happens) - */ - - while(ilength; - while(data-buf>4, buf[14]&0x0F)); - else - dmi_printk((KERN_INFO "DMI present.\n")); - dmi_printk((KERN_INFO "%d structures occupying %d bytes.\n", - num, len)); - dmi_printk((KERN_INFO "DMI table at 0x%08X.\n", - base)); - if(dmi_table(base,len, num, decode)==0) - return 0; - } - fp+=16; - } - return -1; -} - - -char *dmi_ident[DMI_STRING_MAX]; - -/* - * Save a DMI string - */ - -static void __init dmi_save_ident(struct dmi_header *dm, int slot, int string) -{ - char *d = (char*)dm; - char *p = dmi_string(dm, d[string]); - if(p==NULL || *p == 0) - return; - if (dmi_ident[slot]) - return; - dmi_ident[slot] = kmalloc(strlen(p)+1, GFP_KERNEL); - if(dmi_ident[slot]) - strcpy(dmi_ident[slot], p); - else - printk(KERN_ERR "dmi_save_ident: out of memory.\n"); -} - -/* - * Process a DMI table entry. Right now all we care about are the BIOS - * and machine entries. For 2.5 we should pull the smbus controller info - * out of here. - */ - -static void __init dmi_decode(struct dmi_header *dm) -{ - switch(dm->type) - { - case 0: - dmi_printk(("BIOS Vendor: %s\n", - dmi_string(dm, data[4]))); - dmi_save_ident(dm, DMI_BIOS_VENDOR, 4); - dmi_printk(("BIOS Version: %s\n", - dmi_string(dm, data[5]))); - dmi_save_ident(dm, DMI_BIOS_VERSION, 5); - dmi_printk(("BIOS Release: %s\n", - dmi_string(dm, data[8]))); - dmi_save_ident(dm, DMI_BIOS_DATE, 8); - break; - case 1: - dmi_printk(("System Vendor: %s\n", - dmi_string(dm, data[4]))); - dmi_save_ident(dm, DMI_SYS_VENDOR, 4); - dmi_printk(("Product Name: %s\n", - dmi_string(dm, data[5]))); - dmi_save_ident(dm, DMI_PRODUCT_NAME, 5); - dmi_printk(("Version: %s\n", - dmi_string(dm, data[6]))); - dmi_save_ident(dm, DMI_PRODUCT_VERSION, 6); - dmi_printk(("Serial Number: %s\n", - dmi_string(dm, data[7]))); - break; - case 2: - dmi_printk(("Board Vendor: %s\n", - dmi_string(dm, data[4]))); - dmi_save_ident(dm, DMI_BOARD_VENDOR, 4); - dmi_printk(("Board Name: %s\n", - dmi_string(dm, data[5]))); - dmi_save_ident(dm, DMI_BOARD_NAME, 5); - dmi_printk(("Board Version: %s\n", - dmi_string(dm, data[6]))); - dmi_save_ident(dm, DMI_BOARD_VERSION, 6); - break; - } -} - -int __init dmi_scan_mach(void) -{ - int err; - printk("dmi_scan.o version %s (%s)\n", LM_VERSION, LM_DATE); - err = dmi_iterate(dmi_decode); - if(err) - printk("dmi_scan.o: SM BIOS not found\n"); - else - printk("dmi_scan.o: SM BIOS found\n"); - - if(dmi_ident[DMI_SYS_VENDOR] != NULL - && strncmp(dmi_ident[DMI_SYS_VENDOR], "IBM", 3) == 0) - is_unsafe_smbus = 1; - return 0; -} - -MODULE_DESCRIPTION("SM BIOS DMI Scanner"); -MODULE_LICENSE("GPL"); - -module_init(dmi_scan_mach); diff --git a/kernel/busses/i2c-ali1535.c b/kernel/busses/i2c-ali1535.c deleted file mode 100644 index ca3d15b3..00000000 --- a/kernel/busses/i2c-ali1535.c +++ /dev/null @@ -1,529 +0,0 @@ -/* - i2c-ali1535.c - Part of lm_sensors, Linux kernel modules for hardware - monitoring - Copyright (c) 2000 Frodo Looijaard , - Philip Edelbrock , - Mark D. Studebaker , - Dan Eaton and - Stephen Rousset - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -/* - This is the driver for the SMB Host controller on - Acer Labs Inc. (ALI) M1535 South Bridge. - - The M1535 is a South bridge for portable systems. - It is very similar to the M15x3 South bridges also produced - by Acer Labs Inc. Some of the registers within the part - have moved and some have been redefined slightly. Additionally, - the sequencing of the SMBus transactions has been modified - to be more consistent with the sequencing recommended by - the manufacturer and observed through testing. These - changes are reflected in this driver and can be identified - by comparing this driver to the i2c-ali15x3 driver. - For an overview of these chips see http://www.acerlabs.com - - The SMB controller is part of the 7101 device, which is an - ACPI-compliant Power Management Unit (PMU). - - The whole 7101 device has to be enabled for the SMB to work. - You can't just enable the SMB alone. - The SMB and the ACPI have separate I/O spaces. - We make sure that the SMB is enabled. We leave the ACPI alone. - - This driver controls the SMB Host only. - - This driver does not use interrupts. -*/ - - -/* Note: we assume there can only be one ALI1535, with one SMBus interface */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "version.h" -#include "sensors_compat.h" - - -/* ALI1535 SMBus address offsets */ -#define SMBHSTSTS (0 + ali1535_smba) -#define SMBHSTTYP (1 + ali1535_smba) -#define SMBHSTPORT (2 + ali1535_smba) -#define SMBHSTCMD (7 + ali1535_smba) -#define SMBHSTADD (3 + ali1535_smba) -#define SMBHSTDAT0 (4 + ali1535_smba) -#define SMBHSTDAT1 (5 + ali1535_smba) -#define SMBBLKDAT (6 + ali1535_smba) - -/* PCI Address Constants */ -#define SMBCOM 0x004 -#define SMBREV 0x008 -#define SMBCFG 0x0D1 -#define SMBBA 0x0E2 -#define SMBHSTCFG 0x0F0 -#define SMBCLK 0x0F2 - -/* Other settings */ -#define MAX_TIMEOUT 500 /* times 1/100 sec */ -#define ALI1535_SMB_IOSIZE 32 - -/* -*/ -#define ALI1535_SMB_DEFAULTBASE 0x8040 - -/* ALI1535 address lock bits */ -#define ALI1535_LOCK 0x06 < dwe > - -/* ALI1535 command constants */ -#define ALI1535_QUICK 0x00 -#define ALI1535_BYTE 0x10 -#define ALI1535_BYTE_DATA 0x20 -#define ALI1535_WORD_DATA 0x30 -#define ALI1535_BLOCK_DATA 0x40 -#define ALI1535_I2C_READ 0x60 - -#define ALI1535_DEV10B_EN 0x80 /* Enable 10-bit addressing in */ - /* I2C read */ -#define ALI1535_T_OUT 0x08 /* Time-out Command (write) */ -#define ALI1535_A_HIGH_BIT9 0x08 /* Bit 9 of 10-bit address in */ - /* Alert-Response-Address */ - /* (read) */ -#define ALI1535_KILL 0x04 /* Kill Command (write) */ -#define ALI1535_A_HIGH_BIT8 0x04 /* Bit 8 of 10-bit address in */ - /* Alert-Response-Address */ - /* (read) */ - -#define ALI1535_D_HI_MASK 0x03 /* Mask for isolating bits 9-8 */ - /* of 10-bit address in I2C */ - /* Read Command */ - -/* ALI1535 status register bits */ -#define ALI1535_STS_IDLE 0x04 -#define ALI1535_STS_BUSY 0x08 /* host busy */ -#define ALI1535_STS_DONE 0x10 /* transaction complete */ -#define ALI1535_STS_DEV 0x20 /* device error */ -#define ALI1535_STS_BUSERR 0x40 /* bus error */ -#define ALI1535_STS_FAIL 0x80 /* failed bus transaction */ -#define ALI1535_STS_ERR 0xE0 /* all the bad error bits */ - -#define ALI1535_BLOCK_CLR 0x04 /* reset block data index */ - -/* ALI1535 device address register bits */ -#define ALI1535_RD_ADDR 0x01 /* Read/Write Bit in Device */ - /* Address field */ - /* -> Write = 0 */ - /* -> Read = 1 */ -#define ALI1535_SMBIO_EN 0x04 /* SMB I/O Space enable */ - - -static struct pci_driver ali1535_driver; -static unsigned short ali1535_smba = 0; - - -/* Detect whether a ALI1535 can be found, and initialize it, where necessary. - Note the differences between kernels with the old PCI BIOS interface and - newer kernels with the real PCI interface. In compat.h some things are - defined to make the transition easier. */ -int ali1535_setup(struct pci_dev *ALI1535_dev) -{ - int error_return = 0; - unsigned char temp; - -/* Check the following things: - - SMB I/O address is initialized - - Device is enabled - - We can use the addresses -*/ - -/* Determine the address of the SMBus area */ - pci_read_config_word(ALI1535_dev, SMBBA, &ali1535_smba); - ali1535_smba &= (0xffff & ~(ALI1535_SMB_IOSIZE - 1)); - if (ali1535_smba == 0) { - printk - ("i2c-ali1535.o: ALI1535_smb region uninitialized - upgrade BIOS?\n"); - error_return = -ENODEV; - } - - if (error_return == -ENODEV) - goto END; - - if (check_region(ali1535_smba, ALI1535_SMB_IOSIZE)) { - printk - ("i2c-ali1535.o: ALI1535_smb region 0x%x already in use!\n", - ali1535_smba); - error_return = -ENODEV; - } - - if (error_return == -ENODEV) - goto END; - - /* check if whole device is enabled */ - pci_read_config_byte(ALI1535_dev, SMBCFG, &temp); - if ((temp & ALI1535_SMBIO_EN) == 0) { - printk - ("i2c-ali1535.o: SMB device not enabled - upgrade BIOS?\n"); - error_return = -ENODEV; - goto END; - } - -/* Is SMB Host controller enabled? */ - pci_read_config_byte(ALI1535_dev, SMBHSTCFG, &temp); - if ((temp & 1) == 0) { - printk - ("i2c-ali1535.o: SMBus controller not enabled - upgrade BIOS?\n"); - error_return = -ENODEV; - goto END; - } - -/* set SMB clock to 74KHz as recommended in data sheet */ - pci_write_config_byte(ALI1535_dev, SMBCLK, 0x20); - - /* Everything is happy, let's grab the memory and set things up. */ - request_region(ali1535_smba, ALI1535_SMB_IOSIZE, ali1535_driver.name); - -#ifdef DEBUG -/* - The interrupt routing for SMB is set up in register 0x77 in the - 1533 ISA Bridge device, NOT in the 7101 device. - Don't bother with finding the 1533 device and reading the register. - if ((....... & 0x0F) == 1) - printk("i2c-ali1535.o: ALI1535 using Interrupt 9 for SMBus.\n"); -*/ - pci_read_config_byte(ALI1535_dev, SMBREV, &temp); - printk("i2c-ali1535.o: SMBREV = 0x%X\n", temp); - printk("i2c-ali1535.o: ALI1535_smba = 0x%X\n", ali1535_smba); -#endif /* DEBUG */ - - END: - return error_return; -} - - -#define MAX_TIMEOUT_HEROS 100 -#define MAX_TIMEOUT_BLOCK_HEROS 500 -#define MAX_TRY_HEROS 3 - -/* believe it or not this is the delay technique recommended by ALI */ -static void ali1535_delay_loop(void) -{ - int i; - - for(i=0;i<30;i++) - outb_p(0,0xEB); -} - -static int ali1535_wait_for_status(int count,int status) -{ - int i; - int dat; - - for (i = 0; i < count; i++) { - ali1535_delay_loop(); - dat = inb_p(SMBHSTSTS); - if (dat == status) - break; - } - - return i == count ? 1 : 0; -} - -/* Return -1 on error. */ -s32 ali1535_access(struct i2c_adapter * adap, u16 addr, - unsigned short flags, char read_write, u8 command, - int size, union i2c_smbus_data * data) -{ - int i, len; - s32 result = 0; - int timeout = 0; - int oldsize = size; - -repeat: - if(timeout++ > MAX_TRY_HEROS) { - result = -1; - goto EXIT; - } - - /* clear status */ - outb_p(0xFF, SMBHSTSTS); - - if (ali1535_wait_for_status(MAX_TIMEOUT_HEROS,ALI1535_STS_IDLE)) - goto repeat; - - outb_p(ALI1535_KILL,SMBHSTTYP); - - if (ali1535_wait_for_status(MAX_TIMEOUT_HEROS,ALI1535_STS_FAIL)) - goto repeat; - - /* clear status */ - outb_p(0xFF, SMBHSTSTS); - - if (ali1535_wait_for_status(MAX_TIMEOUT_HEROS,ALI1535_STS_IDLE)) - goto repeat; - - switch (size) { - case I2C_SMBUS_QUICK: - outb_p(((addr & 0x7f) << 1) | (read_write & 0x01), SMBHSTADD); - ali1535_delay_loop(); - size = ALI1535_QUICK; - outb_p(size, SMBHSTTYP); /* output command */ - ali1535_delay_loop(); - break; - case I2C_SMBUS_BYTE: - outb_p(((addr & 0x7f) << 1) | (read_write & 0x01), SMBHSTADD); - ali1535_delay_loop(); - size = ALI1535_BYTE; - outb_p(size, SMBHSTTYP); /* output command */ - ali1535_delay_loop(); - if (read_write == I2C_SMBUS_WRITE) { - outb_p(command, SMBHSTCMD); - ali1535_delay_loop(); - } - break; - case I2C_SMBUS_BYTE_DATA: - outb_p(((addr & 0x7f) << 1) | (read_write & 0x01), SMBHSTADD); - ali1535_delay_loop(); - size = ALI1535_BYTE_DATA; - outb_p(size, SMBHSTTYP); /* output command */ - ali1535_delay_loop(); - outb_p(command, SMBHSTCMD); - ali1535_delay_loop(); - if (read_write == I2C_SMBUS_WRITE) { - outb_p(data->byte, SMBHSTDAT0); - ali1535_delay_loop(); - } - break; - case I2C_SMBUS_WORD_DATA: - outb_p(((addr & 0x7f) << 1) | (read_write & 0x01), SMBHSTADD); - ali1535_delay_loop(); - size = ALI1535_WORD_DATA; - outb_p(size, SMBHSTTYP); /* output command */ - outb_p(command, SMBHSTCMD); - ali1535_delay_loop(); - if (read_write == I2C_SMBUS_WRITE) { - outb_p(data->word & 0xff, SMBHSTDAT0); - ali1535_delay_loop(); - outb_p((data->word & 0xff00) >> 8, SMBHSTDAT1); - ali1535_delay_loop(); - } - break; - case I2C_SMBUS_BLOCK_DATA: - outb_p(((addr & 0x7f) << 1) | (read_write & 0x01), SMBHSTADD); - ali1535_delay_loop(); - size = ALI1535_BLOCK_DATA; - outb_p(size, SMBHSTTYP); /* output command */ - outb_p(command, SMBHSTCMD); - ali1535_delay_loop(); - if (read_write == I2C_SMBUS_WRITE) { - len = data->block[0]; - if (len < 0) { - len = 0; - data->block[0] = len; - } - if (len > 32) { - len = 32; - data->block[0] = len; - } - outb_p(len, SMBHSTDAT0); - ali1535_delay_loop(); - { - int val; - - val = inb_p(SMBHSTTYP) | ALI1535_BLOCK_CLR; - ali1535_delay_loop(); - outb_p(val, SMBHSTTYP); /* Reset SMBBLKDAT */ - ali1535_delay_loop(); - } - for (i = 1; i <= len; i++) { - outb_p(data->block[i], SMBBLKDAT); - ali1535_delay_loop(); - } - } - break; - default: - printk - (KERN_WARNING "i2c-ali1535.o: Unsupported transaction %d\n", size); - result = -1; - goto EXIT; - } - - /* start the transaction */ - outb_p(0xFF, SMBHSTPORT); - ali1535_delay_loop(); - - if (ali1535_wait_for_status(size == ALI1535_BLOCK_DATA ? - MAX_TIMEOUT_BLOCK_HEROS : - MAX_TIMEOUT_HEROS , - ALI1535_STS_IDLE | ALI1535_STS_DONE)) { - size = oldsize; - goto repeat; - } - - /* clear status */ - outb_p(0xFF, SMBHSTSTS); - ali1535_delay_loop(); - - if(inb_p(SMBHSTSTS) != ALI1535_STS_IDLE) { - size = oldsize; - goto repeat; - } - - if ((read_write == I2C_SMBUS_WRITE) || (size == ALI1535_QUICK)) { - result = 0; - goto EXIT; - } - - switch (size) { - case ALI1535_BYTE: /* Result put in SMBHSTDAT0 */ - data->byte = inb_p(SMBHSTDAT0); - ali1535_delay_loop(); - break; - case ALI1535_BYTE_DATA: - data->byte = inb_p(SMBHSTDAT0); - ali1535_delay_loop(); - break; - case ALI1535_WORD_DATA: - data->word = inb_p(SMBHSTDAT0) + (inb_p(SMBHSTDAT1) << 8); - ali1535_delay_loop(); - break; - case ALI1535_BLOCK_DATA: - len = inb_p(SMBHSTDAT0); - ali1535_delay_loop(); - if (len > 32) - len = 32; - data->block[0] = len; - { - int val; - - val = inb_p(SMBHSTTYP) | ALI1535_BLOCK_CLR; - ali1535_delay_loop(); - outb_p(val, SMBHSTTYP); /* Reset SMBBLKDAT */ - ali1535_delay_loop(); - } - for (i = 1; i <= data->block[0]; i++) { - data->block[i] = inb_p(SMBBLKDAT); - ali1535_delay_loop(); -#ifdef DEBUG - printk - ("i2c-ali1535.o: Blk: len=%d, i=%d, data=%02x\n", - len, i, data->block[i]); -#endif /* DEBUG */ - } - break; - } -EXIT: - return result; -} - -static void ali1535_inc(struct i2c_adapter *adapter) -{ -#ifdef MODULE - MOD_INC_USE_COUNT; -#endif -} - -static void ali1535_dec(struct i2c_adapter *adapter) -{ -#ifdef MODULE - MOD_DEC_USE_COUNT; -#endif -} - -u32 ali1535_func(struct i2c_adapter *adapter) -{ - return I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE | - I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA | - I2C_FUNC_SMBUS_BLOCK_DATA; -} - -static struct i2c_algorithm smbus_algorithm = { - .name = "Non-i2c SMBus adapter", - .id = I2C_ALGO_SMBUS, - .smbus_xfer = ali1535_access, - .functionality = ali1535_func, -}; - -static struct i2c_adapter ali1535_adapter = { - .id = I2C_ALGO_SMBUS | I2C_HW_SMBUS_ALI1535, - .algo = &smbus_algorithm, - .inc_use = ali1535_inc, - .dec_use = ali1535_dec, -}; - - -static struct pci_device_id ali1535_ids[] __devinitdata = { - { - .vendor = PCI_VENDOR_ID_AL, - .device = PCI_DEVICE_ID_AL_M7101, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - }, - { 0, } -}; - -static int __devinit ali1535_probe(struct pci_dev *dev, const struct pci_device_id *id) -{ - if (ali1535_setup(dev)) { - printk - ("i2c-ali1535.o: ALI1535 not detected, module not inserted.\n"); - return -ENODEV; - } - - sprintf(ali1535_adapter.name, "SMBus ALI1535 adapter at %04x", - ali1535_smba); - return i2c_add_adapter(&ali1535_adapter); -} - -static void __devexit ali1535_remove(struct pci_dev *dev) -{ - i2c_del_adapter(&ali1535_adapter); - release_region(ali1535_smba, ALI1535_SMB_IOSIZE); -} - - -static struct pci_driver ali1535_driver = { - .name = "ali1535 smbus", - .id_table = ali1535_ids, - .probe = ali1535_probe, - .remove = __devexit_p(ali1535_remove), -}; - -static int __init i2c_ali1535_init(void) -{ - printk("i2c-ali1535.o version %s (%s)\n", LM_VERSION, LM_DATE); - return pci_module_init(&ali1535_driver); -} - -static void __exit i2c_ali1535_exit(void) -{ - pci_unregister_driver(&ali1535_driver); -} - -MODULE_AUTHOR - ("Frodo Looijaard , Philip Edelbrock , " - "Mark D. Studebaker and Dan Eaton "); -MODULE_DESCRIPTION("ALI1535 SMBus driver"); -MODULE_LICENSE("GPL"); - -module_init(i2c_ali1535_init); -module_exit(i2c_ali1535_exit); diff --git a/kernel/busses/i2c-ali1563.c b/kernel/busses/i2c-ali1563.c deleted file mode 100644 index 87cc2d2c..00000000 --- a/kernel/busses/i2c-ali1563.c +++ /dev/null @@ -1,464 +0,0 @@ -/** - * i2c-ali1563.c - i2c driver for the ALi 1563 Southbridge - * - * Copyright (C) 2004, 2005 Patrick Mochel, Chunhao Huang - * - * The 1563 southbridge is deceptively similar to the 1533, with a - * few notable exceptions. One of those happens to be the fact they - * upgraded the i2c core to be 2.0 compliant, and happens to be almost - * identical to the i2c controller found in the Intel 801 south - * bridges. - * - * This driver is based on a mix of the 15x3, 1535, and i801 drivers, - * with a little help from the ALi 1563 spec. - * - * Chunhao Huang / Winbond - * Backport to linux-2.4 from linux-2.6 on Mar.2005 - * - * This file is released under the GPLv2 - */ - -#include -#include -#include -#include -#include -#include "version.h" -#include "sensors_compat.h" - -#ifndef PCI_DEVICE_ID_AL_M1563 -#define PCI_DEVICE_ID_AL_M1563 0x1563 -#endif - -#define ALI1563_MAX_TIMEOUT 500 -#define ALI1563_SMBBA 0x80 -#define ALI1563_SMB_IOEN 1 -#define ALI1563_SMB_HOSTEN 2 -#define ALI1563_SMB_IOSIZE 16 - -#define SMB_HST_STS (ali1563_smba + 0) -#define SMB_HST_CNTL1 (ali1563_smba + 1) -#define SMB_HST_CNTL2 (ali1563_smba + 2) -#define SMB_HST_CMD (ali1563_smba + 3) -#define SMB_HST_ADD (ali1563_smba + 4) -#define SMB_HST_DAT0 (ali1563_smba + 5) -#define SMB_HST_DAT1 (ali1563_smba + 6) -#define SMB_BLK_DAT (ali1563_smba + 7) - -#define HST_STS_BUSY 0x01 -#define HST_STS_INTR 0x02 -#define HST_STS_DEVERR 0x04 -#define HST_STS_BUSERR 0x08 -#define HST_STS_FAIL 0x10 -#define HST_STS_DONE 0x80 -#define HST_STS_BAD 0x1c - - -#define HST_CNTL1_TIMEOUT 0x80 -#define HST_CNTL1_LAST 0x40 - -#define HST_CNTL2_KILL 0x04 -#define HST_CNTL2_START 0x40 -#define HST_CNTL2_QUICK 0x00 -#define HST_CNTL2_BYTE 0x01 -#define HST_CNTL2_BYTE_DATA 0x02 -#define HST_CNTL2_WORD_DATA 0x03 -#define HST_CNTL2_BLOCK 0x05 -#define HST_CNTL2_SIZEMASK 0x38 - -static struct pci_driver ali1563_pci_driver; -static unsigned short ali1563_smba; - -static int ali1563_transaction(struct i2c_adapter * a) -{ - u32 data; - int timeout; - - printk(KERN_DEBUG "ali1563: Transaction (pre): STS=%02x, CNTL1=%02x, " - "CNTL2=%02x, CMD=%02x, ADD=%02x, DAT0=%02x, DAT1=%02x\n", - inb_p(SMB_HST_STS), inb_p(SMB_HST_CNTL1), inb_p(SMB_HST_CNTL2), - inb_p(SMB_HST_CMD), inb_p(SMB_HST_ADD), inb_p(SMB_HST_DAT0), - inb_p(SMB_HST_DAT1)); - - data = inb_p(SMB_HST_STS); - if (data & HST_STS_BAD) { - printk(KERN_WARNING "ali1563: Trying to reset busy device\n"); - outb_p(data | HST_STS_BAD,SMB_HST_STS); - data = inb_p(SMB_HST_STS); - if (data & HST_STS_BAD){ - return -EBUSY; - } - } - outb_p(inb_p(SMB_HST_CNTL2) | HST_CNTL2_START, SMB_HST_CNTL2); - - timeout = ALI1563_MAX_TIMEOUT; - do - i2c_delay(1); - while (((data = inb_p(SMB_HST_STS)) & HST_STS_BUSY) && --timeout); - - printk(KERN_DEBUG "ali1563: Transaction (post): STS=%02x, CNTL1=%02x, " - "CNTL2=%02x, CMD=%02x, ADD=%02x, DAT0=%02x, DAT1=%02x\n", - inb_p(SMB_HST_STS), inb_p(SMB_HST_CNTL1), inb_p(SMB_HST_CNTL2), - inb_p(SMB_HST_CMD), inb_p(SMB_HST_ADD), inb_p(SMB_HST_DAT0), - inb_p(SMB_HST_DAT1)); - - if (timeout && !(data & HST_STS_BAD)) { - return 0; - } - - /* modified by Rudolf */ - if (!timeout) { - printk(KERN_ERR "ali1563: Timeout - Trying to KILL transaction!\n"); - /* Issue 'kill' to host controller */ - outb_p(HST_CNTL2_KILL,SMB_HST_CNTL2); - data = inb_p(SMB_HST_STS); - } - - /* device error - probably missing ACK */ - if (data & HST_STS_DEVERR) { - printk(KERN_DEBUG "ali1563: Device error!\n"); - } - - /* bus collision */ - if (data & HST_STS_BUSERR) { - printk(KERN_ERR "ali1563: Bus collision!\n"); - /* Issue timeout, hoping it helps */ - outb_p(HST_CNTL1_TIMEOUT,SMB_HST_CNTL1); - } - - if (data & HST_STS_FAIL) { - printk(KERN_ERR "ali1563: Cleaning fail after KILL!\n"); - outb_p(0x0,SMB_HST_CNTL2); - } - - return -1; -} - -static int ali1563_block_start(struct i2c_adapter * a) -{ - u32 data; - int timeout; - - printk(KERN_DEBUG "ali1563: Block (pre): STS=%02x, CNTL1=%02x, " - "CNTL2=%02x, CMD=%02x, ADD=%02x, DAT0=%02x, DAT1=%02x\n", - inb_p(SMB_HST_STS), inb_p(SMB_HST_CNTL1), inb_p(SMB_HST_CNTL2), - inb_p(SMB_HST_CMD), inb_p(SMB_HST_ADD), inb_p(SMB_HST_DAT0), - inb_p(SMB_HST_DAT1)); - - data = inb_p(SMB_HST_STS); - if (data & HST_STS_BAD) { - printk(KERN_WARNING "ali1563: Trying to reset busy device\n"); - outb_p(data | HST_STS_BAD,SMB_HST_STS); - data = inb_p(SMB_HST_STS); - if (data & HST_STS_BAD){ - return -EBUSY; - } - } - - /* Clear byte-ready bit */ - outb_p(data | HST_STS_DONE, SMB_HST_STS); - - /* Start transaction and wait for byte-ready bit to be set */ - outb_p(inb_p(SMB_HST_CNTL2) | HST_CNTL2_START, SMB_HST_CNTL2); - - timeout = ALI1563_MAX_TIMEOUT; - do - i2c_delay(1); - while (!((data = inb_p(SMB_HST_STS)) & HST_STS_DONE) && --timeout); - - printk(KERN_DEBUG "ali1563: Block (post): STS=%02x, CNTL1=%02x, " - "CNTL2=%02x, CMD=%02x, ADD=%02x, DAT0=%02x, DAT1=%02x\n", - inb_p(SMB_HST_STS), inb_p(SMB_HST_CNTL1), inb_p(SMB_HST_CNTL2), - inb_p(SMB_HST_CMD), inb_p(SMB_HST_ADD), inb_p(SMB_HST_DAT0), - inb_p(SMB_HST_DAT1)); - - if (timeout && !(data & HST_STS_BAD)){ - return 0; - } - printk(KERN_WARNING "ali1563: SMBus Error: %s%s%s%s%s\n", - timeout ? "Timeout " : "", - data & HST_STS_FAIL ? "Transaction Failed " : "", - data & HST_STS_BUSERR ? "No response or Bus Collision " : "", - data & HST_STS_DEVERR ? "Device Error " : "", - !(data & HST_STS_DONE) ? "Transaction Never Finished " : ""); - return -1; -} - -static int ali1563_block(struct i2c_adapter * a, union i2c_smbus_data * data, u8 rw) -{ - int i, len; - int error = 0; - - /* Do we need this? */ - outb_p(HST_CNTL1_LAST,SMB_HST_CNTL1); - - if (rw == I2C_SMBUS_WRITE) { - len = data->block[0]; - if (len < 1) - len = 1; - else if (len > 32) - len = 32; - outb_p(len,SMB_HST_DAT0); - outb_p(data->block[1],SMB_BLK_DAT); - } else - len = 32; - - outb_p(inb_p(SMB_HST_CNTL2) | HST_CNTL2_BLOCK, SMB_HST_CNTL2); - - for (i = 0; i < len; i++) { - if (rw == I2C_SMBUS_WRITE) { - outb_p(data->block[i + 1], SMB_BLK_DAT); - if ((error = ali1563_block_start(a))) - break; - } else { - if ((error = ali1563_block_start(a))) - break; - if (i == 0) { - len = inb_p(SMB_HST_DAT0); - if (len < 1) - len = 1; - else if (len > 32) - len = 32; - } - data->block[i+1] = inb_p(SMB_BLK_DAT); - } - } - /* Do we need this? */ - outb_p(HST_CNTL1_LAST,SMB_HST_CNTL1); - return error; -} - -static s32 ali1563_access(struct i2c_adapter * a, u16 addr, - unsigned short flags, char rw, u8 cmd, - int size, union i2c_smbus_data * data) -{ - int error = 0; - int timeout; - u32 reg; - - for (timeout = ALI1563_MAX_TIMEOUT; timeout; timeout--) { - if (!(reg = inb_p(SMB_HST_STS) & HST_STS_BUSY)) - break; - } - if (!timeout) - printk(KERN_WARNING "ali1563: SMBus not idle. HST_STS = %02x\n",reg); - outb_p(0xff,SMB_HST_STS); - - /* Map the size to what the chip understands */ - switch (size) { - case I2C_SMBUS_PROC_CALL: - printk(KERN_ERR "ali1563: I2C_SMBUS_PROC_CALL not supported!\n"); - error = -EINVAL; - break; - case I2C_SMBUS_QUICK: - size = HST_CNTL2_QUICK; - break; - case I2C_SMBUS_BYTE: - size = HST_CNTL2_BYTE; - break; - case I2C_SMBUS_BYTE_DATA: - size = HST_CNTL2_BYTE_DATA; - break; - case I2C_SMBUS_WORD_DATA: - size = HST_CNTL2_WORD_DATA; - break; - case I2C_SMBUS_BLOCK_DATA: - size = HST_CNTL2_BLOCK; - break; - } - - outb_p(((addr & 0x7f) << 1) | (rw & 0x01), SMB_HST_ADD); - outb_p( (inb_p(SMB_HST_CNTL2)&~HST_CNTL2_SIZEMASK) | (size << 3), SMB_HST_CNTL2); - - /* Write the command register */ - switch(size) { - case HST_CNTL2_BYTE: - if (rw== I2C_SMBUS_WRITE) - /* outb_p(cmd, SMB_HST_CMD); */ - outb_p(cmd, SMB_HST_DAT0); /* modify by Rudolf */ - break; - case HST_CNTL2_BYTE_DATA: - outb_p(cmd, SMB_HST_CMD); - if (rw == I2C_SMBUS_WRITE) - outb_p(data->byte, SMB_HST_DAT0); - break; - case HST_CNTL2_WORD_DATA: - outb_p(cmd, SMB_HST_CMD); - if (rw == I2C_SMBUS_WRITE) { - outb_p(data->word & 0xff, SMB_HST_DAT0); - outb_p((data->word & 0xff00) >> 8, SMB_HST_DAT1); - } - break; - case HST_CNTL2_BLOCK: - outb_p(cmd, SMB_HST_CMD); - error = ali1563_block(a,data,rw); - goto Done; - } - - if ((error = ali1563_transaction(a))){ - goto Done; - } - - if ((rw == I2C_SMBUS_WRITE) || (size == HST_CNTL2_QUICK)){ - goto Done; - } - - switch (size) { - case HST_CNTL2_BYTE: /* Result put in SMBHSTDAT0 */ - data->byte = inb_p(SMB_HST_DAT0); - break; - case HST_CNTL2_BYTE_DATA: - data->byte = inb_p(SMB_HST_DAT0); - break; - case HST_CNTL2_WORD_DATA: - data->word = inb_p(SMB_HST_DAT0) + (inb_p(SMB_HST_DAT1) << 8); - break; - } -Done: - return error; -} - -static u32 ali1563_func(struct i2c_adapter * a) -{ - return ( I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE | - I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA | - I2C_FUNC_SMBUS_BLOCK_DATA ); -} - - -static int __devinit ali1563_setup(struct pci_dev * dev) -{ - u16 ctrl; - - pci_read_config_word(dev,ALI1563_SMBBA,&ctrl); - - /* SMB I/O Base in high 12 bits and must be aligned with the - * size of the I/O space. */ - ali1563_smba = ctrl & ~(ALI1563_SMB_IOSIZE - 1); - if (!ali1563_smba) { - printk(KERN_WARNING "ali1563: ali1563_smba Uninitialized\n"); - goto Err; - } - - /* Check if device is enabled */ - if (!(ctrl & ALI1563_SMB_HOSTEN)) { - printk(KERN_WARNING "ali1563: Host Controller not enabled\n"); - goto Err; - } - if (!(ctrl & ALI1563_SMB_IOEN)) { - printk(KERN_WARNING "I/O space not enabled, trying manually\n"); - pci_write_config_word(dev, ALI1563_SMBBA, - ctrl | ALI1563_SMB_IOEN); - pci_read_config_word(dev, ALI1563_SMBBA, &ctrl); - if (!(ctrl & ALI1563_SMB_IOEN)) { - printk(KERN_WARNING "I/O space still not enabled, " - "giving up\n"); - goto Err; - } - } - - if (!request_region(ali1563_smba, ALI1563_SMB_IOSIZE, - ali1563_pci_driver.name)) { - printk(KERN_WARNING "ali1563: Could not allocate I/O space " - "at 0x%04x\n", ali1563_smba); - goto Err; - } - printk(KERN_INFO "ali1563: Found ALi1563 SMBus at 0x%04x\n", - ali1563_smba); - - return 0; -Err: - return -ENODEV; -} - -static void ali1563_shutdown(struct pci_dev *dev) -{ - release_region(ali1563_smba,ALI1563_SMB_IOSIZE); -} - -static void ali1563_inc(struct i2c_adapter *adapter) -{ -#ifdef MODULE - MOD_INC_USE_COUNT; -#endif -} - -static void ali1563_dec(struct i2c_adapter *adapter) -{ -#ifdef MODULE - MOD_DEC_USE_COUNT; -#endif -} - -static struct i2c_algorithm ali1563_algorithm = { - .name = "Non-i2c SMBus adapter", - .id = I2C_ALGO_SMBUS, - .smbus_xfer = ali1563_access, - .functionality = ali1563_func, -}; - -static struct i2c_adapter ali1563_adapter = { - .algo = &ali1563_algorithm, - .inc_use = ali1563_inc, - .dec_use = ali1563_dec, -}; - -static int __devinit ali1563_probe(struct pci_dev * dev, - const struct pci_device_id * id_table) -{ - int error; - - if ((error = ali1563_setup(dev))) { - printk(KERN_WARNING "ali1563: ALi1563 SMBus probe failed " - "(%d)\n", error); - return error; - } - sprintf(ali1563_adapter.name,"SMBus ALi 1563 Adapter @ %04x", - ali1563_smba); - if ((error = i2c_add_adapter(&ali1563_adapter))) - ali1563_shutdown(dev); - return error; -} - -static void __devexit ali1563_remove(struct pci_dev * dev) -{ - i2c_del_adapter(&ali1563_adapter); - ali1563_shutdown(dev); -} - -static struct pci_device_id ali1563_ids[] __devinitdata = { - { - .vendor = PCI_VENDOR_ID_AL, - .device = PCI_DEVICE_ID_AL_M1563, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - }, - { 0, } -}; - -static struct pci_driver ali1563_pci_driver = { - .name = "ali1563 smbus", - .id_table = ali1563_ids, - .probe = ali1563_probe, - .remove = __devexit_p(ali1563_remove), -}; - -static int __init ali1563_init(void) -{ - printk("i2c-ali1563.o version %s (%s)\n", LM_VERSION, LM_DATE); - return pci_module_init(&ali1563_pci_driver); -} - -module_init(ali1563_init); - -static void __exit ali1563_exit(void) -{ - pci_unregister_driver(&ali1563_pci_driver); -} - -module_exit(ali1563_exit); - -MODULE_AUTHOR("Patrick Mochel , Chunhao Huang"); -MODULE_DESCRIPTION("ALi M1563 southbridge driver for linux-2.4, backported by Chunhao Huang from linux-2.6"); -MODULE_LICENSE("GPL"); - diff --git a/kernel/busses/i2c-ali15x3.c b/kernel/busses/i2c-ali15x3.c deleted file mode 100644 index 19c40207..00000000 --- a/kernel/busses/i2c-ali15x3.c +++ /dev/null @@ -1,548 +0,0 @@ -/* - ali15x3.c - Part of lm_sensors, Linux kernel modules for hardware - monitoring - Copyright (c) 1999 Frodo Looijaard and - Philip Edelbrock and - Mark D. Studebaker - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -/* - This is the driver for the SMB Host controller on - Acer Labs Inc. (ALI) M1541 and M1543C South Bridges. - - The M1543C is a South bridge for desktop systems. - The M1533 is a South bridge for portable systems. - They are part of the following ALI chipsets: - "Aladdin Pro 2": Includes the M1621 Slot 1 North bridge - with AGP and 100MHz CPU Front Side bus - "Aladdin V": Includes the M1541 Socket 7 North bridge - with AGP and 100MHz CPU Front Side bus - "Aladdin IV": Includes the M1541 Socket 7 North bridge - with host bus up to 83.3 MHz. - For an overview of these chips see http://www.acerlabs.com - - The M1533/M1543C devices appear as FOUR separate devices - on the PCI bus. An output of lspci will show something similar - to the following: - - 00:02.0 USB Controller: Acer Laboratories Inc. M5237 - 00:03.0 Bridge: Acer Laboratories Inc. M7101 - 00:07.0 ISA bridge: Acer Laboratories Inc. M1533 - 00:0f.0 IDE interface: Acer Laboratories Inc. M5229 - - The SMB controller is part of the 7101 device, which is an - ACPI-compliant Power Management Unit (PMU). - - The whole 7101 device has to be enabled for the SMB to work. - You can't just enable the SMB alone. - The SMB and the ACPI have separate I/O spaces. - We make sure that the SMB is enabled. We leave the ACPI alone. - - This driver controls the SMB Host only. - The SMB Slave controller on the M15X3 is not enabled. - - This driver does not use interrupts. -*/ - -/* Note: we assume there can only be one ALI15X3, with one SMBus interface */ - -/* #define DEBUG 1 */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "version.h" -#include "sensors_compat.h" - -/* ALI15X3 SMBus address offsets */ -#define SMBHSTSTS (0 + ali15x3_smba) -#define SMBHSTCNT (1 + ali15x3_smba) -#define SMBHSTSTART (2 + ali15x3_smba) -#define SMBHSTCMD (7 + ali15x3_smba) -#define SMBHSTADD (3 + ali15x3_smba) -#define SMBHSTDAT0 (4 + ali15x3_smba) -#define SMBHSTDAT1 (5 + ali15x3_smba) -#define SMBBLKDAT (6 + ali15x3_smba) - -/* PCI Address Constants */ -#define SMBCOM 0x004 -#define SMBBA 0x014 -#define SMBATPC 0x05B /* used to unlock xxxBA registers */ -#define SMBHSTCFG 0x0E0 -#define SMBSLVC 0x0E1 -#define SMBCLK 0x0E2 -#define SMBREV 0x008 - -/* Other settings */ -#define MAX_TIMEOUT 200 /* times 1/100 sec */ -#define ALI15X3_SMB_IOSIZE 32 - -/* this is what the Award 1004 BIOS sets them to on a ASUS P5A MB. - We don't use these here. If the bases aren't set to some value we - tell user to upgrade BIOS and we fail. -*/ -#define ALI15X3_SMB_DEFAULTBASE 0xE800 - -/* ALI15X3 address lock bits */ -#define ALI15X3_LOCK 0x06 - -/* ALI15X3 command constants */ -#define ALI15X3_ABORT 0x02 -#define ALI15X3_T_OUT 0x04 -#define ALI15X3_QUICK 0x00 -#define ALI15X3_BYTE 0x10 -#define ALI15X3_BYTE_DATA 0x20 -#define ALI15X3_WORD_DATA 0x30 -#define ALI15X3_BLOCK_DATA 0x40 -#define ALI15X3_BLOCK_CLR 0x80 - -/* ALI15X3 status register bits */ -#define ALI15X3_STS_IDLE 0x04 -#define ALI15X3_STS_BUSY 0x08 -#define ALI15X3_STS_DONE 0x10 -#define ALI15X3_STS_DEV 0x20 /* device error */ -#define ALI15X3_STS_COLL 0x40 /* collision or no response */ -#define ALI15X3_STS_TERM 0x80 /* terminated by abort */ -#define ALI15X3_STS_ERR 0xE0 /* all the bad error bits */ - - -/* If force_addr is set to anything different from 0, we forcibly enable - the device at the given address. */ -static int force_addr = 0; -MODULE_PARM(force_addr, "i"); -MODULE_PARM_DESC(force_addr, - "Initialize the base address of the i2c controller"); - -static struct pci_driver ali15x3_driver; -static unsigned short ali15x3_smba = 0; - -static int ali15x3_setup(struct pci_dev *ALI15X3_dev) -{ - u16 a; - unsigned char temp; - - /* Check the following things: - - SMB I/O address is initialized - - Device is enabled - - We can use the addresses - */ - - /* Unlock the register. - The data sheet says that the address registers are read-only - if the lock bits are 1, but in fact the address registers - are zero unless you clear the lock bits. - */ - pci_read_config_byte(ALI15X3_dev, SMBATPC, &temp); - if (temp & ALI15X3_LOCK) { - temp &= ~ALI15X3_LOCK; - pci_write_config_byte(ALI15X3_dev, SMBATPC, temp); - } - - /* Determine the address of the SMBus area */ - pci_read_config_word(ALI15X3_dev, SMBBA, &ali15x3_smba); - ali15x3_smba &= (0xffff & ~(ALI15X3_SMB_IOSIZE - 1)); - if (ali15x3_smba == 0 && force_addr == 0) { - dev_err(ALI15X3_dev, "ALI15X3_smb region uninitialized " - "- upgrade BIOS or use force_addr=0xaddr\n"); - return -ENODEV; - } - - if(force_addr) - ali15x3_smba = force_addr & ~(ALI15X3_SMB_IOSIZE - 1); - - if (!request_region(ali15x3_smba, ALI15X3_SMB_IOSIZE, - ali15x3_driver.name)) { - dev_err(ALI15X3_dev, - "ALI15X3_smb region 0x%x already in use!\n", - ali15x3_smba); - return -ENODEV; - } - - if(force_addr) { - dev_info(ALI15X3_dev, "forcing ISA address 0x%04X\n", - ali15x3_smba); - if (PCIBIOS_SUCCESSFUL != - pci_write_config_word(ALI15X3_dev, SMBBA, ali15x3_smba)) - return -ENODEV; - if (PCIBIOS_SUCCESSFUL != - pci_read_config_word(ALI15X3_dev, SMBBA, &a)) - return -ENODEV; - if ((a & ~(ALI15X3_SMB_IOSIZE - 1)) != ali15x3_smba) { - /* make sure it works */ - dev_err(ALI15X3_dev, - "force address failed - not supported?\n"); - return -ENODEV; - } - } - /* check if whole device is enabled */ - pci_read_config_byte(ALI15X3_dev, SMBCOM, &temp); - if ((temp & 1) == 0) { - dev_info(ALI15X3_dev, "enabling SMBus device\n"); - pci_write_config_byte(ALI15X3_dev, SMBCOM, temp | 0x01); - } - - /* Is SMB Host controller enabled? */ - pci_read_config_byte(ALI15X3_dev, SMBHSTCFG, &temp); - if ((temp & 1) == 0) { - dev_info(ALI15X3_dev, "enabling SMBus controller\n"); - pci_write_config_byte(ALI15X3_dev, SMBHSTCFG, temp | 0x01); - } - - /* set SMB clock to 74KHz as recommended in data sheet */ - pci_write_config_byte(ALI15X3_dev, SMBCLK, 0x20); - - /* - The interrupt routing for SMB is set up in register 0x77 in the - 1533 ISA Bridge device, NOT in the 7101 device. - Don't bother with finding the 1533 device and reading the register. - if ((....... & 0x0F) == 1) - dev_dbg(ALI15X3_dev, "ALI15X3 using Interrupt 9 for SMBus.\n"); - */ - pci_read_config_byte(ALI15X3_dev, SMBREV, &temp); - dev_dbg(ALI15X3_dev, "SMBREV = 0x%X\n", temp); - dev_dbg(ALI15X3_dev, "iALI15X3_smba = 0x%X\n", ali15x3_smba); - - return 0; -} - -/* Another internally used function */ -static int ali15x3_transaction(struct i2c_adapter *adap) -{ - int temp; - int result = 0; - int timeout = 0; - - dev_dbg(adap, "Transaction (pre): STS=%02x, CNT=%02x, CMD=%02x, " - "ADD=%02x, DAT0=%02x, DAT1=%02x\n", inb_p(SMBHSTSTS), - inb_p(SMBHSTCNT), inb_p(SMBHSTCMD), inb_p(SMBHSTADD), - inb_p(SMBHSTDAT0), inb_p(SMBHSTDAT1)); - - /* get status */ - temp = inb_p(SMBHSTSTS); - - /* Make sure the SMBus host is ready to start transmitting */ - /* Check the busy bit first */ - if (temp & ALI15X3_STS_BUSY) { - /* - If the host controller is still busy, it may have timed out in the - previous transaction, resulting in a "SMBus Timeout" Dev. - I've tried the following to reset a stuck busy bit. - 1. Reset the controller with an ABORT command. - (this doesn't seem to clear the controller if an external - device is hung) - 2. Reset the controller and the other SMBus devices with a - T_OUT command. (this clears the host busy bit if an - external device is hung, but it comes back upon a new access - to a device) - 3. Disable and reenable the controller in SMBHSTCFG - Worst case, nothing seems to work except power reset. - */ - /* Abort - reset the host controller */ - /* - Try resetting entire SMB bus, including other devices - - This may not work either - it clears the BUSY bit but - then the BUSY bit may come back on when you try and use the chip again. - If that's the case you are stuck. - */ - dev_info(adap, "Resetting entire SMB Bus to " - "clear busy condition (%02x)\n", temp); - outb_p(ALI15X3_T_OUT, SMBHSTCNT); - temp = inb_p(SMBHSTSTS); - } - - /* now check the error bits and the busy bit */ - if (temp & (ALI15X3_STS_ERR | ALI15X3_STS_BUSY)) { - /* do a clear-on-write */ - outb_p(0xFF, SMBHSTSTS); - if ((temp = inb_p(SMBHSTSTS)) & - (ALI15X3_STS_ERR | ALI15X3_STS_BUSY)) { - /* this is probably going to be correctable only by a power reset - as one of the bits now appears to be stuck */ - /* This may be a bus or device with electrical problems. */ - dev_err(adap, "SMBus reset failed! (0x%02x) - " - "controller or device on bus is probably hung\n", - temp); - return -1; - } - } else { - /* check and clear done bit */ - if (temp & ALI15X3_STS_DONE) { - outb_p(temp, SMBHSTSTS); - } - } - - /* start the transaction by writing anything to the start register */ - outb_p(0xFF, SMBHSTSTART); - - /* We will always wait for a fraction of a second! */ - timeout = 0; - do { - i2c_delay(1); - temp = inb_p(SMBHSTSTS); - } while ((!(temp & (ALI15X3_STS_ERR | ALI15X3_STS_DONE))) - && (timeout++ < MAX_TIMEOUT)); - - /* If the SMBus is still busy, we give up */ - if (timeout >= MAX_TIMEOUT) { - result = -1; - dev_err(adap, "SMBus Timeout!\n"); - } - - if (temp & ALI15X3_STS_TERM) { - result = -1; - dev_dbg(adap, "Error: Failed bus transaction\n"); - } - - /* - Unfortunately the ALI SMB controller maps "no response" and "bus - collision" into a single bit. No reponse is the usual case so don't - do a printk. - This means that bus collisions go unreported. - */ - if (temp & ALI15X3_STS_COLL) { - result = -1; - dev_dbg(adap, - "Error: no response or bus collision ADD=%02x\n", - inb_p(SMBHSTADD)); - } - - /* haven't ever seen this */ - if (temp & ALI15X3_STS_DEV) { - result = -1; - dev_err(adap, "Error: device error\n"); - } - dev_dbg(adap, "Transaction (post): STS=%02x, CNT=%02x, CMD=%02x, " - "ADD=%02x, DAT0=%02x, DAT1=%02x\n", inb_p(SMBHSTSTS), - inb_p(SMBHSTCNT), inb_p(SMBHSTCMD), inb_p(SMBHSTADD), - inb_p(SMBHSTDAT0), inb_p(SMBHSTDAT1)); - return result; -} - -/* Return -1 on error. */ -static s32 ali15x3_access(struct i2c_adapter * adap, u16 addr, - unsigned short flags, char read_write, u8 command, - int size, union i2c_smbus_data * data) -{ - int i, len; - int temp; - int timeout; - - /* clear all the bits (clear-on-write) */ - outb_p(0xFF, SMBHSTSTS); - /* make sure SMBus is idle */ - temp = inb_p(SMBHSTSTS); - for (timeout = 0; - (timeout < MAX_TIMEOUT) && !(temp & ALI15X3_STS_IDLE); - timeout++) { - i2c_delay(1); - temp = inb_p(SMBHSTSTS); - } - if (timeout >= MAX_TIMEOUT) { - dev_err(adap, "Idle wait Timeout! STS=0x%02x\n", temp); - } - - switch (size) { - case I2C_SMBUS_QUICK: - outb_p(((addr & 0x7f) << 1) | (read_write & 0x01), - SMBHSTADD); - size = ALI15X3_QUICK; - break; - case I2C_SMBUS_BYTE: - outb_p(((addr & 0x7f) << 1) | (read_write & 0x01), - SMBHSTADD); - if (read_write == I2C_SMBUS_WRITE) - outb_p(command, SMBHSTCMD); - size = ALI15X3_BYTE; - break; - case I2C_SMBUS_BYTE_DATA: - outb_p(((addr & 0x7f) << 1) | (read_write & 0x01), - SMBHSTADD); - outb_p(command, SMBHSTCMD); - if (read_write == I2C_SMBUS_WRITE) - outb_p(data->byte, SMBHSTDAT0); - size = ALI15X3_BYTE_DATA; - break; - case I2C_SMBUS_WORD_DATA: - outb_p(((addr & 0x7f) << 1) | (read_write & 0x01), - SMBHSTADD); - outb_p(command, SMBHSTCMD); - if (read_write == I2C_SMBUS_WRITE) { - outb_p(data->word & 0xff, SMBHSTDAT0); - outb_p((data->word & 0xff00) >> 8, SMBHSTDAT1); - } - size = ALI15X3_WORD_DATA; - break; - case I2C_SMBUS_BLOCK_DATA: - outb_p(((addr & 0x7f) << 1) | (read_write & 0x01), - SMBHSTADD); - outb_p(command, SMBHSTCMD); - if (read_write == I2C_SMBUS_WRITE) { - len = data->block[0]; - if (len < 0) { - len = 0; - data->block[0] = len; - } - if (len > 32) { - len = 32; - data->block[0] = len; - } - outb_p(len, SMBHSTDAT0); - /* Reset SMBBLKDAT */ - outb_p(inb_p(SMBHSTCNT) | ALI15X3_BLOCK_CLR, SMBHSTCNT); - for (i = 1; i <= len; i++) - outb_p(data->block[i], SMBBLKDAT); - } - size = ALI15X3_BLOCK_DATA; - break; - default: - printk - (KERN_WARNING "i2c-ali15x3.o: Unsupported transaction %d\n", size); - return -1; - } - - outb_p(size, SMBHSTCNT); /* output command */ - - if (ali15x3_transaction(adap)) /* Error in transaction */ - return -1; - - if ((read_write == I2C_SMBUS_WRITE) || (size == ALI15X3_QUICK)) - return 0; - - - switch (size) { - case ALI15X3_BYTE: /* Result put in SMBHSTDAT0 */ - data->byte = inb_p(SMBHSTDAT0); - break; - case ALI15X3_BYTE_DATA: - data->byte = inb_p(SMBHSTDAT0); - break; - case ALI15X3_WORD_DATA: - data->word = inb_p(SMBHSTDAT0) + (inb_p(SMBHSTDAT1) << 8); - break; - case ALI15X3_BLOCK_DATA: - len = inb_p(SMBHSTDAT0); - if (len > 32) - len = 32; - data->block[0] = len; - /* Reset SMBBLKDAT */ - outb_p(inb_p(SMBHSTCNT) | ALI15X3_BLOCK_CLR, SMBHSTCNT); - for (i = 1; i <= data->block[0]; i++) { - data->block[i] = inb_p(SMBBLKDAT); - dev_dbg(adap, "Blk: len=%d, i=%d, data=%02x\n", - len, i, data->block[i]); - } - break; - } - return 0; -} - -static void ali15x3_inc(struct i2c_adapter *adapter) -{ -#ifdef MODULE - MOD_INC_USE_COUNT; -#endif -} - -static void ali15x3_dec(struct i2c_adapter *adapter) -{ -#ifdef MODULE - MOD_DEC_USE_COUNT; -#endif -} - -static u32 ali15x3_func(struct i2c_adapter *adapter) -{ - return I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE | - I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA | - I2C_FUNC_SMBUS_BLOCK_DATA; -} - -static struct i2c_algorithm smbus_algorithm = { - .name = "Non-I2C SMBus adapter", - .id = I2C_ALGO_SMBUS, - .smbus_xfer = ali15x3_access, - .functionality = ali15x3_func, -}; - -static struct i2c_adapter ali15x3_adapter = { - .id = I2C_ALGO_SMBUS | I2C_HW_SMBUS_ALI15X3, - .algo = &smbus_algorithm, - .inc_use = ali15x3_inc, - .dec_use = ali15x3_dec, -}; - -static struct pci_device_id ali15x3_ids[] __devinitdata = { - { - .vendor = PCI_VENDOR_ID_AL, - .device = PCI_DEVICE_ID_AL_M7101, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - }, - { 0, } -}; - -static int __devinit ali15x3_probe(struct pci_dev *dev, const struct pci_device_id *id) -{ - if (ali15x3_setup(dev)) { - dev_err(dev, - "ALI15X3 not detected, module not inserted.\n"); - return -ENODEV; - } - - snprintf(ali15x3_adapter.name, 32, - "SMBus ALI15X3 adapter at %04x", ali15x3_smba); - return i2c_add_adapter(&ali15x3_adapter); -} - -static void __devexit ali15x3_remove(struct pci_dev *dev) -{ - i2c_del_adapter(&ali15x3_adapter); - release_region(ali15x3_smba, ALI15X3_SMB_IOSIZE); -} - -static struct pci_driver ali15x3_driver = { - .name = "ali15x3 smbus", - .id_table = ali15x3_ids, - .probe = ali15x3_probe, - .remove = __devexit_p(ali15x3_remove), -}; - -static int __init i2c_ali15x3_init(void) -{ - printk("i2c-ali15x3.o version %s (%s)\n", LM_VERSION, LM_DATE); - return pci_module_init(&ali15x3_driver); -} - -static void __exit i2c_ali15x3_exit(void) -{ - pci_unregister_driver(&ali15x3_driver); -} - -MODULE_AUTHOR ("Frodo Looijaard , " - "Philip Edelbrock , " - "and Mark D. Studebaker "); -MODULE_DESCRIPTION("ALI15X3 SMBus driver"); -MODULE_LICENSE("GPL"); - -module_init(i2c_ali15x3_init); -module_exit(i2c_ali15x3_exit); diff --git a/kernel/busses/i2c-amd756-s4882.c b/kernel/busses/i2c-amd756-s4882.c deleted file mode 100644 index babc9182..00000000 --- a/kernel/busses/i2c-amd756-s4882.c +++ /dev/null @@ -1,265 +0,0 @@ -/* - * i2c-amd756-s4882.c - i2c-amd756 extras for the Tyan S4882 motherboard - * - * Copyright (C) 2004 Jean Delvare - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -/* - * We select the channels by sending commands to the Philips - * PCA9556 chip at I2C address 0x18. The main adapter is used for - * the non-multiplexed part of the bus, and 4 virtual adapters - * are defined for the multiplexed addresses: 0x50-0x53 (memory - * module EEPROM) located on channels 1-4, and 0x4c (LM63) - * located on multiplexed channels 0 and 5-7. We define one - * virtual adapter per CPU, which corresponds to two multiplexed - * channels: - * CPU0: virtual adapter 1, channels 1 and 0 - * CPU1: virtual adapter 2, channels 2 and 5 - * CPU2: virtual adapter 3, channels 3 and 6 - * CPU3: virtual adapter 4, channels 4 and 7 - */ - -#include -#include -#include -#include -#include -#include - -#define DRV_NAME "i2c-amd756-s4882" - -extern struct i2c_adapter amd756_smbus; - -static struct i2c_adapter *s4882_adapter; -static struct i2c_algorithm *s4882_algo; - -/* Wrapper access functions for multiplexed SMBus */ -static DECLARE_MUTEX(amd756_lock); - -static s32 amd756_access_virt0(struct i2c_adapter * adap, u16 addr, - unsigned short flags, char read_write, - u8 command, int size, - union i2c_smbus_data * data) -{ - int error; - - /* We exclude the multiplexed addresses */ - if (addr == 0x4c || (addr & 0xfc) == 0x50 || (addr & 0xfc) == 0x30 - || addr == 0x18) - return -1; - - down(&amd756_lock); - - error = amd756_smbus.algo->smbus_xfer(adap, addr, flags, read_write, - command, size, data); - - up(&amd756_lock); - - return error; -} - -/* We remember the last used channels combination so as to only switch - channels when it is really needed. This greatly reduces the SMBus - overhead, but also assumes that nobody will be writing to the PCA9556 - in our back. */ -static u8 last_channels; - -static inline s32 amd756_access_channel(struct i2c_adapter * adap, u16 addr, - unsigned short flags, char read_write, - u8 command, int size, - union i2c_smbus_data * data, - u8 channels) -{ - int error; - - /* We exclude the non-multiplexed addresses */ - if (addr != 0x4c && (addr & 0xfc) != 0x50 && (addr & 0xfc) != 0x30) - return -1; - - down(&amd756_lock); - - if (last_channels != channels) { - union i2c_smbus_data mplxdata; - mplxdata.byte = channels; - - error = amd756_smbus.algo->smbus_xfer(adap, 0x18, 0, - I2C_SMBUS_WRITE, 0x01, - I2C_SMBUS_BYTE_DATA, - &mplxdata); - if (error) - goto UNLOCK; - last_channels = channels; - } - error = amd756_smbus.algo->smbus_xfer(adap, addr, flags, read_write, - command, size, data); - -UNLOCK: - up(&amd756_lock); - return error; -} - -static s32 amd756_access_virt1(struct i2c_adapter * adap, u16 addr, - unsigned short flags, char read_write, - u8 command, int size, - union i2c_smbus_data * data) -{ - /* CPU0: channels 1 and 0 enabled */ - return amd756_access_channel(adap, addr, flags, read_write, command, - size, data, 0x03); -} - -static s32 amd756_access_virt2(struct i2c_adapter * adap, u16 addr, - unsigned short flags, char read_write, - u8 command, int size, - union i2c_smbus_data * data) -{ - /* CPU1: channels 2 and 5 enabled */ - return amd756_access_channel(adap, addr, flags, read_write, command, - size, data, 0x24); -} - -static s32 amd756_access_virt3(struct i2c_adapter * adap, u16 addr, - unsigned short flags, char read_write, - u8 command, int size, - union i2c_smbus_data * data) -{ - /* CPU2: channels 3 and 6 enabled */ - return amd756_access_channel(adap, addr, flags, read_write, command, - size, data, 0x48); -} - -static s32 amd756_access_virt4(struct i2c_adapter * adap, u16 addr, - unsigned short flags, char read_write, - u8 command, int size, - union i2c_smbus_data * data) -{ - /* CPU3: channels 4 and 7 enabled */ - return amd756_access_channel(adap, addr, flags, read_write, command, - size, data, 0x90); -} - -static int __init amd756_s4882_init(void) -{ - int i, error; - union i2c_smbus_data ioconfig; - - /* Unregister physical bus */ - error = i2c_del_adapter(&amd756_smbus); - if (error) { - if (error != -ENODEV) - printk(KERN_ERR DRV_NAME ": Physical bus removal " - "failed\n"); - goto ERROR0; - } - - printk(KERN_INFO "Enabling SMBus multiplexing for Tyan S4882\n"); - - /* Define the 5 virtual adapters and algorithms structures */ - if (!(s4882_adapter = kmalloc(5 * sizeof(struct i2c_adapter), - GFP_KERNEL))) { - error = -ENOMEM; - goto ERROR1; - } - if (!(s4882_algo = kmalloc(5 * sizeof(struct i2c_algorithm), - GFP_KERNEL))) { - error = -ENOMEM; - goto ERROR2; - } - - /* Fill in the new structures */ - s4882_algo[0] = *(amd756_smbus.algo); - s4882_algo[0].smbus_xfer = amd756_access_virt0; - s4882_adapter[0] = amd756_smbus; - s4882_adapter[0].algo = s4882_algo; - for (i = 1; i < 5; i++) { - s4882_algo[i] = *(amd756_smbus.algo); - s4882_adapter[i] = amd756_smbus; - sprintf(s4882_adapter[i].name, - "SMBus 8111 adapter (CPU%d)", i-1); - s4882_adapter[i].algo = s4882_algo+i; - } - s4882_algo[1].smbus_xfer = amd756_access_virt1; - s4882_algo[2].smbus_xfer = amd756_access_virt2; - s4882_algo[3].smbus_xfer = amd756_access_virt3; - s4882_algo[4].smbus_xfer = amd756_access_virt4; - - /* Configure the PCA9556 multiplexer */ - ioconfig.byte = 0x00; /* All I/O to output mode */ - error = amd756_smbus.algo->smbus_xfer(&amd756_smbus, 0x18, 0, - I2C_SMBUS_WRITE, 0x03, - I2C_SMBUS_BYTE_DATA, &ioconfig); - if (error) { - printk(KERN_ERR DRV_NAME ": PCA9556 configuration failed\n"); - error = -EIO; - goto ERROR3; - } - - /* Register virtual adapters */ - for (i = 0; i < 5; i++) { - error = i2c_add_adapter(s4882_adapter+i); - if (error) { - printk(KERN_ERR DRV_NAME - ": Virtual adapter %d registration " - "failed, module not inserted\n", i); - for (i--; i >= 0; i--) - i2c_del_adapter(s4882_adapter+i); - goto ERROR3; - } - } - - return 0; - -ERROR3: - kfree(s4882_algo); - s4882_algo = NULL; -ERROR2: - kfree(s4882_adapter); - s4882_adapter = NULL; -ERROR1: - /* Restore physical bus */ - i2c_add_adapter(&amd756_smbus); -ERROR0: - return error; -} - -static void __exit amd756_s4882_exit(void) -{ - if (s4882_adapter) { - int i; - - for (i = 0; i < 5; i++) - i2c_del_adapter(s4882_adapter+i); - kfree(s4882_adapter); - s4882_adapter = NULL; - } - if (s4882_algo) { - kfree(s4882_algo); - s4882_algo = NULL; - } - - /* Restore physical bus */ - if (i2c_add_adapter(&amd756_smbus)) - printk(KERN_ERR DRV_NAME ": Physical bus restoration " - "failed\n"); -} - -MODULE_AUTHOR("Jean Delvare "); -MODULE_DESCRIPTION("S4882 SMBus multiplexing"); -MODULE_LICENSE("GPL"); - -module_init(amd756_s4882_init); -module_exit(amd756_s4882_exit); diff --git a/kernel/busses/i2c-amd756.c b/kernel/busses/i2c-amd756.c deleted file mode 100644 index 4382380e..00000000 --- a/kernel/busses/i2c-amd756.c +++ /dev/null @@ -1,442 +0,0 @@ -/* - amd756.c - Part of lm_sensors, Linux kernel modules for hardware - monitoring - - Copyright (c) 1999-2002 Merlin Hughes - - Shamelessly ripped from i2c-piix4.c: - - Copyright (c) 1998, 1999 Frodo Looijaard and - Philip Edelbrock - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -/* - 2002-04-08: Added nForce support. (Csaba Halasz) - 2002-10-03: Fixed nForce PnP I/O port. (Michael Steil) - 2002-12-28: Rewritten into something that resembles a Linux driver (hch) - 2003-11-29: Added back AMD8111 removed by the previous rewrite. - (Philip Pokorny) - 2004-02-15: Don't register driver to avoid driver conflicts. - (Daniel Rune Jensen) -*/ - -/* - Supports AMD756, AMD766, AMD768, AMD8111 and nVidia nForce - Note: we assume there can only be one device, with one SMBus interface. -*/ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "version.h" - -#define DRV_NAME "i2c-amd756" - -/* AMD756 SMBus address offsets */ -#define SMB_ADDR_OFFSET 0xE0 -#define SMB_IOSIZE 16 -#define SMB_GLOBAL_STATUS (0x0 + amd756_ioport) -#define SMB_GLOBAL_ENABLE (0x2 + amd756_ioport) -#define SMB_HOST_ADDRESS (0x4 + amd756_ioport) -#define SMB_HOST_DATA (0x6 + amd756_ioport) -#define SMB_HOST_COMMAND (0x8 + amd756_ioport) -#define SMB_HOST_BLOCK_DATA (0x9 + amd756_ioport) -#define SMB_HAS_DATA (0xA + amd756_ioport) -#define SMB_HAS_DEVICE_ADDRESS (0xC + amd756_ioport) -#define SMB_HAS_HOST_ADDRESS (0xE + amd756_ioport) -#define SMB_SNOOP_ADDRESS (0xF + amd756_ioport) - -/* PCI Address Constants */ - -/* address of I/O space */ -#define SMBBA 0x058 /* mh */ -#define SMBBANFORCE 0x014 - -/* general configuration */ -#define SMBGCFG 0x041 /* mh */ - -/* silicon revision code */ -#define SMBREV 0x008 - -/* Other settings */ -#define MAX_TIMEOUT 500 - -/* AMD756 constants */ -#define AMD756_QUICK 0x00 -#define AMD756_BYTE 0x01 -#define AMD756_BYTE_DATA 0x02 -#define AMD756_WORD_DATA 0x03 -#define AMD756_PROCESS_CALL 0x04 -#define AMD756_BLOCK_DATA 0x05 - - -static unsigned short amd756_ioport = 0; - -/* - SMBUS event = I/O 28-29 bit 11 - see E0 for the status bits and enabled in E2 - -*/ - -#define GS_ABRT_STS (1 << 0) -#define GS_COL_STS (1 << 1) -#define GS_PRERR_STS (1 << 2) -#define GS_HST_STS (1 << 3) -#define GS_HCYC_STS (1 << 4) -#define GS_TO_STS (1 << 5) -#define GS_SMB_STS (1 << 11) - -#define GS_CLEAR_STS (GS_ABRT_STS | GS_COL_STS | GS_PRERR_STS | \ - GS_HCYC_STS | GS_TO_STS ) - -#define GE_CYC_TYPE_MASK (7) -#define GE_HOST_STC (1 << 3) -#define GE_ABORT (1 << 5) - - -static int amd756_transaction(void) -{ - int temp; - int result = 0; - int timeout = 0; - - pr_debug(DRV_NAME - ": Transaction (pre): GS=%04x, GE=%04x, ADD=%04x, DAT=%04x\n", - inw_p(SMB_GLOBAL_STATUS), inw_p(SMB_GLOBAL_ENABLE), - inw_p(SMB_HOST_ADDRESS), inb_p(SMB_HOST_DATA)); - - /* Make sure the SMBus host is ready to start transmitting */ - if ((temp = inw_p(SMB_GLOBAL_STATUS)) & (GS_HST_STS | GS_SMB_STS)) { - pr_debug(DRV_NAME ": SMBus busy (%04x). Waiting...\n", temp); - do { - i2c_delay(1); - temp = inw_p(SMB_GLOBAL_STATUS); - } while ((temp & (GS_HST_STS | GS_SMB_STS)) && - (timeout++ < MAX_TIMEOUT)); - /* If the SMBus is still busy, we give up */ - if (timeout >= MAX_TIMEOUT) { - pr_debug(DRV_NAME ": Busy wait timeout (%04x)\n", temp); - goto abort; - } - timeout = 0; - } - - /* start the transaction by setting the start bit */ - outw_p(inw(SMB_GLOBAL_ENABLE) | GE_HOST_STC, SMB_GLOBAL_ENABLE); - - /* We will always wait for a fraction of a second! */ - do { - i2c_delay(1); - temp = inw_p(SMB_GLOBAL_STATUS); - } while ((temp & GS_HST_STS) && (timeout++ < MAX_TIMEOUT)); - - /* If the SMBus is still busy, we give up */ - if (timeout >= MAX_TIMEOUT) { - pr_debug(DRV_NAME ": Completion timeout!\n"); - goto abort; - } - - if (temp & GS_PRERR_STS) { - result = -1; - pr_debug(DRV_NAME ": SMBus Protocol error (no response)!\n"); - } - - if (temp & GS_COL_STS) { - result = -1; - printk(KERN_WARNING DRV_NAME ": SMBus collision!\n"); - } - - if (temp & GS_TO_STS) { - result = -1; - pr_debug(DRV_NAME ": SMBus protocol timeout!\n"); - } - - if (temp & GS_HCYC_STS) - pr_debug(DRV_NAME ": SMBus protocol success!\n"); - - outw_p(GS_CLEAR_STS, SMB_GLOBAL_STATUS); - -#ifdef DEBUG - if (((temp = inw_p(SMB_GLOBAL_STATUS)) & GS_CLEAR_STS) != 0x00) { - pr_debug(DRV_NAME - ": Failed reset at end of transaction (%04x)\n", temp); - } - - pr_debug(DRV_NAME - ": Transaction (post): GS=%04x, GE=%04x, ADD=%04x, DAT=%04x\n", - inw_p(SMB_GLOBAL_STATUS), inw_p(SMB_GLOBAL_ENABLE), - inw_p(SMB_HOST_ADDRESS), inb_p(SMB_HOST_DATA)); -#endif - - return result; - - abort: - printk(KERN_WARNING DRV_NAME ": Sending abort.\n"); - outw_p(inw(SMB_GLOBAL_ENABLE) | GE_ABORT, SMB_GLOBAL_ENABLE); - i2c_delay(100); - outw_p(GS_CLEAR_STS, SMB_GLOBAL_STATUS); - return -1; -} - -/* Return -1 on error. */ - -static s32 amd756_access(struct i2c_adapter * adap, u16 addr, - unsigned short flags, char read_write, - u8 command, int size, union i2c_smbus_data * data) -{ - int i, len; - - switch (size) { - case I2C_SMBUS_QUICK: - outw_p(((addr & 0x7f) << 1) | (read_write & 0x01), - SMB_HOST_ADDRESS); - size = AMD756_QUICK; - break; - case I2C_SMBUS_BYTE: - outw_p(((addr & 0x7f) << 1) | (read_write & 0x01), - SMB_HOST_ADDRESS); - if (read_write == I2C_SMBUS_WRITE) - outb_p(command, SMB_HOST_DATA); - size = AMD756_BYTE; - break; - case I2C_SMBUS_BYTE_DATA: - outw_p(((addr & 0x7f) << 1) | (read_write & 0x01), - SMB_HOST_ADDRESS); - outb_p(command, SMB_HOST_COMMAND); - if (read_write == I2C_SMBUS_WRITE) - outw_p(data->byte, SMB_HOST_DATA); - size = AMD756_BYTE_DATA; - break; - case I2C_SMBUS_WORD_DATA: - outw_p(((addr & 0x7f) << 1) | (read_write & 0x01), - SMB_HOST_ADDRESS); - outb_p(command, SMB_HOST_COMMAND); - if (read_write == I2C_SMBUS_WRITE) - outw_p(data->word, SMB_HOST_DATA); /* TODO: endian???? */ - size = AMD756_WORD_DATA; - break; - case I2C_SMBUS_BLOCK_DATA: - outw_p(((addr & 0x7f) << 1) | (read_write & 0x01), - SMB_HOST_ADDRESS); - outb_p(command, SMB_HOST_COMMAND); - if (read_write == I2C_SMBUS_WRITE) { - len = data->block[0]; - if (len < 0) - len = 0; - if (len > 32) - len = 32; - outw_p(len, SMB_HOST_DATA); - /* i = inw_p(SMBHSTCNT); Reset SMBBLKDAT */ - for (i = 1; i <= len; i++) - outb_p(data->block[i], - SMB_HOST_BLOCK_DATA); - } - size = AMD756_BLOCK_DATA; - break; - default: - printk - (KERN_WARNING "i2c-amd756.o: Unsupported transaction %d\n", size); - return -1; - } - - /* How about enabling interrupts... */ - outw_p(size & GE_CYC_TYPE_MASK, SMB_GLOBAL_ENABLE); - - if (amd756_transaction()) /* Error in transaction */ - return -1; - - if ((read_write == I2C_SMBUS_WRITE) || (size == AMD756_QUICK)) - return 0; - - - switch (size) { - case AMD756_BYTE: - data->byte = inw_p(SMB_HOST_DATA); - break; - case AMD756_BYTE_DATA: - data->byte = inw_p(SMB_HOST_DATA); - break; - case AMD756_WORD_DATA: - data->word = inw_p(SMB_HOST_DATA); /* TODO: endian???? */ - break; - case AMD756_BLOCK_DATA: - data->block[0] = inw_p(SMB_HOST_DATA) & 0x3f; - if(data->block[0] > 32) - data->block[0] = 32; - /* i = inw_p(SMBHSTCNT); Reset SMBBLKDAT */ - for (i = 1; i <= data->block[0]; i++) - data->block[i] = inb_p(SMB_HOST_BLOCK_DATA); - break; - } - - return 0; -} - -static void amd756_inc(struct i2c_adapter *adapter) -{ -#ifdef MODULE - MOD_INC_USE_COUNT; -#endif -} - -static void amd756_dec(struct i2c_adapter *adapter) -{ -#ifdef MODULE - MOD_DEC_USE_COUNT; -#endif -} - -static u32 amd756_func(struct i2c_adapter *adapter) -{ - return I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE | - I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA | - I2C_FUNC_SMBUS_BLOCK_DATA; -} - -static struct i2c_algorithm smbus_algorithm = { - .name = "Non-I2C SMBus adapter", - .id = I2C_ALGO_SMBUS, - .smbus_xfer = amd756_access, - .functionality = amd756_func, -}; - -struct i2c_adapter amd756_smbus = { - .id = I2C_ALGO_SMBUS | I2C_HW_SMBUS_AMD756, - .algo = &smbus_algorithm, - .inc_use = amd756_inc, - .dec_use = amd756_dec, -}; - -enum chiptype { AMD756, AMD766, AMD768, NFORCE, AMD8111 }; -static const char* chipname[] = { - "AMD756", "AMD766", "AMD768", - "nVidia nForce", "AMD8111", -}; - -static struct pci_device_id amd756_ids[] __devinitdata = { - {PCI_VENDOR_ID_AMD, 0x740B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AMD756 }, - {PCI_VENDOR_ID_AMD, 0x7413, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AMD766 }, - {PCI_VENDOR_ID_AMD, 0x7443, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AMD768 }, - {PCI_VENDOR_ID_AMD, 0x746B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AMD8111 }, - {PCI_VENDOR_ID_NVIDIA, 0x01B4, PCI_ANY_ID, PCI_ANY_ID, 0, 0, NFORCE }, - { 0, } -}; - -static int __devinit amd756_probe(struct pci_dev *pdev, - const struct pci_device_id *id) -{ - int nforce = (id->driver_data == NFORCE); - int error; - u8 temp; - - if (amd756_ioport) { - printk(KERN_ERR DRV_NAME ": Only one device supported. " - "(you have a strange motherboard, btw..)\n"); - return -ENODEV; - } - - if (nforce) { - if (PCI_FUNC(pdev->devfn) != 1) - return -ENODEV; - - pci_read_config_word(pdev, SMBBANFORCE, &amd756_ioport); - amd756_ioport &= 0xfffc; - } else { /* amd */ - if (PCI_FUNC(pdev->devfn) != 3) - return -ENODEV; - - pci_read_config_byte(pdev, SMBGCFG, &temp); - if ((temp & 128) == 0) { - printk(KERN_ERR DRV_NAME - ": Error: SMBus controller I/O not enabled!\n"); - return -ENODEV; - } - - /* Determine the address of the SMBus areas */ - /* Technically it is a dword but... */ - pci_read_config_word(pdev, SMBBA, &amd756_ioport); - amd756_ioport &= 0xff00; - amd756_ioport += SMB_ADDR_OFFSET; - } - - if (!request_region(amd756_ioport, SMB_IOSIZE, "amd756-smbus")) { - printk(KERN_ERR DRV_NAME - ": SMB region 0x%x already in use!\n", amd756_ioport); - return -ENODEV; - } - -#ifdef DEBUG - pci_read_config_byte(pdev, SMBREV, &temp); - printk(KERN_DEBUG DRV_NAME ": SMBREV = 0x%X\n", temp); - printk(KERN_DEBUG DRV_NAME ": AMD756_smba = 0x%X\n", amd756_ioport); -#endif - - sprintf(amd756_smbus.name, "SMBus %s adapter at %04x", - chipname[id->driver_data], amd756_ioport); - - error = i2c_add_adapter(&amd756_smbus); - if (error) { - printk(KERN_ERR DRV_NAME - ": Adapter registration failed, module not inserted.\n"); - goto out_err; - } - - return 0; - - out_err: - release_region(amd756_ioport, SMB_IOSIZE); - return error; -} - - -static int __init i2c_amd756_init(void) -{ - struct pci_dev *dev; - const struct pci_device_id *id; - - printk(KERN_INFO "i2c-amd756.o version %s (%s)\n", LM_VERSION, LM_DATE); - - pci_for_each_dev(dev) { - id = pci_match_device(amd756_ids, dev); - if (id && amd756_probe(dev, id) >= 0) - return 0; - } - - return -ENODEV; -} - - -static void __exit i2c_amd756_exit(void) -{ - i2c_del_adapter(&amd756_smbus); - release_region(amd756_ioport, SMB_IOSIZE); -} - -MODULE_AUTHOR("Merlin Hughes "); -MODULE_DESCRIPTION("AMD756/766/768/8111 and nVidia nForce SMBus driver"); -MODULE_LICENSE("GPL"); - -EXPORT_SYMBOL(amd756_smbus); - -module_init(i2c_amd756_init) -module_exit(i2c_amd756_exit) diff --git a/kernel/busses/i2c-amd8111.c b/kernel/busses/i2c-amd8111.c deleted file mode 100644 index a6bc973a..00000000 --- a/kernel/busses/i2c-amd8111.c +++ /dev/null @@ -1,424 +0,0 @@ -/* - * SMBus 2.0 driver for AMD-8111 IO-Hub. - * - * Copyright (c) 2002 Vojtech Pavlik - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation version 2. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "version.h" -#include "sensors_compat.h" - -#ifndef I2C_HW_SMBUS_AMD8111 -#error Your i2c is too old - i2c-2.7.0 or greater required! -#endif - -MODULE_LICENSE("GPL"); -MODULE_AUTHOR ("Vojtech Pavlik "); -MODULE_DESCRIPTION("AMD8111 SMBus 2.0 driver"); - -struct amd_smbus { - struct pci_dev *dev; - struct i2c_adapter adapter; - int base; - int size; -}; - -static struct pci_driver amd8111_driver; - -/* - * AMD PCI control registers definitions. - */ - -#define AMD_PCI_MISC 0x48 - -#define AMD_PCI_MISC_SCI 0x04 /* deliver SCI */ -#define AMD_PCI_MISC_INT 0x02 /* deliver PCI IRQ */ -#define AMD_PCI_MISC_SPEEDUP 0x01 /* 16x clock speedup */ - -/* - * ACPI 2.0 chapter 13 PCI interface definitions. - */ - -#define AMD_EC_DATA 0x00 /* data register */ -#define AMD_EC_SC 0x04 /* status of controller */ -#define AMD_EC_CMD 0x04 /* command register */ -#define AMD_EC_ICR 0x08 /* interrupt control register */ - -#define AMD_EC_SC_SMI 0x04 /* smi event pending */ -#define AMD_EC_SC_SCI 0x02 /* sci event pending */ -#define AMD_EC_SC_BURST 0x01 /* burst mode enabled */ -#define AMD_EC_SC_CMD 0x08 /* byte in data reg is command */ -#define AMD_EC_SC_IBF 0x02 /* data ready for embedded controller */ -#define AMD_EC_SC_OBF 0x01 /* data ready for host */ - -#define AMD_EC_CMD_RD 0x80 /* read EC */ -#define AMD_EC_CMD_WR 0x81 /* write EC */ -#define AMD_EC_CMD_BE 0x82 /* enable burst mode */ -#define AMD_EC_CMD_BD 0x83 /* disable burst mode */ -#define AMD_EC_CMD_QR 0x84 /* query EC */ - -/* - * ACPI 2.0 chapter 13 access of registers of the EC - */ - -unsigned int amd_ec_wait_write(struct amd_smbus *smbus) -{ - int timeout = 500; - - while (timeout-- && (inb(smbus->base + AMD_EC_SC) & AMD_EC_SC_IBF)) - udelay(1); - - if (!timeout) { - printk(KERN_WARNING "i2c-amd8111.c: Timeout while waiting for IBF to clear\n"); - return -1; - } - - return 0; -} - -unsigned int amd_ec_wait_read(struct amd_smbus *smbus) -{ - int timeout = 500; - - while (timeout-- && (~inb(smbus->base + AMD_EC_SC) & AMD_EC_SC_OBF)) - udelay(1); - - if (!timeout) { - printk(KERN_WARNING "i2c-amd8111.c: Timeout while waiting for OBF to set\n"); - return -1; - } - - return 0; -} - -unsigned int amd_ec_read(struct amd_smbus *smbus, unsigned char address, unsigned char *data) -{ - if (amd_ec_wait_write(smbus)) - return -1; - outb(AMD_EC_CMD_RD, smbus->base + AMD_EC_CMD); - - if (amd_ec_wait_write(smbus)) - return -1; - outb(address, smbus->base + AMD_EC_DATA); - - if (amd_ec_wait_read(smbus)) - return -1; - *data = inb(smbus->base + AMD_EC_DATA); - - return 0; -} - -unsigned int amd_ec_write(struct amd_smbus *smbus, unsigned char address, unsigned char data) -{ - if (amd_ec_wait_write(smbus)) - return -1; - outb(AMD_EC_CMD_WR, smbus->base + AMD_EC_CMD); - - if (amd_ec_wait_write(smbus)) - return -1; - outb(address, smbus->base + AMD_EC_DATA); - - if (amd_ec_wait_write(smbus)) - return -1; - outb(data, smbus->base + AMD_EC_DATA); - - return 0; -} - -/* - * ACPI 2.0 chapter 13 SMBus 2.0 EC register model - */ - -#define AMD_SMB_PRTCL 0x00 /* protocol, PEC */ -#define AMD_SMB_STS 0x01 /* status */ -#define AMD_SMB_ADDR 0x02 /* address */ -#define AMD_SMB_CMD 0x03 /* command */ -#define AMD_SMB_DATA 0x04 /* 32 data registers */ -#define AMD_SMB_BCNT 0x24 /* number of data bytes */ -#define AMD_SMB_ALRM_A 0x25 /* alarm address */ -#define AMD_SMB_ALRM_D 0x26 /* 2 bytes alarm data */ - -#define AMD_SMB_STS_DONE 0x80 -#define AMD_SMB_STS_ALRM 0x40 -#define AMD_SMB_STS_RES 0x20 -#define AMD_SMB_STS_STATUS 0x1f - -#define AMD_SMB_STATUS_OK 0x00 -#define AMD_SMB_STATUS_FAIL 0x07 -#define AMD_SMB_STATUS_DNAK 0x10 -#define AMD_SMB_STATUS_DERR 0x11 -#define AMD_SMB_STATUS_CMD_DENY 0x12 -#define AMD_SMB_STATUS_UNKNOWN 0x13 -#define AMD_SMB_STATUS_ACC_DENY 0x17 -#define AMD_SMB_STATUS_TIMEOUT 0x18 -#define AMD_SMB_STATUS_NOTSUP 0x19 -#define AMD_SMB_STATUS_BUSY 0x1A -#define AMD_SMB_STATUS_PEC 0x1F - -#define AMD_SMB_PRTCL_WRITE 0x00 -#define AMD_SMB_PRTCL_READ 0x01 -#define AMD_SMB_PRTCL_QUICK 0x02 -#define AMD_SMB_PRTCL_BYTE 0x04 -#define AMD_SMB_PRTCL_BYTE_DATA 0x06 -#define AMD_SMB_PRTCL_WORD_DATA 0x08 -#define AMD_SMB_PRTCL_BLOCK_DATA 0x0a -#define AMD_SMB_PRTCL_PROC_CALL 0x0c -#define AMD_SMB_PRTCL_BLOCK_PROC_CALL 0x0d -#define AMD_SMB_PRTCL_I2C_BLOCK_DATA 0x4a -#define AMD_SMB_PRTCL_PEC 0x80 - - -s32 amd8111_access(struct i2c_adapter * adap, u16 addr, unsigned short flags, - char read_write, u8 command, int size, union i2c_smbus_data * data) -{ - struct amd_smbus *smbus = adap->algo_data; - unsigned char protocol, len, pec, temp[2]; - int i; - - protocol = (read_write == I2C_SMBUS_READ) ? AMD_SMB_PRTCL_READ : AMD_SMB_PRTCL_WRITE; - pec = (flags & I2C_CLIENT_PEC) ? AMD_SMB_PRTCL_PEC : 0; - - switch (size) { - - case I2C_SMBUS_QUICK: - protocol |= AMD_SMB_PRTCL_QUICK; - read_write = I2C_SMBUS_WRITE; - break; - - case I2C_SMBUS_BYTE: - if (read_write == I2C_SMBUS_WRITE) - amd_ec_write(smbus, AMD_SMB_CMD, command); - protocol |= AMD_SMB_PRTCL_BYTE; - break; - - case I2C_SMBUS_BYTE_DATA: - amd_ec_write(smbus, AMD_SMB_CMD, command); - if (read_write == I2C_SMBUS_WRITE) - amd_ec_write(smbus, AMD_SMB_DATA, data->byte); - protocol |= AMD_SMB_PRTCL_BYTE_DATA; - break; - - case I2C_SMBUS_WORD_DATA: - amd_ec_write(smbus, AMD_SMB_CMD, command); - if (read_write == I2C_SMBUS_WRITE) { - amd_ec_write(smbus, AMD_SMB_DATA, data->word & 0xff); - amd_ec_write(smbus, AMD_SMB_DATA + 1, data->word >> 8); - } - protocol |= AMD_SMB_PRTCL_WORD_DATA | pec; - break; - - case I2C_SMBUS_BLOCK_DATA: - amd_ec_write(smbus, AMD_SMB_CMD, command); - if (read_write == I2C_SMBUS_WRITE) { - len = min_t(u8, data->block[0], I2C_SMBUS_BLOCK_MAX); - amd_ec_write(smbus, AMD_SMB_BCNT, len); - for (i = 0; i < len; i++) - amd_ec_write(smbus, AMD_SMB_DATA + i, data->block[i + 1]); - } - protocol |= AMD_SMB_PRTCL_BLOCK_DATA | pec; - break; - - case I2C_SMBUS_I2C_BLOCK_DATA: - len = min_t(u8, data->block[0], I2C_SMBUS_BLOCK_MAX); - amd_ec_write(smbus, AMD_SMB_CMD, command); - amd_ec_write(smbus, AMD_SMB_BCNT, len); - if (read_write == I2C_SMBUS_WRITE) - for (i = 0; i < len; i++) - amd_ec_write(smbus, AMD_SMB_DATA + i, data->block[i + 1]); - protocol |= AMD_SMB_PRTCL_I2C_BLOCK_DATA; - break; - - case I2C_SMBUS_PROC_CALL: - amd_ec_write(smbus, AMD_SMB_CMD, command); - amd_ec_write(smbus, AMD_SMB_DATA, data->word & 0xff); - amd_ec_write(smbus, AMD_SMB_DATA + 1, data->word >> 8); - protocol = AMD_SMB_PRTCL_PROC_CALL | pec; - read_write = I2C_SMBUS_READ; - break; - - case I2C_SMBUS_BLOCK_PROC_CALL: - len = min_t(u8, data->block[0], I2C_SMBUS_BLOCK_MAX - 1); - amd_ec_write(smbus, AMD_SMB_CMD, command); - amd_ec_write(smbus, AMD_SMB_BCNT, len); - for (i = 0; i < len; i++) - amd_ec_write(smbus, AMD_SMB_DATA + i, data->block[i + 1]); - protocol = AMD_SMB_PRTCL_BLOCK_PROC_CALL | pec; - read_write = I2C_SMBUS_READ; - break; - - default: - printk(KERN_WARNING "i2c-amd8111.c: Unsupported transaction %d\n", size); - return -1; - } - - amd_ec_write(smbus, AMD_SMB_ADDR, addr << 1); - amd_ec_write(smbus, AMD_SMB_PRTCL, protocol); - - amd_ec_read(smbus, AMD_SMB_STS, temp + 0); - - if (~temp[0] & AMD_SMB_STS_DONE) { - udelay(500); - amd_ec_read(smbus, AMD_SMB_STS, temp + 0); - } - - if (~temp[0] & AMD_SMB_STS_DONE) { - i2c_delay(HZ/100); - amd_ec_read(smbus, AMD_SMB_STS, temp + 0); - } - - if ((~temp[0] & AMD_SMB_STS_DONE) || (temp[0] & AMD_SMB_STS_STATUS)) - return -1; - - if (read_write == I2C_SMBUS_WRITE) - return 0; - - switch (size) { - - case I2C_SMBUS_BYTE: - case I2C_SMBUS_BYTE_DATA: - amd_ec_read(smbus, AMD_SMB_DATA, &data->byte); - break; - - case I2C_SMBUS_WORD_DATA: - case I2C_SMBUS_PROC_CALL: - amd_ec_read(smbus, AMD_SMB_DATA, temp + 0); - amd_ec_read(smbus, AMD_SMB_DATA + 1, temp + 1); - data->word = (temp[1] << 8) | temp[0]; - break; - - case I2C_SMBUS_BLOCK_DATA: - case I2C_SMBUS_BLOCK_PROC_CALL: - amd_ec_read(smbus, AMD_SMB_BCNT, &len); - len = min_t(u8, len, I2C_SMBUS_BLOCK_MAX); - case I2C_SMBUS_I2C_BLOCK_DATA: - for (i = 0; i < len; i++) - amd_ec_read(smbus, AMD_SMB_DATA + i, data->block + i + 1); - data->block[0] = len; - break; - } - - return 0; -} - -static void amd8111_inc(struct i2c_adapter *adapter) -{ -#ifdef MODULE - MOD_INC_USE_COUNT; -#endif -} - -static void amd8111_dec(struct i2c_adapter *adapter) -{ -#ifdef MODULE - MOD_DEC_USE_COUNT; -#endif -} - -u32 amd8111_func(struct i2c_adapter *adapter) -{ - return I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE | I2C_FUNC_SMBUS_BYTE_DATA | - I2C_FUNC_SMBUS_WORD_DATA | I2C_FUNC_SMBUS_BLOCK_DATA | - I2C_FUNC_SMBUS_PROC_CALL | I2C_FUNC_SMBUS_BLOCK_PROC_CALL | - I2C_FUNC_SMBUS_I2C_BLOCK | I2C_FUNC_SMBUS_HWPEC_CALC; -} - -static struct i2c_algorithm smbus_algorithm = { - .name = "Non-I2C SMBus 2.0 adapter", - .id = I2C_ALGO_SMBUS, - .smbus_xfer = amd8111_access, - .functionality = amd8111_func, -}; - - -static struct pci_device_id amd8111_ids[] __devinitdata = { - { 0x1022, 0x746a, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, - { 0, } -}; - -static int __devinit amd8111_probe(struct pci_dev *dev, const struct pci_device_id *id) -{ - struct amd_smbus *smbus; - int error; - - if (!(pci_resource_flags(dev, 0) & IORESOURCE_IO)) - return -ENODEV; - - if (!(smbus = kmalloc(sizeof(struct amd_smbus), GFP_KERNEL))) - return -ENOMEM; - memset(smbus, 0, sizeof(struct amd_smbus)); - - pci_set_drvdata(dev, smbus); - smbus->dev = dev; - smbus->base = pci_resource_start(dev, 0); - smbus->size = pci_resource_len(dev, 0); - - if (!request_region(smbus->base, smbus->size, amd8111_driver.name)) { - kfree(smbus); - return -EBUSY; - } - - sprintf(smbus->adapter.name, "SMBus2 AMD8111 adapter at %04x", smbus->base); - smbus->adapter.id = I2C_ALGO_SMBUS | I2C_HW_SMBUS_AMD8111; - smbus->adapter.algo = &smbus_algorithm; - smbus->adapter.algo_data = smbus; - smbus->adapter.inc_use = amd8111_inc; - smbus->adapter.dec_use = amd8111_dec; - - pci_write_config_dword(smbus->dev, AMD_PCI_MISC, 0); - - error = i2c_add_adapter(&smbus->adapter); - if (error) { - printk(KERN_WARNING "i2c-amd8111.c: Failed to register adapter.\n"); - release_region(smbus->base, smbus->size); - kfree(smbus); - return error; - } - - printk(KERN_INFO "i2c-amd8111.c: AMD8111 SMBus 2.0 adapter at %#x\n", smbus->base); - return 0; -} - - -static void __devexit amd8111_remove(struct pci_dev *dev) -{ - struct amd_smbus *smbus = (void*) pci_get_drvdata(dev); - i2c_del_adapter(&smbus->adapter); - release_region(smbus->base, smbus->size); - kfree(smbus); -} - -static struct pci_driver amd8111_driver = { - .name = "amd8111 smbus 2.0", - .id_table = amd8111_ids, - .probe = amd8111_probe, - .remove = __devexit_p(amd8111_remove), -}; - -static int __init i2c_amd8111_init(void) -{ - printk(KERN_INFO "i2c-amd8111.o version %s (%s)\n", LM_VERSION, LM_DATE); - return pci_module_init(&amd8111_driver); -} - - -static void __exit i2c_amd8111_exit(void) -{ - pci_unregister_driver(&amd8111_driver); -} - -module_init(i2c_amd8111_init); -module_exit(i2c_amd8111_exit); diff --git a/kernel/busses/i2c-hydra.c b/kernel/busses/i2c-hydra.c deleted file mode 100644 index eb904e9f..00000000 --- a/kernel/busses/i2c-hydra.c +++ /dev/null @@ -1,191 +0,0 @@ -/* - i2c-hydra.c - Part of lm_sensors, Linux kernel modules - for hardware monitoring - - i2c Support for the Apple `Hydra' Mac I/O - - Copyright (c) 1999 Geert Uytterhoeven - - Based on i2c Support for Via Technologies 82C586B South Bridge - Copyright (c) 1998, 1999 Kyösti Mälkki - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include /* for HZ */ -#include "sensors_compat.h" - -MODULE_LICENSE("GPL"); - - -#define HYDRA_CACHE_PD 0x00000030 - -#define HYDRA_CPD_PD0 0x00000001 /* CachePD lines */ -#define HYDRA_CPD_PD1 0x00000002 -#define HYDRA_CPD_PD2 0x00000004 -#define HYDRA_CPD_PD3 0x00000008 - -#define HYDRA_SCLK HYDRA_CPD_PD0 -#define HYDRA_SDAT HYDRA_CPD_PD1 -#define HYDRA_SCLK_OE 0x00000010 -#define HYDRA_SDAT_OE 0x00000020 - -static unsigned long hydra_base; - -static inline void pdregw(u32 val) -{ - writel(val, hydra_base + HYDRA_CACHE_PD); -} - -static inline u32 pdregr(void) -{ - u32 val = readl(hydra_base + HYDRA_CACHE_PD); - return val; -} - -static void bit_hydra_setscl(void *data, int state) -{ - u32 val = pdregr(); - if (state) - val &= ~HYDRA_SCLK_OE; - else { - val &= ~HYDRA_SCLK; - val |= HYDRA_SCLK_OE; - } - pdregw(val); - pdregr(); /* flush posted write */ -} - -static void bit_hydra_setsda(void *data, int state) -{ - u32 val = pdregr(); - if (state) - val &= ~HYDRA_SDAT_OE; - else { - val &= ~HYDRA_SDAT; - val |= HYDRA_SDAT_OE; - } - pdregw(val); - pdregr(); /* flush posted write */ -} - -static int bit_hydra_getscl(void *data) -{ - return (pdregr() & HYDRA_SCLK) != 0; -} - -static int bit_hydra_getsda(void *data) -{ - return (pdregr() & HYDRA_SDAT) != 0; -} - -static void bit_hydra_inc(struct i2c_adapter *adap) -{ -#ifdef MODULE - MOD_INC_USE_COUNT; -#endif -} - -static void bit_hydra_dec(struct i2c_adapter *adap) -{ -#ifdef MODULE - MOD_DEC_USE_COUNT; -#endif -} - -/* ------------------------------------------------------------------------ */ - -static struct i2c_algo_bit_data bit_hydra_data = { - .setsda = bit_hydra_setsda, - .setscl = bit_hydra_setscl, - .getsda = bit_hydra_getsda, - .getscl = bit_hydra_getscl, - .udelay = 5, - .mdelay = 5, - .timeout = HZ -}; - -static struct i2c_adapter bit_hydra_ops = { - .name = "Hydra i2c", - .id = I2C_HW_B_HYDRA, - .algo_data = &bit_hydra_data, - .inc_use = bit_hydra_inc, - .dec_use = bit_hydra_dec, -}; - -static struct pci_device_id hydra_ids[] __devinitdata = { - { - .vendor = PCI_VENDOR_ID_APPLE, - .device = PCI_DEVICE_ID_APPLE_HYDRA, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - }, - { 0, } -}; - -static int __devinit hydra_probe(struct pci_dev *dev, const struct pci_device_id *id) -{ - unsigned int base_addr; - - base_addr = dev->resource[0].start; - hydra_base = (unsigned long) ioremap(base_addr, 0x100); - - pdregw(0); /* clear SCLK_OE and SDAT_OE */ - return i2c_bit_add_bus(&bit_hydra_ops); -} - -static void __devexit hydra_remove(struct pci_dev *dev) -{ - pdregw(0); /* clear SCLK_OE and SDAT_OE */ - i2c_bit_del_bus(&bit_hydra_ops); - iounmap((void *) hydra_base); -} - - -static struct pci_driver hydra_driver = { - .name = "hydra smbus", - .id_table = hydra_ids, - .probe = hydra_probe, - .remove = __devexit_p(hydra_remove), -}; - -static int __init i2c_hydra_init(void) -{ - return pci_module_init(&hydra_driver); -} - - -static void __exit i2c_hydra_exit(void) -{ - pci_unregister_driver(&hydra_driver); -} - - - -MODULE_AUTHOR("Geert Uytterhoeven "); -MODULE_DESCRIPTION("i2c for Apple Hydra Mac I/O"); - -module_init(i2c_hydra_init); -module_exit(i2c_hydra_exit); - diff --git a/kernel/busses/i2c-i801.c b/kernel/busses/i2c-i801.c deleted file mode 100644 index aaf0afa7..00000000 --- a/kernel/busses/i2c-i801.c +++ /dev/null @@ -1,743 +0,0 @@ -/* - i2c-i801.c - Part of lm_sensors, Linux kernel modules for hardware - monitoring - Copyright (c) 1998 - 2002 Frodo Looijaard , - Philip Edelbrock , and Mark D. Studebaker - - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -/* - SUPPORTED DEVICES PCI ID - 82801AA 2413 - 82801AB 2423 - 82801BA 2443 - 82801CA/CAM 2483 - 82801DB 24C3 (HW PEC supported, 32 byte buffer not supported) - 82801EB 24D3 (HW PEC supported, 32 byte buffer not supported) - 6300ESB 25A4 ("") - ICH6 266A ("") - ICH7 27DA ("") - ESB2 269B ("") - ICH8 283E ("") - ICH9 2930 ("") - Tolapai 5032 ("") - ICH10 3A30 ("") - ICH10 3A60 ("") - PCH 3B30 ("") - - This driver supports several versions of Intel's I/O Controller Hubs (ICH). - For SMBus support, they are similar to the PIIX4 and are part - of Intel's '810' and other chipsets. - See the doc/busses/i2c-i801 file for details. - I2C Block Read not supported. - Block Process Call are not supported. -*/ - -/* Note: we assume there can only be one I801, with one SMBus interface */ - -/* #define DEBUG 1 */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "version.h" -#include "sensors_compat.h" - -/* 82801CA is undefined before kernel 2.4.13 */ -#ifndef PCI_DEVICE_ID_INTEL_82801CA_3 -#define PCI_DEVICE_ID_INTEL_82801CA_3 0x2483 -#endif - -/* 82801DB is undefined before kernel 2.4.19 */ -#ifndef PCI_DEVICE_ID_INTEL_82801DB_3 -#define PCI_DEVICE_ID_INTEL_82801DB_3 0x24c3 -#endif - -/* 82801EB is undefined before kernel 2.4.21 */ -#ifndef PCI_DEVICE_ID_INTEL_82801EB_3 -#define PCI_DEVICE_ID_INTEL_82801EB_3 0x24d3 -#endif - -/* ESB is undefined before kernel 2.4.22 */ -#ifndef PCI_DEVICE_ID_INTEL_ESB_4 -#define PCI_DEVICE_ID_INTEL_ESB_4 0x25a4 -#endif - -/* ESB2 - Enterprise Southbridge is undefined */ -#ifndef PCI_DEVICE_ID_INTEL_ESB2_17 -#define PCI_DEVICE_ID_INTEL_ESB2_17 0x269b -#endif - -/* ICH6 is undefined */ -#ifndef PCI_DEVICE_ID_INTEL_ICH6_16 -#define PCI_DEVICE_ID_INTEL_ICH6_16 0x266a -#endif - -/* ICH7 is undefined */ -#ifndef PCI_DEVICE_ID_INTEL_ICH7_17 -#define PCI_DEVICE_ID_INTEL_ICH7_17 0x27da -#endif - -/* ICH8 is undefined */ -#ifndef PCI_DEVICE_ID_INTEL_ICH8_5 -#define PCI_DEVICE_ID_INTEL_ICH8_5 0x283e -#endif - -/* ICH9 is undefined */ -#ifndef PCI_DEVICE_ID_INTEL_ICH9_6 -#define PCI_DEVICE_ID_INTEL_ICH9_6 0x2930 -#endif - -#ifndef PCI_DEVICE_ID_INTEL_TOLAPAI_1 -#define PCI_DEVICE_ID_INTEL_TOLAPAI_1 0x5032 -#endif - -#ifndef PCI_DEVICE_ID_INTEL_ICH10_4 -#define PCI_DEVICE_ID_INTEL_ICH10_4 0x3a30 -#endif - -#ifndef PCI_DEVICE_ID_INTEL_ICH10_5 -#define PCI_DEVICE_ID_INTEL_ICH10_5 0x3a60 -#endif - -#ifndef PCI_DEVICE_ID_INTEL_PCH_SMBUS -#define PCI_DEVICE_ID_INTEL_PCH_SMBUS 0x3b30 -#endif - -#ifdef I2C_CLIENT_PEC -#define HAVE_PEC -#endif - -/* I801 SMBus address offsets */ -#define SMBHSTSTS (0 + i801_smba) -#define SMBHSTCNT (2 + i801_smba) -#define SMBHSTCMD (3 + i801_smba) -#define SMBHSTADD (4 + i801_smba) -#define SMBHSTDAT0 (5 + i801_smba) -#define SMBHSTDAT1 (6 + i801_smba) -#define SMBBLKDAT (7 + i801_smba) -#define SMBPEC (8 + i801_smba) /* ICH4 only */ -#define SMBAUXSTS (12 + i801_smba) /* ICH4 only */ -#define SMBAUXCTL (13 + i801_smba) /* ICH4 only */ - -/* PCI Address Constants */ -#define SMBBA 0x020 -#define SMBHSTCFG 0x040 -#define SMBREV 0x008 - -/* Host configuration bits for SMBHSTCFG */ -#define SMBHSTCFG_HST_EN 1 -#define SMBHSTCFG_SMB_SMI_EN 2 -#define SMBHSTCFG_I2C_EN 4 - -/* Other settings */ -#define MAX_TIMEOUT 100 -#define ENABLE_INT9 0 /* set to 0x01 to enable - untested */ - -/* I801 command constants */ -#define I801_QUICK 0x00 -#define I801_BYTE 0x04 -#define I801_BYTE_DATA 0x08 -#define I801_WORD_DATA 0x0C -#define I801_PROC_CALL 0x10 /* later chips only, unimplemented */ -#define I801_BLOCK_DATA 0x14 -#define I801_I2C_BLOCK_DATA 0x18 /* unimplemented */ -#define I801_BLOCK_LAST 0x34 -#define I801_I2C_BLOCK_LAST 0x38 /* unimplemented */ -#define I801_START 0x40 -#define I801_PEC_EN 0x80 /* ich4 and later */ - -/* insmod parameters */ - -/* If force_addr is set to anything different from 0, we forcibly enable - the I801 at the given address. VERY DANGEROUS! */ -static int force_addr = 0; -MODULE_PARM(force_addr, "i"); -MODULE_PARM_DESC(force_addr, - "Forcibly enable the I801 at the given address. " - "EXTREMELY DANGEROUS!"); - -static unsigned short i801_smba; -static struct pci_driver i801_driver; -static struct pci_dev *I801_dev; -static int isich4; /* is PEC supported? */ - -static int __devinit i801_setup(struct pci_dev *dev) -{ - unsigned char temp; - - I801_dev = dev; - if (dev->device == PCI_DEVICE_ID_INTEL_82801DB_3 || - dev->device == PCI_DEVICE_ID_INTEL_82801EB_3 || - dev->device == PCI_DEVICE_ID_INTEL_ESB_4 || - dev->device == PCI_DEVICE_ID_INTEL_ESB2_17 || - dev->device == PCI_DEVICE_ID_INTEL_ICH6_16 || - dev->device == PCI_DEVICE_ID_INTEL_ICH7_17 || - dev->device == PCI_DEVICE_ID_INTEL_ICH8_5 || - dev->device == PCI_DEVICE_ID_INTEL_ICH9_6 || - dev->device == PCI_DEVICE_ID_INTEL_TOLAPAI_1 || - dev->device == PCI_DEVICE_ID_INTEL_ICH10_4 || - dev->device == PCI_DEVICE_ID_INTEL_ICH10_5 || - dev->device == PCI_DEVICE_ID_INTEL_PCH_SMBUS) - isich4 = 1; - else - isich4 = 0; - - /* Determine the address of the SMBus area */ - if (force_addr) { - i801_smba = force_addr & 0xfff0; - } else { - pci_read_config_word(I801_dev, SMBBA, &i801_smba); - i801_smba &= 0xfff0; - if(i801_smba == 0) { - dev_err(dev, "SMB base address uninitialized " - "- upgrade BIOS or use force_addr=0xaddr\n"); - return -ENODEV; - } - } - - if (!request_region(i801_smba, (isich4 ? 16 : 8), i801_driver.name)) { - dev_err(dev, "I801_smb region 0x%x already in use!\n", - i801_smba); - return -EBUSY; - } - - pci_read_config_byte(I801_dev, SMBHSTCFG, &temp); - temp &= ~SMBHSTCFG_I2C_EN; /* SMBus timing */ - pci_write_config_byte(I801_dev, SMBHSTCFG, temp); - - /* If force_addr is set, we program the new address here. Just to make - sure, we disable the device first. */ - if (force_addr) { - pci_write_config_byte(I801_dev, SMBHSTCFG, - temp & ~SMBHSTCFG_HST_EN); - pci_write_config_word(I801_dev, SMBBA, i801_smba); - pci_write_config_byte(I801_dev, SMBHSTCFG, - temp | SMBHSTCFG_HST_EN); - dev_warn(dev, "WARNING: I801 SMBus interface set to " - "new address %04x!\n", i801_smba); - } else if (!(temp & SMBHSTCFG_HST_EN)) { - pci_write_config_byte(I801_dev, SMBHSTCFG, - temp | SMBHSTCFG_HST_EN); - dev_warn(dev, "enabling SMBus device\n"); - } - - if (temp & SMBHSTCFG_SMB_SMI_EN) - dev_dbg(dev, "I801 using Interrupt SMI# for SMBus.\n"); - else - dev_dbg(dev, "I801 using PCI Interrupt for SMBus.\n"); - - pci_read_config_byte(I801_dev, SMBREV, &temp); - dev_dbg(dev, "SMBREV = 0x%X\n", temp); - dev_dbg(dev, "I801_smba = 0x%X\n", i801_smba); - - return 0; -} - - -static int i801_transaction(void) -{ - int temp; - int result = 0; - int timeout = 0; - - /* Make sure the SMBus host is ready to start transmitting */ - /* 0x1f = Failed, Bus_Err, Dev_Err, Intr, Host_Busy */ - if ((temp = (0x1f & inb_p(SMBHSTSTS))) != 0x00) { - dev_dbg(I801_dev, "SMBus busy (%02x). Resetting...\n", - temp); - outb_p(temp, SMBHSTSTS); - if ((temp = (0x1f & inb_p(SMBHSTSTS))) != 0x00) { - dev_dbg(I801_dev, "Failed! (%02x)\n", temp); - return -1; - } else { - dev_dbg(I801_dev, "Successful!\n"); - } - } - - outb_p(inb(SMBHSTCNT) | I801_START, SMBHSTCNT); - - /* We will always wait for a fraction of a second! */ - do { - i2c_delay(1); - temp = inb_p(SMBHSTSTS); - } while ((temp & 0x01) && (timeout++ < MAX_TIMEOUT)); - - /* If the SMBus is still busy, we give up */ - if (timeout >= MAX_TIMEOUT) { - dev_dbg(I801_dev, "SMBus Timeout!\n"); - result = -1; - } - - if (temp & 0x10) { - result = -1; - dev_dbg(I801_dev, "Error: Failed bus transaction\n"); - } - - if (temp & 0x08) { - result = -1; - dev_err(I801_dev, "Lost arbitration\n"); - } - - if (temp & 0x04) { - result = -1; - dev_dbg(I801_dev, "Error: no response!\n"); - } - - if ((inb_p(SMBHSTSTS) & 0x1f) != 0x00) - outb_p(inb(SMBHSTSTS), SMBHSTSTS); - - if ((temp = (0x1f & inb_p(SMBHSTSTS))) != 0x00) { - dev_dbg(I801_dev, "Failed reset at end of transaction " - "(%02x)\n", temp); - } - return result; -} - -/* All-inclusive block transaction function */ -static int i801_block_transaction(union i2c_smbus_data *data, char read_write, - int command, int hwpec) -{ - int i, len; - int smbcmd; - int temp; - int result = 0; - int timeout; - unsigned char hostc, errmask; - - if (command == I2C_SMBUS_I2C_BLOCK_DATA) { - if (read_write == I2C_SMBUS_WRITE) { - /* set I2C_EN bit in configuration register */ - pci_read_config_byte(I801_dev, SMBHSTCFG, &hostc); - pci_write_config_byte(I801_dev, SMBHSTCFG, - hostc | SMBHSTCFG_I2C_EN); - } else { - dev_err(I801_dev, - "I2C_SMBUS_I2C_BLOCK_READ unsupported!\n"); - return -1; - } - } - - if (read_write == I2C_SMBUS_WRITE) { - len = data->block[0]; - if (len < 1) - len = 1; - if (len > I2C_SMBUS_BLOCK_MAX) - len = I2C_SMBUS_BLOCK_MAX; - outb_p(len, SMBHSTDAT0); - outb_p(data->block[1], SMBBLKDAT); - } else { - len = 32; /* max for reads */ - } - - for (i = 1; i <= len; i++) { - if (i == len && read_write == I2C_SMBUS_READ) - smbcmd = I801_BLOCK_LAST; - else - smbcmd = I801_BLOCK_DATA; - outb_p(smbcmd | ENABLE_INT9, SMBHSTCNT); - - /* Make sure the SMBus host is ready to start transmitting */ - temp = inb_p(SMBHSTSTS); - if (i == 1) { - /* Erroneous conditions before transaction: - * Byte_Done, Failed, Bus_Err, Dev_Err, Intr, Host_Busy */ - errmask = 0x9f; - } else { - /* Erroneous conditions during transaction: - * Failed, Bus_Err, Dev_Err, Intr */ - errmask = 0x1e; - } - if (temp & errmask) { - dev_dbg(I801_dev, "SMBus busy (%02x). " - "Resetting...\n", temp); - outb_p(temp, SMBHSTSTS); - if (((temp = inb_p(SMBHSTSTS)) & errmask) != 0x00) { - dev_err(I801_dev, - "Reset failed! (%02x)\n", temp); - result = -1; - goto END; - } - if (i != 1) { - /* if die in middle of block transaction, fail */ - result = -1; - goto END; - } - } - - if (i == 1) - outb_p(inb(SMBHSTCNT) | I801_START, SMBHSTCNT); - - /* We will always wait for a fraction of a second! */ - timeout = 0; - do { - i2c_delay(1); - temp = inb_p(SMBHSTSTS); - } - while ((!(temp & 0x80)) - && (timeout++ < MAX_TIMEOUT)); - - /* If the SMBus is still busy, we give up */ - if (timeout >= MAX_TIMEOUT) { - result = -1; - dev_dbg(I801_dev, "SMBus Timeout!\n"); - } - - if (temp & 0x10) { - result = -1; - dev_dbg(I801_dev, - "Error: Failed bus transaction\n"); - } else if (temp & 0x08) { - result = -1; - dev_err(I801_dev, "Lost arbitration\n"); - } else if (temp & 0x04) { - result = -1; - dev_dbg(I801_dev, "Error: no response!\n"); - } - - if (i == 1 && read_write == I2C_SMBUS_READ) { - len = inb_p(SMBHSTDAT0); - if (len < 1) - len = 1; - if (len > I2C_SMBUS_BLOCK_MAX) - len = I2C_SMBUS_BLOCK_MAX; - data->block[0] = len; - } - - /* Retrieve/store value in SMBBLKDAT */ - if (read_write == I2C_SMBUS_READ) - data->block[i] = inb_p(SMBBLKDAT); - if (read_write == I2C_SMBUS_WRITE && i+1 <= len) - outb_p(data->block[i+1], SMBBLKDAT); - if ((temp & 0x9e) != 0x00) - outb_p(temp, SMBHSTSTS); /* signals SMBBLKDAT ready */ - - if ((temp = (0x1e & inb_p(SMBHSTSTS))) != 0x00) { - dev_dbg(I801_dev, - "Bad status (%02x) at end of transaction\n", - temp); - } - - if (result < 0) - goto END; - } - - if (hwpec) { - /* wait for INTR bit as advised by Intel */ - timeout = 0; - do { - i2c_delay(1); - temp = inb_p(SMBHSTSTS); - } while ((!(temp & 0x02)) - && (timeout++ < MAX_TIMEOUT)); - - if (timeout >= MAX_TIMEOUT) { - dev_dbg(I801_dev, "PEC Timeout!\n"); - } - outb_p(temp, SMBHSTSTS); - } - result = 0; -END: - if (command == I2C_SMBUS_I2C_BLOCK_DATA && - read_write == I2C_SMBUS_WRITE) { - /* restore saved configuration register value */ - pci_write_config_byte(I801_dev, SMBHSTCFG, hostc); - } - return result; -} - -/* Return -1 on error. */ -static s32 i801_access(struct i2c_adapter * adap, u16 addr, - unsigned short flags, char read_write, u8 command, - int size, union i2c_smbus_data * data) -{ - int hwpec = 0; - int block = 0; - int ret, xact = 0; - -#ifdef HAVE_PEC - hwpec = isich4 && (flags & I2C_CLIENT_PEC) - && size != I2C_SMBUS_QUICK - && size != I2C_SMBUS_I2C_BLOCK_DATA; -#endif - - switch (size) { - case I2C_SMBUS_QUICK: - outb_p(((addr & 0x7f) << 1) | (read_write & 0x01), - SMBHSTADD); - xact = I801_QUICK; - break; - case I2C_SMBUS_BYTE: - outb_p(((addr & 0x7f) << 1) | (read_write & 0x01), - SMBHSTADD); - if (read_write == I2C_SMBUS_WRITE) - outb_p(command, SMBHSTCMD); - xact = I801_BYTE; - break; - case I2C_SMBUS_BYTE_DATA: - outb_p(((addr & 0x7f) << 1) | (read_write & 0x01), - SMBHSTADD); - outb_p(command, SMBHSTCMD); - if (read_write == I2C_SMBUS_WRITE) - outb_p(data->byte, SMBHSTDAT0); - xact = I801_BYTE_DATA; - break; - case I2C_SMBUS_WORD_DATA: - outb_p(((addr & 0x7f) << 1) | (read_write & 0x01), - SMBHSTADD); - outb_p(command, SMBHSTCMD); - if (read_write == I2C_SMBUS_WRITE) { - outb_p(data->word & 0xff, SMBHSTDAT0); - outb_p((data->word & 0xff00) >> 8, SMBHSTDAT1); - } - xact = I801_WORD_DATA; - break; - case I2C_SMBUS_BLOCK_DATA: - case I2C_SMBUS_I2C_BLOCK_DATA: - outb_p(((addr & 0x7f) << 1) | (read_write & 0x01), - SMBHSTADD); - outb_p(command, SMBHSTCMD); - block = 1; - break; - case I2C_SMBUS_PROC_CALL: - default: - dev_err(I801_dev, "Unsupported transaction %d\n", size); - return -1; - } - - outb_p(hwpec, SMBAUXCTL); /* enable/disable hardware PEC */ - - if(block) - ret = i801_block_transaction(data, read_write, size, hwpec); - else { - outb_p(xact | ENABLE_INT9, SMBHSTCNT); - ret = i801_transaction(); - } - - /* Some BIOSes don't like it when PEC is enabled at reboot or resume - time, so we forcibly disable it after every transaction. */ - if (hwpec) - outb_p(0, SMBAUXCTL); - - if(block) - return ret; - if(ret) - return -1; - if ((read_write == I2C_SMBUS_WRITE) || (xact == I801_QUICK)) - return 0; - - switch (xact & 0x7f) { - case I801_BYTE: /* Result put in SMBHSTDAT0 */ - case I801_BYTE_DATA: - data->byte = inb_p(SMBHSTDAT0); - break; - case I801_WORD_DATA: - data->word = inb_p(SMBHSTDAT0) + (inb_p(SMBHSTDAT1) << 8); - break; - } - return 0; -} - -static void i801_inc(struct i2c_adapter *adapter) -{ -#ifdef MODULE - MOD_INC_USE_COUNT; -#endif -} - -static void i801_dec(struct i2c_adapter *adapter) -{ -#ifdef MODULE - MOD_DEC_USE_COUNT; -#endif -} - -static u32 i801_func(struct i2c_adapter *adapter) -{ - return I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE | - I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA | - I2C_FUNC_SMBUS_BLOCK_DATA | I2C_FUNC_SMBUS_WRITE_I2C_BLOCK -#ifdef HAVE_PEC - | (isich4 ? I2C_FUNC_SMBUS_HWPEC_CALC : 0) -#endif - ; -} - -static struct i2c_algorithm smbus_algorithm = { - .name = "Non-I2C SMBus adapter", - .id = I2C_ALGO_SMBUS, - .smbus_xfer = i801_access, - .functionality = i801_func, -}; - -static struct i2c_adapter i801_adapter = { - .id = I2C_ALGO_SMBUS | I2C_HW_SMBUS_I801, - .algo = &smbus_algorithm, - .inc_use = i801_inc, - .dec_use = i801_dec, -}; - -static struct pci_device_id i801_ids[] __devinitdata = { - { - .vendor = PCI_VENDOR_ID_INTEL, - .device = PCI_DEVICE_ID_INTEL_82801AA_3, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - }, - { - .vendor = PCI_VENDOR_ID_INTEL, - .device = PCI_DEVICE_ID_INTEL_82801AB_3, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - }, - { - .vendor = PCI_VENDOR_ID_INTEL, - .device = PCI_DEVICE_ID_INTEL_82801BA_2, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - }, - { - .vendor = PCI_VENDOR_ID_INTEL, - .device = PCI_DEVICE_ID_INTEL_82801CA_3, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - }, - { - .vendor = PCI_VENDOR_ID_INTEL, - .device = PCI_DEVICE_ID_INTEL_82801DB_3, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - }, - { - .vendor = PCI_VENDOR_ID_INTEL, - .device = PCI_DEVICE_ID_INTEL_82801EB_3, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - }, - { - .vendor = PCI_VENDOR_ID_INTEL, - .device = PCI_DEVICE_ID_INTEL_ESB_4, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - }, - { - .vendor = PCI_VENDOR_ID_INTEL, - .device = PCI_DEVICE_ID_INTEL_ESB2_17, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - }, - { - .vendor = PCI_VENDOR_ID_INTEL, - .device = PCI_DEVICE_ID_INTEL_ICH6_16, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - }, - { - .vendor = PCI_VENDOR_ID_INTEL, - .device = PCI_DEVICE_ID_INTEL_ICH7_17, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - }, - { - .vendor = PCI_VENDOR_ID_INTEL, - .device = PCI_DEVICE_ID_INTEL_ICH8_5, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - }, - { - .vendor = PCI_VENDOR_ID_INTEL, - .device = PCI_DEVICE_ID_INTEL_ICH9_6, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - }, - { - .vendor = PCI_VENDOR_ID_INTEL, - .device = PCI_DEVICE_ID_INTEL_TOLAPAI_1, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - }, - { - .vendor = PCI_VENDOR_ID_INTEL, - .device = PCI_DEVICE_ID_INTEL_ICH10_4, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - }, - { - .vendor = PCI_VENDOR_ID_INTEL, - .device = PCI_DEVICE_ID_INTEL_ICH10_5, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - }, - { - .vendor = PCI_VENDOR_ID_INTEL, - .device = PCI_DEVICE_ID_INTEL_PCH_SMBUS, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - }, - { 0, } -}; - -static int __devinit i801_probe(struct pci_dev *dev, const struct pci_device_id *id) -{ - int err; - - if ((err = i801_setup(dev))) - return err; - - snprintf(i801_adapter.name, 32, - "SMBus I801 adapter at %04x", i801_smba); - return i2c_add_adapter(&i801_adapter); -} - -static void __devexit i801_remove(struct pci_dev *dev) -{ - i2c_del_adapter(&i801_adapter); - release_region(i801_smba, (isich4 ? 16 : 8)); -} - -static struct pci_driver i801_driver = { - .name = "i801 smbus", - .id_table = i801_ids, - .probe = i801_probe, - .remove = __devexit_p(i801_remove), -}; - -static int __init i2c_i801_init(void) -{ - printk(KERN_INFO "i2c-i801 version %s (%s)\n", LM_VERSION, LM_DATE); - return pci_module_init(&i801_driver); -} - -static void __exit i2c_i801_exit(void) -{ - pci_unregister_driver(&i801_driver); -} - -MODULE_AUTHOR ("Frodo Looijaard , " - "Philip Edelbrock , " - "and Mark D. Studebaker "); -MODULE_DESCRIPTION("I801 SMBus driver"); -MODULE_LICENSE("GPL"); - -module_init(i2c_i801_init); -module_exit(i2c_i801_exit); diff --git a/kernel/busses/i2c-i810.c b/kernel/busses/i2c-i810.c deleted file mode 100644 index 804890ee..00000000 --- a/kernel/busses/i2c-i810.c +++ /dev/null @@ -1,327 +0,0 @@ -/* - i2c-i810.c - Part of lm_sensors, Linux kernel modules for hardware - monitoring - Copyright (c) 1998, 1999, 2000 Frodo Looijaard , - Philip Edelbrock , - Ralph Metzler , and - Mark D. Studebaker - - Based on code written by Ralph Metzler and - Simon Vogl - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ -/* - This interfaces to the I810/I815 to provide access to - the DDC Bus and the I2C Bus. - - SUPPORTED DEVICES PCI ID - i810AA 7121 - i810AB 7123 - i810E 7125 - i815 1132 - i845G 2562 -*/ - - -#include -#include -#include -#include -#include -#include -#include /* for HZ */ -#include "version.h" -#include "sensors_compat.h" - -MODULE_LICENSE("GPL"); - -/* Not defined by any Linux 2.4 kernel */ -#define PCI_DEVICE_ID_INTEL_82810E_IG 0x7125 -#define PCI_DEVICE_ID_INTEL_82815_CGC 0x1132 -#define PCI_DEVICE_ID_INTEL_82845G_IG 0x2562 - -/* GPIO register locations */ -#define I810_IOCONTROL_OFFSET 0x5000 -#define I810_HVSYNC 0x00 /* not used */ -#define I810_GPIOA 0x10 -#define I810_GPIOB 0x14 - -/* bit locations in the registers */ -#define SCL_DIR_MASK 0x0001 -#define SCL_DIR 0x0002 -#define SCL_VAL_MASK 0x0004 -#define SCL_VAL_OUT 0x0008 -#define SCL_VAL_IN 0x0010 -#define SDA_DIR_MASK 0x0100 -#define SDA_DIR 0x0200 -#define SDA_VAL_MASK 0x0400 -#define SDA_VAL_OUT 0x0800 -#define SDA_VAL_IN 0x1000 - -/* initialization states */ -#define INIT1 0x1 -#define INIT2 0x2 -#define INIT3 0x4 - -/* delays */ -#define CYCLE_DELAY 10 -#define TIMEOUT (HZ / 2) - - -static void config_i810(struct pci_dev *dev); - - -static unsigned long ioaddr; - -/* The i810 GPIO registers have individual masks for each bit - so we never have to read before writing. Nice. */ - -static void bit_i810i2c_setscl(void *data, int val) -{ - writel((val ? SCL_VAL_OUT : 0) | SCL_DIR | SCL_DIR_MASK | SCL_VAL_MASK, - ioaddr + I810_GPIOB); - readl(ioaddr + I810_GPIOB); /* flush posted write */ -} - -static void bit_i810i2c_setsda(void *data, int val) -{ - writel((val ? SDA_VAL_OUT : 0) | SDA_DIR | SDA_DIR_MASK | SDA_VAL_MASK, - ioaddr + I810_GPIOB); - readl(ioaddr + I810_GPIOB); /* flush posted write */ -} - -/* The GPIO pins are open drain, so the pins could always remain outputs. - However, some chip versions don't latch the inputs unless they - are set as inputs. - We rely on the i2c-algo-bit routines to set the pins high before - reading the input from other chips. Following guidance in the 815 - prog. ref. guide, we do a "dummy write" of 0 to the register before - reading which forces the input value to be latched. We presume this - applies to the 810 as well; shouldn't hurt anyway. This is necessary to get - i2c_algo_bit bit_test=1 to pass. */ - -static int bit_i810i2c_getscl(void *data) -{ - writel(SCL_DIR_MASK, ioaddr + I810_GPIOB); - writel(0, ioaddr + I810_GPIOB); - return (0 != (readl(ioaddr + I810_GPIOB) & SCL_VAL_IN)); -} - -static int bit_i810i2c_getsda(void *data) -{ - writel(SDA_DIR_MASK, ioaddr + I810_GPIOB); - writel(0, ioaddr + I810_GPIOB); - return (0 != (readl(ioaddr + I810_GPIOB) & SDA_VAL_IN)); -} - -static void bit_i810ddc_setscl(void *data, int val) -{ - writel((val ? SCL_VAL_OUT : 0) | SCL_DIR | SCL_DIR_MASK | SCL_VAL_MASK, - ioaddr + I810_GPIOA); - readl(ioaddr + I810_GPIOA); /* flush posted write */ -} - -static void bit_i810ddc_setsda(void *data, int val) -{ - writel((val ? SDA_VAL_OUT : 0) | SDA_DIR | SDA_DIR_MASK | SDA_VAL_MASK, - ioaddr + I810_GPIOA); - readl(ioaddr + I810_GPIOA); /* flush posted write */ -} - -static int bit_i810ddc_getscl(void *data) -{ - writel(SCL_DIR_MASK, ioaddr + I810_GPIOA); - writel(0, ioaddr + I810_GPIOA); - return (0 != (readl(ioaddr + I810_GPIOA) & SCL_VAL_IN)); -} - -static int bit_i810ddc_getsda(void *data) -{ - writel(SDA_DIR_MASK, ioaddr + I810_GPIOA); - writel(0, ioaddr + I810_GPIOA); - return (0 != (readl(ioaddr + I810_GPIOA) & SDA_VAL_IN)); -} - - -/* Configures the chip */ -void config_i810(struct pci_dev *dev) -{ - unsigned long cadr; - - /* map I810 memory */ - cadr = dev->resource[1].start; - cadr += I810_IOCONTROL_OFFSET; - cadr &= PCI_BASE_ADDRESS_MEM_MASK; - ioaddr = (unsigned long)ioremap_nocache(cadr, 0x1000); - if(ioaddr) { - bit_i810i2c_setscl(NULL, 1); - bit_i810i2c_setsda(NULL, 1); - bit_i810ddc_setscl(NULL, 1); - bit_i810ddc_setsda(NULL, 1); - } -} - -static void i810_inc(struct i2c_adapter *adapter) -{ -#ifdef MODULE - MOD_INC_USE_COUNT; -#endif -} - -static void i810_dec(struct i2c_adapter *adapter) -{ -#ifdef MODULE - MOD_DEC_USE_COUNT; -#endif -} - -static struct i2c_algo_bit_data i810_i2c_bit_data = { - .setsda = bit_i810i2c_setsda, - .setscl = bit_i810i2c_setscl, - .getsda = bit_i810i2c_getsda, - .getscl = bit_i810i2c_getscl, - .udelay = CYCLE_DELAY, - .mdelay = CYCLE_DELAY, - .timeout = TIMEOUT, -}; - -static struct i2c_adapter i810_i2c_adapter = { - .name = "I810/I815 I2C Adapter", - .id = I2C_HW_B_I810, - .algo_data = &i810_i2c_bit_data, - .inc_use = i810_inc, - .dec_use = i810_dec, -}; - -static struct i2c_algo_bit_data i810_ddc_bit_data = { - .setsda = bit_i810ddc_setsda, - .setscl = bit_i810ddc_setscl, - .getsda = bit_i810ddc_getsda, - .getscl = bit_i810ddc_getscl, - .udelay = CYCLE_DELAY, - .mdelay = CYCLE_DELAY, - .timeout = TIMEOUT, -}; - -static struct i2c_adapter i810_ddc_adapter = { - .name = "I810/I815 DDC Adapter", - .id = I2C_HW_B_I810, - .algo_data = &i810_ddc_bit_data, - .inc_use = i810_inc, - .dec_use = i810_dec, -}; - - -static struct pci_device_id i810_ids[] __devinitdata = { - { - .vendor = PCI_VENDOR_ID_INTEL, - .device = PCI_DEVICE_ID_INTEL_82810_IG1, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - }, - { - .vendor = PCI_VENDOR_ID_INTEL, - .device = PCI_DEVICE_ID_INTEL_82810_IG3, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - }, - { - .vendor = PCI_VENDOR_ID_INTEL, - .device = PCI_DEVICE_ID_INTEL_82810E_IG, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - }, - { - .vendor = PCI_VENDOR_ID_INTEL, - .device = PCI_DEVICE_ID_INTEL_82815_CGC, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - }, - { - .vendor = PCI_VENDOR_ID_INTEL, - .device = PCI_DEVICE_ID_INTEL_82845G_IG, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - }, - { 0, } -}; - -static int __devinit i810_probe(struct pci_dev *dev, const struct pci_device_id *id) -{ - int retval; - - config_i810(dev); - printk("i2c-i810.o: i810/i815 found.\n"); - - retval = i2c_bit_add_bus(&i810_i2c_adapter); - if(retval) - return retval; - retval = i2c_bit_add_bus(&i810_ddc_adapter); - if(retval) - i2c_bit_del_bus(&i810_i2c_adapter); - return retval; -} - -static void __devexit i810_remove(struct pci_dev *dev) -{ - i2c_bit_del_bus(&i810_ddc_adapter); - i2c_bit_del_bus(&i810_i2c_adapter); -} - - -/* Don't register driver to avoid driver conflicts */ -/* -static struct pci_driver i810_driver = { - .name = "i810 smbus", - .id_table = i810_ids, - .probe = i810_probe, - .remove = __devexit_p(i810_remove), -}; -*/ - -static int __init i2c_i810_init(void) -{ - struct pci_dev *dev; - const struct pci_device_id *id; - - printk("i2c-i810.o version %s (%s)\n", LM_VERSION, LM_DATE); -/* - return pci_module_init(&i810_driver); -*/ - pci_for_each_dev(dev) { - id = pci_match_device(i810_ids, dev); - if(id) - if(i810_probe(dev, id) >= 0) - return 0; - } - return -ENODEV; -} - -static void __exit i2c_i810_exit(void) -{ -/* - pci_unregister_driver(&i810_driver); -*/ - i810_remove(NULL); - iounmap((void *)ioaddr); -} - -MODULE_AUTHOR - ("Frodo Looijaard , Philip Edelbrock , Ralph Metzler , and Mark D. Studebaker "); -MODULE_DESCRIPTION("I810/I815 I2C/DDC driver"); - -module_init(i2c_i810_init); -module_exit(i2c_i810_exit); diff --git a/kernel/busses/i2c-ipmb.c b/kernel/busses/i2c-ipmb.c deleted file mode 100644 index b11b0d0b..00000000 --- a/kernel/busses/i2c-ipmb.c +++ /dev/null @@ -1,380 +0,0 @@ -/* - i2c-ipmb.c - Part of lm_sensors, Linux kernel modules for hardware - monitoring - Copyright (c) 2002 Mark D. Studebaker - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -/* - THIS DOESN'T WORK YET - DON'T BOTHER TRYING IT. - This implements an i2c adapter for the BMC IPMB. -*/ - -#include -#include -#include -#include -#include -#include "version.h" - - -static u32 i2c_ipmb_func(struct i2c_adapter *adapter); -int ipmb_access(struct i2c_adapter *adap,struct i2c_msg msgs[], - int num); - - -/* I2C Data */ -static struct i2c_algorithm i2c_ipmb_algorithm = { - .name = "IPMB algorithm", - .id = I2C_ALGO_IPMB, - .master_xfer = ipmb_access, - .functionality = i2c_ipmb_func, -}; - -#define MAX_IPMB_ADAPTERS 8 -static struct i2c_adapter i2c_ipmb_adapter[MAX_IPMB_ADAPTERS]; - -/* IPMI Data */ -#define IPMI_IPMB_CHANNEL 0 -static ipmi_user_t i2c_ipmb_user; -static unsigned char ipmi_version_major; -static unsigned char ipmi_version_minor; -static const char msgdata[IPMI_MAX_ADDR_SIZE]; /* ?? */ -static struct ipmi_system_interface_addr address = { - IPMI_SYSTEM_INTERFACE_ADDR_TYPE, - IPMI_BMC_CHANNEL, - 0 -}; /* send address */ -static struct ipmi_ipmb_addr ipmb_address = { - IPMI_IPMB_ADDR_TYPE, - IPMI_IPMB_CHANNEL, - 0, - 0 -}; /* send address */ -static long msgid; /* message ID */ -static int interfaces; /* number of BMC's found */ -static struct ipmi_msg tx_message; /* send message */ -static unsigned char tx_msg_data[IPMI_MAX_MSG_LENGTH + 50]; -static unsigned char rx_msg_data[IPMI_MAX_MSG_LENGTH + 50]; /* sloppy */ - -/* IPMI Message defs */ -/* Network Function Codes */ -#define IPMI_NETFN_APP 0x06 -/* Commands */ -#define IPMI_ENABLE_CHANNEL 0x32 -#define IPMI_SEND_MSG 0x34 -#define IPMI_GET_CHANNEL_INFO 0x42 /* unfortunately, IPMI 1.5 only */ -#define IPMI_MASTER_WR 0x52 - - -/************** Message Sending **************/ - -static void ipmb_i2c_send_message(struct ipmi_addr *address, - int id, struct ipmi_msg * msg) -{ - int err; - -#ifdef IPMI_RESPONSE_RESPONSE_TYPE - err = ipmi_request(i2c_ipmb_user, address, id, msg, NULL, 0); -#else - err = ipmi_request(i2c_ipmb_user, address, id, msg, 0); -#endif - if (err) - printk(KERN_INFO "i2c-ipmb.o: ipmi_request error %d\n", - err); -} - -/* not used */ -static void ipmb_i2c_bmc_send_message(int id, struct ipmi_msg * msg) -{ - address.channel = IPMI_BMC_CHANNEL; - ipmb_i2c_send_message((struct ipmi_addr *) &address, id, msg); -} - -/* this is for sending commands like master w/r */ -static void ipmb_i2c_ipmb_send_message(int id, struct ipmi_msg * msg) -{ -/* - address.channel = IPMI_IPMB_CHANNEL; -*/ - address.channel = IPMI_BMC_CHANNEL; - ipmb_i2c_send_message((struct ipmi_addr *) &address, id, msg); -} - -#if 0 -/* not used */ -/* this is for an smi message, not for things like master w/r */ -static void ipmb_i2c_ipmb_send_smi(int addr, int id, struct ipmi_msg * msg) -{ - ipmb_address.slave_addr = addr; - ipmb_address.lun = 0; /* pass in */ - ipmb_i2c_send_message((struct ipmi_addr *) &ipmb_address, id, msg); -} - -/* not used */ -/* Compose and send a "Enable Channel Receive" message */ -static void ipmb_enable_channel_rcv(int channel, int code) -{ - tx_message.netfn = IPMI_NETFN_APP; - tx_message.cmd = IPMI_ENABLE_CHANNEL; - tx_message.data_len = 2; - tx_message.data = tx_msg_data; - tx_msg_data[0] = channel; - tx_msg_data[1] = code; - ipmb_i2c_bmc_send_message(msgid++, &tx_message); -} - -/* not used */ -/* Compose and send a "Get Channel Info" message (1.5 only) */ -static void ipmb_get_channel_info(int channel) -{ - tx_message.netfn = IPMI_NETFN_APP; - tx_message.cmd = IPMI_GET_CHANNEL_INFO; - tx_message.data_len = 1; - tx_message.data = tx_msg_data; - tx_msg_data[0] = channel; - ipmb_i2c_bmc_send_message(msgid++, &tx_message); -} -#endif /* 0 */ - -/* Compose and send a "Master W/R" message */ -static void ipmb_master_wr(int bus, u8 addr, u8 rdcount, - u8 wrcount, u8 *wrdata) -{ - printk(KERN_INFO "i2c-ipmb.o: trying bus %d ...\n", bus); - tx_message.netfn = IPMI_NETFN_APP; - tx_message.cmd = IPMI_MASTER_WR; - tx_message.data_len = 3 + wrcount; - tx_msg_data[0] = bus & 0x0f; - tx_msg_data[1] = addr << 1; - tx_msg_data[2] = rdcount; - if(wrcount > 0) - memcpy(tx_msg_data + 3, wrdata, wrcount); - tx_message.data = tx_msg_data; - ipmb_i2c_ipmb_send_message(msgid++, &tx_message); -} - -int xchan; -int xbus; -/* look for channels. IPMI 1.5 defines multiple channels and an - easy way to get the information. - We don't bother using SDR type 14 for IPMI 1.0; that isn't - always present anyway. We could try "enable message channel receive" - with a channel state = 2 (query) but 1.0 is likely to have only - IPMB busses anyway. Therefore, we assume there is only - the IPMB at channel 0. -*/ -static void ipmb_get_all_channel_info(void) - -{ -#if 0 - if(ipmi_version_major > 1 || - (ipmi_version_major == 1 && ipmi_version_minor >= 5)) - ipmb_get_channel_info(0); -#endif -/* - else - scan SDR's for type 14 - else { - for all xchan 0-15 - ipmb_enable_channel_rcv(xchan, 2); -*/ - xbus = 0; - ipmb_master_wr(xbus, 0x2d, 1, 1, "\0"); -/* -*/ -/* - else - assume IPMB at channel 0 only -*/ -} - -/************** Message Receiving **************/ - -/* not used */ -static void ipmb_rcv_channel_info(struct ipmi_msg *msg) -{ - u8 channel, type, protocol; - - channel = msg->data[1] & 0x0f; - type = msg->data[2] & 0x7f; - protocol = msg->data[3] & 0x1f; - printk(KERN_INFO "i2c-ipmb.o: Channel %d; type 0x%x; protocol 0x%x\n", - channel, type, protocol); -} -/* - return i2c_add_adapter(&i2c_ipmb_adapter); - if (error) { - printk(KERN_ERR "i2c-ipmb.o: Adapter registration failed, " - "module i2c-ipmb.o is not inserted\n."); - return; - } -*/ -/* - if(channel < 7) - ipmb_get_channel_info(channel + 1); -*/ -static void ipmb_rcv_master_resp(struct ipmi_msg *msg) -{ - if(++xbus > 0x0f) - return; - ipmb_master_wr(xbus, 0x2d, 1, 1, "\0"); -} - -#if 0 -/* not used */ -static void ipmb_rcv_channel_enable(struct ipmi_msg *msg) -{ - int state; - - state = msg->data[2] & 1; - - printk(KERN_INFO "i2c-ipmb.o: Channel %d; state %d\n", - xchan, state); - if(++xchan > 0x0f) - return; - ipmb_enable_channel_rcv(xchan, 2); -} -#endif /* 0 */ - -static void ipmb_i2c_msg_handler(struct ipmi_recv_msg *msg, - void *handler_data) -{ - int rcvid = msg->msgid & 0xffffff; - int client = (msg->msgid >> 24) & 0xf; - - if (msg->msg.data[0] != 0) - printk(KERN_WARNING "i2c-ipmb.o: Error 0x%x on cmd 0x%x/0x%x\n", - msg->msg.data[0], msg->msg.netfn & 0xfe, msg->msg.cmd); -/* - else -*/ - ipmb_rcv_master_resp(&(msg->msg)); - - - - - - ipmi_free_recv_msg(msg); -} - -static struct ipmi_user_hndl ipmb_hndlrs = -{ - .ipmi_recv_hndl = ipmb_i2c_msg_handler, -}; - -/*************** I2C funtions *******************/ - -/* Return -1 on error. */ -int ipmb_access(struct i2c_adapter *adap,struct i2c_msg msgs[], - int num) -{ - - - - - - -} - -static u32 i2c_ipmb_func(struct i2c_adapter *adapter) -{ - return 0; /* fixme */ -} - -/**************** Initialization ****************/ - -/* callback for each BMC found */ -static void ipmb_register(int ipmi_intf) -{ - unsigned long flags; - int rv; - - if(interfaces > 0) { /* 1 max for now */ - printk(KERN_INFO - "i2c-ipmb.o: Additional IPMI interface %d not supported\n", - ipmi_intf); - return; - } - - rv = ipmi_create_user(ipmi_intf, &ipmb_hndlrs, NULL, &i2c_ipmb_user); - if (rv < 0) { - printk(KERN_ERR "i2c-ipmb.o: Unable to register with ipmi\n"); - return; - } - - ipmi_get_version(i2c_ipmb_user, &ipmi_version_major, - &ipmi_version_minor); - printk(KERN_INFO - "i2c-ipmb.o: Registered IPMI interface %d with version %d.%d\n", - ipmi_intf, ipmi_version_major, ipmi_version_minor); - interfaces++; - - ipmb_get_all_channel_info(); -} - -static void ipmb_new_smi(int if_num) -{ - ipmb_register(if_num); -} - -static void ipmb_smi_gone(int if_num) -{ - if (interfaces >= 1) { -/* - i2c_del_adapter(&i2c_ipmb_adapter); -*/ - ipmi_destroy_user(i2c_ipmb_user); - interfaces--; - } -} - -static struct ipmi_smi_watcher smi_watcher = -{ - .new_smi = ipmb_new_smi, - .smi_gone = ipmb_smi_gone -}; - -static int __init i2c_ipmb_init(void) -{ - int rv; - - printk(KERN_INFO "i2c-ipmb.o version %s (%s)\n", LM_VERSION, LM_DATE); - - rv = ipmi_smi_watcher_register(&smi_watcher); - if (rv) { - printk(KERN_WARNING - "ipmi_watchdog: can't register smi watcher\n"); - return rv; - } - - printk(KERN_INFO "i2c-ipmb.o: BMC access for i2c modules initialized.\n"); - return 0; -} - - -static void __exit i2c_ipmi_exit(void) -{ - ipmi_smi_watcher_unregister(&smi_watcher); - ipmb_smi_gone(0); -} - -MODULE_AUTHOR("M. D. Studebaker "); -MODULE_DESCRIPTION("IPMB-BMC access through i2c"); -MODULE_LICENSE("GPL"); - -module_init(i2c_ipmb_init); -module_exit(i2c_ipmi_exit); diff --git a/kernel/busses/i2c-ipmi.c b/kernel/busses/i2c-ipmi.c deleted file mode 100644 index cae78e36..00000000 --- a/kernel/busses/i2c-ipmi.c +++ /dev/null @@ -1,251 +0,0 @@ -/* - i2c-ipmi.c - Part of lm_sensors, Linux kernel modules for hardware - monitoring - Copyright (c) 2002 Mark D. Studebaker - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -/* - This implements a "dummy" i2c adapter for clients to access the - BMC via IPMI messages. Supports only one BMC and one client for now! -*/ - -#include -#include -#include -#include -#include -#include "version.h" - - -static u32 i2c_ipmi_func(struct i2c_adapter *adapter); -static int bmcclient_i2c_send_message(struct i2c_adapter *, char *, int); - -static void i2c_ipmi_inc_use(struct i2c_adapter *adapter) -{ -#ifdef MODULE - MOD_INC_USE_COUNT; -#endif -} - -static void i2c_ipmi_dec_use(struct i2c_adapter *adapter) -{ -#ifdef MODULE - MOD_DEC_USE_COUNT; -#endif -} - -/* I2C Data */ -static struct i2c_algorithm i2c_ipmi_algorithm = { - .name = "IPMI algorithm", - .id = I2C_ALGO_IPMI, - .slave_send = &bmcclient_i2c_send_message, - .functionality = &i2c_ipmi_func, -}; - -static struct i2c_adapter i2c_ipmi_adapter = { - .name = "IPMI adapter", - .id = I2C_ALGO_IPMI | I2C_HW_IPMI, - .algo = &i2c_ipmi_algorithm, - .inc_use = &i2c_ipmi_inc_use, - .dec_use = &i2c_ipmi_dec_use, -}; - -/* IPMI Data */ -static ipmi_user_t i2c_ipmi_user; -static unsigned char ipmi_version_major; -static unsigned char ipmi_version_minor; -static const char msgdata[IPMI_MAX_ADDR_SIZE]; /* ?? */ -static struct ipmi_addr address = { - IPMI_SYSTEM_INTERFACE_ADDR_TYPE, - IPMI_BMC_CHANNEL, - {0} -}; /* send address */ -static int interfaces; /* number of BMC's found */ - - -/* Dummy adapter... */ -static u32 i2c_ipmi_func(struct i2c_adapter *adapter) -{ - return 0; -} - -/************** Message Sending **************/ - -static int find_client(struct i2c_client * client) -{ - int i; - - for (i = 0; i < I2C_CLIENT_MAX; i++) - if (client == i2c_ipmi_adapter.clients[i]) - return i; - return -1; -} - -static void ipmi_i2c_send_message(int id, struct ipmi_msg * msg) -{ -#ifdef IPMI_RESPONSE_RESPONSE_TYPE - ipmi_request(i2c_ipmi_user, &address, (long) id, msg, NULL, 0); -#else - ipmi_request(i2c_ipmi_user, &address, (long) id, msg, 0); -#endif -} - -/* This is the message send function exported to the client - via the i2c_adapter struct. - We use the existing (but unused) slave_send function pointer. - Hence the ugly casts. */ -static int bmcclient_i2c_send_message(struct i2c_adapter *clnt, - char * mesg, int id) -{ - struct ipmi_msg *msg = (struct ipmi_msg *) mesg; - struct i2c_client *client = (struct i2c_client *) clnt; - int clientid; - -#ifdef DEBUG - if(msg->data == NULL) - printk(KERN_INFO "i2c-ipmi.o: Send 0x%x\n", msg->cmd); - else - printk(KERN_INFO "i2c-ipmi.o: Send 0x%x 0x%x 0x%x\n", msg->cmd, msg->data[0], msg->data[1]); -#endif - /* save the client number in the upper 8 bits of the message id */ - if((clientid = find_client(client)) < 0) { - printk(KERN_WARNING "i2c-ipmi.o: Request from unknown client\n"); - return -1; - } - - id = (id & 0xffffff) | (clientid << 24); - ipmi_i2c_send_message(id, msg); - return 0; -} - -/************** Message Receiving **************/ - -static void ipmi_i2c_msg_handler(struct ipmi_recv_msg *msg, - void *handler_data) -{ - int rcvid = msg->msgid & 0xffffff; - int clientid = (msg->msgid >> 24) & 0xff; - -#ifdef DEBUG - if (msg->msg.data[0] != 0) - printk(KERN_WARNING "i2c-ipmi.o: Error 0x%x on cmd 0x%x/0x%x\n", - msg->msg.data[0], msg->msg.netfn, msg->msg.cmd); -#endif - /* Protect ourselves here; verify the client and its callback - since the client may have gone away since - the message was sent! */ - if(clientid < I2C_CLIENT_MAX && - i2c_ipmi_adapter.clients[clientid] != NULL && - i2c_ipmi_adapter.clients[clientid]->driver->command != NULL) - (* i2c_ipmi_adapter.clients[clientid]->driver->command) - (i2c_ipmi_adapter.clients[clientid], rcvid, msg); - else { - printk(KERN_WARNING "i2c-ipmi.o: Response for unknown client\n"); - ipmi_free_recv_msg(msg); - } -} - -static struct ipmi_user_hndl ipmi_hndlrs = -{ - .ipmi_recv_hndl = ipmi_i2c_msg_handler, -}; - -/**************** Initialization ****************/ - -/* callback for each BMC found */ -static void ipmi_register_bmc(int ipmi_intf) -{ - int error; - - if(interfaces > 0) { /* 1 max for now */ - printk(KERN_INFO - "i2c-ipmi.o: Additional IPMI interface %d not supported\n", - ipmi_intf); - return; - } - - error = ipmi_create_user(ipmi_intf, &ipmi_hndlrs, NULL, &i2c_ipmi_user); - if (error < 0) { - printk(KERN_ERR "i2c-ipmi.o: Unable to register with ipmi\n"); - return; - } - - error = i2c_add_adapter(&i2c_ipmi_adapter); - if (error) { - printk(KERN_ERR "i2c-ipmi.o: Adapter registration failed, " - "module i2c-ipmi.o is not inserted\n."); - return; - } - - ipmi_get_version(i2c_ipmi_user, &ipmi_version_major, - &ipmi_version_minor); - printk(KERN_INFO - "i2c-ipmi.o: Registered IPMI interface %d with version %d.%d\n", - ipmi_intf, ipmi_version_major, ipmi_version_minor); - interfaces++; -} - -static void ipmi_new_smi(int if_num) -{ - ipmi_register_bmc(if_num); -} - -static void ipmi_smi_gone(int if_num) -{ - if (interfaces >= 1) { - i2c_del_adapter(&i2c_ipmi_adapter); - ipmi_destroy_user(i2c_ipmi_user); - interfaces--; - } -} - -static struct ipmi_smi_watcher smi_watcher = -{ - .new_smi = ipmi_new_smi, - .smi_gone = ipmi_smi_gone -}; - -static int __init i2c_ipmi_init(void) -{ - int rv; - - printk(KERN_INFO "i2c-ipmi.o version %s (%s)\n", LM_VERSION, LM_DATE); - - rv = ipmi_smi_watcher_register(&smi_watcher); - if (rv) { - printk(KERN_WARNING - "ipmi_watchdog: can't register smi watcher\n"); - return rv; - } - - printk(KERN_INFO "i2c-ipmi.o: BMC access for i2c modules initialized.\n"); - return 0; -} - - -static void __exit i2c_ipmi_exit(void) -{ - ipmi_smi_watcher_unregister(&smi_watcher); - ipmi_smi_gone(0); -} - -MODULE_AUTHOR("M. D. Studebaker "); -MODULE_DESCRIPTION("IPMI-BMC access through i2c"); -MODULE_LICENSE("GPL"); - -module_init(i2c_ipmi_init); -module_exit(i2c_ipmi_exit); diff --git a/kernel/busses/i2c-isa.c b/kernel/busses/i2c-isa.c deleted file mode 100644 index 517cef67..00000000 --- a/kernel/busses/i2c-isa.c +++ /dev/null @@ -1,88 +0,0 @@ -/* - i2c-isa.c - Part of lm_sensors, Linux kernel modules for hardware - monitoring - Copyright (c) 1998, 1999 Frodo Looijaard - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -/* This implements an i2c algorithm/adapter for ISA bus. Not that this is - on first sight very useful; almost no functionality is preserved. - Except that it makes writing drivers for chips which can be on both - the SMBus and the ISA bus very much easier. See lm78.c for an example - of this. */ - -#include -#include -#include -#include -#include -#include "version.h" - -static u32 isa_func(struct i2c_adapter *adapter); - -/* This is the actual algorithm we define */ -static struct i2c_algorithm isa_algorithm = { - .name = "ISA bus algorithm", - .id = I2C_ALGO_ISA, - .functionality = isa_func, -}; - -static void isa_inc_use(struct i2c_adapter *adapter) -{ -#ifdef MODULE - MOD_INC_USE_COUNT; -#endif -} - -static void isa_dec_use(struct i2c_adapter *adapter) -{ -#ifdef MODULE - MOD_DEC_USE_COUNT; -#endif -} - -/* There can only be one... */ -static struct i2c_adapter isa_adapter = { - .name = "ISA main adapter", - .id = I2C_ALGO_ISA | I2C_HW_ISA, - .algo = &isa_algorithm, - .inc_use = isa_inc_use, - .dec_use = isa_dec_use, -}; - -/* We can't do a thing... */ -static u32 isa_func(struct i2c_adapter *adapter) -{ - return 0; -} - -static int __init i2c_isa_init(void) -{ - printk("i2c-isa.o version %s (%s)\n", LM_VERSION, LM_DATE); - return i2c_add_adapter(&isa_adapter); -} - -static void __exit i2c_isa_exit(void) -{ - i2c_del_adapter(&isa_adapter); -} - -MODULE_AUTHOR("Frodo Looijaard "); -MODULE_DESCRIPTION("ISA bus access through i2c"); -MODULE_LICENSE("GPL"); - -module_init(i2c_isa_init); -module_exit(i2c_isa_exit); diff --git a/kernel/busses/i2c-keywest.c b/kernel/busses/i2c-keywest.c deleted file mode 100644 index 02ee7245..00000000 --- a/kernel/busses/i2c-keywest.c +++ /dev/null @@ -1,619 +0,0 @@ -/* - i2c Support for Apple Keywest I2C Bus Controller - - Copyright (c) 2001 Benjamin Herrenschmidt - - Original work by - - Copyright (c) 2000 Philip Edelbrock - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - - Changes: - - 2001/12/13 BenH New implementation - 2001/12/15 BenH Add support for "byte" and "quick" - transfers. Add i2c_xfer routine. - - My understanding of the various modes supported by keywest are: - - - Dumb mode : not implemented, probably direct tweaking of lines - - Standard mode : simple i2c transaction of type - S Addr R/W A Data A Data ... T - - Standard sub mode : combined 8 bit subaddr write with data read - S Addr R/W A SubAddr A Data A Data ... T - - Combined mode : Subaddress and Data sequences appended with no stop - S Addr R/W A SubAddr S Addr R/W A Data A Data ... T - - Currently, this driver uses only Standard mode for i2c xfer, and - smbus byte & quick transfers ; and uses StandardSub mode for - other smbus transfers instead of combined as we need that for the - sound driver to be happy -*/ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include "i2c-keywest.h" - -#define DBG(x...) do {\ - if (debug > 0) \ - printk(KERN_DEBUG "KW:" x); \ - } while(0) - - -MODULE_AUTHOR("Benjamin Herrenschmidt "); -MODULE_DESCRIPTION("I2C driver for Apple's Keywest"); -MODULE_LICENSE("GPL"); -MODULE_PARM(debug, "i"); - -int debug = 0; - -static struct keywest_iface *ifaces = NULL; - - -static void -do_stop(struct keywest_iface* iface, int result) -{ - write_reg(reg_control, read_reg(reg_control) | KW_I2C_CTL_STOP); - iface->state = state_stop; - iface->result = result; -} - -/* Main state machine for standard & standard sub mode */ -static int -handle_interrupt(struct keywest_iface *iface, u8 isr) -{ - int ack; - int rearm_timer = 1; - - DBG("handle_interrupt(), got: %x, status: %x, state: %d\n", - isr, read_reg(reg_status), iface->state); - if (isr == 0 && iface->state != state_stop) { - do_stop(iface, -1); - return rearm_timer; - } - if (isr & KW_I2C_IRQ_STOP && iface->state != state_stop) { - iface->result = -1; - iface->state = state_stop; - } - switch(iface->state) { - case state_addr: - if (!(isr & KW_I2C_IRQ_ADDR)) { - do_stop(iface, -1); - break; - } - ack = read_reg(reg_status); - DBG("ack on set address: %x\n", ack); - if ((ack & KW_I2C_STAT_LAST_AAK) == 0) { - do_stop(iface, -1); - break; - } - /* Handle rw "quick" mode */ - if (iface->datalen == 0) - do_stop(iface, 0); - else if (iface->read_write == I2C_SMBUS_READ) { - iface->state = state_read; - if (iface->datalen > 1) - write_reg(reg_control, read_reg(reg_control) - | KW_I2C_CTL_AAK); - } else { - iface->state = state_write; - DBG("write byte: %x\n", *(iface->data)); - write_reg(reg_data, *(iface->data++)); - iface->datalen--; - } - - break; - case state_read: - if (!(isr & KW_I2C_IRQ_DATA)) { - do_stop(iface, -1); - break; - } - *(iface->data++) = read_reg(reg_data); - DBG("read byte: %x\n", *(iface->data-1)); - iface->datalen--; - if (iface->datalen == 0) - iface->state = state_stop; - else - write_reg(reg_control, 0); - break; - case state_write: - if (!(isr & KW_I2C_IRQ_DATA)) { - do_stop(iface, -1); - break; - } - /* Check ack status */ - ack = read_reg(reg_status); - DBG("ack on data write: %x\n", ack); - if ((ack & KW_I2C_STAT_LAST_AAK) == 0) { - do_stop(iface, -1); - break; - } - if (iface->datalen) { - DBG("write byte: %x\n", *(iface->data)); - write_reg(reg_data, *(iface->data++)); - iface->datalen--; - } else - do_stop(iface, 0); - break; - - case state_stop: - if (!(isr & KW_I2C_IRQ_STOP) && (++iface->stopretry) < 10) - do_stop(iface, -1); - else { - rearm_timer = 0; - iface->state = state_idle; - write_reg(reg_control, 0x00); - write_reg(reg_ier, 0x00); - complete(&iface->complete); - } - break; - } - - write_reg(reg_isr, isr); - - return rearm_timer; -} - -/* Interrupt handler */ -static void -keywest_irq(int irq, void *dev_id, struct pt_regs *regs) -{ - struct keywest_iface *iface = (struct keywest_iface *)dev_id; - - spin_lock(&iface->lock); - del_timer(&iface->timeout_timer); - if (handle_interrupt(iface, read_reg(reg_isr))) { - iface->timeout_timer.expires = jiffies + POLL_TIMEOUT; - add_timer(&iface->timeout_timer); - } - spin_unlock(&iface->lock); -} - -static void -keywest_timeout(unsigned long data) -{ - struct keywest_iface *iface = (struct keywest_iface *)data; - - DBG("timeout !\n"); - spin_lock_irq(&iface->lock); - if (iface->state != state_idle) { - iface->timeout_timer.expires = jiffies + POLL_TIMEOUT; - add_timer(&iface->timeout_timer); - } - spin_unlock(&iface->lock); -} - -/* - * SMBUS-type transfer entrypoint - */ -static s32 -keywest_smbus_xfer( struct i2c_adapter* adap, - u16 addr, - unsigned short flags, - char read_write, - u8 command, - int size, - union i2c_smbus_data* data) -{ - struct keywest_chan* chan = (struct keywest_chan*)adap->data; - struct keywest_iface* iface = chan->iface; - int len; - u8* buffer; - u16 cur_word; - int rc = 0; - - if (iface->state == state_dead) - return -1; - - /* Prepare datas & select mode */ - iface->cur_mode &= ~KW_I2C_MODE_MODE_MASK; - switch (size) { - case I2C_SMBUS_QUICK: - len = 0; - buffer = NULL; - iface->cur_mode |= KW_I2C_MODE_STANDARD; - break; - case I2C_SMBUS_BYTE: - len = 1; - buffer = &data->byte; - iface->cur_mode |= KW_I2C_MODE_STANDARD; - break; - case I2C_SMBUS_BYTE_DATA: - len = 1; - buffer = &data->byte; - iface->cur_mode |= KW_I2C_MODE_STANDARDSUB; - //iface->cur_mode |= KW_I2C_MODE_COMBINED; - break; - case I2C_SMBUS_WORD_DATA: - len = 2; - cur_word = cpu_to_le16(data->word); - buffer = (u8 *)&cur_word; - iface->cur_mode |= KW_I2C_MODE_STANDARDSUB; - //iface->cur_mode |= KW_I2C_MODE_COMBINED; - break; - case I2C_SMBUS_BLOCK_DATA: - len = data->block[0]; - buffer = &data->block[1]; - iface->cur_mode |= KW_I2C_MODE_STANDARDSUB; - //iface->cur_mode |= KW_I2C_MODE_COMBINED; - break; - default: - return -1; - } - - /* Original driver had this limitation */ - if (len > 32) - len = 32; - - down(&iface->sem); - - DBG("chan: %d, addr: 0x%x, transfer len: %d, read: %d\n", - chan->chan_no, addr, len, read_write == I2C_SMBUS_READ); - - iface->data = buffer; - iface->datalen = len; - iface->state = state_addr; - iface->result = 0; - iface->stopretry = 0; - iface->read_write = read_write; - - /* Setup channel & clear pending irqs */ - write_reg(reg_mode, iface->cur_mode | (chan->chan_no << 4)); - write_reg(reg_isr, read_reg(reg_isr)); - write_reg(reg_status, 0); - - /* Set up address and r/w bit */ - write_reg(reg_addr, - (addr << 1) | ((read_write == I2C_SMBUS_READ) ? 0x01 : 0x00)); - - /* Set up the sub address */ - if ((iface->cur_mode & KW_I2C_MODE_MODE_MASK) == KW_I2C_MODE_STANDARDSUB - || (iface->cur_mode & KW_I2C_MODE_MODE_MASK) == KW_I2C_MODE_COMBINED) - write_reg(reg_subaddr, command); - - /* Arm timeout */ - iface->timeout_timer.expires = jiffies + POLL_TIMEOUT; - add_timer(&iface->timeout_timer); - - /* Start sending address & enable interrupt*/ - write_reg(reg_control, read_reg(reg_control) | KW_I2C_CTL_XADDR); - write_reg(reg_ier, KW_I2C_IRQ_MASK); - - wait_for_completion(&iface->complete); - - rc = iface->result; - DBG("transfer done, result: %d\n", rc); - - if (rc == 0 && size == I2C_SMBUS_WORD_DATA && read_write == I2C_SMBUS_READ) - data->word = le16_to_cpu(cur_word); - - /* Release sem */ - up(&iface->sem); - - return rc; -} - -/* - * Generic i2c master transfer entrypoint - */ -static int -keywest_xfer( struct i2c_adapter *adap, - struct i2c_msg msgs[], - int num) -{ - struct keywest_chan* chan = (struct keywest_chan*)adap->data; - struct keywest_iface* iface = chan->iface; - struct i2c_msg *pmsg; - int i, completed; - int rc = 0; - - down(&iface->sem); - - /* Set adapter to standard mode */ - iface->cur_mode &= ~KW_I2C_MODE_MODE_MASK; - iface->cur_mode |= KW_I2C_MODE_STANDARD; - - completed = 0; - for (i = 0; rc >= 0 && i < num;) { - u8 addr; - - pmsg = &msgs[i++]; - addr = pmsg->addr; - if (pmsg->flags & I2C_M_TEN) { - printk(KERN_ERR "i2c-keywest: 10 bits addr not supported !\n"); - rc = -EINVAL; - break; - } - DBG("xfer: chan: %d, doing %s %d bytes to 0x%02x - %d of %d messages\n", - chan->chan_no, - pmsg->flags & I2C_M_RD ? "read" : "write", - pmsg->len, addr, i, num); - - /* Setup channel & clear pending irqs */ - write_reg(reg_mode, iface->cur_mode | (chan->chan_no << 4)); - write_reg(reg_isr, read_reg(reg_isr)); - write_reg(reg_status, 0); - - iface->data = pmsg->buf; - iface->datalen = pmsg->len; - iface->state = state_addr; - iface->result = 0; - iface->stopretry = 0; - if (pmsg->flags & I2C_M_RD) - iface->read_write = I2C_SMBUS_READ; - else - iface->read_write = I2C_SMBUS_WRITE; - - /* Set up address and r/w bit */ - if (pmsg->flags & I2C_M_REV_DIR_ADDR) - addr ^= 1; - write_reg(reg_addr, - (addr << 1) | - ((iface->read_write == I2C_SMBUS_READ) ? 0x01 : 0x00)); - - /* Arm timeout */ - iface->timeout_timer.expires = jiffies + POLL_TIMEOUT; - add_timer(&iface->timeout_timer); - - /* Start sending address & enable interrupt*/ - write_reg(reg_control, read_reg(reg_control) | KW_I2C_CTL_XADDR); - write_reg(reg_ier, KW_I2C_IRQ_MASK); - - wait_for_completion(&iface->complete); - - rc = iface->result; - if (rc == 0) - completed++; - DBG("transfer done, result: %d\n", rc); - } - - /* Release sem */ - up(&iface->sem); - - return completed; -} - -static u32 -keywest_func(struct i2c_adapter * adapter) -{ - return I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE | - I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA | - I2C_FUNC_SMBUS_BLOCK_DATA; -} - -static void -keywest_inc(struct i2c_adapter *adapter) -{ -#ifdef MODULE - MOD_INC_USE_COUNT; -#endif -} - -static void -keywest_dec(struct i2c_adapter *adapter) -{ -#ifdef MODULE - MOD_DEC_USE_COUNT; -#endif -} - -/* For now, we only handle combined mode (smbus) */ -static struct i2c_algorithm keywest_algorithm = { - .name = "Keywest i2c", - .id = I2C_ALGO_SMBUS, - .smbus_xfer = keywest_smbus_xfer, - .master_xfer = keywest_xfer, - .functionality = keywest_func, -}; - - -static int __init -create_iface(struct device_node* np) -{ - unsigned long steps, *psteps, *prate; - unsigned bsteps, tsize, i, nchan, addroffset; - struct keywest_iface* iface; - int error; - - psteps = (unsigned long *)get_property(np, "AAPL,address-step", NULL); - steps = psteps ? (*psteps) : 0x10; - - /* Hrm... maybe we can be smarter here */ - for (bsteps = 0; (steps & 0x01) == 0; bsteps++) - steps >>= 1; - - if (!strcmp(np->parent->name, "uni-n")) { - nchan = 2; - addroffset = 3; - } else { - addroffset = 0; - nchan = 1; - } - - tsize = sizeof(struct keywest_iface) + - (sizeof(struct keywest_chan) + 4) * nchan; - iface = kmalloc(tsize, GFP_KERNEL); - if (iface == NULL) { - printk(KERN_ERR "i2c-keywest: can't allocate inteface !\n"); - return -ENOMEM; - } - memset(iface, 0, tsize); - init_MUTEX(&iface->sem); - spin_lock_init(&iface->lock); - init_completion(&iface->complete); - iface->bsteps = bsteps; - iface->chan_count = nchan; - iface->state = state_idle; - iface->irq = np->intrs[0].line; - iface->channels = (struct keywest_chan *) - (((unsigned long)(iface + 1) + 3UL) & ~3UL); - iface->base = (unsigned long)ioremap(np->addrs[0].address + addroffset, - np->addrs[0].size); - if (iface->base == 0) { - printk(KERN_ERR "i2c-keywest: can't map inteface !\n"); - kfree(iface); - return -ENOMEM; - } - - init_timer(&iface->timeout_timer); - iface->timeout_timer.function = keywest_timeout; - iface->timeout_timer.data = (unsigned long)iface; - - /* Select interface rate */ - iface->cur_mode = KW_I2C_MODE_100KHZ; - prate = (unsigned long *)get_property(np, "AAPL,i2c-rate", NULL); - if (prate) switch(*prate) { - case 100: - iface->cur_mode = KW_I2C_MODE_100KHZ; - break; - case 50: - iface->cur_mode = KW_I2C_MODE_50KHZ; - break; - case 25: - iface->cur_mode = KW_I2C_MODE_25KHZ; - break; - default: - printk(KERN_WARNING "i2c-keywest: unknown rate %ldKhz, using 100KHz\n", - *prate); - } - - /* Select standard mode by default */ - iface->cur_mode |= KW_I2C_MODE_STANDARD; - - /* Write mode */ - write_reg(reg_mode, iface->cur_mode); - - /* Switch interrupts off & clear them*/ - write_reg(reg_ier, 0x00); - write_reg(reg_isr, KW_I2C_IRQ_MASK); - - /* Request chip interrupt */ - error = request_irq(iface->irq, keywest_irq, 0, "keywest i2c", iface); - if (error) { - printk(KERN_ERR "i2c-keywest: can't get IRQ %d !\n", iface->irq); - iounmap((void *)iface->base); - kfree(iface); - return -ENODEV; - } - - for (i=0; ichannels[i]; - - sprintf(chan->adapter.name, "%s %d", np->parent->name, i); - chan->iface = iface; - chan->chan_no = i; - chan->adapter.id = I2C_ALGO_SMBUS; - chan->adapter.algo = &keywest_algorithm; - chan->adapter.algo_data = NULL; - chan->adapter.inc_use = keywest_inc; - chan->adapter.dec_use = keywest_dec; - chan->adapter.client_register = NULL; - chan->adapter.client_unregister = NULL; - chan->adapter.data = chan; - - error = i2c_add_adapter(&chan->adapter); - if (error) { - printk("i2c-keywest.c: Adapter %s registration failed\n", - chan->adapter.name); - chan->adapter.data = NULL; - } - } - - printk(KERN_INFO "Found KeyWest i2c on \"%s\", %d channel%s, stepping: %d bits\n", - np->parent->name, nchan, nchan > 1 ? "s" : "", bsteps); - - iface->next = ifaces; - ifaces = iface; - return 0; -} - -static void __exit -dispose_iface(struct keywest_iface *iface) -{ - int i, error; - - ifaces = iface->next; - - /* Make sure we stop all activity */ - down(&iface->sem); - spin_lock_irq(&iface->lock); - while (iface->state != state_idle) { - spin_unlock_irq(&iface->lock); - set_task_state(current,TASK_UNINTERRUPTIBLE); - schedule_timeout(HZ/10); - spin_lock_irq(&iface->lock); - } - iface->state = state_dead; - spin_unlock_irq(&iface->lock); - free_irq(iface->irq, iface); - up(&iface->sem); - - /* Release all channels */ - for (i=0; ichan_count; i++) { - struct keywest_chan* chan = &iface->channels[i]; - if (!chan->adapter.data) - continue; - i2c_del_adapter(&chan->adapter); - chan->adapter.data = NULL; - /* We aren't that prepared to deal with this... */ - if (error) - printk("i2c-keywest.c: i2c_del_adapter failed, that's bad !\n"); - } - iounmap((void *)iface->base); - kfree(iface); -} - -static int __init i2c_keywest_init(void) -{ - struct device_node *np; - int error = -ENODEV; - - np = find_compatible_devices("i2c", "keywest"); - while (np != 0) { - if (np->n_addrs >= 1 && np->n_intrs >= 1) - error = create_iface(np); - np = np->next; - } - if (ifaces) - error = 0; - return error; -} - -static void __exit i2c_keywest_exit(void) -{ - while(ifaces) - dispose_iface(ifaces); -} - -module_init(i2c_keywest_init); -module_exit(i2c_keywest_exit); diff --git a/kernel/busses/i2c-keywest.h b/kernel/busses/i2c-keywest.h deleted file mode 100644 index 906a6f12..00000000 --- a/kernel/busses/i2c-keywest.h +++ /dev/null @@ -1,113 +0,0 @@ -#ifndef __I2C_KEYWEST_H__ -#define __I2C_KEYWEST_H__ - -#include - -/* The Tumbler audio equalizer can be really slow sometimes */ -#define POLL_TIMEOUT (2*HZ) - -/* Register indices */ -typedef enum { - reg_mode = 0, - reg_control, - reg_status, - reg_isr, - reg_ier, - reg_addr, - reg_subaddr, - reg_data -} reg_t; - - -/* Mode register */ -#define KW_I2C_MODE_100KHZ 0x00 -#define KW_I2C_MODE_50KHZ 0x01 -#define KW_I2C_MODE_25KHZ 0x02 -#define KW_I2C_MODE_DUMB 0x00 -#define KW_I2C_MODE_STANDARD 0x04 -#define KW_I2C_MODE_STANDARDSUB 0x08 -#define KW_I2C_MODE_COMBINED 0x0C -#define KW_I2C_MODE_MODE_MASK 0x0C -#define KW_I2C_MODE_CHAN_MASK 0xF0 - -/* Control register */ -#define KW_I2C_CTL_AAK 0x01 -#define KW_I2C_CTL_XADDR 0x02 -#define KW_I2C_CTL_STOP 0x04 -#define KW_I2C_CTL_START 0x08 - -/* Status register */ -#define KW_I2C_STAT_BUSY 0x01 -#define KW_I2C_STAT_LAST_AAK 0x02 -#define KW_I2C_STAT_LAST_RW 0x04 -#define KW_I2C_STAT_SDA 0x08 -#define KW_I2C_STAT_SCL 0x10 - -/* IER & ISR registers */ -#define KW_I2C_IRQ_DATA 0x01 -#define KW_I2C_IRQ_ADDR 0x02 -#define KW_I2C_IRQ_STOP 0x04 -#define KW_I2C_IRQ_START 0x08 -#define KW_I2C_IRQ_MASK 0x0F - -/* Physical interface */ -struct keywest_iface -{ - unsigned long base; - unsigned bsteps; - int irq; - struct semaphore sem; - spinlock_t lock; - struct keywest_chan* channels; - unsigned chan_count; - u8 cur_mode; - char read_write; - u8* data; - unsigned datalen; - int state; - int result; - int stopretry; - struct timer_list timeout_timer; - struct completion complete; - struct keywest_iface* next; -}; - -enum { - state_idle, - state_addr, - state_read, - state_write, - state_stop, - state_dead -}; - -/* Channel on an interface */ -struct keywest_chan -{ - struct i2c_adapter adapter; - struct keywest_iface* iface; - unsigned chan_no; -}; - -/* Register access */ - -static inline u8 __read_reg(struct keywest_iface *iface, reg_t reg) -{ - return in_8(((volatile u8 *)iface->base) - + (((unsigned)reg) << iface->bsteps)); -} - -static inline void __write_reg(struct keywest_iface *iface, reg_t reg, u8 val) -{ - out_8(((volatile u8 *)iface->base) - + (((unsigned)reg) << iface->bsteps), val); - (void)__read_reg(iface, reg); - udelay(10); -} - -#define write_reg(reg, val) __write_reg(iface, reg, val) -#define read_reg(reg) __read_reg(iface, reg) - - - -#endif /* __I2C_KEYWEST_H__ */ diff --git a/kernel/busses/i2c-nforce2.c b/kernel/busses/i2c-nforce2.c deleted file mode 100644 index fde34905..00000000 --- a/kernel/busses/i2c-nforce2.c +++ /dev/null @@ -1,434 +0,0 @@ -/* - SMBus driver for nVidia nForce2 MCP - - Copyright (c) 2003 Hans-Frieder Vogt , - Based on - SMBus 2.0 driver for AMD-8111 IO-Hub - Copyright (c) 2002 Vojtech Pavlik - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -/* - SUPPORTED DEVICES PCI ID - nForce2 MCP 0064 - nForce2 Ultra 400 MCP 0084 - nForce3 Pro150 MCP 00D4 - nForce3 250Gb MCP 00E4 - nForce4 MCP 0052 - nForce4 MCP-04 0034 - nForce4 MCP51 0264 - nForce4 MCP55 0368 - nForce MCP61 03EB - nForce MCP65 0446 - - This driver supports the 2 SMBuses that are included in the MCP of the - nForce2/3/4 chipsets. -*/ - -/* Note: we assume there can only be one nForce2, with two SMBus interfaces */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "version.h" -#include "sensors_compat.h" - -MODULE_LICENSE("GPL"); -MODULE_AUTHOR ("Hans-Frieder Vogt "); -MODULE_DESCRIPTION("nForce2 SMBus driver"); - -#ifndef PCI_DEVICE_ID_NVIDIA_NFORCE2_SMBUS -#define PCI_DEVICE_ID_NVIDIA_NFORCE2_SMBUS 0x0064 -#endif - -#ifndef PCI_DEVICE_ID_NVIDIA_NFORCE2S_SMBUS -#define PCI_DEVICE_ID_NVIDIA_NFORCE2S_SMBUS 0x0084 -#endif - -#ifndef PCI_DEVICE_ID_NVIDIA_NFORCE3_SMBUS -#define PCI_DEVICE_ID_NVIDIA_NFORCE3_SMBUS 0x00D4 -#endif - -#ifndef PCI_DEVICE_ID_NVIDIA_NFORCE3S_SMBUS -#define PCI_DEVICE_ID_NVIDIA_NFORCE3S_SMBUS 0x00E4 -#endif - -#ifndef PCI_DEVICE_ID_NVIDIA_NFORCE4_SMBUS -#define PCI_DEVICE_ID_NVIDIA_NFORCE4_SMBUS 0x0052 -#endif - -#define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP04_SMBUS 0x0034 -#define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP51_SMBUS 0x0264 -#define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP55_SMBUS 0x0368 -#define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP61_SMBUS 0x03EB -#define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP65_SMBUS 0x0446 - - -struct nforce2_smbus { - struct i2c_adapter adapter; - int base; - int size; -}; - - -/* - * nVidia nForce2 SMBus control register definitions - * (Newer incarnations use standard BARs 4 and 5 instead) - */ -#define NFORCE_PCI_SMB1 0x50 -#define NFORCE_PCI_SMB2 0x54 - - -/* - * ACPI 2.0 chapter 13 SMBus 2.0 EC register model - */ -#define NVIDIA_SMB_PRTCL (smbus->base + 0x00) /* protocol, PEC */ -#define NVIDIA_SMB_STS (smbus->base + 0x01) /* status */ -#define NVIDIA_SMB_ADDR (smbus->base + 0x02) /* address */ -#define NVIDIA_SMB_CMD (smbus->base + 0x03) /* command */ -#define NVIDIA_SMB_DATA (smbus->base + 0x04) /* 32 data registers */ -#define NVIDIA_SMB_BCNT (smbus->base + 0x24) /* number of data bytes */ -#define NVIDIA_SMB_ALRM_A (smbus->base + 0x25) /* alarm address */ -#define NVIDIA_SMB_ALRM_D (smbus->base + 0x26) /* 2 bytes alarm data */ - -#define NVIDIA_SMB_STS_DONE 0x80 -#define NVIDIA_SMB_STS_ALRM 0x40 -#define NVIDIA_SMB_STS_RES 0x20 -#define NVIDIA_SMB_STS_STATUS 0x1f - -#define NVIDIA_SMB_PRTCL_WRITE 0x00 -#define NVIDIA_SMB_PRTCL_READ 0x01 -#define NVIDIA_SMB_PRTCL_QUICK 0x02 -#define NVIDIA_SMB_PRTCL_BYTE 0x04 -#define NVIDIA_SMB_PRTCL_BYTE_DATA 0x06 -#define NVIDIA_SMB_PRTCL_WORD_DATA 0x08 -#define NVIDIA_SMB_PRTCL_BLOCK_DATA 0x0a -#define NVIDIA_SMB_PRTCL_PROC_CALL 0x0c -#define NVIDIA_SMB_PRTCL_BLOCK_PROC_CALL 0x0d -#define NVIDIA_SMB_PRTCL_I2C_BLOCK_DATA 0x4a -#define NVIDIA_SMB_PRTCL_PEC 0x80 - -static struct pci_driver nforce2_driver; - -static s32 nforce2_access(struct i2c_adapter *adap, u16 addr, - unsigned short flags, char read_write, - u8 command, int size, union i2c_smbus_data *data); -static u32 nforce2_func(struct i2c_adapter *adapter); - - -static struct i2c_algorithm smbus_algorithm = { - .name = "Non-I2C SMBus adapter", - .id = I2C_ALGO_SMBUS, - .smbus_xfer = nforce2_access, - .functionality = nforce2_func, -}; - -/* Return -1 on error. See smbus.h for more information */ -s32 nforce2_access(struct i2c_adapter * adap, u16 addr, unsigned short flags, - char read_write, u8 command, int size, - union i2c_smbus_data * data) -{ - struct nforce2_smbus *smbus = adap->algo_data; - unsigned char protocol, pec, temp; - unsigned char len = 0; /* to keep the compiler quiet */ - int i; - - protocol = (read_write == I2C_SMBUS_READ) ? NVIDIA_SMB_PRTCL_READ : NVIDIA_SMB_PRTCL_WRITE; - pec = (flags & I2C_CLIENT_PEC) ? NVIDIA_SMB_PRTCL_PEC : 0; - - switch (size) { - - case I2C_SMBUS_QUICK: - protocol |= NVIDIA_SMB_PRTCL_QUICK; - read_write = I2C_SMBUS_WRITE; - break; - - case I2C_SMBUS_BYTE: - if (read_write == I2C_SMBUS_WRITE) - outb_p(command, NVIDIA_SMB_CMD); - protocol |= NVIDIA_SMB_PRTCL_BYTE; - break; - - case I2C_SMBUS_BYTE_DATA: - outb_p(command, NVIDIA_SMB_CMD); - if (read_write == I2C_SMBUS_WRITE) - outb_p(data->byte, NVIDIA_SMB_DATA); - protocol |= NVIDIA_SMB_PRTCL_BYTE_DATA; - break; - - case I2C_SMBUS_WORD_DATA: - outb_p(command, NVIDIA_SMB_CMD); - if (read_write == I2C_SMBUS_WRITE) { - outb_p(data->word, NVIDIA_SMB_DATA); - outb_p(data->word >> 8, NVIDIA_SMB_DATA+1); - } - protocol |= NVIDIA_SMB_PRTCL_WORD_DATA | pec; - break; - - case I2C_SMBUS_BLOCK_DATA: - outb_p(command, NVIDIA_SMB_CMD); - if (read_write == I2C_SMBUS_WRITE) { - len = min_t(u8, data->block[0], 32); - outb_p(len, NVIDIA_SMB_BCNT); - for (i = 0; i < len; i++) - outb_p(data->block[i + 1], NVIDIA_SMB_DATA+i); - } - protocol |= NVIDIA_SMB_PRTCL_BLOCK_DATA | pec; - break; - - case I2C_SMBUS_I2C_BLOCK_DATA: - len = min_t(u8, data->block[0], 32); - outb_p(command, NVIDIA_SMB_CMD); - outb_p(len, NVIDIA_SMB_BCNT); - if (read_write == I2C_SMBUS_WRITE) - for (i = 0; i < len; i++) - outb_p(data->block[i + 1], NVIDIA_SMB_DATA+i); - protocol |= NVIDIA_SMB_PRTCL_I2C_BLOCK_DATA; - break; - - case I2C_SMBUS_PROC_CALL: - printk(KERN_WARNING "i2c-nforce2.o: I2C_SMBUS_PROC_CALL not supported!\n"); - return -1; - - case I2C_SMBUS_BLOCK_PROC_CALL: - printk(KERN_WARNING "i2c-nforce2.o: I2C_SMBUS_BLOCK_PROC_CALL not supported!\n"); - return -1; - - default: - printk(KERN_WARNING "i2c-nforce2.c: Unsupported transaction %d\n", size); - return -1; - } - - outb_p((addr & 0x7f) << 1, NVIDIA_SMB_ADDR); - outb_p(protocol, NVIDIA_SMB_PRTCL); - - temp = inb_p(NVIDIA_SMB_STS); - - if (~temp & NVIDIA_SMB_STS_DONE) { - udelay(500); - temp = inb_p(NVIDIA_SMB_STS); - } - if (~temp & NVIDIA_SMB_STS_DONE) { - i2c_delay(HZ/100); - temp = inb_p(NVIDIA_SMB_STS); - } - - if ((~temp & NVIDIA_SMB_STS_DONE) || (temp & NVIDIA_SMB_STS_STATUS)) { - printk(KERN_DEBUG "i2c-nforce2.o: SMBus Timeout! (0x%02x)\n", - temp); - return -1; - } - - if (read_write == I2C_SMBUS_WRITE) - return 0; - - switch (size) { - - case I2C_SMBUS_BYTE: - case I2C_SMBUS_BYTE_DATA: - data->byte = inb_p(NVIDIA_SMB_DATA); - break; - - case I2C_SMBUS_WORD_DATA: - /* case I2C_SMBUS_PROC_CALL: not supported */ - data->word = inb_p(NVIDIA_SMB_DATA) | (inb_p(NVIDIA_SMB_DATA+1) << 8); - break; - - case I2C_SMBUS_BLOCK_DATA: - /* case I2C_SMBUS_BLOCK_PROC_CALL: not supported */ - len = inb_p(NVIDIA_SMB_BCNT); - len = min_t(u8, len, 32); - case I2C_SMBUS_I2C_BLOCK_DATA: - for (i = 0; i < len; i++) - data->block[i+1] = inb_p(NVIDIA_SMB_DATA + i); - data->block[0] = len; - break; - } - - return 0; -} - - -u32 nforce2_func(struct i2c_adapter *adapter) -{ - /* other functionality might be possible, but is not tested */ - return I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE | - I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA | - I2C_FUNC_SMBUS_HWPEC_CALC; -} - -static void nforce2_inc(struct i2c_adapter *adapter) -{ -#ifdef MODULE - MOD_INC_USE_COUNT; -#endif -} - -static void nforce2_dec(struct i2c_adapter *adapter) -{ -#ifdef MODULE - MOD_DEC_USE_COUNT; -#endif -} - -static struct pci_device_id nforce2_ids[] = { - { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE2_SMBUS, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, - { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE2S_SMBUS, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, - { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE3_SMBUS, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, - { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE3S_SMBUS, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, - { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE4_SMBUS, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, - { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP04_SMBUS, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, - { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP51_SMBUS, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, - { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP55_SMBUS, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, - { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP61_SMBUS, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, - { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP65_SMBUS, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, - { 0 } -}; - - -static int __devinit nforce2_probe_smb(struct pci_dev *dev, int bar, - int alt_reg, struct nforce2_smbus *smbus, const char *name) -{ - int error; - - smbus->base = pci_resource_start(dev, bar); - if (smbus->base) { - smbus->size = pci_resource_len(dev, bar); - } else { - /* Older incarnations of the device used non-standard BARs */ - u16 iobase; - - if (pci_read_config_word(dev, alt_reg, &iobase) - != PCIBIOS_SUCCESSFUL) { - printk(KERN_ERR "i2c-nforce2.o: Error reading PCI " - "config for %s\n", name); - return -1; - } - - smbus->base = iobase & PCI_BASE_ADDRESS_IO_MASK; - smbus->size = 8; - } - - if (!request_region(smbus->base, smbus->size, nforce2_driver.name)) { - printk (KERN_ERR "i2c-nforce2.o: Error requesting region %02x .. %02X for %s\n", smbus->base, smbus->base+smbus->size-1, name); - return -1; - } - - sprintf(smbus->adapter.name, "SMBus nForce2 adapter at %04x", smbus->base); - smbus->adapter.id = I2C_ALGO_SMBUS | I2C_HW_SMBUS_NFORCE2; - smbus->adapter.algo = &smbus_algorithm; - smbus->adapter.algo_data = smbus; - smbus->adapter.inc_use = nforce2_inc; - smbus->adapter.dec_use = nforce2_dec; - - error = i2c_add_adapter(&smbus->adapter); - if (error) { - printk(KERN_WARNING "i2c-nforce2.o: Failed to register adapter.\n"); - release_region(smbus->base, smbus->size); - return -1; - } - printk(KERN_INFO "i2c-nforce2.o: nForce2 SMBus adapter at %#x\n", smbus->base); - return 0; -} - - -static int __devinit nforce2_probe(struct pci_dev *dev, const struct pci_device_id *id) -{ - struct nforce2_smbus *smbuses; - int res1, res2; - - /* we support 2 SMBus adapters */ - if (!(smbuses = kmalloc(2*sizeof(struct nforce2_smbus), GFP_KERNEL))) - return -ENOMEM; - memset (smbuses, 0, 2*sizeof(struct nforce2_smbus)); - pci_set_drvdata(dev, smbuses); - - /* SMBus adapter 1 */ - res1 = nforce2_probe_smb(dev, 4, NFORCE_PCI_SMB1, &smbuses[0], "SMB1"); - if (res1 < 0) { - printk (KERN_ERR "i2c-nforce2.o: Error probing SMB1.\n"); - smbuses[0].base = 0; /* to have a check value */ - } - /* SMBus adapter 2 */ - res2 = nforce2_probe_smb(dev, 5, NFORCE_PCI_SMB2, &smbuses[1], "SMB2"); - if (res2 < 0) { - printk (KERN_ERR "i2c-nforce2.o: Error probing SMB2.\n"); - smbuses[1].base = 0; /* to have a check value */ - } - if ((res1 < 0) && (res2 < 0)) { - /* we did not find even one of the SMBuses, so we give up */ - kfree(smbuses); - return -ENODEV; - } - - return 0; -} - - -static void __devexit nforce2_remove(struct pci_dev *dev) -{ - struct nforce2_smbus *smbuses = (void*) pci_get_drvdata(dev); - - if (smbuses[0].base) { - i2c_del_adapter(&smbuses[0].adapter); - release_region(smbuses[0].base, smbuses[0].size); - } - if (smbuses[1].base) { - i2c_del_adapter(&smbuses[1].adapter); - release_region(smbuses[1].base, smbuses[1].size); - } - kfree(smbuses); -} - -static struct pci_driver nforce2_driver = { - .name = "nForce2 SMBus", - .id_table = nforce2_ids, - .probe = nforce2_probe, - .remove = __devexit_p(nforce2_remove), -}; - -int __init nforce2_init(void) -{ - printk(KERN_INFO "i2c-nforce2.o version %s (%s)\n", LM_VERSION, LM_DATE); - return pci_module_init(&nforce2_driver); -} - -void __exit nforce2_exit(void) -{ - pci_unregister_driver(&nforce2_driver); -} - -module_init(nforce2_init); -module_exit(nforce2_exit); - diff --git a/kernel/busses/i2c-piix4.c b/kernel/busses/i2c-piix4.c deleted file mode 100644 index 260bd2b0..00000000 --- a/kernel/busses/i2c-piix4.c +++ /dev/null @@ -1,570 +0,0 @@ -/* - piix4.c - Part of lm_sensors, Linux kernel modules for hardware - monitoring - Copyright (c) 1998 - 2002 Frodo Looijaard and - Philip Edelbrock - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -/* - Supports: - Intel PIIX4, 440MX - Serverworks OSB4, CSB5, CSB6, HT-1000 - ATI IXP200, IXP300, IXP400, SB600, SB700, SB800 - SMSC Victory66 - - Note: we assume there can only be one device, with one SMBus interface. -*/ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "version.h" -#include "sensors_compat.h" - - -/* PIIX4 SMBus address offsets */ -#define SMBHSTSTS (0 + piix4_smba) -#define SMBHSLVSTS (1 + piix4_smba) -#define SMBHSTCNT (2 + piix4_smba) -#define SMBHSTCMD (3 + piix4_smba) -#define SMBHSTADD (4 + piix4_smba) -#define SMBHSTDAT0 (5 + piix4_smba) -#define SMBHSTDAT1 (6 + piix4_smba) -#define SMBBLKDAT (7 + piix4_smba) -#define SMBSLVCNT (8 + piix4_smba) -#define SMBSHDWCMD (9 + piix4_smba) -#define SMBSLVEVT (0xA + piix4_smba) -#define SMBSLVDAT (0xC + piix4_smba) - -/* count for request_region */ -#define SMBIOSIZE 8 - -/* PCI Address Constants */ -#define SMBBA 0x090 -#define SMBHSTCFG 0x0D2 -#define SMBSLVC 0x0D3 -#define SMBSHDW1 0x0D4 -#define SMBSHDW2 0x0D5 -#define SMBREV 0x0D6 - -/* Other settings */ -#define MAX_TIMEOUT 500 -#define ENABLE_INT9 0 - -/* PIIX4 constants */ -#define PIIX4_QUICK 0x00 -#define PIIX4_BYTE 0x04 -#define PIIX4_BYTE_DATA 0x08 -#define PIIX4_WORD_DATA 0x0C -#define PIIX4_BLOCK_DATA 0x14 - -/* insmod parameters */ - -/* If force is set to anything different from 0, we forcibly enable the - PIIX4. DANGEROUS! */ -static int force = 0; -MODULE_PARM(force, "i"); -MODULE_PARM_DESC(force, "Forcibly enable the PIIX4. DANGEROUS!"); - -/* If force_addr is set to anything different from 0, we forcibly enable - the PIIX4 at the given address. VERY DANGEROUS! */ -static int force_addr = 0; -MODULE_PARM(force_addr, "i"); -MODULE_PARM_DESC(force_addr, - "Forcibly enable the PIIX4 at the given address. " - "EXTREMELY DANGEROUS!"); - -static unsigned short piix4_smba = 0; -static struct pci_driver piix4_driver; - -#ifdef CONFIG_X86 -/* - * Get DMI information. - */ - -extern int is_unsafe_smbus; - -static int __devinit ibm_dmi_probe(void) -{ - return is_unsafe_smbus; -} -#endif - -/* Detect whether a PIIX4 can be found, and initialize it, where necessary. - Note the differences between kernels with the old PCI BIOS interface and - newer kernels with the real PCI interface. In compat.h some things are - defined to make the transition easier. */ -static int __devinit piix4_setup(struct pci_dev *PIIX4_dev, - const struct pci_device_id *id) -{ - unsigned char temp; - - /* match up the function */ - if (PCI_FUNC(PIIX4_dev->devfn) != id->driver_data) - return -ENODEV; - - printk(KERN_INFO "Found %s device\n", PIIX4_dev->name); - -#ifdef CONFIG_X86 - if(ibm_dmi_probe() && PIIX4_dev->vendor == PCI_VENDOR_ID_INTEL) { - printk(KERN_ERR "i2c-piix4.o: IBM system detected; this module " - "may corrupt your serial eeprom! Refusing to load " - "module!\n"); - return -EPERM; - } -#endif - - /* Determine the address of the SMBus areas */ - if (force_addr) { - piix4_smba = force_addr & 0xfff0; - force = 0; - } else { - pci_read_config_word(PIIX4_dev, SMBBA, &piix4_smba); - piix4_smba &= 0xfff0; - if(piix4_smba == 0) { - printk(KERN_ERR "i2c-piix4.o: SMBus base address " - "uninitialized - upgrade BIOS or use " - "force_addr=0xaddr\n"); - return -ENODEV; - } - } - - if (!request_region(piix4_smba, SMBIOSIZE, piix4_driver.name)) { - printk(KERN_ERR "i2c-piix4.o: SMBus region 0x%x already in " - "use!\n", piix4_smba); - return -ENODEV; - } - - pci_read_config_byte(PIIX4_dev, SMBHSTCFG, &temp); - - /* If force_addr is set, we program the new address here. Just to make - sure, we disable the PIIX4 first. */ - if (force_addr) { - pci_write_config_byte(PIIX4_dev, SMBHSTCFG, temp & 0xfe); - pci_write_config_word(PIIX4_dev, SMBBA, piix4_smba); - pci_write_config_byte(PIIX4_dev, SMBHSTCFG, temp | 0x01); - printk(KERN_INFO "i2c-piix4.o: WARNING: SMBus interface set to " - "new address %04x!\n", piix4_smba); - } else if ((temp & 1) == 0) { - if (force) { - /* This should never need to be done, but has been - * noted that many Dell machines have the SMBus - * interface on the PIIX4 disabled!? NOTE: This assumes - * I/O space and other allocations WERE done by the - * Bios! Don't complain if your hardware does weird - * things after enabling this. :') Check for Bios - * updates before resorting to this. - */ - pci_write_config_byte(PIIX4_dev, SMBHSTCFG, - temp | 1); - printk(KERN_NOTICE "i2c-piix4.o: WARNING: SMBus " - "interface has been FORCEFULLY ENABLED!\n"); - } else { - printk(KERN_ERR "i2c-piix4.o: Host SMBus controller " - "not enabled!\n"); - release_region(piix4_smba, SMBIOSIZE); - piix4_smba = 0; - return -ENODEV; - } - } - -#ifdef DEBUG - if (((temp & 0x0E) == 8) || ((temp & 0x0E) == 2)) - printk(KERN_DEBUG "i2c-piix4.o: Using Interrupt 9 for " - "SMBus.\n"); - else if ((temp & 0x0E) == 0) - printk(KERN_DEBUG "i2c-piix4.o: Using Interrupt SMI# " - "for SMBus.\n"); - else - printk(KERN_ERR "i2c-piix4.o: Illegal Interrupt configuration " - "(or code out of date)!\n"); - - pci_read_config_byte(PIIX4_dev, SMBREV, &temp); - printk(KERN_DEBUG "i2c-piix4.o: SMBREV = 0x%X\n", temp); - printk(KERN_DEBUG "i2c-piix4.o: SMBA = 0x%X\n", piix4_smba); -#endif /* DEBUG */ - - return 0; -} - - -/* Another internally used function */ -int piix4_transaction(void) -{ - int temp; - int result = 0; - int timeout = 0; - -#ifdef DEBUG - printk - (KERN_DEBUG "i2c-piix4.o: Transaction (pre): CNT=%02x, CMD=%02x, ADD=%02x, DAT0=%02x, " - "DAT1=%02x\n", inb_p(SMBHSTCNT), inb_p(SMBHSTCMD), - inb_p(SMBHSTADD), inb_p(SMBHSTDAT0), inb_p(SMBHSTDAT1)); -#endif - - /* Make sure the SMBus host is ready to start transmitting */ - if ((temp = inb_p(SMBHSTSTS)) != 0x00) { -#ifdef DEBUG - printk(KERN_DEBUG "i2c-piix4.o: SMBus busy (%02x). Resetting...\n", - temp); -#endif - outb_p(temp, SMBHSTSTS); - if ((temp = inb_p(SMBHSTSTS)) != 0x00) { -#ifdef DEBUG - printk(KERN_ERR "i2c-piix4.o: Failed! (%02x)\n", temp); -#endif - return -1; - } else { -#ifdef DEBUG - printk(KERN_DEBUG "i2c-piix4.o: Successful!\n"); -#endif - } - } - - /* start the transaction by setting bit 6 */ - outb_p(inb(SMBHSTCNT) | 0x040, SMBHSTCNT); - - /* We will always wait for a fraction of a second! (See PIIX4 docs errata) */ - do { - i2c_delay(1); - temp = inb_p(SMBHSTSTS); - } while ((temp & 0x01) && (timeout++ < MAX_TIMEOUT)); - -#ifdef DEBUG - /* If the SMBus is still busy, we give up */ - if (timeout >= MAX_TIMEOUT) { - printk(KERN_ERR "i2c-piix4.o: SMBus Timeout!\n"); - result = -1; - } -#endif - - if (temp & 0x10) { - result = -1; -#ifdef DEBUG - printk(KERN_ERR "i2c-piix4.o: Error: Failed bus transaction\n"); -#endif - } - - if (temp & 0x08) { - result = -1; - printk - (KERN_ERR "i2c-piix4.o: Bus collision! SMBus may be locked until next hard\n" - "reset. (sorry!)\n"); - /* Clock stops and slave is stuck in mid-transmission */ - } - - if (temp & 0x04) { - result = -1; -#ifdef DEBUG - printk(KERN_ERR "i2c-piix4.o: Error: no response!\n"); -#endif - } - - if (inb_p(SMBHSTSTS) != 0x00) - outb_p(inb(SMBHSTSTS), SMBHSTSTS); - -#ifdef DEBUG - if ((temp = inb_p(SMBHSTSTS)) != 0x00) { - printk - (KERN_ERR "i2c-piix4.o: Failed reset at end of transaction (%02x)\n", - temp); - } - printk - (KERN_DEBUG "i2c-piix4.o: Transaction (post): CNT=%02x, CMD=%02x, ADD=%02x, " - "DAT0=%02x, DAT1=%02x\n", inb_p(SMBHSTCNT), inb_p(SMBHSTCMD), - inb_p(SMBHSTADD), inb_p(SMBHSTDAT0), inb_p(SMBHSTDAT1)); -#endif - return result; -} - -/* Return -1 on error. */ -s32 piix4_access(struct i2c_adapter * adap, u16 addr, - unsigned short flags, char read_write, - u8 command, int size, union i2c_smbus_data * data) -{ - int i, len; - - switch (size) { - case I2C_SMBUS_QUICK: - outb_p(((addr & 0x7f) << 1) | (read_write & 0x01), - SMBHSTADD); - size = PIIX4_QUICK; - break; - case I2C_SMBUS_BYTE: - outb_p(((addr & 0x7f) << 1) | (read_write & 0x01), - SMBHSTADD); - if (read_write == I2C_SMBUS_WRITE) - outb_p(command, SMBHSTCMD); - size = PIIX4_BYTE; - break; - case I2C_SMBUS_BYTE_DATA: - outb_p(((addr & 0x7f) << 1) | (read_write & 0x01), - SMBHSTADD); - outb_p(command, SMBHSTCMD); - if (read_write == I2C_SMBUS_WRITE) - outb_p(data->byte, SMBHSTDAT0); - size = PIIX4_BYTE_DATA; - break; - case I2C_SMBUS_WORD_DATA: - outb_p(((addr & 0x7f) << 1) | (read_write & 0x01), - SMBHSTADD); - outb_p(command, SMBHSTCMD); - if (read_write == I2C_SMBUS_WRITE) { - outb_p(data->word & 0xff, SMBHSTDAT0); - outb_p((data->word & 0xff00) >> 8, SMBHSTDAT1); - } - size = PIIX4_WORD_DATA; - break; - case I2C_SMBUS_BLOCK_DATA: - outb_p(((addr & 0x7f) << 1) | (read_write & 0x01), - SMBHSTADD); - outb_p(command, SMBHSTCMD); - if (read_write == I2C_SMBUS_WRITE) { - len = data->block[0]; - if (len < 0) - len = 0; - if (len > 32) - len = 32; - outb_p(len, SMBHSTDAT0); - i = inb_p(SMBHSTCNT); /* Reset SMBBLKDAT */ - for (i = 1; i <= len; i++) - outb_p(data->block[i], SMBBLKDAT); - } - size = PIIX4_BLOCK_DATA; - break; - default: - printk - (KERN_WARNING "i2c-piix4.o: Unsupported transaction %d\n", size); - return -1; - } - - outb_p((size & 0x1C) + (ENABLE_INT9 & 1), SMBHSTCNT); - - if (piix4_transaction()) /* Error in transaction */ - return -1; - - if ((read_write == I2C_SMBUS_WRITE) || (size == PIIX4_QUICK)) - return 0; - - - switch (size) { - case PIIX4_BYTE: - case PIIX4_BYTE_DATA: - data->byte = inb_p(SMBHSTDAT0); - break; - case PIIX4_WORD_DATA: - data->word = inb_p(SMBHSTDAT0) + (inb_p(SMBHSTDAT1) << 8); - break; - case PIIX4_BLOCK_DATA: - data->block[0] = inb_p(SMBHSTDAT0); - i = inb_p(SMBHSTCNT); /* Reset SMBBLKDAT */ - for (i = 1; i <= data->block[0]; i++) - data->block[i] = inb_p(SMBBLKDAT); - break; - } - return 0; -} - -static void piix4_inc(struct i2c_adapter *adapter) -{ -#ifdef MODULE - MOD_INC_USE_COUNT; -#endif -} - -static void piix4_dec(struct i2c_adapter *adapter) -{ -#ifdef MODULE - MOD_DEC_USE_COUNT; -#endif -} - -u32 piix4_func(struct i2c_adapter *adapter) -{ - return I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE | - I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA | - I2C_FUNC_SMBUS_BLOCK_DATA; -} - -static struct i2c_algorithm smbus_algorithm = { - .name = "Non-I2C SMBus adapter", - .id = I2C_ALGO_SMBUS, - .smbus_xfer = piix4_access, - .functionality = piix4_func, -}; - -static struct i2c_adapter piix4_adapter = { - .id = I2C_ALGO_SMBUS | I2C_HW_SMBUS_PIIX4, - .algo = &smbus_algorithm, - .inc_use = piix4_inc, - .dec_use = piix4_dec, -}; - -#define PCI_DEVICE_ID_ATI_IXP200_SMBUS 0x4353 -#define PCI_DEVICE_ID_ATI_IXP300_SMBUS 0x4363 -#define PCI_DEVICE_ID_ATI_IXP400_SMBUS 0x4372 -#define PCI_DEVICE_ID_ATI_SBX00_SMBUS 0x4385 - -#ifndef PCI_DEVICE_ID_SERVERWORKS_CSB6 -#define PCI_DEVICE_ID_SERVERWORKS_CSB6 0x0203 -#endif - -#define PCI_DEVICE_ID_SERVERWORKS_HT1000SB 0x0205 - -static struct pci_device_id piix4_ids[] __devinitdata = { - { - .vendor = PCI_VENDOR_ID_INTEL, - .device = PCI_DEVICE_ID_INTEL_82371AB_3, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - .driver_data = 3 - }, - { - .vendor = PCI_VENDOR_ID_ATI, - .device = PCI_DEVICE_ID_ATI_IXP200_SMBUS, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - .driver_data = 0, - }, - { - .vendor = PCI_VENDOR_ID_ATI, - .device = PCI_DEVICE_ID_ATI_IXP300_SMBUS, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - .driver_data = 0, - }, - { - .vendor = PCI_VENDOR_ID_ATI, - .device = PCI_DEVICE_ID_ATI_IXP400_SMBUS, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - .driver_data = 0, - }, - { - .vendor = PCI_VENDOR_ID_ATI, - .device = PCI_DEVICE_ID_ATI_SBX00_SMBUS, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - .driver_data = 0, - }, - { - .vendor = PCI_VENDOR_ID_SERVERWORKS, - .device = PCI_DEVICE_ID_SERVERWORKS_OSB4, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - .driver_data = 0, - }, - { - .vendor = PCI_VENDOR_ID_SERVERWORKS, - .device = PCI_DEVICE_ID_SERVERWORKS_CSB5, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - .driver_data = 0, - }, - { - .vendor = PCI_VENDOR_ID_SERVERWORKS, - .device = PCI_DEVICE_ID_SERVERWORKS_CSB6, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - .driver_data = 0, - }, - { - .vendor = PCI_VENDOR_ID_SERVERWORKS, - .device = PCI_DEVICE_ID_SERVERWORKS_HT1000SB, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - .driver_data = 0, - }, - { - .vendor = PCI_VENDOR_ID_INTEL, - .device = PCI_DEVICE_ID_INTEL_82443MX_3, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - .driver_data = 3, - }, - { - .vendor = PCI_VENDOR_ID_EFAR, - .device = PCI_DEVICE_ID_EFAR_SLC90E66_3, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - .driver_data = 0, - }, - { 0, } -}; - -static int __devinit piix4_probe(struct pci_dev *dev, - const struct pci_device_id *id) -{ - int retval; - - retval = piix4_setup(dev, id); - if (retval) - return retval; - - sprintf(piix4_adapter.name, "SMBus PIIX4 adapter at %04x", - piix4_smba); - - if ((retval = i2c_add_adapter(&piix4_adapter))) { - printk(KERN_ERR "i2c-piix4.o: Couldn't register adapter!\n"); - release_region(piix4_smba, SMBIOSIZE); - piix4_smba = 0; - } - - return retval; -} - -static void __devexit piix4_remove(struct pci_dev *dev) -{ - if (piix4_smba) { - i2c_del_adapter(&piix4_adapter); - release_region(piix4_smba, SMBIOSIZE); - piix4_smba = 0; - } -} - -static struct pci_driver piix4_driver = { - .name = "piix4 smbus", - .id_table = piix4_ids, - .probe = piix4_probe, - .remove = __devexit_p(piix4_remove), -}; - -static int __init i2c_piix4_init(void) -{ - printk("i2c-piix4.o version %s (%s)\n", LM_VERSION, LM_DATE); - return pci_module_init(&piix4_driver); -} - -static void __exit i2c_piix4_exit(void) -{ - pci_unregister_driver(&piix4_driver); -} - -MODULE_AUTHOR("Frodo Looijaard and " - "Philip Edelbrock "); -MODULE_DESCRIPTION("PIIX4 SMBus driver"); -MODULE_LICENSE("GPL"); - -module_init(i2c_piix4_init); -module_exit(i2c_piix4_exit); diff --git a/kernel/busses/i2c-savage4.c b/kernel/busses/i2c-savage4.c deleted file mode 100644 index 429757ce..00000000 --- a/kernel/busses/i2c-savage4.c +++ /dev/null @@ -1,223 +0,0 @@ -/* - i2c-savage4.c - Part of lm_sensors, Linux kernel modules for hardware - monitoring - Copyright (C) 1998-2003 The LM Sensors Team - Alexander Wold - Mark D. Studebaker - - Based on i2c-voodoo3.c. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -/* This interfaces to the I2C bus of the Savage4 to gain access to - the BT869 and possibly other I2C devices. The DDC bus is not - yet supported because its register is not memory-mapped. -*/ - -#include -#include -#include -#include -#include -#include -#include /* for HZ */ -#include "version.h" -#include "sensors_compat.h" - -/* device IDs */ -#define PCI_CHIP_SAVAGE4 0x8A22 -#define PCI_CHIP_SAVAGE2000 0x9102 - -#define REG 0xff20 /* Serial Port 1 Register */ - -/* bit locations in the register */ -#define I2C_ENAB 0x00000020 -#define I2C_SCL_OUT 0x00000001 -#define I2C_SDA_OUT 0x00000002 -#define I2C_SCL_IN 0x00000008 -#define I2C_SDA_IN 0x00000010 - -/* delays */ -#define CYCLE_DELAY 10 -#define TIMEOUT (HZ / 2) - - -static void config_s4(struct pci_dev *dev); - -static unsigned long ioaddr; - -/* The sav GPIO registers don't have individual masks for each bit - so we always have to read before writing. */ - -static void bit_savi2c_setscl(void *data, int val) -{ - unsigned int r; - r = readl(ioaddr + REG); - if(val) - r |= I2C_SCL_OUT; - else - r &= ~I2C_SCL_OUT; - writel(r, ioaddr + REG); - readl(ioaddr + REG); /* flush posted write */ -} - -static void bit_savi2c_setsda(void *data, int val) -{ - unsigned int r; - r = readl(ioaddr + REG); - if(val) - r |= I2C_SDA_OUT; - else - r &= ~I2C_SDA_OUT; - writel(r, ioaddr + REG); - readl(ioaddr + REG); /* flush posted write */ -} - -/* The GPIO pins are open drain, so the pins always remain outputs. - We rely on the i2c-algo-bit routines to set the pins high before - reading the input from other chips. */ - -static int bit_savi2c_getscl(void *data) -{ - return (0 != (readl(ioaddr + REG) & I2C_SCL_IN)); -} - -static int bit_savi2c_getsda(void *data) -{ - return (0 != (readl(ioaddr + REG) & I2C_SDA_IN)); -} - -/* Configures the chip */ - -void config_s4(struct pci_dev *dev) -{ - unsigned int cadr; - - /* map memory */ - cadr = dev->resource[0].start; - cadr &= PCI_BASE_ADDRESS_MEM_MASK; - ioaddr = (unsigned long)ioremap_nocache(cadr, 0x0080000); - if(ioaddr) { -// writel(0x8160, ioaddr + REG2); - writel(0x00000020, ioaddr + REG); - printk("i2c-savage4: Using Savage4 at 0x%lx\n", ioaddr); - } -} - -static void savage4_inc(struct i2c_adapter *adapter) -{ -#ifdef MODULE - MOD_INC_USE_COUNT; -#endif -} - -static void savage4_dec(struct i2c_adapter *adapter) -{ -#ifdef MODULE - MOD_DEC_USE_COUNT; -#endif -} - -static struct i2c_algo_bit_data sav_i2c_bit_data = { - .setsda = bit_savi2c_setsda, - .setscl = bit_savi2c_setscl, - .getsda = bit_savi2c_getsda, - .getscl = bit_savi2c_getscl, - .udelay = CYCLE_DELAY, - .mdelay = CYCLE_DELAY, - .timeout = TIMEOUT -}; - -static struct i2c_adapter savage4_i2c_adapter = { - .name = "I2C Savage4 adapter", - .id = I2C_HW_B_SAVG, - .algo_data = &sav_i2c_bit_data, - .inc_use = savage4_inc, - .dec_use = savage4_dec, -}; - -static struct pci_device_id savage4_ids[] __devinitdata = { - { - .vendor = PCI_VENDOR_ID_S3, - .device = PCI_CHIP_SAVAGE4, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - }, - { - .vendor = PCI_VENDOR_ID_S3, - .device = PCI_CHIP_SAVAGE2000, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - }, - { 0, } -}; - -static int __devinit savage4_probe(struct pci_dev *dev, const struct pci_device_id *id) -{ - config_s4(dev); - return i2c_bit_add_bus(&savage4_i2c_adapter); -} - -static void __devexit savage4_remove(struct pci_dev *dev) -{ - i2c_bit_del_bus(&savage4_i2c_adapter); -} - - -/* Don't register driver to avoid driver conflicts */ -/* -static struct pci_driver savage4_driver = { - .name = "savage4 smbus", - .id_table = savage4_ids, - .probe = savage4_probe, - .remove = __devexit_p(savage4_remove), -}; -*/ - -static int __init i2c_savage4_init(void) -{ - struct pci_dev *dev; - const struct pci_device_id *id; - - printk("i2c-savage4.o version %s (%s)\n", LM_VERSION, LM_DATE); -/* - return pci_module_init(&savage4_driver); -*/ - pci_for_each_dev(dev) { - id = pci_match_device(savage4_ids, dev); - if(id) - if(savage4_probe(dev, id) >= 0) - return 0; - } - return -ENODEV; -} - -static void __exit i2c_savage4_exit(void) -{ -/* - pci_unregister_driver(&savage4_driver); -*/ - savage4_remove(NULL); - iounmap((void *)ioaddr); -} - -MODULE_AUTHOR("Alexander Wold " - "and Mark D. Studebaker "); -MODULE_DESCRIPTION("Savage4 I2C/SMBus driver"); -MODULE_LICENSE("GPL"); - -module_init(i2c_savage4_init); -module_exit(i2c_savage4_exit); diff --git a/kernel/busses/i2c-sis5595.c b/kernel/busses/i2c-sis5595.c deleted file mode 100644 index 6c729ce7..00000000 --- a/kernel/busses/i2c-sis5595.c +++ /dev/null @@ -1,487 +0,0 @@ -/* - sis5595.c - Part of lm_sensors, Linux kernel modules for hardware - monitoring - Copyright (c) 1998, 1999 Frodo Looijaard and - Philip Edelbrock - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -/* Note: we assume there can only be one SIS5595 with one SMBus interface */ - -/* - Note: all have mfr. ID 0x1039. - SUPPORTED PCI ID - 5595 0008 - - Note: these chips contain a 0008 device which is incompatible with the - 5595. We recognize these by the presence of the listed - "blacklist" PCI ID and refuse to load. - - NOT SUPPORTED PCI ID BLACKLIST PCI ID - 540 0008 0540 - 550 0008 0550 - 5513 0008 5511 - 5581 0008 5597 - 5582 0008 5597 - 5597 0008 5597 - 5598 0008 5597/5598 - 630 0008 0630 - 645 0008 0645 - 646 0008 0646 - 648 0008 0648 - 650 0008 0650 - 651 0008 0651 - 730 0008 0730 - 735 0008 0735 - 745 0008 0745 - 746 0008 0746 -*/ - -/* TO DO: - * Add Block Transfers (ugly, but supported by the adapter) - * Add adapter resets - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "version.h" -#include "sensors_compat.h" - -MODULE_LICENSE("GPL"); - -static int blacklist[] = { - PCI_DEVICE_ID_SI_540, - PCI_DEVICE_ID_SI_550, - PCI_DEVICE_ID_SI_630, - PCI_DEVICE_ID_SI_730, - PCI_DEVICE_ID_SI_5511, /* 5513 chip has the 0008 device but - that ID shows up in other chips so we - use the 5511 ID for recognition */ - PCI_DEVICE_ID_SI_5597, - PCI_DEVICE_ID_SI_5598, - 0x645, - 0x646, - 0x648, - 0x650, - 0x651, - 0x735, - 0x745, - 0x746, - 0 }; - -/* Length of ISA address segment */ -#define SIS5595_EXTENT 8 -/* SIS5595 SMBus registers */ -#define SMB_STS_LO 0x00 -#define SMB_STS_HI 0x01 -#define SMB_CTL_LO 0x02 -#define SMB_CTL_HI 0x03 -#define SMB_ADDR 0x04 -#define SMB_CMD 0x05 -#define SMB_PCNT 0x06 -#define SMB_CNT 0x07 -#define SMB_BYTE 0x08 -#define SMB_DEV 0x10 -#define SMB_DB0 0x11 -#define SMB_DB1 0x12 -#define SMB_HAA 0x13 - -/* PCI Address Constants */ -#define SMB_INDEX 0x38 -#define SMB_DAT 0x39 -#define SIS5595_ENABLE_REG 0x40 -#define ACPI_BASE 0x90 - -/* Other settings */ -#define MAX_TIMEOUT 500 - -/* SIS5595 constants */ -#define SIS5595_QUICK 0x00 -#define SIS5595_BYTE 0x02 -#define SIS5595_BYTE_DATA 0x04 -#define SIS5595_WORD_DATA 0x06 -#define SIS5595_PROC_CALL 0x08 -#define SIS5595_BLOCK_DATA 0x0A - -/* insmod parameters */ - -/* If force_addr is set to anything different from 0, we forcibly enable - the device at the given address. */ -static int force_addr = 0; -MODULE_PARM(force_addr, "i"); -MODULE_PARM_DESC(force_addr, - "Initialize the base address of the i2c controller"); - -static int sis5595_transaction(void); - -static struct pci_driver sis5595_driver; -static unsigned short sis5595_base = 0; - -static u8 sis5595_read(u8 reg) -{ - outb(reg, sis5595_base + SMB_INDEX); - return inb(sis5595_base + SMB_DAT); -} - -static void sis5595_write(u8 reg, u8 data) -{ - outb(reg, sis5595_base + SMB_INDEX); - outb(data, sis5595_base + SMB_DAT); -} - - -/* Detect whether a SIS5595 can be found, and initialize it, where necessary. - Note the differences between kernels with the old PCI BIOS interface and - newer kernels with the real PCI interface. In compat.h some things are - defined to make the transition easier. */ -int sis5595_setup(struct pci_dev *SIS5595_dev) -{ - u16 a; - u8 val; - int *i; - - /* Look for imposters */ - for(i = blacklist; *i != 0; i++) { - if (pci_find_device(PCI_VENDOR_ID_SI, *i, NULL)) { - printk("i2c-sis5595.o: Error: Looked for SIS5595 but found unsupported device %.4X\n", *i); - return -ENODEV; - } - } - -/* Determine the address of the SMBus areas */ - pci_read_config_word(SIS5595_dev, ACPI_BASE, &sis5595_base); - if(sis5595_base == 0 && force_addr == 0) { - printk("i2c-sis5595.o: ACPI base address uninitialized - upgrade BIOS or use force_addr=0xaddr\n"); - return -ENODEV; - } - - if(force_addr) - sis5595_base = force_addr & ~(SIS5595_EXTENT - 1); -#ifdef DEBUG - printk("ACPI Base address: %04x\n", sis5595_base); -#endif - /* NB: We grab just the two SMBus registers here, but this may still - * interfere with ACPI :-( */ - if (check_region(sis5595_base + SMB_INDEX, 2)) { - printk - ("i2c-sis5595.o: SMBus registers 0x%04x-0x%04x already in use!\n", - sis5595_base + SMB_INDEX, - sis5595_base + SMB_INDEX + 1); - return -ENODEV; - } - - if(force_addr) { - printk("i2c-sis5595.o: forcing ISA address 0x%04X\n", sis5595_base); - if (PCIBIOS_SUCCESSFUL != - pci_write_config_word(SIS5595_dev, ACPI_BASE, sis5595_base)) - return -ENODEV; - if (PCIBIOS_SUCCESSFUL != - pci_read_config_word(SIS5595_dev, ACPI_BASE, &a)) - return -ENODEV; - if ((a & ~(SIS5595_EXTENT - 1)) != sis5595_base) { - /* doesn't work for some chips! */ - printk("i2c-sis5595.o: force address failed - not supported?\n"); - return -ENODEV; - } - } - - if (PCIBIOS_SUCCESSFUL != - pci_read_config_byte(SIS5595_dev, SIS5595_ENABLE_REG, &val)) - return -ENODEV; - if((val & 0x80) == 0) { - printk("sis5595.o: enabling ACPI\n"); - if (PCIBIOS_SUCCESSFUL != - pci_write_config_byte(SIS5595_dev, SIS5595_ENABLE_REG, - val | 0x80)) - return -ENODEV; - if (PCIBIOS_SUCCESSFUL != - pci_read_config_byte(SIS5595_dev, SIS5595_ENABLE_REG, &val)) - return -ENODEV; - if((val & 0x80) == 0) { /* doesn't work for some chips? */ - printk("sis5595.o: ACPI enable failed - not supported?\n"); - return -ENODEV; - } - } - - /* Everything is happy, let's grab the memory and set things up. */ - request_region(sis5595_base + SMB_INDEX, 2, sis5595_driver.name); - return(0); -} - - -/* Another internally used function */ -int sis5595_transaction(void) -{ - int temp; - int result = 0; - int timeout = 0; - - /* Make sure the SMBus host is ready to start transmitting */ - if ( - (temp = - sis5595_read(SMB_STS_LO) + (sis5595_read(SMB_STS_HI) << 8)) != - 0x00) { -#ifdef DEBUG - printk("i2c-sis5595.o: SMBus busy (%04x). Resetting...\n", - temp); -#endif - sis5595_write(SMB_STS_LO, temp & 0xff); - sis5595_write(SMB_STS_HI, temp >> 8); - if ( - (temp = - sis5595_read(SMB_STS_LO) + - (sis5595_read(SMB_STS_HI) << 8)) != 0x00) { -#ifdef DEBUG - printk("i2c-sis5595.o: Failed! (%02x)\n", temp); -#endif - return -1; - } else { -#ifdef DEBUG - printk("i2c-sis5595.o: Successful!\n"); -#endif - } - } - - /* start the transaction by setting bit 4 */ - sis5595_write(SMB_CTL_LO, sis5595_read(SMB_CTL_LO) | 0x10); - - /* We will always wait for a fraction of a second! */ - do { - i2c_delay(1); - temp = sis5595_read(SMB_STS_LO); - } while (!(temp & 0x40) && (timeout++ < MAX_TIMEOUT)); - - /* If the SMBus is still busy, we give up */ - if (timeout >= MAX_TIMEOUT) { -#ifdef DEBUG - printk("i2c-sis5595.o: SMBus Timeout!\n"); -#endif - result = -1; - } - - if (temp & 0x10) { - result = -1; -#ifdef DEBUG - printk("i2c-sis5595.o: Error: Failed bus transaction\n"); -#endif - } - - if (temp & 0x20) { - result = -1; - printk - ("i2c-sis5595.o: Bus collision! SMBus may be locked until next hard\n" - "reset (or not...)\n"); - /* Clock stops and slave is stuck in mid-transmission */ - } - - if ( - (temp = - sis5595_read(SMB_STS_LO) + (sis5595_read(SMB_STS_HI) << 8)) != - 0x00) { - sis5595_write(SMB_STS_LO, temp & 0xff); - sis5595_write(SMB_STS_HI, temp >> 8); - } - - if ( - (temp = - sis5595_read(SMB_STS_LO) + (sis5595_read(SMB_STS_HI) << 8)) != - 0x00) { - -#ifdef DEBUG - printk - ("i2c-sis5595.o: Failed reset at end of transaction (%02x)\n", - temp); -#endif - } - return result; -} - -/* Return -1 on error. */ -s32 sis5595_access(struct i2c_adapter * adap, u16 addr, - unsigned short flags, char read_write, - u8 command, int size, union i2c_smbus_data * data) -{ - switch (size) { - case I2C_SMBUS_QUICK: - sis5595_write(SMB_ADDR, - ((addr & 0x7f) << 1) | (read_write & 0x01)); - size = SIS5595_QUICK; - break; - case I2C_SMBUS_BYTE: - sis5595_write(SMB_ADDR, - ((addr & 0x7f) << 1) | (read_write & 0x01)); - if (read_write == I2C_SMBUS_WRITE) - sis5595_write(SMB_CMD, command); - size = SIS5595_BYTE; - break; - case I2C_SMBUS_BYTE_DATA: - sis5595_write(SMB_ADDR, - ((addr & 0x7f) << 1) | (read_write & 0x01)); - sis5595_write(SMB_CMD, command); - if (read_write == I2C_SMBUS_WRITE) - sis5595_write(SMB_BYTE, data->byte); - size = SIS5595_BYTE_DATA; - break; - case I2C_SMBUS_PROC_CALL: - case I2C_SMBUS_WORD_DATA: - sis5595_write(SMB_ADDR, - ((addr & 0x7f) << 1) | (read_write & 0x01)); - sis5595_write(SMB_CMD, command); - if (read_write == I2C_SMBUS_WRITE) { - sis5595_write(SMB_BYTE, data->word & 0xff); - sis5595_write(SMB_BYTE + 1, - (data->word & 0xff00) >> 8); - } - size = - (size == - I2C_SMBUS_PROC_CALL) ? SIS5595_PROC_CALL : - SIS5595_WORD_DATA; - break; - default: - printk - (KERN_WARNING "sis5595.o: Unsupported transaction %d\n", size); - return -1; - } - - sis5595_write(SMB_CTL_LO, ((size & 0x0E))); - - if (sis5595_transaction()) /* Error in transaction */ - return -1; - - if ((size != SIS5595_PROC_CALL) && - ((read_write == I2C_SMBUS_WRITE) || (size == SIS5595_QUICK))) - return 0; - - - switch (size) { - case SIS5595_BYTE: - case SIS5595_BYTE_DATA: - data->byte = sis5595_read(SMB_BYTE); - break; - case SIS5595_WORD_DATA: - case SIS5595_PROC_CALL: - data->word = - sis5595_read(SMB_BYTE) + - (sis5595_read(SMB_BYTE + 1) << 8); - break; - } - return 0; -} - -static void sis5595_inc(struct i2c_adapter *adapter) -{ -#ifdef MODULE - MOD_INC_USE_COUNT; -#endif -} - -static void sis5595_dec(struct i2c_adapter *adapter) -{ -#ifdef MODULE - MOD_DEC_USE_COUNT; -#endif -} - -u32 sis5595_func(struct i2c_adapter *adapter) -{ - return I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE | - I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA | - I2C_FUNC_SMBUS_PROC_CALL; -} - - -static struct i2c_algorithm smbus_algorithm = { - .name = "Non-I2C SMBus adapter", - .id = I2C_ALGO_SMBUS, - .smbus_xfer = sis5595_access, - .functionality = sis5595_func, -}; - -static struct i2c_adapter sis5595_adapter = { - .id = I2C_ALGO_SMBUS | I2C_HW_SMBUS_SIS5595, - .algo = &smbus_algorithm, - .inc_use = sis5595_inc, - .dec_use = sis5595_dec, -}; - - -static struct pci_device_id sis5595_ids[] __devinitdata = { - { - .vendor = PCI_VENDOR_ID_SI, - .device = PCI_DEVICE_ID_SI_503, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - }, - { 0, } -}; - -static int __devinit sis5595_probe(struct pci_dev *dev, const struct pci_device_id *id) -{ - - if (sis5595_setup(dev)) { - printk - ("i2c-sis5595.o: SIS5595 not detected, module not inserted.\n"); - - return -ENODEV; - } - - sprintf(sis5595_adapter.name, "SMBus SIS5595 adapter at %04x", - sis5595_base + SMB_INDEX); - i2c_add_adapter(&sis5595_adapter); - - return 0; -} - -static void __devexit sis5595_remove(struct pci_dev *dev) -{ - i2c_del_adapter(&sis5595_adapter); - release_region(sis5595_base + SMB_INDEX, 2); -} - - -static struct pci_driver sis5595_driver = { - .name = "sis5595 smbus", - .id_table = sis5595_ids, - .probe = sis5595_probe, - .remove = __devexit_p(sis5595_remove), -}; - -static int __init i2c_sis5595_init(void) -{ - printk("i2c-sis5595.o version %s (%s)\n", LM_VERSION, LM_DATE); - return pci_module_init(&sis5595_driver); -} - - -static void __exit i2c_sis5595_exit(void) -{ - pci_unregister_driver(&sis5595_driver); -} - - - -MODULE_AUTHOR("Frodo Looijaard "); -MODULE_DESCRIPTION("SIS5595 SMBus driver"); - -module_init(i2c_sis5595_init); -module_exit(i2c_sis5595_exit); diff --git a/kernel/busses/i2c-sis630.c b/kernel/busses/i2c-sis630.c deleted file mode 100644 index 88c02d9f..00000000 --- a/kernel/busses/i2c-sis630.c +++ /dev/null @@ -1,544 +0,0 @@ -/* - i2c-sis630.c - Part of lm_sensors, Linux kernel modules for hardware - monitoring - - Copyright (c) 2002,2003 Alexander Malysh - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -/* - Changes: - 24.08.2002 - Fixed the typo in sis630_access (Thanks to Mark M. Hoffman) - Changed sis630_transaction.(Thanks to Mark M. Hoffman) - 18.09.2002 - Added SIS730 as supported. - 21.09.2002 - Added high_clock module option.If this option is set - used Host Master Clock 56KHz (default 14KHz).For now we save old Host - Master Clock and after transaction completed restore (otherwise - it's confuse BIOS and hung Machine). - 24.09.2002 - Fixed typo in sis630_access - Fixed logical error by restoring of Host Master Clock - 31.07.2003 - Added block data read/write support. -*/ - -/* - Status: beta - - Supports: - SIS 630 - SIS 730 - - Note: we assume there can only be one device, with one SMBus interface. -*/ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "version.h" -#include "sensors_compat.h" - - -#ifdef DEBUG -#define DBG(x...) printk(KERN_DEBUG "i2c-sis630.o: " x) -#else -#define DBG(x...) -#endif - -/* SIS630 SMBus registers */ -#define SMB_STS 0x80 /* status */ -#define SMB_EN 0x81 /* status enable */ -#define SMB_CNT 0x82 -#define SMBHOST_CNT 0x83 -#define SMB_ADDR 0x84 -#define SMB_CMD 0x85 -#define SMB_PCOUNT 0x86 /* processed count */ -#define SMB_COUNT 0x87 -#define SMB_BYTE 0x88 /* ~0x8F data byte field */ -#define SMBDEV_ADDR 0x90 -#define SMB_DB0 0x91 -#define SMB_DB1 0x92 -#define SMB_SAA 0x93 - -/* register count for request_region */ -#define SIS630_SMB_IOREGION 20 - -/* PCI address constants */ -/* acpi base address register */ -#define SIS630_ACPI_BASE_REG 0x74 -/* bios control register */ -#define SIS630_BIOS_CTL_REG 0x40 - -/* Other settings */ -#define MAX_TIMEOUT 500 - -/* SIS630 constants */ -#define SIS630_QUICK 0x00 -#define SIS630_BYTE 0x01 -#define SIS630_BYTE_DATA 0x02 -#define SIS630_WORD_DATA 0x03 -#define SIS630_PCALL 0x04 -#define SIS630_BLOCK_DATA 0x05 - -static struct pci_driver sis630_driver; - -/* insmod parameters */ -static int high_clock = 0; -static int force = 0; -MODULE_PARM(high_clock, "i"); -MODULE_PARM_DESC(high_clock, "Set Host Master Clock to 56KHz (default 14KHz)."); -MODULE_PARM(force, "i"); -MODULE_PARM_DESC(force, "Forcibly enable the SIS630. DANGEROUS!"); - -/* acpi base address */ -static unsigned short acpi_base = 0; - -/* supported chips */ -static int supported[] = { - PCI_DEVICE_ID_SI_630, - PCI_DEVICE_ID_SI_730, - 0 /* terminates the list */ -}; - -static inline u8 sis630_read(u8 reg) { - return inb(acpi_base + reg); -} - -static inline void sis630_write(u8 reg, u8 data) { - outb(data, acpi_base + reg); -} - -static int sis630_transaction_start(int size, u8 *oldclock) { - int temp; - - /* - Make sure the SMBus host is ready to start transmitting. - */ - if ((temp = sis630_read(SMB_CNT) & 0x03) != 0x00) { - DBG("SMBus busy (%02x).Resetting...\n",temp); - /* kill smbus transaction */ - sis630_write(SMBHOST_CNT, 0x20); - - if ((temp = sis630_read(SMB_CNT) & 0x03) != 0x00) { - DBG("Failed! (%02x)\n", temp); - return -1; - } else { - DBG("Successful!\n"); - } - } - - /* save old clock, so we can prevent machine for hung */ - *oldclock = sis630_read(SMB_CNT); - - DBG("saved clock 0x%02x\n", *oldclock); - - /* disable timeout interrupt , set Host Master Clock to 56KHz if requested */ - if (high_clock > 0) - sis630_write(SMB_CNT, 0x20); - else - sis630_write(SMB_CNT, (*oldclock & ~0x40)); - - /* clear all sticky bits */ - temp = sis630_read(SMB_STS); - sis630_write(SMB_STS, temp & 0x1e); - - /* start the transaction by setting bit 4 and size */ - sis630_write(SMBHOST_CNT,0x10 | (size & 0x07)); - - return 0; -} - -static int sis630_transaction_wait(int size) { - int temp, result = 0, timeout = 0; - - /* We will always wait for a fraction of a second! */ - do { - i2c_delay(1); - temp = sis630_read(SMB_STS); - /* check if block transmitted */ - if (size == SIS630_BLOCK_DATA && (temp & 0x10)) - break; - } while (!(temp & 0x0e) && (timeout++ < MAX_TIMEOUT)); - - /* If the SMBus is still busy, we give up */ - if (timeout >= MAX_TIMEOUT) { - DBG("SMBus Timeout!\n"); - result = -1; - } - - if (temp & 0x02) { - result = -1; - DBG("Error: Failed bus transaction\n"); - } - - if (temp & 0x04) { - result = -1; - printk(KERN_ERR "i2c-sis630.o: Bus collision!\n"); - /* - TBD: Datasheet say: - the software should clear this bit and restart SMBUS operation. - Should we do it or user start request again? - */ - } - - return result; -} - -static void sis630_transaction_end(u8 oldclock) { - int temp = 0; - - /* clear all status "sticky" bits */ - sis630_write(SMB_STS, temp); - - DBG("SMB_CNT before clock restore 0x%02x\n", sis630_read(SMB_CNT)); - - /* - * restore old Host Master Clock if high_clock is set - * and oldclock was not 56KHz - */ - if (high_clock > 0 && !(oldclock & 0x20)) - sis630_write(SMB_CNT,(sis630_read(SMB_CNT) & ~0x20)); - - DBG("SMB_CNT after clock restore 0x%02x\n", sis630_read(SMB_CNT)); -} - -static int sis630_transaction(int size) { - int result = 0; - u8 oldclock = 0; - - if (!(result = sis630_transaction_start(size, &oldclock))) { - result = sis630_transaction_wait(size); - sis630_transaction_end(oldclock); - } - - return result; -} - -static int sis630_block_data(union i2c_smbus_data * data, int read_write) { - int i, len = 0, rc = 0; - u8 oldclock = 0; - - if (read_write == I2C_SMBUS_WRITE) { - len = data->block[0]; - if (len < 0) - len = 0; - else if (len > 32) - len = 32; - sis630_write(SMB_COUNT, len); - for (i=1; i <= len; i++) { - DBG("set data 0x%02x\n", data->block[i]); - /* set data */ - sis630_write(SMB_BYTE+(i-1)%8, data->block[i]); - if (i==8 || (len<8 && i==len)) { - DBG("start trans len=%d i=%d\n",len ,i); - /* first transaction */ - if (sis630_transaction_start(SIS630_BLOCK_DATA, &oldclock)) - return -1; - } - else if ((i-1)%8 == 7 || i==len) { - DBG("trans_wait len=%d i=%d\n",len,i); - if (i>8) { - DBG("clear smbary_sts len=%d i=%d\n",len,i); - /* - If this is not first transaction, - we must clear sticky bit. - clear SMBARY_STS - */ - sis630_write(SMB_STS,0x10); - } - if (sis630_transaction_wait(SIS630_BLOCK_DATA)) { - DBG("trans_wait failed\n"); - rc = -1; - break; - } - - } - } - } - else { /* read request */ - data->block[0] = len = 0; - if (sis630_transaction_start(SIS630_BLOCK_DATA, &oldclock)) { - return -1; - } - do { - if (sis630_transaction_wait(SIS630_BLOCK_DATA)) { - DBG("trans_wait failed\n"); - rc = -1; - break; - } - /* if this first transaction then read byte count */ - if (len == 0) - data->block[0] = sis630_read(SMB_COUNT); - - /* just to be sure */ - if (data->block[0] > 32) - data->block[0] = 32; - - DBG("block data read len=0x%x\n", data->block[0]); - - for (i=0; i < 8 && len < data->block[0]; i++,len++) { - DBG("read i=%d len=%d\n", i, len); - data->block[len+1] = sis630_read(SMB_BYTE+i); - } - - DBG("clear smbary_sts len=%d i=%d\n",len,i); - - /* clear SMBARY_STS */ - sis630_write(SMB_STS,0x10); - } while(len < data->block[0]); - } - - sis630_transaction_end(oldclock); - - return rc; -} - -/* Return -1 on error. */ -static s32 sis630_access(struct i2c_adapter * adap, u16 addr, - unsigned short flags, char read_write, - u8 command, int size, union i2c_smbus_data * data) -{ - - switch (size) { - case I2C_SMBUS_QUICK: - sis630_write(SMB_ADDR, ((addr & 0x7f) << 1) | (read_write & 0x01)); - size = SIS630_QUICK; - break; - case I2C_SMBUS_BYTE: - sis630_write(SMB_ADDR, ((addr & 0x7f) << 1) | (read_write & 0x01)); - if (read_write == I2C_SMBUS_WRITE) - sis630_write(SMB_CMD, command); - size = SIS630_BYTE; - break; - case I2C_SMBUS_BYTE_DATA: - sis630_write(SMB_ADDR, ((addr & 0x7f) << 1) | (read_write & 0x01)); - sis630_write(SMB_CMD, command); - if (read_write == I2C_SMBUS_WRITE) - sis630_write(SMB_BYTE, data->byte); - size = SIS630_BYTE_DATA; - break; - case I2C_SMBUS_PROC_CALL: - case I2C_SMBUS_WORD_DATA: - sis630_write(SMB_ADDR,((addr & 0x7f) << 1) | (read_write & 0x01)); - sis630_write(SMB_CMD, command); - if (read_write == I2C_SMBUS_WRITE) { - sis630_write(SMB_BYTE, data->word & 0xff); - sis630_write(SMB_BYTE + 1,(data->word & 0xff00) >> 8); - } - size = (size == I2C_SMBUS_PROC_CALL ? SIS630_PCALL : SIS630_WORD_DATA); - break; - case I2C_SMBUS_BLOCK_DATA: - sis630_write(SMB_ADDR,((addr & 0x7f) << 1) | (read_write & 0x01)); - sis630_write(SMB_CMD, command); - size = SIS630_BLOCK_DATA; - return sis630_block_data(data, read_write); - default: - printk("Unsupported I2C size\n"); - return -1; - break; - } - - - if (sis630_transaction(size)) - return -1; - - if ((size != SIS630_PCALL) && - ((read_write == I2C_SMBUS_WRITE) || (size == SIS630_QUICK))) { - return 0; - } - - switch(size) { - case SIS630_BYTE: - case SIS630_BYTE_DATA: - data->byte = sis630_read(SMB_BYTE); - break; - case SIS630_PCALL: - case SIS630_WORD_DATA: - data->word = sis630_read(SMB_BYTE) + (sis630_read(SMB_BYTE + 1) << 8); - break; - default: - return -1; - break; - } - - return 0; -} - -static void sis630_inc(struct i2c_adapter *adapter) -{ -#ifdef MODULE - MOD_INC_USE_COUNT; -#endif -} - -static void sis630_dec(struct i2c_adapter *adapter) -{ -#ifdef MODULE - MOD_DEC_USE_COUNT; -#endif -} - - -static u32 sis630_func(struct i2c_adapter *adapter) { - return I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE | I2C_FUNC_SMBUS_BYTE_DATA | - I2C_FUNC_SMBUS_WORD_DATA | I2C_FUNC_SMBUS_PROC_CALL | - I2C_FUNC_SMBUS_BLOCK_DATA; -} - -static int __devinit sis630_setup(struct pci_dev *sis630_dev) { - unsigned char b; - struct pci_dev *dummy = NULL; - int i; - - /* check for supported SiS devices */ - for (i=0; supported[i] > 0; i++) { - if ((dummy = pci_find_device(PCI_VENDOR_ID_SI, supported[i], dummy))) - break; /* found */ - } - - if (!dummy && force > 0) { - printk(KERN_ERR "i2c-sis630.o: WARNING: Can't detect SIS630 compatible device, but " - "loading because of force option enabled\n"); - } - else if (!dummy) { - return -ENODEV; - } - - /* - Enable ACPI first , so we can accsess reg 74-75 - in acpi io space and read acpi base addr - */ - if (PCIBIOS_SUCCESSFUL != - pci_read_config_byte(sis630_dev, SIS630_BIOS_CTL_REG,&b)) { - printk(KERN_ERR "i2c-sis630.o: Error: Can't read bios ctl reg\n"); - return -ENODEV; - } - - /* if ACPI already enabled , do nothing */ - if (!(b & 0x80) && - PCIBIOS_SUCCESSFUL != - pci_write_config_byte(sis630_dev,SIS630_BIOS_CTL_REG,b|0x80)) { - printk(KERN_ERR "i2c-sis630.o: Error: Can't enable ACPI\n"); - return -ENODEV; - } - /* Determine the ACPI base address */ - if (PCIBIOS_SUCCESSFUL != - pci_read_config_word(sis630_dev,SIS630_ACPI_BASE_REG,&acpi_base)) { - printk(KERN_ERR "i2c-sis630.o: Error: Can't determine ACPI base address\n"); - return -ENODEV; - } - - DBG("ACPI base at 0x%04x\n", acpi_base); - - /* Everything is happy, let's grab the memory and set things up. */ - if (!request_region(acpi_base + SMB_STS, SIS630_SMB_IOREGION, - sis630_driver.name)){ - printk(KERN_ERR "i2c-sis630.o: SMBus registers 0x%04x-0x%04x " - "already in use!\n",acpi_base + SMB_STS, acpi_base + SMB_SAA); - acpi_base = 0; /* reset acpi_base */ - return -ENODEV; - } - - return 0; -} - - -static struct i2c_algorithm smbus_algorithm = { - .name = "Non-I2C SMBus adapter", - .id = I2C_ALGO_SMBUS, - .smbus_xfer = sis630_access, - .functionality = sis630_func, -}; - -static struct i2c_adapter sis630_adapter = { - .id = I2C_ALGO_SMBUS | I2C_HW_SMBUS_SIS630, - .algo = &smbus_algorithm, - .inc_use = sis630_inc, - .dec_use = sis630_dec, -}; - - -static struct pci_device_id sis630_ids[] __devinitdata = { - { - .vendor = PCI_VENDOR_ID_SI, - .device = PCI_DEVICE_ID_SI_503, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - }, - { 0, } -}; - -static int __devinit sis630_probe(struct pci_dev *dev, const struct pci_device_id *id) -{ - if (sis630_setup(dev)) { - printk(KERN_ERR "i2c-sis630.o: SIS630 comp. bus not detected, module not inserted.\n"); - return -ENODEV; - } - - sprintf(sis630_adapter.name, "SMBus SIS630 adapter at %04x", - acpi_base + SMB_STS); - - return i2c_add_adapter(&sis630_adapter); -} - -static void __devexit sis630_remove(struct pci_dev *dev) -{ - if (acpi_base) { - i2c_del_adapter(&sis630_adapter); - release_region(acpi_base + SMB_STS, SIS630_SMB_IOREGION); - acpi_base = 0; - } -} - - -static struct pci_driver sis630_driver = { - .name = "sis630 smbus", - .id_table = sis630_ids, - .probe = sis630_probe, - .remove = __devexit_p(sis630_remove), -}; - -static int __init i2c_sis630_init(void) -{ - printk("i2c-sis630.o version %s (%s)\n", LM_VERSION, LM_DATE); - return pci_module_init(&sis630_driver); -} - - -static void __exit i2c_sis630_exit(void) -{ - pci_unregister_driver(&sis630_driver); -} - - - - -MODULE_LICENSE("GPL"); - -MODULE_AUTHOR("Alexander Malysh "); -MODULE_DESCRIPTION("SIS630 SMBus driver"); - -module_init(i2c_sis630_init); -module_exit(i2c_sis630_exit); diff --git a/kernel/busses/i2c-sis645.c b/kernel/busses/i2c-sis645.c deleted file mode 100644 index 52916cf8..00000000 --- a/kernel/busses/i2c-sis645.c +++ /dev/null @@ -1,605 +0,0 @@ -/* - sis645.c - Part of lm_sensors, Linux kernel modules for hardware - monitoring - - Copyright (c) 2003 Mark M. Hoffman - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -/* - This module must be considered BETA unless and until - the chipset manufacturer releases a datasheet. - - The register definitions are based on the SiS630. - The method for *finding* the registers is based on trial and error. - - A history of changes to this file is available by SVN: - http://www.lm-sensors.org/wiki/Download -*/ - -/* 25th March 2004 - Support for Sis655 chipsets added by Ken Healy -*/ - -/* - Note: we assume there can only be one SiS645 with one SMBus interface -*/ - -/* #define DEBUG 1 */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "version.h" -#include "sensors_compat.h" - -#define DRV_NAME "i2c-sis645" - -/* SiS645DX north bridge (defined in 2.4.21) */ -#ifndef PCI_DEVICE_ID_SI_646 -#define PCI_DEVICE_ID_SI_646 0x0646 -#endif - -/* SiS648 north bridge (defined in 2.4.21) */ -#ifndef PCI_DEVICE_ID_SI_648 -#define PCI_DEVICE_ID_SI_648 0x0648 -#endif - -/* SiS650 north bridge (defined in 2.4.19) */ -#ifndef PCI_DEVICE_ID_SI_650 -#define PCI_DEVICE_ID_SI_650 0x0650 -#endif - -/* SiS651 north bridge (defined in 2.4.21)*/ -#ifndef PCI_DEVICE_ID_SI_651 -#define PCI_DEVICE_ID_SI_651 0x0651 -#endif - -/* SiS655 north bridge (defined in 2.4.22)*/ -#ifndef PCI_DEVICE_ID_SI_655 -#define PCI_DEVICE_ID_SI_655 0x0655 -#endif - -/* SiS746 north bridge (defined in 2.4.21) */ -#ifndef PCI_DEVICE_ID_SI_746 -#define PCI_DEVICE_ID_SI_746 0x0746 -#endif - -/* SiS85C503/5513 (LPC Bridge) */ -#ifndef PCI_DEVICE_ID_SI_LPC -#define PCI_DEVICE_ID_SI_LPC 0x0018 -#endif - -/* SiS961 south bridge */ -#ifndef PCI_DEVICE_ID_SI_961 -#define PCI_DEVICE_ID_SI_961 0x0961 -#endif - -/* SiS962 south bridge */ -#ifndef PCI_DEVICE_ID_SI_962 -#define PCI_DEVICE_ID_SI_962 0x0962 -#endif - -/* SiS963 south bridge */ -#ifndef PCI_DEVICE_ID_SI_963 -#define PCI_DEVICE_ID_SI_963 0x0963 -#endif - -/* SMBus ID */ -#ifndef PCI_DEVICE_ID_SI_SMBUS -#define PCI_DEVICE_ID_SI_SMBUS 0x16 -#endif - -/* base address register in PCI config space */ -#define SIS645_BAR 0x04 - -/* SiS645 SMBus registers */ -#define SMB_STS 0x00 -#define SMB_EN 0x01 -#define SMB_CNT 0x02 -#define SMB_HOST_CNT 0x03 -#define SMB_ADDR 0x04 -#define SMB_CMD 0x05 -#define SMB_PCOUNT 0x06 -#define SMB_COUNT 0x07 -#define SMB_BYTE 0x08 -#define SMB_DEV_ADDR 0x10 -#define SMB_DB0 0x11 -#define SMB_DB1 0x12 -#define SMB_SAA 0x13 - -/* register count for request_region */ -#define SMB_IOSIZE 0x20 - -/* Other settings */ -#define MAX_TIMEOUT 500 - -/* SiS645 SMBus constants */ -#define SIS645_QUICK 0x00 -#define SIS645_BYTE 0x01 -#define SIS645_BYTE_DATA 0x02 -#define SIS645_WORD_DATA 0x03 -#define SIS645_PROC_CALL 0x04 -#define SIS645_BLOCK_DATA 0x05 - -static struct pci_driver sis645_driver; -static struct i2c_adapter sis645_adapter; -static u16 sis645_smbus_base = 0; - -static inline u8 sis645_read(u8 reg) -{ - return inb(sis645_smbus_base + reg) ; -} - -static inline void sis645_write(u8 reg, u8 data) -{ - outb(data, sis645_smbus_base + reg) ; -} - -#ifdef CONFIG_HOTPLUG - -/* Turns on SMBus device if it is not; return 0 iff successful - */ -static int __devinit sis645_enable_smbus(struct pci_dev *dev) -{ - u8 val = 0; - - pci_read_config_byte(dev, 0x77, &val); - -#ifdef DEBUG - printk(KERN_DEBUG DRV_NAME ": Config byte was 0x%02x.\n", val); -#endif - - pci_write_config_byte(dev, 0x77, val & ~0x10); - - pci_read_config_byte(dev, 0x77, &val); - - if (val & 0x10) { -#ifdef DEBUG - printk(KERN_DEBUG DRV_NAME ": Config byte stuck!\n"); -#endif - return -1; - } - - return 0; -} - -/* Builds the basic pci_dev for SiS645 SMBus - */ -static int __devinit sis645_build_dev(struct pci_dev **smbus_dev, - struct pci_dev *bridge_dev) -{ - struct pci_dev temp_dev; - u16 vid = 0, did = 0; - int ret; - - /* fill in the device structure for search */ - memset(&temp_dev, 0, sizeof(temp_dev)); - temp_dev.bus = bridge_dev->bus; - temp_dev.sysdata = bridge_dev->bus->sysdata; - temp_dev.hdr_type = PCI_HEADER_TYPE_NORMAL; - - /* the SMBus device is function 1 on the same unit as the ISA bridge */ - temp_dev.devfn = bridge_dev->devfn + 1; - - /* query to make sure */ - ret = pci_read_config_word(&temp_dev, PCI_VENDOR_ID, &vid); - if (ret || PCI_VENDOR_ID_SI != vid) { - printk(KERN_ERR DRV_NAME ": Couldn't find SMBus device!\n"); - return ret; - } - temp_dev.vendor = vid; - - ret = pci_read_config_word(&temp_dev, PCI_DEVICE_ID, &did); - if (ret || PCI_DEVICE_ID_SI_SMBUS != did) { - printk(KERN_ERR DRV_NAME ": Couldn't find SMBus device!\n"); - return ret; - } - temp_dev.device = did; - - /* ok, we've got it... request some memory and finish it off */ - *smbus_dev = kmalloc(sizeof(**smbus_dev), GFP_ATOMIC); - if (NULL == *smbus_dev) { - printk(KERN_ERR DRV_NAME ": Out of memory!\n"); - return -ENOMEM; - } - - **smbus_dev = temp_dev; - - ret = pci_setup_device(*smbus_dev); - if (ret) { - printk(KERN_ERR DRV_NAME ": pci_setup_device failed (0x%08x)\n",ret); - } - return ret; -} - -/* See if a SMBus can be found, and enable it if possible. - */ -static int __devinit sis645_hotplug_smbus(void) -{ - int ret; - struct pci_dev *smbus_dev, *bridge_dev ; - - if ((bridge_dev = pci_find_device(PCI_VENDOR_ID_SI, - PCI_DEVICE_ID_SI_961, NULL))) - printk(KERN_INFO DRV_NAME ": Found SiS961 south bridge.\n"); - - else if ((bridge_dev = pci_find_device(PCI_VENDOR_ID_SI, - PCI_DEVICE_ID_SI_962, NULL))) - printk(KERN_INFO DRV_NAME ": Found SiS962 [MuTIOL Media IO].\n"); - - else if ((bridge_dev = pci_find_device(PCI_VENDOR_ID_SI, - PCI_DEVICE_ID_SI_963, NULL))) - printk(KERN_INFO DRV_NAME ": Found SiS963 [MuTIOL Media IO].\n"); - - else if ((bridge_dev = pci_find_device(PCI_VENDOR_ID_SI, - PCI_DEVICE_ID_SI_503, NULL)) || - (bridge_dev = pci_find_device(PCI_VENDOR_ID_SI, - PCI_DEVICE_ID_SI_LPC, NULL))) { - - printk(KERN_INFO DRV_NAME ": Found SiS south bridge in compatability mode(?)\n"); - - /* look for known compatible north bridges */ - if ((NULL == pci_find_device(PCI_VENDOR_ID_SI, - PCI_DEVICE_ID_SI_645, NULL)) - && (NULL == pci_find_device(PCI_VENDOR_ID_SI, - PCI_DEVICE_ID_SI_646, NULL)) - && (NULL == pci_find_device(PCI_VENDOR_ID_SI, - PCI_DEVICE_ID_SI_648, NULL)) - && (NULL == pci_find_device(PCI_VENDOR_ID_SI, - PCI_DEVICE_ID_SI_650, NULL)) - && (NULL == pci_find_device(PCI_VENDOR_ID_SI, - PCI_DEVICE_ID_SI_651, NULL)) - && (NULL == pci_find_device(PCI_VENDOR_ID_SI, - PCI_DEVICE_ID_SI_655, NULL)) - && (NULL == pci_find_device(PCI_VENDOR_ID_SI, - PCI_DEVICE_ID_SI_735, NULL)) - && (NULL == pci_find_device(PCI_VENDOR_ID_SI, - PCI_DEVICE_ID_SI_745, NULL)) - && (NULL == pci_find_device(PCI_VENDOR_ID_SI, - PCI_DEVICE_ID_SI_746, NULL))) { - printk(KERN_ERR DRV_NAME ": Can't find suitable host bridge!\n"); - return -ENODEV; - } - } else { - printk(KERN_ERR DRV_NAME ": Can't find suitable south bridge!\n"); - return -ENODEV; - } - - /* if we get this far, we think the smbus device is present */ - - if ((ret = sis645_enable_smbus(bridge_dev))) - return ret; - - if ((ret = sis645_build_dev(&smbus_dev, bridge_dev))) - return ret; - - if ((ret = pci_enable_device(smbus_dev))) { - printk(KERN_ERR DRV_NAME ": Can't pci_enable SMBus device!" - " (0x%08x)\n", ret); - return ret; - } - - pci_insert_device(smbus_dev, smbus_dev->bus); - - return 0; -} -#endif /* CONFIG_HOTPLUG */ - -/* Execute a SMBus transaction. - int size is from SIS645_QUICK to SIS645_BLOCK_DATA - */ -static int sis645_transaction(int size) -{ - int temp; - int result = 0; - int timeout = 0; - - /* Make sure the SMBus host is ready to start transmitting */ - if (((temp = sis645_read(SMB_CNT)) & 0x03) != 0x00) { -#ifdef DEBUG - printk(KERN_DEBUG DRV_NAME ": SMBus busy (0x%02x). Resetting...\n", - temp); -#endif - - /* kill the transaction */ - sis645_write(SMB_HOST_CNT, 0x20); - - /* check it again */ - if (((temp = sis645_read(SMB_CNT)) & 0x03) != 0x00) { -#ifdef DEBUG - printk(KERN_DEBUG DRV_NAME ": Failed! (0x%02x)\n", temp); -#endif - return -1; - } else { -#ifdef DEBUG - printk(KERN_DEBUG DRV_NAME ": Successful!\n"); -#endif - } - } - - /* Turn off timeout interrupts, set fast host clock */ - sis645_write(SMB_CNT, 0x20); - - /* clear all (sticky) status flags */ - temp = sis645_read(SMB_STS); - sis645_write(SMB_STS, temp & 0x1e); - - /* start the transaction by setting bit 4 and size bits */ - sis645_write(SMB_HOST_CNT, 0x10 | (size & 0x07)); - - /* We will always wait for a fraction of a second! */ - do { - i2c_delay(1); - temp = sis645_read(SMB_STS); - } while (!(temp & 0x0e) && (timeout++ < MAX_TIMEOUT)); - - /* If the SMBus is still busy, we give up */ - if (timeout >= MAX_TIMEOUT) { - printk(KERN_DEBUG DRV_NAME ": SMBus Timeout! (0x%02x)\n",temp); - result = -1; - } - - /* device error - probably missing ACK */ - if (temp & 0x02) { -#ifdef DEBUG - printk(KERN_DEBUG DRV_NAME ": Failed bus transaction!\n"); -#endif - result = -1; - } - - /* bus collision */ - if (temp & 0x04) { -#ifdef DEBUG - printk(KERN_DEBUG DRV_NAME ": Bus collision!\n"); -#endif - result = -1; - } - - /* Finish up by resetting the bus */ - sis645_write(SMB_STS, temp); - if ((temp = sis645_read(SMB_STS))) { -#ifdef DEBUG - printk(KERN_DEBUG DRV_NAME ": Failed reset at end of transaction!" - " (0x%02x)\n", temp); -#endif - } - - return result; -} - -/* Return -1 on error. */ -static s32 sis645_access(struct i2c_adapter * adap, u16 addr, - unsigned short flags, char read_write, - u8 command, int size, union i2c_smbus_data * data) -{ - - switch (size) { - case I2C_SMBUS_QUICK: - sis645_write(SMB_ADDR, ((addr & 0x7f) << 1) | (read_write & 0x01)); - size = SIS645_QUICK; - break; - - case I2C_SMBUS_BYTE: - sis645_write(SMB_ADDR, ((addr & 0x7f) << 1) | (read_write & 0x01)); - if (read_write == I2C_SMBUS_WRITE) - sis645_write(SMB_CMD, command); - size = SIS645_BYTE; - break; - - case I2C_SMBUS_BYTE_DATA: - sis645_write(SMB_ADDR, ((addr & 0x7f) << 1) | (read_write & 0x01)); - sis645_write(SMB_CMD, command); - if (read_write == I2C_SMBUS_WRITE) - sis645_write(SMB_BYTE, data->byte); - size = SIS645_BYTE_DATA; - break; - - case I2C_SMBUS_PROC_CALL: - case I2C_SMBUS_WORD_DATA: - sis645_write(SMB_ADDR, ((addr & 0x7f) << 1) | (read_write & 0x01)); - sis645_write(SMB_CMD, command); - if (read_write == I2C_SMBUS_WRITE) { - sis645_write(SMB_BYTE, data->word & 0xff); - sis645_write(SMB_BYTE + 1, (data->word & 0xff00) >> 8); - } - size = (size == I2C_SMBUS_PROC_CALL ? SIS645_PROC_CALL : SIS645_WORD_DATA); - break; - - case I2C_SMBUS_BLOCK_DATA: - /* TO DO: */ - printk(KERN_INFO DRV_NAME ": SMBus block not implemented!\n"); - return -1; - break; - - default: - printk(KERN_INFO DRV_NAME ": Unsupported I2C size\n"); - return -1; - break; - } - - if (sis645_transaction(size)) - return -1; - - if ((size != SIS645_PROC_CALL) && - ((read_write == I2C_SMBUS_WRITE) || (size == SIS645_QUICK))) - return 0; - - switch (size) { - case SIS645_BYTE: - case SIS645_BYTE_DATA: - data->byte = sis645_read(SMB_BYTE); - break; - - case SIS645_WORD_DATA: - case SIS645_PROC_CALL: - data->word = sis645_read(SMB_BYTE) + - (sis645_read(SMB_BYTE + 1) << 8); - break; - } - return 0; -} - -static void sis645_inc(struct i2c_adapter *adapter) -{ -#ifdef MODULE - MOD_INC_USE_COUNT; -#endif -} - -static void sis645_dec(struct i2c_adapter *adapter) -{ -#ifdef MODULE - MOD_DEC_USE_COUNT; -#endif -} - -static u32 sis645_func(struct i2c_adapter *adapter) -{ - return I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE | - I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA | - I2C_FUNC_SMBUS_PROC_CALL; -} - -static struct i2c_algorithm smbus_algorithm = { - .name = "Non-I2C SMBus adapter", - .id = I2C_ALGO_SMBUS, - .smbus_xfer = sis645_access, - .functionality = sis645_func, -}; - -static struct i2c_adapter sis645_adapter = { - .id = I2C_ALGO_SMBUS | I2C_HW_SMBUS_SIS645, - .algo = &smbus_algorithm, - .inc_use = sis645_inc, - .dec_use = sis645_dec, -}; - -static struct pci_device_id sis645_ids[] __devinitdata = { - { - .vendor = PCI_VENDOR_ID_SI, - .device = PCI_DEVICE_ID_SI_SMBUS, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - }, - { 0, } -}; - -static int __devinit sis645_probe(struct pci_dev *dev, - const struct pci_device_id *id) -{ - u16 ww = 0; - int retval; - - if (sis645_smbus_base) { - dev_err(dev, "Only one device supported.\n"); - return -EBUSY; - } - - pci_read_config_word(dev, PCI_CLASS_DEVICE, &ww); - if (PCI_CLASS_SERIAL_SMBUS != ww) { - dev_err(dev, "Unsupported device class 0x%04x!\n", ww); - return -ENODEV; - } - - sis645_smbus_base = pci_resource_start(dev, SIS645_BAR); - if (!sis645_smbus_base) { - dev_err(dev, "SiS645 SMBus base address " - "not initialized!\n"); - return -EINVAL; - } - dev_info(dev, "SiS645 SMBus base address: 0x%04x\n", - sis645_smbus_base); - - /* Everything is happy, let's grab the memory and set things up. */ - if (!request_region(sis645_smbus_base, SMB_IOSIZE, - sis645_driver.name)) { - dev_err(dev, "SMBus registers 0x%04x-0x%04x " - "already in use!\n", sis645_smbus_base, - sis645_smbus_base + SMB_IOSIZE - 1); - - sis645_smbus_base = 0; - return -EINVAL; - } - - sprintf(sis645_adapter.name, "SiS645 SMBus adapter at 0x%04x", - sis645_smbus_base); - - if ((retval = i2c_add_adapter(&sis645_adapter))) { - dev_err(dev, "Couldn't register adapter!\n"); - release_region(sis645_smbus_base, SMB_IOSIZE); - sis645_smbus_base = 0; - } - - return retval; -} - -static void __devexit sis645_remove(struct pci_dev *dev) -{ - if (sis645_smbus_base) { - i2c_del_adapter(&sis645_adapter); - release_region(sis645_smbus_base, SMB_IOSIZE); - sis645_smbus_base = 0; - } -} - -static struct pci_driver sis645_driver = { - .name = "sis645 smbus", - .id_table = sis645_ids, - .probe = sis645_probe, - .remove = __devexit_p(sis645_remove), -}; - -static int __init i2c_sis645_init(void) -{ - printk(KERN_INFO DRV_NAME ".o version %s (%s)\n", LM_VERSION, LM_DATE); - - /* if the required device id is not present, try to HOTPLUG it first */ - if (!pci_find_device(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_SMBUS, NULL)) { - - printk(KERN_INFO DRV_NAME ": " - "Attempting to enable SiS645 SMBus device\n"); - -#ifdef CONFIG_HOTPLUG - sis645_hotplug_smbus(); -#else - printk(KERN_INFO DRV_NAME ": " - "Requires kernel with CONFIG_HOTPLUG, sorry!\n"); -#endif - } - - return pci_module_init(&sis645_driver); -} - -static void __exit i2c_sis645_exit(void) -{ - pci_unregister_driver(&sis645_driver); -} - -MODULE_AUTHOR("Mark M. Hoffman "); -MODULE_DESCRIPTION("SiS645 SMBus driver"); -MODULE_LICENSE("GPL"); - -/* Register initialization functions using helper macros */ -module_init(i2c_sis645_init); -module_exit(i2c_sis645_exit); diff --git a/kernel/busses/i2c-tsunami.c b/kernel/busses/i2c-tsunami.c deleted file mode 100644 index 7b27c56b..00000000 --- a/kernel/busses/i2c-tsunami.c +++ /dev/null @@ -1,170 +0,0 @@ -/* - i2c-tsunami.c - Part of lm_sensors, Linux kernel modules for hardware - monitoring - Copyright (c) 2001 Oleg Vdovikin - - Based on code written by Ralph Metzler and - Simon Vogl - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -/* This interfaces to the I2C bus of the Tsunami/Typhoon 21272 chipsets - to gain access to the on-board I2C devices. - - For more information refer to Compaq's - "Tsunami/Typhoon 21272 Chipset Hardware Reference Manual" - Order Number: DS-0025-TE -*/ - -#include -#include -#include -#include -#include -#include -#include -#include "version.h" -#include "sensors_compat.h" - -MODULE_LICENSE("GPL"); - -/* Memory Presence Detect Register (MPD-RW) bits - with except of reserved RAZ bits */ - -#define MPD_DR 0x8 /* Data receive - RO */ -#define MPD_CKR 0x4 /* Clock receive - RO */ -#define MPD_DS 0x2 /* Data send - Must be a 1 to receive - WO */ -#define MPD_CKS 0x1 /* Clock send - WO */ - -static inline void writempd(unsigned long value) -{ - TSUNAMI_cchip->mpd.csr = value; - mb(); -} - -static inline unsigned long readmpd(void) -{ - return TSUNAMI_cchip->mpd.csr; -} - -static void bit_tsunami_setscl(void *data, int val) -{ - /* read currently setted bits to modify them */ - unsigned long bits = readmpd() >> 2; /* assume output == input */ - - if (val) - bits |= MPD_CKS; - else - bits &= ~MPD_CKS; - - writempd(bits); -} - -static void bit_tsunami_setsda(void *data, int val) -{ - /* read currently setted bits to modify them */ - unsigned long bits = readmpd() >> 2; /* assume output == input */ - - if (val) - bits |= MPD_DS; - else - bits &= ~MPD_DS; - - writempd(bits); -} - -/* The MPD pins are open drain, so the pins always remain outputs. - We rely on the i2c-algo-bit routines to set the pins high before - reading the input from other chips. */ - -static int bit_tsunami_getscl(void *data) -{ - return (0 != (readmpd() & MPD_CKR)); -} - -static int bit_tsunami_getsda(void *data) -{ - return (0 != (readmpd() & MPD_DR)); -} - -static void i2c_tsunami_inc(struct i2c_adapter *adapter) -{ -#ifdef MODULE - MOD_INC_USE_COUNT; -#endif -} - -static void i2c_tsunami_dec(struct i2c_adapter *adapter) -{ -#ifdef MODULE - MOD_DEC_USE_COUNT; -#endif -} - -static struct i2c_algo_bit_data tsunami_i2c_bit_data = { - .setsda = bit_tsunami_setsda, - .setscl = bit_tsunami_setscl, - .getsda = bit_tsunami_getsda, - .getscl = bit_tsunami_getscl, - .udelay = 10, - .mdelay = 10, - .timeout = HZ/2 -}; - -static struct i2c_adapter tsunami_i2c_adapter = { - .name = "I2C Tsunami/Typhoon adapter", - .id = I2C_HW_B_TSUNA, - .algo_data = &tsunami_i2c_bit_data, - .inc_use = i2c_tsunami_inc, - .dec_use = i2c_tsunami_dec, -}; - - -#if 0 -static struct pci_driver tsunami_driver = { - .name = "tsunami smbus", - .id_table = tsunami_ids, - .probe = tsunami_probe, - .remove = __devexit_p(tsunami_remove), -}; -#endif - -static int __init i2c_tsunami_init(void) -{ - printk("i2c-tsunami.o version %s (%s)\n", LM_VERSION, LM_DATE); - - if (hwrpb->sys_type != ST_DEC_TSUNAMI) { - printk("i2c-tsunami.o: not Tsunami based system (%ld), module not inserted.\n", hwrpb->sys_type); - return -ENXIO; - } else { - printk("i2c-tsunami.o: using Cchip MPD at 0x%lx.\n", (long) &TSUNAMI_cchip->mpd); - } - return i2c_bit_add_bus(&tsunami_i2c_adapter); -} - - -static void __exit i2c_tsunami_exit(void) -{ - i2c_bit_del_bus(&tsunami_i2c_adapter); -} - - - -MODULE_AUTHOR("Oleg I. Vdovikin "); -MODULE_DESCRIPTION("Tsunami I2C/SMBus driver"); - -module_init(i2c_tsunami_init); -module_exit(i2c_tsunami_exit); diff --git a/kernel/busses/i2c-via.c b/kernel/busses/i2c-via.c deleted file mode 100644 index efe4f54a..00000000 --- a/kernel/busses/i2c-via.c +++ /dev/null @@ -1,199 +0,0 @@ -/* - i2c-via.c - Part of lm_sensors, Linux kernel modules - for hardware monitoring - - i2c Support for Via Technologies 82C586B South Bridge - - Copyright (c) 1998, 1999 Kyösti Mälkki - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include /* for HZ */ -#include "version.h" -#include "sensors_compat.h" - -/* Power management registers */ - -#define PM_CFG_REVID 0x08 /* silicon revision code */ -#define PM_CFG_IOBASE0 0x20 -#define PM_CFG_IOBASE1 0x48 - -#define I2C_DIR (pm_io_base+0x40) -#define I2C_OUT (pm_io_base+0x42) -#define I2C_IN (pm_io_base+0x44) -#define I2C_SCL 0x02 /* clock bit in DIR/OUT/IN register */ -#define I2C_SDA 0x04 - -/* io-region reservation */ -#define IOSPACE 0x06 -#define IOTEXT "via-i2c" - -static u16 pm_io_base = 0; - -/* - It does not appear from the datasheet that the GPIO pins are - open drain. So a we set a low value by setting the direction to - output and a high value by setting the direction to input and - relying on the required I2C pullup. The data value is initialized - to 0 in via_init() and never changed. -*/ - -static void bit_via_setscl(void *data, int state) -{ - outb(state ? inb(I2C_DIR) & ~I2C_SCL : inb(I2C_DIR) | I2C_SCL, - I2C_DIR); -} - -static void bit_via_setsda(void *data, int state) -{ - outb(state ? inb(I2C_DIR) & ~I2C_SDA : inb(I2C_DIR) | I2C_SDA, - I2C_DIR); -} - -static int bit_via_getscl(void *data) -{ - return (0 != (inb(I2C_IN) & I2C_SCL)); -} - -static int bit_via_getsda(void *data) -{ - return (0 != (inb(I2C_IN) & I2C_SDA)); -} - -static void bit_via_inc(struct i2c_adapter *adapter) -{ -#ifdef MODULE - MOD_INC_USE_COUNT; -#endif -} - -static void bit_via_dec(struct i2c_adapter *adapter) -{ -#ifdef MODULE - MOD_DEC_USE_COUNT; -#endif -} - -static struct i2c_algo_bit_data bit_data = { - .setsda = bit_via_setsda, - .setscl = bit_via_setscl, - .getsda = bit_via_getsda, - .getscl = bit_via_getscl, - .udelay = 5, - .mdelay = 5, - .timeout = HZ -}; - -static struct i2c_adapter vt586b_adapter = { - .name = "VIA i2c", - .id = I2C_HW_B_VIA, - .algo_data = &bit_data, - .inc_use = bit_via_inc, - .dec_use = bit_via_dec, -}; - - -static struct pci_device_id vt586b_ids[] __initdata = { - { PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C586_3, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, - { 0, } -}; - -static int __init vt586b_probe(struct pci_dev *dev, - const struct pci_device_id *id) -{ - u16 base; - u8 rev; - int res; - - if (pm_io_base) { - printk(KERN_ERR "i2c-via.o: Will only support one host\n"); - return -EBUSY; - } - - pci_read_config_byte(dev, PM_CFG_REVID, &rev); - - switch (rev) { - case 0x00: - base = PM_CFG_IOBASE0; - break; - case 0x01: - case 0x10: - base = PM_CFG_IOBASE1; - break; - - default: - base = PM_CFG_IOBASE1; - /* later revision */ - } - - pci_read_config_word(dev, base, &pm_io_base); - pm_io_base &= (0xff << 8); - - if (! request_region(I2C_DIR, IOSPACE, IOTEXT)) { - printk("i2c-via.o: IO 0x%x-0x%x already in use\n", - I2C_DIR, I2C_DIR + IOSPACE); - return -EBUSY; - } - outb(inb(I2C_DIR) & ~(I2C_SDA | I2C_SCL), I2C_DIR); - outb(inb(I2C_OUT) & ~(I2C_SDA | I2C_SCL), I2C_OUT); - - res = i2c_bit_add_bus(&vt586b_adapter); - if ( res < 0 ) { - release_region(I2C_DIR, IOSPACE); - pm_io_base = 0; - return res; - } - return 0; -} - -static int __init i2c_vt586b_init(void) -{ - struct pci_dev *dev; - const struct pci_device_id *id; - - printk("i2c-via.o version %s (%s)\n", LM_VERSION, LM_DATE); - pci_for_each_dev(dev) { - id = pci_match_device(vt586b_ids, dev); - if(id) - if(vt586b_probe(dev, id) >= 0) - return 0; - } - return -ENODEV; -} - - -static void __exit i2c_vt586b_exit(void) -{ - i2c_bit_del_bus(&vt586b_adapter); - release_region(I2C_DIR, IOSPACE); -} - - -MODULE_AUTHOR("Kyösti Mälkki "); -MODULE_DESCRIPTION("i2c for Via vt82c586b southbridge"); -MODULE_LICENSE("GPL"); - -module_init(i2c_vt586b_init); -module_exit(i2c_vt586b_exit); diff --git a/kernel/busses/i2c-viapro.c b/kernel/busses/i2c-viapro.c deleted file mode 100644 index 9b7a25bd..00000000 --- a/kernel/busses/i2c-viapro.c +++ /dev/null @@ -1,577 +0,0 @@ -/* - i2c-viapro.c - Part of lm_sensors, Linux kernel modules for hardware - monitoring - Copyright (c) 1998 - 2002 Frodo Looijaard , - Philip Edelbrock , Kyösti Mälkki , - Mark D. Studebaker - Copyright (C) 2005 - 2007 Jean Delvare - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -/* - Supports the following VIA south bridges: - - Chip name PCI ID REV I2C block - VT82C596A 0x3050 no - VT82C596B 0x3051 no - VT82C686A 0x3057 0x30 no - VT82C686B 0x3057 0x40 yes - VT8231 0x8235 no? - VT8233 0x3074 yes - VT8233A 0x3147 yes? - VT8235 0x3177 yes - VT8237R 0x3227 yes - VT8237A 0x3337 yes - VT8251 0x3287 yes - CX700 0x8324 yes - VX800/VX820 0x8353 yes - - Note: we assume there can only be one device, with one SMBus interface. -*/ - -#include -#include -#include -#include -#include -#include -#include -#include -#include "version.h" -#include "sensors_compat.h" - -/* 8233A is undefined before kernel 2.4.19 */ -#ifndef PCI_DEVICE_ID_VIA_8233A -#define PCI_DEVICE_ID_VIA_8233A 0x3147 -#endif -/* 8235 is undefined before kernel 2.4.21 */ -#ifndef PCI_DEVICE_ID_VIA_8235 -#define PCI_DEVICE_ID_VIA_8235 0x3177 -#endif -/* 8237 is undefined before kernel 2.4.21 */ -#ifndef PCI_DEVICE_ID_VIA_8237 -#define PCI_DEVICE_ID_VIA_8237 0x3227 -#endif -/* 8237A is undefined */ -#ifndef PCI_DEVICE_ID_VIA_8237A -#define PCI_DEVICE_ID_VIA_8237A 0x3337 -#endif -/* 8251 is undefined */ -#ifndef PCI_DEVICE_ID_VIA_8251 -#define PCI_DEVICE_ID_VIA_8251 0x3287 -#endif -/* CX700 is undefined */ -#ifndef PCI_DEVICE_ID_VIA_CX700 -#define PCI_DEVICE_ID_VIA_CX700 0x8324 -#endif -/* VX800 is undefined */ -#ifndef PCI_DEVICE_ID_VIA_VX800 -#define PCI_DEVICE_ID_VIA_VX800 0x8353 -#endif - -#define SMBBA1 0x90 -#define SMBBA2 0x80 -#define SMBBA3 0xD0 - -/* SMBus address offsets */ -static unsigned short vt596_smba; -#define SMBHSTSTS (vt596_smba + 0) -#define SMBHSTCNT (vt596_smba + 2) -#define SMBHSTCMD (vt596_smba + 3) -#define SMBHSTADD (vt596_smba + 4) -#define SMBHSTDAT0 (vt596_smba + 5) -#define SMBHSTDAT1 (vt596_smba + 6) -#define SMBBLKDAT (vt596_smba + 7) - -/* PCI Address Constants */ - -/* SMBus data in configuration space can be found in two places, - We try to select the better one */ - -static unsigned short SMBHSTCFG = 0xD2; - -/* Other settings */ -#define MAX_TIMEOUT 500 - -/* VT82C596 constants */ -#define VT596_QUICK 0x00 -#define VT596_BYTE 0x04 -#define VT596_BYTE_DATA 0x08 -#define VT596_WORD_DATA 0x0C -#define VT596_BLOCK_DATA 0x14 -#define VT596_I2C_BLOCK_DATA 0x34 - - -/* If force is set to anything different from 0, we forcibly enable the - VT596. DANGEROUS! */ -static int force; -MODULE_PARM(force, "i"); -MODULE_PARM_DESC(force, "Forcibly enable the SMBus. DANGEROUS!"); - -/* If force_addr is set to anything different from 0, we forcibly enable - the VT596 at the given address. VERY DANGEROUS! */ -static int force_addr; -MODULE_PARM(force_addr, "i"); -MODULE_PARM_DESC(force_addr, - "Forcibly enable the SMBus at the given address. " - "EXTREMELY DANGEROUS!"); - - -static struct i2c_adapter vt596_adapter; - -#define FEATURE_I2CBLOCK (1<<0) -static unsigned int vt596_features; - -#ifdef DEBUG -static void vt596_dump_regs(const char *msg, u8 size) -{ - dev_dbg(&vt596_adapter, "%s: STS=%02x CNT=%02x CMD=%02x ADD=%02x " - "DAT=%02x,%02x\n", msg, inb_p(SMBHSTSTS), inb_p(SMBHSTCNT), - inb_p(SMBHSTCMD), inb_p(SMBHSTADD), inb_p(SMBHSTDAT0), - inb_p(SMBHSTDAT1)); - - if (size == VT596_BLOCK_DATA - || size == VT596_I2C_BLOCK_DATA) { - int i; - - dev_dbg(&vt596_adapter, "BLK="); - for (i = 0; i < I2C_SMBUS_BLOCK_MAX / 2; i++) - printk("%02x,", inb_p(SMBBLKDAT)); - printk("\n"); - dev_dbg(&vt596_adapter, " "); - for (; i < I2C_SMBUS_BLOCK_MAX - 1; i++) - printk("%02x,", inb_p(SMBBLKDAT)); - printk("%02x\n", inb_p(SMBBLKDAT)); - } -} -#else -static inline void vt596_dump_regs(const char *msg, u8 size) { } -#endif - -/* Return -1 on error, 0 on success */ -static int vt596_transaction(u8 size) -{ - int temp; - int result = 0; - int timeout = 0; - - vt596_dump_regs("Transaction (pre)", size); - - /* Make sure the SMBus host is ready to start transmitting */ - if ((temp = inb_p(SMBHSTSTS)) & 0x1F) { - dev_dbg(&vt596_adapter, "SMBus busy (0x%02x). " - "Resetting...\n", temp); - - outb_p(temp, SMBHSTSTS); - if ((temp = inb_p(SMBHSTSTS)) & 0x1F) { - dev_err(&vt596_adapter, "SMBus reset failed! " - "(0x%02x)\n", temp); - return -1; - } - } - - /* Start the transaction by setting bit 6 */ - outb_p(0x40 | size, SMBHSTCNT); - - /* We will always wait for a fraction of a second */ - do { - i2c_delay(1); - temp = inb_p(SMBHSTSTS); - } while ((temp & 0x01) && (timeout++ < MAX_TIMEOUT)); - - /* If the SMBus is still busy, we give up */ - if (timeout >= MAX_TIMEOUT) { - result = -1; - dev_err(&vt596_adapter, "SMBus Timeout!\n"); - } - - if (temp & 0x10) { - result = -1; - dev_err(&vt596_adapter, "Transaction failed (0x%02x)\n", size); - } - - if (temp & 0x08) { - result = -1; - dev_err(&vt596_adapter, "SMBus collision!\n"); - } - - if (temp & 0x04) { - int read = inb_p(SMBHSTADD) & 0x01; - result = -1; - /* The quick and receive byte commands are used to probe - for chips, so errors are expected, and we don't want - to frighten the user. */ - if (!((size == VT596_QUICK && !read) || - (size == VT596_BYTE && read))) - dev_err(&vt596_adapter, "Transaction error!\n"); - } - - /* Resetting status register */ - if (temp & 0x1F) - outb_p(temp, SMBHSTSTS); - - vt596_dump_regs("Transaction (post)", size); - - return result; -} - -/* Return -1 on error, 0 on success */ -static s32 vt596_access(struct i2c_adapter *adap, u16 addr, - unsigned short flags, char read_write, u8 command, - int size, union i2c_smbus_data *data) -{ - int i; - - switch (size) { - case I2C_SMBUS_QUICK: - size = VT596_QUICK; - break; - case I2C_SMBUS_BYTE: - if (read_write == I2C_SMBUS_WRITE) - outb_p(command, SMBHSTCMD); - size = VT596_BYTE; - break; - case I2C_SMBUS_BYTE_DATA: - outb_p(command, SMBHSTCMD); - if (read_write == I2C_SMBUS_WRITE) - outb_p(data->byte, SMBHSTDAT0); - size = VT596_BYTE_DATA; - break; - case I2C_SMBUS_WORD_DATA: - outb_p(command, SMBHSTCMD); - if (read_write == I2C_SMBUS_WRITE) { - outb_p(data->word & 0xff, SMBHSTDAT0); - outb_p((data->word & 0xff00) >> 8, SMBHSTDAT1); - } - size = VT596_WORD_DATA; - break; - case I2C_SMBUS_I2C_BLOCK_DATA: - if (!(vt596_features & FEATURE_I2CBLOCK)) - goto exit_unsupported; - if (read_write == I2C_SMBUS_READ) - outb_p(I2C_SMBUS_BLOCK_MAX, SMBHSTDAT0); - /* Fall through */ - case I2C_SMBUS_BLOCK_DATA: - outb_p(command, SMBHSTCMD); - if (read_write == I2C_SMBUS_WRITE) { - u8 len = data->block[0]; - if (len > I2C_SMBUS_BLOCK_MAX) - len = I2C_SMBUS_BLOCK_MAX; - outb_p(len, SMBHSTDAT0); - inb_p(SMBHSTCNT); /* Reset SMBBLKDAT */ - for (i = 1; i <= len; i++) - outb_p(data->block[i], SMBBLKDAT); - } - size = (size == I2C_SMBUS_I2C_BLOCK_DATA) ? - VT596_I2C_BLOCK_DATA : VT596_BLOCK_DATA; - break; - default: - goto exit_unsupported; - } - - outb_p(((addr & 0x7f) << 1) | read_write, SMBHSTADD); - - if (vt596_transaction(size)) /* Error in transaction */ - return -1; - - if ((read_write == I2C_SMBUS_WRITE) || (size == VT596_QUICK)) - return 0; - - switch (size) { - case VT596_BYTE: - case VT596_BYTE_DATA: - data->byte = inb_p(SMBHSTDAT0); - break; - case VT596_WORD_DATA: - data->word = inb_p(SMBHSTDAT0) + (inb_p(SMBHSTDAT1) << 8); - break; - case VT596_I2C_BLOCK_DATA: - case VT596_BLOCK_DATA: - data->block[0] = inb_p(SMBHSTDAT0); - if (data->block[0] > I2C_SMBUS_BLOCK_MAX) - data->block[0] = I2C_SMBUS_BLOCK_MAX; - inb_p(SMBHSTCNT); /* Reset SMBBLKDAT */ - for (i = 1; i <= data->block[0]; i++) - data->block[i] = inb_p(SMBBLKDAT); - break; - } - return 0; - -exit_unsupported: - dev_warn(&vt596_adapter, "Unsupported command invoked! (0x%02x)\n", - size); - return -1; -} - -static void vt596_inc(struct i2c_adapter *adapter) -{ -#ifdef MODULE - MOD_INC_USE_COUNT; -#endif -} - -static void vt596_dec(struct i2c_adapter *adapter) -{ -#ifdef MODULE - MOD_DEC_USE_COUNT; -#endif -} - -static u32 vt596_func(struct i2c_adapter *adapter) -{ - u32 func = I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE | - I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA | - I2C_FUNC_SMBUS_BLOCK_DATA; - - if (vt596_features & FEATURE_I2CBLOCK) - func |= I2C_FUNC_SMBUS_I2C_BLOCK; - return func; -} - -static struct i2c_algorithm smbus_algorithm = { - .name = "Non-I2C SMBus adapter", - .id = I2C_ALGO_SMBUS, - .smbus_xfer = vt596_access, - .functionality = vt596_func, -}; - -static struct i2c_adapter vt596_adapter = { - .id = I2C_ALGO_SMBUS | I2C_HW_SMBUS_VIA2, - .algo = &smbus_algorithm, - .inc_use = vt596_inc, - .dec_use = vt596_dec, -}; - -static int __init vt596_probe(struct pci_dev *pdev, - const struct pci_device_id *id) -{ - unsigned char temp; - int error = -ENODEV; - - /* Determine the address of the SMBus areas */ - if (force_addr) { - vt596_smba = force_addr & 0xfff0; - force = 0; - goto found; - } - - if ((pci_read_config_word(pdev, id->driver_data, &vt596_smba)) || - !(vt596_smba & 0x0001)) { - /* try 2nd address and config reg. for 596 */ - if (id->device == PCI_DEVICE_ID_VIA_82C596_3 && - !pci_read_config_word(pdev, SMBBA2, &vt596_smba) && - (vt596_smba & 0x0001)) { - SMBHSTCFG = 0x84; - } else { - /* no matches at all */ - dev_err(pdev, "Cannot configure " - "SMBus I/O Base address\n"); - return -ENODEV; - } - } - - vt596_smba &= 0xfff0; - if (vt596_smba == 0) { - dev_err(pdev, "SMBus base address " - "uninitialized - upgrade BIOS or use " - "force_addr=0xaddr\n"); - return -ENODEV; - } - -found: - if (!request_region(vt596_smba, 8, "viapro-smbus")) { - dev_err(pdev, "SMBus region 0x%x already in use!\n", - vt596_smba); - return -ENODEV; - } - - pci_read_config_byte(pdev, SMBHSTCFG, &temp); - /* If force_addr is set, we program the new address here. Just to make - sure, we disable the VT596 first. */ - if (force_addr) { - pci_write_config_byte(pdev, SMBHSTCFG, temp & 0xfe); - pci_write_config_word(pdev, id->driver_data, vt596_smba); - pci_write_config_byte(pdev, SMBHSTCFG, temp | 0x01); - dev_warn(pdev, "WARNING: SMBus interface set to new " - "address 0x%04x!\n", vt596_smba); - } else if (!(temp & 0x01)) { - if (force) { - /* NOTE: This assumes I/O space and other allocations - * WERE done by the Bios! Don't complain if your - * hardware does weird things after enabling this. - * :') Check for Bios updates before resorting to - * this. - */ - pci_write_config_byte(pdev, SMBHSTCFG, temp | 0x01); - dev_info(pdev, "Enabling SMBus device\n"); - } else { - dev_err(pdev, "SMBUS: Error: Host SMBus " - "controller not enabled! - upgrade BIOS or " - "use force=1\n"); - goto release_region; - } - } - - dev_dbg(pdev, "VT596_smba = 0x%X\n", vt596_smba); - - switch (id->device) { - case PCI_DEVICE_ID_VIA_CX700: - case PCI_DEVICE_ID_VIA_VX800: - case PCI_DEVICE_ID_VIA_8251: - case PCI_DEVICE_ID_VIA_8237: - case PCI_DEVICE_ID_VIA_8237A: - case PCI_DEVICE_ID_VIA_8235: - case PCI_DEVICE_ID_VIA_8233A: - case PCI_DEVICE_ID_VIA_8233_0: - vt596_features |= FEATURE_I2CBLOCK; - break; - case PCI_DEVICE_ID_VIA_82C686_4: - /* The VT82C686B (rev 0x40) does support I2C block - transactions, but the VT82C686A (rev 0x30) doesn't */ - if (!pci_read_config_byte(pdev, PCI_REVISION_ID, &temp) - && temp >= 0x40) - vt596_features |= FEATURE_I2CBLOCK; - break; - } - - snprintf(vt596_adapter.name, 32, - "SMBus Via Pro adapter at %04x", vt596_smba); - - return i2c_add_adapter(&vt596_adapter); - -release_region: - release_region(vt596_smba, 8); - return error; -} - -static struct pci_device_id vt596_ids[] __initdata = { - { - .vendor = PCI_VENDOR_ID_VIA, - .device = PCI_DEVICE_ID_VIA_82C596_3, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - .driver_data = SMBBA1, - }, - { - .vendor = PCI_VENDOR_ID_VIA, - .device = PCI_DEVICE_ID_VIA_82C596B_3, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - .driver_data = SMBBA1, - }, - { - .vendor = PCI_VENDOR_ID_VIA, - .device = PCI_DEVICE_ID_VIA_82C686_4, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - .driver_data = SMBBA1, - }, - { - .vendor = PCI_VENDOR_ID_VIA, - .device = PCI_DEVICE_ID_VIA_8233_0, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - .driver_data = SMBBA3 - }, - { - .vendor = PCI_VENDOR_ID_VIA, - .device = PCI_DEVICE_ID_VIA_8233A, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - .driver_data = SMBBA3, - }, - { - .vendor = PCI_VENDOR_ID_VIA, - .device = PCI_DEVICE_ID_VIA_8235, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - .driver_data = SMBBA3 - }, - { - .vendor = PCI_VENDOR_ID_VIA, - .device = PCI_DEVICE_ID_VIA_8237, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - .driver_data = SMBBA3 - }, - { - .vendor = PCI_VENDOR_ID_VIA, - .device = PCI_DEVICE_ID_VIA_8237A, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - .driver_data = SMBBA3 - }, - { - .vendor = PCI_VENDOR_ID_VIA, - .device = PCI_DEVICE_ID_VIA_8231_4, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - .driver_data = SMBBA1, - }, - { - .vendor = PCI_VENDOR_ID_VIA, - .device = PCI_DEVICE_ID_VIA_8251, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - .driver_data = SMBBA3 - }, - { - .vendor = PCI_VENDOR_ID_VIA, - .device = PCI_DEVICE_ID_VIA_CX700, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - .driver_data = SMBBA3 - }, - { - .vendor = PCI_VENDOR_ID_VIA, - .device = PCI_DEVICE_ID_VIA_VX800, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - .driver_data = SMBBA3 - }, - { 0, } -}; - -static int __init i2c_vt596_init(void) -{ - struct pci_dev *dev; - const struct pci_device_id *id; - - printk("i2c-viapro.o version %s (%s)\n", LM_VERSION, LM_DATE); - pci_for_each_dev(dev) { - id = pci_match_device(vt596_ids, dev); - if(id) - if(vt596_probe(dev, id) >= 0) - return 0; - } - return -ENODEV; -} - - -static void __exit i2c_vt596_exit(void) -{ - i2c_del_adapter(&vt596_adapter); - release_region(vt596_smba, 8); -} - -MODULE_AUTHOR("Kyosti Malkki , " - "Mark D. Studebaker and " - "Jean Delvare "); -MODULE_DESCRIPTION("vt82c596 SMBus driver"); -MODULE_LICENSE("GPL"); - -module_init(i2c_vt596_init); -module_exit(i2c_vt596_exit); diff --git a/kernel/busses/i2c-virtual.c b/kernel/busses/i2c-virtual.c deleted file mode 100644 index 7af5c1df..00000000 --- a/kernel/busses/i2c-virtual.c +++ /dev/null @@ -1,430 +0,0 @@ -/* - * i2c-virtual.c - Virtual I2C bus driver. - * - * Simplifies access to complex multiplexed I2C bus topologies, by presenting - * each multiplexed bus segment as a virtual I2C adapter. Supports multi-level - * mux'ing (mux behind a mux), as well as arbitration for exclusive bus access - * for those systems which require it (some bladed chassis for example). - * - * Copyright (c) 2004 Google, Inc. (Ken Harrenstien) - * - * Based on: - * i2c-virtual.c from Brian Kuschak - * which was: - * Adapted from i2c-adap-ibm_ocp.c - * Original file Copyright 2000-2002 MontaVista Software Inc. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include "i2c-virtual.h" -#include -#include -#include - -#include -#include -#include - -#ifdef DEBUG -# define DBG(x) x -#else -# define DBG(x) {} -#endif - -#define I2C_VIRT_PROCMAP 0 /* 1 for /proc/driver/i2c/virtual_i2c_map */ - -#define VIRT_TIMEOUT (HZ/2) /* 500msec */ -#define VIRT_RETRIES 3 - -/* exclusive access to the bus */ -#define I2C_LOCK(adap) down(&adap->bus) -#define I2C_UNLOCK(adap) up(&adap->bus) - -#if I2C_VIRT_PROCMAP -/* pointer to the list of i2c_bus_mappings */ -static LIST_HEAD(i2c_map_list); -struct i2c_bus_mapping { - struct i2c_adapter *parent; - struct i2c_adapter *virt; - unsigned long mux_addr; - unsigned long mux_val; - struct list_head list; -}; -static void *i2c_virt_add_map(struct i2c_adapter *parent, - struct i2c_adapter *virt, - unsigned long mux_addr, - unsigned long mux_val); -#endif - -/* First the I2C 'algorithm' driver code: */ - -/* - * Description: acquire exclusive access (if needed), select the mux, - * perform the transfer on the parent i2c adapter, deselect mux and drop - * exclusive access. - */ -static int -i2c_virt_master_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num) -{ - struct i2c_virt_priv *priv = (struct i2c_virt_priv *)adap->data; - struct i2c_adapter *parent = priv->parent_adap; - int ret; - - -#ifdef I2C_REQUIRE_ARBITRATION - /* Acquire exclusive access to a shared I2C bus _before_ taking the - local I2C lock to prevent stalling local I2C transactions while - waiting for exclusive access. - */ - if(parent->algo->acquire_exclusive) - if ((ret = parent->algo->acquire_exclusive(parent)) < 0) - return ret; -#endif - /* Grab the lock for the parent adapter. We already hold the lock for - the virtual adapter. Then select the right mux port and perform - the transfer. - */ - DBG(printk(KERN_DEBUG "%s: Locking parent bus %0lX\n", - __FUNCTION__, (unsigned long)parent)); - I2C_LOCK(parent); - if ((ret = priv->mux.select(parent, &priv->mux)) == 0) { - ret = parent->algo->master_xfer(parent, msgs, num); - } - (void) priv->mux.deselect(parent, &priv->mux); - I2C_UNLOCK(parent); - DBG(printk(KERN_DEBUG "%s: Unlocked parent bus %0lX\n", - __FUNCTION__, (unsigned long)parent)); - -#ifdef I2C_REQUIRE_ARBITRATION - { - int ret2; - /* Release exclusive bus access */ - if(parent->algo->release_exclusive) - if ((ret2 = parent->algo->release_exclusive(parent)) < 0) - return ret2; - } -#endif - return ret; -} - -static int -i2c_virt_smbus_xfer(struct i2c_adapter *adap, u16 addr, - unsigned short flags, char read_write, - u8 command, int size, union i2c_smbus_data * data) -{ - struct i2c_virt_priv *priv = (struct i2c_virt_priv *)adap->data; - struct i2c_adapter *parent = priv->parent_adap; - int ret; - -#ifdef I2C_REQUIRE_ARBITRATION - /* Acquire exclusive access to a shared I2C bus _before_ taking the - local I2C lock to prevent stalling local I2C transactions while - waiting for exclusive access. - */ - if(parent->algo->acquire_exclusive) - if ((ret = parent->algo->acquire_exclusive(parent)) < 0) - return ret; -#endif - /* Grab the lock for the parent adapter. We already hold the lock for - the virtual adapter. Then select the right mux port and perform - the transfer. - */ - DBG(printk(KERN_DEBUG "%s: Locking parent bus %0lX\n", - __FUNCTION__, (unsigned long)parent)); - I2C_LOCK(parent); - if ((ret = priv->mux.select(parent, &priv->mux)) == 0) { - ret = parent->algo->smbus_xfer(parent, addr, flags, - read_write, command, size, data); - } - (void) priv->mux.deselect(parent, &priv->mux); - I2C_UNLOCK(parent); - DBG(printk(KERN_DEBUG "%s: Unlocked parent bus %0lX\n", - __FUNCTION__, (unsigned long)parent)); - -#ifdef I2C_REQUIRE_ARBITRATION - { - int ret2; - /* Release exclusive bus access */ - if(parent->algo->release_exclusive) - if ((ret2 = parent->algo->release_exclusive(parent)) < 0) - return ret2; - } -#endif - return ret; -} - -/* - * Description: Implements device specific ioctls. - * We don't support any yet. - */ -static int -i2c_virt_algo_control(struct i2c_adapter *adap, unsigned int cmd, - unsigned long arg) -{ - return 0; -} - -/* Virtual adapter functionality; returns functionality of parent adapter. - * OK if parent itself is virtual, as this will go all the way up to the - * real adapter. - */ -static u32 -i2c_virt_functionality(struct i2c_adapter *adap) -{ - struct i2c_virt_priv *priv = (struct i2c_virt_priv *)adap->data; - struct i2c_adapter *parent = priv->parent_adap; - - return parent->algo->functionality(parent); -} - -/* ===================================================================== */ - -/* The 'adapter' driver code: */ - -static int -i2c_virt_reg(struct i2c_client *client) -{ - return 0; -} -static int -i2c_virt_unreg(struct i2c_client *client) -{ - return 0; -} - - -/* - * Called to create a 'virtual' i2c bus which represents a multiplexed bus - * segment. Client and mux_val are passed to the select and deselect - * callback functions to perform hardware-specific mux control. - */ -struct i2c_adapter *i2c_virt_create_adapter(struct i2c_adapter *parent_adap, - struct i2c_client *client, - unsigned long mux_val, - void *select_cb, - void *deselect_cb) -{ - struct i2c_adapter *adap; - struct i2c_virt_priv *priv; - struct i2c_algorithm *algo; - - if (!(adap = kmalloc(sizeof (struct i2c_adapter) - + sizeof(struct i2c_virt_priv) - + sizeof(struct i2c_algorithm), - GFP_KERNEL))) { - printk(KERN_ERR "i2c_virt_register_adap: Failed allocation\n"); - return NULL; - } - - memset(adap, 0, sizeof(struct i2c_adapter) - + sizeof(struct i2c_virt_priv) - + sizeof(struct i2c_algorithm)); - priv = (struct i2c_virt_priv *) (adap+1); - algo = (struct i2c_algorithm *) (priv+1); - - /* Set up private adapter data */ - priv->parent_adap = parent_adap; - priv->mux.client = client; - priv->mux.addr = client->addr; - priv->mux.value = mux_val; - priv->mux.select = select_cb; - priv->mux.deselect = deselect_cb; - - /* Need to do algo dynamically because we don't know ahead - of time what sort of physical adapter we'll be dealing with. - */ - algo->id = I2C_ALGO_VIRT; - strcpy(algo->name, "Virtual I2C algorithm driver"); - algo->master_xfer = (parent_adap->algo->master_xfer - ? i2c_virt_master_xfer : NULL); - algo->smbus_xfer = (parent_adap->algo->smbus_xfer - ? i2c_virt_smbus_xfer : NULL); - algo->slave_send = NULL; - algo->slave_recv = NULL; - algo->algo_control = i2c_virt_algo_control; - algo->functionality = i2c_virt_functionality; -#ifdef I2C_REQUIRE_ARBITRATION - algo->acquire_exclusive = NULL; - algo->release_exclusive = NULL; -#endif - - /* Now fill out new adapter structure */ - adap->inc_use = NULL; - adap->dec_use = NULL; - snprintf(adap->name, sizeof(adap->name), - "Virtual I2C (i2c-%d, mux %02lx:%02lx)", - i2c_adapter_id(parent_adap), - (unsigned long)client->addr, mux_val); - adap->id = I2C_HW_VIRT | algo->id; - adap->algo = algo; - adap->algo_data = NULL; /* XXX: Use this?? */ - adap->client_register = i2c_virt_reg; - adap->client_unregister = i2c_virt_unreg; - adap->data = priv; - adap->flags = 0; - adap->timeout = VIRT_TIMEOUT; - adap->retries = VIRT_RETRIES; - - DBG(printk(KERN_DEBUG "%s: Adding virt bus %0lX\n", - __FUNCTION__, (unsigned long)adap)); - - if (i2c_add_adapter_nolock(adap) < 0) { - kfree(adap); - return NULL; - } - - printk(KERN_NOTICE "i2c%d: Virtual I2C bus " - "(Physical bus i2c%d, multiplexer %02lx port %ld)\n", - i2c_adapter_id(adap), i2c_adapter_id(parent_adap), - priv->mux.addr, mux_val); - -#if I2C_VIRT_PROCMAP - i2c_virt_add_map(priv->parent_adap, adap, - priv->mux.addr, priv->value); -#endif - - MOD_INC_USE_COUNT; - DBG(printk(KERN_DEBUG "%s: Added virt bus %0lX\n", - __FUNCTION__, (unsigned long)adap)); - - return adap; -} - -int i2c_virt_remove_adapter(struct i2c_adapter *adap) -{ - int ret; - - DBG(printk(KERN_DEBUG "%s: Removing virt bus %0lX\n", - __FUNCTION__, (unsigned long)adap)); - - if ((ret = i2c_del_adapter_nolock(adap)) < 0) - return ret; - kfree(adap); - - MOD_DEC_USE_COUNT; - return 0; -} - - -/* ------------------------------------------------------------------ */ - -#if I2C_VIRT_PROCMAP -/* Dubious stuff to implement a /proc/driver/i2c/virtual_i2c_map - * listing of all virtual busses. - * - * XXX: LOCKING??? - */ -static int i2c_virt_read_proc(char *page, char **start, off_t off, - int count, int *eof, void *data) -{ - int len; - char *buf = page; - struct list_head *l; - struct i2c_bus_mapping *pmap; - - /* XXX: BUFFER BOUNDS CHECKING? */ - - buf += sprintf(buf, "i2c bus_mapping\n"); - - list_for_each(l, &i2c_map_list) { - pmap = list_entry(l, struct i2c_bus_mapping, list); - - if(pmap) - buf += sprintf(buf, "base=iic%d mux_addr=%02hx, mux_val=%02hx => iic%d\n", - i2c_adapter_id(pmap->parent), - pmap->mux_addr, pmap->mux_val, - i2c_adapter_id(pmap->virt)); - } - - len = buf - page; - if (len <= off+count) *eof = 1; - *start = page + off; - len -= off; - if (len>count) len = count; - if (len<0) len = 0; - return len; -} - - -static void *i2c_virt_add_map(struct i2c_adapter *parent, - struct i2c_adapter *virt, - unsigned long mux_addr, - unsigned long mux_val) -{ - struct i2c_bus_mapping *pmap; - - if((pmap = kmalloc(sizeof(struct i2c_bus_mapping), GFP_KERNEL)) - == NULL) { - printk(KERN_ERR "%s: Failed to allocate bus mapping\n", - __FUNCTION__); - return; - } - pmap->virt = virt; - pmap->parent = parent; - pmap->mux_addr = mux_addr; - pmap->mux_val = mux_val; - - if (list_empty(&i2c_map_list)) { - /* If first time, ensure proc entry exists */ - /* XXX: Maybe do this with module_init() */ - create_proc_read_entry("driver/i2c/virtual_i2c_map", 0, NULL, - &i2c_virt_read_proc, NULL); - } - list_add_tail(&pmap->list, &i2c_map_list); -} - - -#if 0 /* Not used by anything, but kept for a while in case */ - -/* Called to find out which i2c bus to use to get to a specific bus segment. - */ -struct i2c_adapter *i2c_lookup_adapter(struct i2c_adapter *base, - unsigned long mux_addr, - unsigned long mux_val) -{ - struct list_head *l; - struct i2c_bus_mapping *pmap; - - list_for_each(l, &i2c_map_list) { - pmap = list_entry(l, struct i2c_bus_mapping, list); - if(pmap->parent == base - && pmap->mux_addr == mux_addr - && pmap->mux_val == mux_val) - return pmap->virt; - } - return NULL; /* none found */ -} - -EXPORT_SYMBOL(i2c_lookup_adapter); -#endif /* 0 */ - - -#endif /* I2C_VIRT_PROCMAP */ - -EXPORT_SYMBOL(i2c_virt_create_adapter); -EXPORT_SYMBOL(i2c_virt_remove_adapter); - -MODULE_AUTHOR("Ken Harrenstien (from Brian Kuschak)"); -MODULE_DESCRIPTION("Virtual I2C driver for multiplexed I2C busses"); -MODULE_LICENSE("GPL"); diff --git a/kernel/busses/i2c-voodoo3.c b/kernel/busses/i2c-voodoo3.c deleted file mode 100644 index 567ba9ea..00000000 --- a/kernel/busses/i2c-voodoo3.c +++ /dev/null @@ -1,296 +0,0 @@ -/* - voodoo3.c - Part of lm_sensors, Linux kernel modules for hardware - monitoring - Copyright (c) 1998, 1999 Frodo Looijaard , - Philip Edelbrock , - Ralph Metzler , and - Mark D. Studebaker - - Based on code written by Ralph Metzler and - Simon Vogl - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -/* This interfaces to the I2C bus of the Voodoo3 to gain access to - the BT869 and possibly other I2C devices. */ - -#include -#include -#include -#include -#include -#include -#include /* for HZ */ -#include "version.h" -#include "sensors_compat.h" - -MODULE_LICENSE("GPL"); - -/* the only registers we use */ -#define REG 0x78 -#define REG2 0x70 - -/* bit locations in the register */ -#define DDC_ENAB 0x00040000 -#define DDC_SCL_OUT 0x00080000 -#define DDC_SDA_OUT 0x00100000 -#define DDC_SCL_IN 0x00200000 -#define DDC_SDA_IN 0x00400000 -#define I2C_ENAB 0x00800000 -#define I2C_SCL_OUT 0x01000000 -#define I2C_SDA_OUT 0x02000000 -#define I2C_SCL_IN 0x04000000 -#define I2C_SDA_IN 0x08000000 - -/* initialization states */ -#define INIT2 0x2 -#define INIT3 0x4 - -/* delays */ -#define CYCLE_DELAY 10 -#define TIMEOUT (HZ / 2) - - -static void config_v3(struct pci_dev *dev); - -static unsigned long ioaddr; - -/* The voo GPIO registers don't have individual masks for each bit - so we always have to read before writing. */ - -static void bit_vooi2c_setscl(void *data, int val) -{ - unsigned int r; - r = readl(ioaddr + REG); - if(val) - r |= I2C_SCL_OUT; - else - r &= ~I2C_SCL_OUT; - writel(r, ioaddr + REG); - readl(ioaddr + REG); /* flush posted write */ -} - -static void bit_vooi2c_setsda(void *data, int val) -{ - unsigned int r; - r = readl(ioaddr + REG); - if(val) - r |= I2C_SDA_OUT; - else - r &= ~I2C_SDA_OUT; - writel(r, ioaddr + REG); - readl(ioaddr + REG); /* flush posted write */ -} - -/* The GPIO pins are open drain, so the pins always remain outputs. - We rely on the i2c-algo-bit routines to set the pins high before - reading the input from other chips. */ - -static int bit_vooi2c_getscl(void *data) -{ - return (0 != (readl(ioaddr + REG) & I2C_SCL_IN)); -} - -static int bit_vooi2c_getsda(void *data) -{ - return (0 != (readl(ioaddr + REG) & I2C_SDA_IN)); -} - -static void bit_vooddc_setscl(void *data, int val) -{ - unsigned int r; - r = readl(ioaddr + REG); - if(val) - r |= DDC_SCL_OUT; - else - r &= ~DDC_SCL_OUT; - writel(r, ioaddr + REG); - readl(ioaddr + REG); /* flush posted write */ -} - -static void bit_vooddc_setsda(void *data, int val) -{ - unsigned int r; - r = readl(ioaddr + REG); - if(val) - r |= DDC_SDA_OUT; - else - r &= ~DDC_SDA_OUT; - writel(r, ioaddr + REG); - readl(ioaddr + REG); /* flush posted write */ -} - -static int bit_vooddc_getscl(void *data) -{ - return (0 != (readl(ioaddr + REG) & DDC_SCL_IN)); -} - -static int bit_vooddc_getsda(void *data) -{ - return (0 != (readl(ioaddr + REG) & DDC_SDA_IN)); -} - - -/* Configures the chip */ - -void config_v3(struct pci_dev *dev) -{ - unsigned int cadr; - - /* map Voodoo3 memory */ - cadr = dev->resource[0].start; - cadr &= PCI_BASE_ADDRESS_MEM_MASK; - ioaddr = (unsigned long)ioremap_nocache(cadr, 0x1000); - if(ioaddr) { - writel(0x8160, ioaddr + REG2); - writel(0xcffc0020, ioaddr + REG); - printk("i2c-voodoo3: Using Banshee/Voodoo3 at 0x%lx\n", ioaddr); - } -} - -static void voodoo3_inc(struct i2c_adapter *adapter) -{ -#ifdef MODULE - MOD_INC_USE_COUNT; -#endif -} - -void voodoo3_dec(struct i2c_adapter *adapter) -{ -#ifdef MODULE - MOD_DEC_USE_COUNT; -#endif -} - -static struct i2c_algo_bit_data voo_i2c_bit_data = { - .setsda = bit_vooi2c_setsda, - .setscl = bit_vooi2c_setscl, - .getsda = bit_vooi2c_getsda, - .getscl = bit_vooi2c_getscl, - .udelay = CYCLE_DELAY, - .mdelay = CYCLE_DELAY, - .timeout = TIMEOUT -}; - -static struct i2c_adapter voodoo3_i2c_adapter = { - .name = "I2C Voodoo3/Banshee adapter", - .id = I2C_HW_B_VOO, - .algo_data = &voo_i2c_bit_data, - .inc_use = voodoo3_inc, - .dec_use = voodoo3_dec, -}; - -static struct i2c_algo_bit_data voo_ddc_bit_data = { - .setsda = bit_vooddc_setsda, - .setscl = bit_vooddc_setscl, - .getsda = bit_vooddc_getsda, - .getscl = bit_vooddc_getscl, - .udelay = CYCLE_DELAY, - .mdelay = CYCLE_DELAY, - .timeout = TIMEOUT -}; - -static struct i2c_adapter voodoo3_ddc_adapter = { - .name = "DDC Voodoo3/Banshee adapter", - .id = I2C_HW_B_VOO, - .algo_data = &voo_ddc_bit_data, - .inc_use = voodoo3_inc, - .dec_use = voodoo3_dec, -}; - - -static struct pci_device_id voodoo3_ids[] __devinitdata = { - { - .vendor = PCI_VENDOR_ID_3DFX, - .device = PCI_DEVICE_ID_3DFX_VOODOO3, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - }, - { - .vendor = PCI_VENDOR_ID_3DFX, - .device = PCI_DEVICE_ID_3DFX_BANSHEE, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - }, - { 0, } -}; - -static int __devinit voodoo3_probe(struct pci_dev *dev, const struct pci_device_id *id) -{ - int retval; - - config_v3(dev); - retval = i2c_bit_add_bus(&voodoo3_i2c_adapter); - if(retval) - return retval; - retval = i2c_bit_add_bus(&voodoo3_ddc_adapter); - if(retval) - i2c_bit_del_bus(&voodoo3_i2c_adapter); - return retval; -} - -static void __devexit voodoo3_remove(struct pci_dev *dev) -{ - i2c_bit_del_bus(&voodoo3_i2c_adapter); - i2c_bit_del_bus(&voodoo3_ddc_adapter); -} - - -/* Don't register driver to avoid driver conflicts */ -/* -static struct pci_driver voodoo3_driver = { - .name = "voodoo3 smbus", - .id_table = voodoo3_ids, - .probe = voodoo3_probe, - .remove = __devexit_p(voodoo3_remove), -}; -*/ - -static int __init i2c_voodoo3_init(void) -{ - struct pci_dev *dev; - const struct pci_device_id *id; - - printk("i2c-voodoo3.o version %s (%s)\n", LM_VERSION, LM_DATE); -/* - return pci_module_init(&voodoo3_driver); -*/ - pci_for_each_dev(dev) { - id = pci_match_device(voodoo3_ids, dev); - if(id) - if(voodoo3_probe(dev, id) >= 0) - return 0; - } - return -ENODEV; -} - - -static void __exit i2c_voodoo3_exit(void) -{ -/* - pci_unregister_driver(&voodoo3_driver); -*/ - voodoo3_remove(NULL); - iounmap((void *)ioaddr); -} - - -MODULE_AUTHOR - ("Frodo Looijaard , Philip Edelbrock , Ralph Metzler , and Mark D. Studebaker "); -MODULE_DESCRIPTION("Voodoo3 I2C/SMBus driver"); - -module_init(i2c_voodoo3_init); -module_exit(i2c_voodoo3_exit); diff --git a/kernel/chips/Module.mk b/kernel/chips/Module.mk deleted file mode 100644 index f84cad2f..00000000 --- a/kernel/chips/Module.mk +++ /dev/null @@ -1,215 +0,0 @@ -# Module.mk - Makefile for a Linux module for reading sensor data. -# Copyright (c) 1998 - 2001 Frodo Looijaard -# -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - -# Note that MODULE_DIR (the directory in which this file resides) is a -# 'simply expanded variable'. That means that its value is substituted -# verbatim in the rules, until it is redefined. -MODULE_DIR := kernel/chips -KERNELCHIPSDIR := $(MODULE_DIR) - -# Regrettably, even 'simply expanded variables' will not put their currently -# defined value verbatim into the command-list of rules... - -# These targets are NOT included in 'mkpatch' -KERNELCHIPSTARGETS := -ifeq ($(shell if grep -q '^CONFIG_IPMI_HANDLER=' $(LINUX)/.config; then echo 1; fi),1) -KERNELCHIPSTARGETS += $(MODULE_DIR)/bmcsensors.o -endif -KERNELCHIPSTARGETS += $(MODULE_DIR)/ds1307.o -KERNELCHIPSTARGETS += $(MODULE_DIR)/ltc1710.o -KERNELCHIPSTARGETS += $(MODULE_DIR)/mic74.o -KERNELCHIPSTARGETS += $(MODULE_DIR)/saa1064.o -KERNELCHIPSTARGETS += $(MODULE_DIR)/smartbatt.o -KERNELCHIPSTARGETS += $(MODULE_DIR)/smbus-arp.o - - -# These targets ARE included in 'mkpatch' -ifneq ($(shell if grep -q '^CONFIG_SENSORS_ADM1021=y' $(LINUX)/.config; then echo 1; fi),1) -KERNELCHIPSTARGETS += $(MODULE_DIR)/adm1021.o -endif -ifneq ($(shell if grep -q '^CONFIG_SENSORS_ADM1024=y' $(LINUX)/.config; then echo 1; fi),1) -KERNELCHIPSTARGETS += $(MODULE_DIR)/adm1024.o -endif -ifneq ($(shell if grep -q '^CONFIG_SENSORS_ADM1025=y' $(LINUX)/.config; then echo 1; fi),1) -KERNELCHIPSTARGETS += $(MODULE_DIR)/adm1025.o -endif -ifneq ($(shell if grep -q '^CONFIG_SENSORS_ADM1026=y' $(LINUX)/.config; then echo 1; fi),1) -KERNELCHIPSTARGETS += $(MODULE_DIR)/adm1026.o -endif -ifneq ($(shell if grep -q '^CONFIG_SENSORS_ADM1031=y' $(LINUX)/.config; then echo 1; fi),1) -KERNELCHIPSTARGETS += $(MODULE_DIR)/adm1031.o -endif -ifneq ($(shell if grep -q '^CONFIG_SENSORS_ADM9240=y' $(LINUX)/.config; then echo 1; fi),1) -KERNELCHIPSTARGETS += $(MODULE_DIR)/adm9240.o -endif -ifneq ($(shell if grep -q '^CONFIG_SENSORS_ASB100=y' $(LINUX)/.config; then echo 1; fi),1) -KERNELCHIPSTARGETS += $(MODULE_DIR)/asb100.o -endif -ifneq ($(shell if grep -q '^CONFIG_SENSORS_BT869=y' $(LINUX)/.config; then echo 1; fi),1) -KERNELCHIPSTARGETS += $(MODULE_DIR)/bt869.o -endif -ifneq ($(shell if grep -q '^CONFIG_SENSORS_DDCMON=y' $(LINUX)/.config; then echo 1; fi),1) -KERNELCHIPSTARGETS += $(MODULE_DIR)/ddcmon.o -endif -ifneq ($(shell if grep -q '^CONFIG_SENSORS_DS1621=y' $(LINUX)/.config; then echo 1; fi),1) -KERNELCHIPSTARGETS += $(MODULE_DIR)/ds1621.o -endif -ifneq ($(shell if grep -q '^CONFIG_SENSORS_EEPROM=y' $(LINUX)/.config; then echo 1; fi),1) -KERNELCHIPSTARGETS += $(MODULE_DIR)/eeprom.o -endif -ifneq ($(shell if grep -q '^CONFIG_SENSORS_F71805F=y' $(LINUX)/.config; then echo 1; fi),1) -KERNELCHIPSTARGETS += $(MODULE_DIR)/f71805f.o -endif -ifneq ($(shell if grep -q '^CONFIG_SENSORS_FSCHER=y' $(LINUX)/.config; then echo 1; fi),1) -KERNELCHIPSTARGETS += $(MODULE_DIR)/fscher.o -endif -ifneq ($(shell if grep -q '^CONFIG_SENSORS_FSCPOS=y' $(LINUX)/.config; then echo 1; fi),1) -KERNELCHIPSTARGETS += $(MODULE_DIR)/fscpos.o -endif -ifneq ($(shell if grep -q '^CONFIG_SENSORS_FSCSCY=y' $(LINUX)/.config; then echo 1; fi),1) -KERNELCHIPSTARGETS += $(MODULE_DIR)/fscscy.o -endif -ifneq ($(shell if grep -q '^CONFIG_SENSORS_GL518SM=y' $(LINUX)/.config; then echo 1; fi),1) -KERNELCHIPSTARGETS += $(MODULE_DIR)/gl518sm.o -endif -ifneq ($(shell if grep -q '^CONFIG_SENSORS_GL520SM=y' $(LINUX)/.config; then echo 1; fi),1) -KERNELCHIPSTARGETS += $(MODULE_DIR)/gl520sm.o -endif -ifneq ($(shell if grep -q '^CONFIG_SENSORS_IT87=y' $(LINUX)/.config; then echo 1; fi),1) -KERNELCHIPSTARGETS += $(MODULE_DIR)/it87.o -endif -ifneq ($(shell if grep -q '^CONFIG_SENSORS_LM63=y' $(LINUX)/.config; then echo 1; fi),1) -KERNELCHIPSTARGETS += $(MODULE_DIR)/lm63.o -endif -ifneq ($(shell if grep -q '^CONFIG_SENSORS_LM75=y' $(LINUX)/.config; then echo 1; fi),1) -KERNELCHIPSTARGETS += $(MODULE_DIR)/lm75.o -endif -ifneq ($(shell if grep -q '^CONFIG_SENSORS_LM78=y' $(LINUX)/.config; then echo 1; fi),1) -KERNELCHIPSTARGETS += $(MODULE_DIR)/lm78.o -endif -ifneq ($(shell if grep -q '^CONFIG_SENSORS_LM80=y' $(LINUX)/.config; then echo 1; fi),1) -KERNELCHIPSTARGETS += $(MODULE_DIR)/lm80.o -endif -ifneq ($(shell if grep -q '^CONFIG_SENSORS_LM83=y' $(LINUX)/.config; then echo 1; fi),1) -KERNELCHIPSTARGETS += $(MODULE_DIR)/lm83.o -endif -ifneq ($(shell if grep -q '^CONFIG_SENSORS_LM85=y' $(LINUX)/.config; then echo 1; fi),1) -KERNELCHIPSTARGETS += $(MODULE_DIR)/lm85.o -endif -ifneq ($(shell if grep -q '^CONFIG_SENSORS_LM87=y' $(LINUX)/.config; then echo 1; fi),1) -KERNELCHIPSTARGETS += $(MODULE_DIR)/lm87.o -endif -ifneq ($(shell if grep -q '^CONFIG_SENSORS_LM90=y' $(LINUX)/.config; then echo 1; fi),1) -KERNELCHIPSTARGETS += $(MODULE_DIR)/lm90.o -endif -ifneq ($(shell if grep -q '^CONFIG_SENSORS_LM92=y' $(LINUX)/.config; then echo 1; fi),1) -KERNELCHIPSTARGETS += $(MODULE_DIR)/lm92.o -endif -ifneq ($(shell if grep -q '^CONFIG_SENSORS_LM93=y' $(LINUX)/.config; then echo 1; fi),1) -KERNELCHIPSTARGETS += $(MODULE_DIR)/lm93.o -endif -ifneq ($(shell if grep -q '^CONFIG_SENSORS_MATORB=y' $(LINUX)/.config; then echo 1; fi),1) -KERNELCHIPSTARGETS += $(MODULE_DIR)/matorb.o -endif -ifneq ($(shell if grep -q '^CONFIG_SENSORS_MAX1619=y' $(LINUX)/.config; then echo 1; fi),1) -KERNELCHIPSTARGETS += $(MODULE_DIR)/max1619.o -endif -ifneq ($(shell if grep -q '^CONFIG_SENSORS_MAX6650=y' $(LINUX)/.config; then echo 1; fi),1) -KERNELCHIPSTARGETS += $(MODULE_DIR)/max6650.o -endif -ifneq ($(shell if grep -q '^CONFIG_SENSORS_MAXILIFE=y' $(LINUX)/.config; then echo 1; fi),1) -KERNELCHIPSTARGETS += $(MODULE_DIR)/maxilife.o -endif -ifneq ($(shell if grep -q '^CONFIG_SENSORS_MTP008=y' $(LINUX)/.config; then echo 1; fi),1) -KERNELCHIPSTARGETS += $(MODULE_DIR)/mtp008.o -endif -ifneq ($(shell if grep -q '^CONFIG_SENSORS_PC87360=y' $(LINUX)/.config; then echo 1; fi),1) -KERNELCHIPSTARGETS += $(MODULE_DIR)/pc87360.o -endif -ifneq ($(shell if grep -q '^CONFIG_SENSORS_PCA9540=y' $(LINUX)/.config; then echo 1; fi),1) -KERNELCHIPSTARGETS += $(MODULE_DIR)/pca9540.o -endif -ifneq ($(shell if grep -q '^CONFIG_SENSORS_PCF8574=y' $(LINUX)/.config; then echo 1; fi),1) -KERNELCHIPSTARGETS += $(MODULE_DIR)/pcf8574.o -endif -ifneq ($(shell if grep -q '^CONFIG_SENSORS_PCF8591=y' $(LINUX)/.config; then echo 1; fi),1) -KERNELCHIPSTARGETS += $(MODULE_DIR)/pcf8591.o -endif -ifneq ($(shell if grep -q '^CONFIG_SENSORS_SIS5595=y' $(LINUX)/.config; then echo 1; fi),1) -KERNELCHIPSTARGETS += $(MODULE_DIR)/sis5595.o -endif -ifneq ($(shell if grep -q '^CONFIG_SENSORS_SMSC47M1=y' $(LINUX)/.config; then echo 1; fi),1) -KERNELCHIPSTARGETS += $(MODULE_DIR)/smsc47m1.o -endif -ifneq ($(shell if grep -q '^CONFIG_SENSORS_THMC50=y' $(LINUX)/.config; then echo 1; fi),1) -KERNELCHIPSTARGETS += $(MODULE_DIR)/thmc50.o -endif -ifneq ($(shell if grep -q '^CONFIG_SENSORS_W83781D=y' $(LINUX)/.config; then echo 1; fi),1) -KERNELCHIPSTARGETS += $(MODULE_DIR)/w83781d.o -endif -ifneq ($(shell if grep -q '^CONFIG_SENSORS_VIA686A=y' $(LINUX)/.config; then echo 1; fi),1) -KERNELCHIPSTARGETS += $(MODULE_DIR)/via686a.o -endif -ifneq ($(shell if grep -q '^CONFIG_SENSORS_VT1211=y' $(LINUX)/.config; then echo 1; fi),1) -KERNELCHIPSTARGETS += $(MODULE_DIR)/vt1211.o -endif -ifneq ($(shell if grep -q '^CONFIG_SENSORS_VT8231=y' $(LINUX)/.config; then echo 1; fi),1) -KERNELCHIPSTARGETS += $(MODULE_DIR)/vt8231.o -endif -ifneq ($(shell if grep -q '^CONFIG_SENSORS_W83792D=y' $(LINUX)/.config; then echo 1; fi),1) -KERNELCHIPSTARGETS += $(MODULE_DIR)/w83792d.o -endif -ifneq ($(shell if grep -q '^CONFIG_SENSORS_W83627HF=y' $(LINUX)/.config; then echo 1; fi),1) -KERNELCHIPSTARGETS += $(MODULE_DIR)/w83627hf.o -endif -ifneq ($(shell if grep -q '^CONFIG_SENSORS_W83627EHF=y' $(LINUX)/.config; then echo 1; fi),1) -KERNELCHIPSTARGETS += $(MODULE_DIR)/w83627ehf.o -endif -ifneq ($(shell if grep -q '^CONFIG_SENSORS_W83L785TS=y' $(LINUX)/.config; then echo 1; fi),1) -KERNELCHIPSTARGETS += $(MODULE_DIR)/w83l785ts.o -endif -ifneq ($(shell if grep -q '^CONFIG_SENSORS_XEONTEMP=y' $(LINUX)/.config; then echo 1; fi),1) -KERNELCHIPSTARGETS += $(MODULE_DIR)/xeontemp.o -endif - -# Include all dependency files -INCLUDEFILES += $(KERNELCHIPSTARGETS:.o=.d) - -all-kernel-chips: $(KERNELCHIPSTARGETS) -all :: all-kernel-chips - -# -# If $MODPREF/kernel exists, we presume the new (2.4.0) /lib/modules/x.y.z directory -# layout, so we install in kernel/drivers/i2c/chips/ and remove old versions in misc/ -# and kernel/drivers/sensors/ . Otherwise we install in misc/ as before. -# -install-kernel-chips: all-kernel-chips - if [ -n "$(KERNELCHIPSTARGETS)" ] ; then \ - $(MKDIR) $(DESTDIR)$(MODPREF)/kernel/drivers/i2c/chips ; \ - $(INSTALL) -m 644 $(KERNELCHIPSTARGETS) $(DESTDIR)$(MODPREF)/kernel/drivers/i2c/chips ; \ - for i in $(KERNELCHIPSTARGETS) ; do \ - $(RM) $(DESTDIR)$(MODPREF)/misc/`basename $$i` $(DESTDIR)$(MODPREF)/kernel/drivers/sensors/`basename $$i` \ - $(DESTDIR)$(MODPREF)/kernel/drivers/sensors/`basename $$i`.gz $(DESTDIR)$(MODPREF)/kernel/drivers/chips/`basename $$i`.gz ; \ - done ; \ - $(RMDIR) $(DESTDIR)$(MODPREF)/misc $(DESTDIR)$(MODPREF)/kernel/drivers/sensors 2> /dev/null || true ; \ - fi - -install :: install-kernel-chips - -clean-kernel-chips: - $(RM) $(KERNELCHIPSDIR)/*.o $(KERNELCHIPSDIR)/*.d -clean :: clean-kernel-chips diff --git a/kernel/chips/adm1021.c b/kernel/chips/adm1021.c deleted file mode 100644 index c1ecf1ba..00000000 --- a/kernel/chips/adm1021.c +++ /dev/null @@ -1,587 +0,0 @@ -/* - adm1021.c - Part of lm_sensors, Linux kernel modules for hardware - monitoring - Copyright (c) 1998, 1999 Frodo Looijaard and - Philip Edelbrock - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#include -#include -#include -#include -#include -#include "version.h" - -/* Addresses to scan */ -static unsigned short normal_i2c[] = { SENSORS_I2C_END }; -static unsigned short normal_i2c_range[] = { 0x18, 0x1a, 0x29, 0x2b, - 0x4c, 0x4e, SENSORS_I2C_END -}; -static unsigned int normal_isa[] = { SENSORS_ISA_END }; -static unsigned int normal_isa_range[] = { SENSORS_ISA_END }; - -/* Insmod parameters */ -SENSORS_INSMOD_8(adm1021, adm1023, max1617, max1617a, thmc10, lm84, gl523sm, mc1066); - -/* adm1021 constants specified below */ - -/* The adm1021 registers */ -/* Read-only */ -#define ADM1021_REG_TEMP 0x00 -#define ADM1021_REG_REMOTE_TEMP 0x01 -#define ADM1021_REG_STATUS 0x02 -#define ADM1021_REG_MAN_ID 0x0FE /* 0x41 = Analog Devices, 0x49 = TI, - 0x4D = Maxim, 0x23 = Genesys , 0x54 = Onsemi*/ -#define ADM1021_REG_DEV_ID 0x0FF /* ADM1021 = 0x0X, ADM1021A/ADM1023 = 0x3X */ -#define ADM1021_REG_DIE_CODE 0x0FF /* MAX1617A */ -/* These use different addresses for reading/writing */ -#define ADM1021_REG_CONFIG_R 0x03 -#define ADM1021_REG_CONFIG_W 0x09 -#define ADM1021_REG_CONV_RATE_R 0x04 -#define ADM1021_REG_CONV_RATE_W 0x0A -/* These are for the ADM1023's additional precision on the remote temp sensor */ -#define ADM1021_REG_REM_TEMP_PREC 0x010 -#define ADM1021_REG_REM_OFFSET 0x011 -#define ADM1021_REG_REM_OFFSET_PREC 0x012 -#define ADM1021_REG_REM_TOS_PREC 0x013 -#define ADM1021_REG_REM_THYST_PREC 0x014 -/* limits */ -#define ADM1021_REG_TOS_R 0x05 -#define ADM1021_REG_TOS_W 0x0B -#define ADM1021_REG_REMOTE_TOS_R 0x07 -#define ADM1021_REG_REMOTE_TOS_W 0x0D -#define ADM1021_REG_THYST_R 0x06 -#define ADM1021_REG_THYST_W 0x0C -#define ADM1021_REG_REMOTE_THYST_R 0x08 -#define ADM1021_REG_REMOTE_THYST_W 0x0E -/* write-only */ -#define ADM1021_REG_ONESHOT 0x0F - -#define ADM1021_ALARM_TEMP (ADM1021_ALARM_TEMP_HIGH | ADM1021_ALARM_TEMP_LOW) -#define ADM1021_ALARM_RTEMP (ADM1021_ALARM_RTEMP_HIGH | ADM1021_ALARM_RTEMP_LOW\ - | ADM1021_ALARM_RTEMP_NA) -#define ADM1021_ALARM_ALL (ADM1021_ALARM_TEMP | ADM1021_ALARM_RTEMP) - -/* Conversions. Rounding and limit checking is only done on the TO_REG - variants. Note that you should be a bit careful with which arguments - these macros are called: arguments may be evaluated more than once. - Fixing this is just not worth it. */ -/* Conversions note: 1021 uses normal integer signed-byte format*/ -#define TEMP_FROM_REG(val) (val > 127 ? val-256 : val) -#define TEMP_TO_REG(val) (SENSORS_LIMIT((val < 0 ? val+256 : val),0,255)) - -/* Each client has this additional data */ -struct adm1021_data { - struct i2c_client client; - int sysctl_id; - enum chips type; - - struct semaphore update_lock; - char valid; /* !=0 if following fields are valid */ - unsigned long last_updated; /* In jiffies */ - - u8 temp, temp_os, temp_hyst; /* Register values */ - u8 remote_temp, remote_temp_os, remote_temp_hyst, alarms, die_code; - u8 fail; - /* Special values for ADM1023 only */ - u8 remote_temp_prec, remote_temp_os_prec, remote_temp_hyst_prec, - remote_temp_offset, remote_temp_offset_prec; -}; - -static int adm1021_attach_adapter(struct i2c_adapter *adapter); -static int adm1021_detect(struct i2c_adapter *adapter, int address, - unsigned short flags, int kind); -static void adm1021_init_client(struct i2c_client *client); -static int adm1021_detach_client(struct i2c_client *client); -static int adm1021_read_value(struct i2c_client *client, u8 reg); -static int adm1021_rd_good(u8 *val, struct i2c_client *client, u8 reg, u8 mask); -static int adm1021_write_value(struct i2c_client *client, u8 reg, - u16 value); -static void adm1021_temp(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void adm1021_remote_temp(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, - long *results); -static void adm1021_alarms(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void adm1021_die_code(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void adm1021_update_client(struct i2c_client *client); - -/* (amalysh) read only mode, otherwise any limit's writing confuse BIOS */ -static int read_only = 0; - - -/* This is the driver that will be inserted */ -static struct i2c_driver adm1021_driver = { - .name = "ADM1021, MAX1617 sensor driver", - .id = I2C_DRIVERID_ADM1021, - .flags = I2C_DF_NOTIFY, - .attach_adapter = adm1021_attach_adapter, - .detach_client = adm1021_detach_client, -}; - -/* -- SENSORS SYSCTL START -- */ - -#define ADM1021_SYSCTL_TEMP 1200 -#define ADM1021_SYSCTL_REMOTE_TEMP 1201 -#define ADM1021_SYSCTL_DIE_CODE 1202 -#define ADM1021_SYSCTL_ALARMS 1203 - -#define ADM1021_ALARM_TEMP_HIGH 0x40 -#define ADM1021_ALARM_TEMP_LOW 0x20 -#define ADM1021_ALARM_RTEMP_HIGH 0x10 -#define ADM1021_ALARM_RTEMP_LOW 0x08 -#define ADM1021_ALARM_RTEMP_NA 0x04 - -/* -- SENSORS SYSCTL END -- */ - -/* These files are created for each detected adm1021. This is just a template; - though at first sight, you might think we could use a statically - allocated list, we need some way to get back to the parent - which - is done through one of the 'extra' fields which are initialized - when a new copy is allocated. */ -static ctl_table adm1021_dir_table_template[] = { - {ADM1021_SYSCTL_TEMP, "temp1", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &adm1021_temp}, - {ADM1021_SYSCTL_REMOTE_TEMP, "temp2", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &adm1021_remote_temp}, - {ADM1021_SYSCTL_DIE_CODE, "die_code", NULL, 0, 0444, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &adm1021_die_code}, - {ADM1021_SYSCTL_ALARMS, "alarms", NULL, 0, 0444, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &adm1021_alarms}, - {0} -}; - -static ctl_table adm1021_max_dir_table_template[] = { - {ADM1021_SYSCTL_TEMP, "temp1", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &adm1021_temp}, - {ADM1021_SYSCTL_REMOTE_TEMP, "temp2", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &adm1021_remote_temp}, - {ADM1021_SYSCTL_ALARMS, "alarms", NULL, 0, 0444, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &adm1021_alarms}, - {0} -}; - -static int adm1021_attach_adapter(struct i2c_adapter *adapter) -{ - return i2c_detect(adapter, &addr_data, adm1021_detect); -} - -static int adm1021_detect(struct i2c_adapter *adapter, int address, - unsigned short flags, int kind) -{ - int i; - struct i2c_client *new_client; - struct adm1021_data *data; - int err = 0; - const char *type_name = ""; - const char *client_name = ""; - - /* Make sure we aren't probing the ISA bus!! This is just a safety check - at this moment; i2c_detect really won't call us. */ -#ifdef DEBUG - if (i2c_is_isa_adapter(adapter)) { - printk - ("adm1021.o: adm1021_detect called for an ISA bus adapter?!?\n"); - return 0; - } -#endif - - if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) - goto error0; - - /* OK. For now, we presume we have a valid client. We now create the - client structure, even though we cannot fill it completely yet. - But it allows us to access adm1021_{read,write}_value. */ - - if (!(data = kmalloc(sizeof(struct adm1021_data), GFP_KERNEL))) { - err = -ENOMEM; - goto error0; - } - - new_client = &data->client; - new_client->addr = address; - new_client->data = data; - new_client->adapter = adapter; - new_client->driver = &adm1021_driver; - new_client->flags = 0; - - /* Now, we do the remaining detection. */ - - if (kind < 0) { - if ((adm1021_read_value(new_client, ADM1021_REG_STATUS) & 0x03) != 0x00 - || (adm1021_read_value(new_client, ADM1021_REG_CONFIG_R) & 0x3F) != 0x00 - || (adm1021_read_value(new_client, ADM1021_REG_CONV_RATE_R) & 0xF8) != 0x00) - goto error1; - } - - /* Determine the chip type. */ - - if (kind <= 0) { - i = adm1021_read_value(new_client, ADM1021_REG_MAN_ID); - if (i == 0x41) - if ((adm1021_read_value (new_client, ADM1021_REG_DEV_ID) & 0xF0) == 0x30) - kind = adm1023; - else - kind = adm1021; - else if (i == 0x49) - kind = thmc10; - else if (i == 0x23) - kind = gl523sm; - else if ((i == 0x4d) && - (adm1021_read_value - (new_client, ADM1021_REG_DEV_ID) == 0x01)) - kind = max1617a; - else if (i == 0x54) - kind = mc1066; - /* LM84 Mfr ID in a different place, and it has more unused bits */ - else if (adm1021_read_value(new_client, ADM1021_REG_CONV_RATE_R) == 0x00 - && (kind == 0 /* skip extra detection */ - || ((adm1021_read_value(new_client, ADM1021_REG_CONFIG_R) & 0x7F) == 0x00 - && (adm1021_read_value(new_client, ADM1021_REG_STATUS) & 0xAB) == 0x00))) - kind = lm84; - else - kind = max1617; - } - - if (kind == max1617) { - type_name = "max1617"; - client_name = "MAX1617 chip"; - } else if (kind == max1617a) { - type_name = "max1617a"; - client_name = "MAX1617A chip"; - } else if (kind == adm1021) { - type_name = "adm1021"; - client_name = "ADM1021 chip"; - } else if (kind == adm1023) { - type_name = "adm1023"; - client_name = "ADM1023 chip"; - } else if (kind == thmc10) { - type_name = "thmc10"; - client_name = "THMC10 chip"; - } else if (kind == lm84) { - type_name = "lm84"; - client_name = "LM84 chip"; - } else if (kind == gl523sm) { - type_name = "gl523sm"; - client_name = "GL523SM chip"; - } else if (kind == mc1066) { - type_name = "mc1066"; - client_name = "MC1066 chip"; - } - - /* Fill in the remaining client fields and put it into the global list */ - strcpy(new_client->name, client_name); - data->type = kind; - data->valid = 0; - init_MUTEX(&data->update_lock); - - /* Tell the I2C layer a new client has arrived */ - if ((err = i2c_attach_client(new_client))) - goto error3; - - /* Register a new directory entry with module sensors */ - if ((i = i2c_register_entry(new_client, type_name, - data->type == adm1021 ? adm1021_dir_table_template : - adm1021_max_dir_table_template, - THIS_MODULE)) < 0) { - err = i; - goto error4; - } - data->sysctl_id = i; - - /* Initialize the ADM1021 chip */ - if (kind != lm84) - adm1021_init_client(new_client); - return 0; - - error4: - i2c_detach_client(new_client); - error3: - error1: - kfree(data); - error0: - return err; -} - -static void adm1021_init_client(struct i2c_client *client) -{ - /* Enable ADC and disable suspend mode */ - adm1021_write_value(client, ADM1021_REG_CONFIG_W, - adm1021_read_value(client, ADM1021_REG_CONFIG_R) & 0xBF); - /* Set Conversion rate to 1/sec (this can be tinkered with) */ - adm1021_write_value(client, ADM1021_REG_CONV_RATE_W, 0x04); -} - -static int adm1021_detach_client(struct i2c_client *client) -{ - int err; - - i2c_deregister_entry(((struct adm1021_data *) (client->data))-> - sysctl_id); - - if ((err = i2c_detach_client(client))) { - printk - ("adm1021.o: Client deregistration failed, client not detached.\n"); - return err; - } - - kfree(client->data); - - return 0; -} - - -/* All registers are byte-sized */ -static int adm1021_read_value(struct i2c_client *client, u8 reg) -{ - return i2c_smbus_read_byte_data(client, reg); -} - -/* only update value if read succeeded; set fail bit if failed */ -static int adm1021_rd_good(u8 *val, struct i2c_client *client, u8 reg, u8 mask) -{ - int i; - struct adm1021_data *data = client->data; - - i = i2c_smbus_read_byte_data(client, reg); - if (i < 0) { - data->fail |= mask; - return i; - } - *val = i; - return 0; -} - -static int adm1021_write_value(struct i2c_client *client, u8 reg, u16 value) -{ - if (read_only > 0) - return 0; - - return i2c_smbus_write_byte_data(client, reg, value); -} - -static void adm1021_update_client(struct i2c_client *client) -{ - struct adm1021_data *data = client->data; - - down(&data->update_lock); - - if ((jiffies - data->last_updated > HZ + HZ / 2) || - (jiffies < data->last_updated) || !data->valid) { - -#ifdef DEBUG - printk("Starting adm1021 update\n"); -#endif - - data->fail = 0; - adm1021_rd_good(&(data->temp), client, ADM1021_REG_TEMP, - ADM1021_ALARM_TEMP); - adm1021_rd_good(&(data->temp_os), client, ADM1021_REG_TOS_R, - ADM1021_ALARM_TEMP); - adm1021_rd_good(&(data->temp_hyst), client, - ADM1021_REG_THYST_R, ADM1021_ALARM_TEMP); - adm1021_rd_good(&(data->remote_temp), client, - ADM1021_REG_REMOTE_TEMP, ADM1021_ALARM_RTEMP); - adm1021_rd_good(&(data->remote_temp_os), client, - ADM1021_REG_REMOTE_TOS_R, ADM1021_ALARM_RTEMP); - adm1021_rd_good(&(data->remote_temp_hyst), client, - ADM1021_REG_REMOTE_THYST_R, - ADM1021_ALARM_RTEMP); - data->alarms = ADM1021_ALARM_ALL; - if (!adm1021_rd_good(&(data->alarms), client, - ADM1021_REG_STATUS, 0)) - data->alarms &= ADM1021_ALARM_ALL; - if (data->type == adm1021) - adm1021_rd_good(&(data->die_code), client, - ADM1021_REG_DIE_CODE, 0); - if (data->type == adm1023) { - adm1021_rd_good(&(data->remote_temp_prec), client, - ADM1021_REG_REM_TEMP_PREC, - ADM1021_ALARM_TEMP); - adm1021_rd_good(&(data->remote_temp_os_prec), client, - ADM1021_REG_REM_TOS_PREC, - ADM1021_ALARM_RTEMP); - adm1021_rd_good(&(data->remote_temp_hyst_prec), client, - ADM1021_REG_REM_THYST_PREC, - ADM1021_ALARM_RTEMP); - adm1021_rd_good(&(data->remote_temp_offset), client, - ADM1021_REG_REM_OFFSET, - ADM1021_ALARM_RTEMP); - adm1021_rd_good(&(data->remote_temp_offset_prec), - client, ADM1021_REG_REM_OFFSET_PREC, - ADM1021_ALARM_RTEMP); - } - data->last_updated = jiffies; - data->valid = 1; - } - - up(&data->update_lock); -} - - -void adm1021_temp(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct adm1021_data *data = client->data; - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - adm1021_update_client(client); - results[0] = TEMP_FROM_REG(data->temp_os); - results[1] = TEMP_FROM_REG(data->temp_hyst); - results[2] = TEMP_FROM_REG(data->temp); - *nrels_mag = 3; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag >= 1) { - data->temp_os = TEMP_TO_REG(results[0]); - adm1021_write_value(client, ADM1021_REG_TOS_W, - data->temp_os); - } - if (*nrels_mag >= 2) { - data->temp_hyst = TEMP_TO_REG(results[1]); - adm1021_write_value(client, ADM1021_REG_THYST_W, - data->temp_hyst); - } - } -} - -void adm1021_remote_temp(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results) -{ - struct adm1021_data *data = client->data; - int prec = 0; - - if (operation == SENSORS_PROC_REAL_INFO) - if (data->type == adm1023) { *nrels_mag = 3; } - else { *nrels_mag = 0; } - else if (operation == SENSORS_PROC_REAL_READ) { - adm1021_update_client(client); - results[0] = TEMP_FROM_REG(data->remote_temp_os); - results[1] = TEMP_FROM_REG(data->remote_temp_hyst); - results[2] = TEMP_FROM_REG(data->remote_temp); - if (data->type == adm1023) { - results[0]=results[0]*1000 + - ((data->remote_temp_os_prec >> 5) * 125); - results[1]=results[1]*1000 + - ((data->remote_temp_hyst_prec >> 5) * 125); - results[2]=(TEMP_FROM_REG(data->remote_temp_offset)*1000) + - ((data->remote_temp_offset_prec >> 5) * 125); - results[3]=TEMP_FROM_REG(data->remote_temp)*1000 + - ((data->remote_temp_prec >> 5) * 125); - *nrels_mag = 4; - } else { - *nrels_mag = 3; - } - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag >= 1) { - if (data->type == adm1023) { - prec=((results[0]-((results[0]/1000)*1000))/125)<<5; - adm1021_write_value(client, - ADM1021_REG_REM_TOS_PREC, - prec); - results[0]=results[0]/1000; - data->remote_temp_os_prec=prec; - } - data->remote_temp_os = TEMP_TO_REG(results[0]); - adm1021_write_value(client, - ADM1021_REG_REMOTE_TOS_W, - data->remote_temp_os); - } - if (*nrels_mag >= 2) { - if (data->type == adm1023) { - prec=((results[1]-((results[1]/1000)*1000))/125)<<5; - adm1021_write_value(client, - ADM1021_REG_REM_THYST_PREC, - prec); - results[1]=results[1]/1000; - data->remote_temp_hyst_prec=prec; - } - data->remote_temp_hyst = TEMP_TO_REG(results[1]); - adm1021_write_value(client, - ADM1021_REG_REMOTE_THYST_W, - data->remote_temp_hyst); - } - if (*nrels_mag >= 3) { - if (data->type == adm1023) { - prec=((results[2]-((results[2]/1000)*1000))/125)<<5; - adm1021_write_value(client, - ADM1021_REG_REM_OFFSET_PREC, - prec); - results[2]=results[2]/1000; - data->remote_temp_offset_prec=prec; - data->remote_temp_offset=results[2]; - adm1021_write_value(client, - ADM1021_REG_REM_OFFSET, - data->remote_temp_offset); - } - } - } -} - -void adm1021_die_code(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results) -{ - struct adm1021_data *data = client->data; - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - adm1021_update_client(client); - results[0] = data->die_code; - *nrels_mag = 1; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - /* Can't write to it */ - } -} - -void adm1021_alarms(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct adm1021_data *data = client->data; - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - adm1021_update_client(client); - results[0] = data->alarms | data->fail; - *nrels_mag = 1; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - /* Can't write to it */ - } -} - -static int __init sm_adm1021_init(void) -{ - printk(KERN_INFO "adm1021.o version %s (%s)\n", LM_VERSION, LM_DATE); - return i2c_add_driver(&adm1021_driver); -} - -static void __exit sm_adm1021_exit(void) -{ - i2c_del_driver(&adm1021_driver); -} - -MODULE_AUTHOR - ("Frodo Looijaard and Philip Edelbrock "); -MODULE_DESCRIPTION("adm1021 driver"); -MODULE_LICENSE("GPL"); - -MODULE_PARM(read_only, "i"); -MODULE_PARM_DESC(read_only, "Don't set any values, read only mode"); - -module_init(sm_adm1021_init) -module_exit(sm_adm1021_exit) diff --git a/kernel/chips/adm1024.c b/kernel/chips/adm1024.c deleted file mode 100644 index 680b8337..00000000 --- a/kernel/chips/adm1024.c +++ /dev/null @@ -1,776 +0,0 @@ -/* - adm1024.c - Part of lm_sensors, Linux kernel modules for hardware - monitoring - Add by Ken Bowley from the adm1025.c written by - Gordon Wu and from adm9240.c written by - Copyright (c) 1999 Frodo Looijaard - and Philip Edelbrock - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -/* Supports the Analog Devices ADM1024. See doc/chips/adm1024 for details */ - -#include -#include -#include -#include -#include -#include "version.h" - -/* Addresses to scan */ -static unsigned short normal_i2c[] = { SENSORS_I2C_END }; -static unsigned short normal_i2c_range[] = { 0x2c, 0x2e, SENSORS_I2C_END }; -static unsigned int normal_isa[] = { SENSORS_ISA_END }; -static unsigned int normal_isa_range[] = { SENSORS_ISA_END }; - -/* Insmod parameters */ -SENSORS_INSMOD_1(adm1024); - -/* Many ADM1024 constants specified below */ - -#define ADM1024_REG_IN_MAX(nr) (0x2b + (nr) * 2) -#define ADM1024_REG_IN_MIN(nr) (0x2c + (nr) * 2) -#define ADM1024_REG_IN(nr) (0x20 + (nr)) - -/* The ADM1024 registers */ -#define ADM1024_REG_INT_TEMP_TRIP_SET 0x13 -#define ADM1024_REG_EXT_TEMP_TRIP_SET 0x14 -#define ADM1024_REG_TEST 0x15 -#define ADM1024_REG_CHANNEL_MODE 0x16 -#define ADM1024_REG_INT_TEMP_TRIP 0x17 /* read only */ -#define ADM1024_REG_EXT_TEMP_TRIP 0x18 /* read only */ -#define ADM1024_REG_ANALOG_OUT 0x19 -#define ADM1024_REG_AIN1_LOW_LIMIT 0x1A -#define ADM1024_REG_AIN2_LOW_LIMIT 0x1B -/* These are all read-only */ -#define ADM1024_REG_2_5V 0x20 /* 2.5V Measured Value/EXT Temp 2 */ -#define ADM1024_REG_VCCP1 0x21 -#define ADM1024_REG_3_3V 0x22 /* VCC Measured Value */ -#define ADM1024_REG_5V 0x23 -#define ADM1024_REG_12V 0x24 -#define ADM1024_REG_VCCP2 0x25 -#define ADM1024_REG_EXT_TEMP1 0x26 -#define ADM1024_REG_TEMP 0x27 -#define ADM1024_REG_FAN1 0x28 /* FAN1/AIN1 Value */ -#define ADM1024_REG_FAN2 0x29 /* FAN2/AIN2 Value */ -#define ADM1024_REG_COMPANY_ID 0x3E /* 0x41 for ADM1024 */ -#define ADM1024_REG_DIE_REV 0x3F -/* These are read/write */ -#define ADM1024_REG_2_5V_HIGH 0x2B /* 2.5V/Ext Temp2 High Limit */ -#define ADM1024_REG_2_5V_LOW 0x2C /* 2.5V/Ext Temp2 Low Limit */ -#define ADM1024_REG_VCCP1_HIGH 0x2D -#define ADM1024_REG_VCCP1_LOW 0x2E -#define ADM1024_REG_3_3V_HIGH 0x2F /* VCC High Limit */ -#define ADM1024_REG_3_3V_LOW 0x30 /* VCC Low Limit */ -#define ADM1024_REG_5V_HIGH 0x31 -#define ADM1024_REG_5V_LOW 0x32 -#define ADM1024_REG_12V_HIGH 0x33 -#define ADM1024_REG_12V_LOW 0x34 -#define ADM1024_REG_VCCP2_HIGH 0x35 -#define ADM1024_REG_VCCP2_LOW 0x36 -#define ADM1024_REG_EXT_TEMP1_HIGH 0x37 -#define ADM1024_REG_EXT_TEMP1_LOW 0x38 -#define ADM1024_REG_TOS 0x39 -#define ADM1024_REG_THYST 0x3A -#define ADM1024_REG_FAN1_MIN 0x3B -#define ADM1024_REG_FAN2_MIN 0x3C - -#define ADM1024_REG_CONFIG 0x40 -#define ADM1024_REG_INT1_STAT 0x41 -#define ADM1024_REG_INT2_STAT 0x42 -#define ADM1024_REG_INT1_MASK 0x43 -#define ADM1024_REG_INT2_MASK 0x44 - -#define ADM1024_REG_CHASSIS_CLEAR 0x46 -#define ADM1024_REG_VID_FAN_DIV 0x47 -#define ADM1024_REG_I2C_ADDR 0x48 -#define ADM1024_REG_VID4 0x49 -#define ADM1024_REG_CONFIG2 0x4A -#define ADM1024_REG_TEMP_CONFIG 0x4B -#define ADM1024_REG_EXTMODE1 0x4C /* Interupt Status Register Mirror No. 1 */ -#define ADM1024_REG_EXTMODE2 0x4D /* Interupt Status Register Mirror No. 2 */ - -/* Conversions. Rounding and limit checking is only done on the TO_REG - variants. Note that you should be a bit careful with which arguments - these macros are called: arguments may be evaluated more than once. - Fixing this is just not worth it. */ -#define IN_TO_REG(val,nr) (SENSORS_LIMIT(((val) & 0xff),0,255)) -#define IN_FROM_REG(val,nr) (val) - -static inline u8 FAN_TO_REG(long rpm, int div) -{ - if (rpm == 0) - return 255; - rpm = SENSORS_LIMIT(rpm, 1, 1000000); - return SENSORS_LIMIT((1350000 + rpm * div / 2) / (rpm * div), 1, - 254); -} - -#define FAN_FROM_REG(val,div) ((val)==0?-1:\ - (val)==255?0:1350000/((div)*(val))) - -#define TEMP_FROM_REG(temp) \ - ((temp)<256?((((temp)&0x1fe) >> 1) * 10) + ((temp) & 1) * 5: \ - ((((temp)&0x1fe) >> 1) -255) * 10 - ((temp) & 1) * 5) \ - -#define EXT_TEMP_FROM_REG(temp) (((temp)>0x80?(temp)-0x100:(temp))*10) - - -#define TEMP_LIMIT_FROM_REG(val) (((val)>0x80?(val)-0x100:(val))*10) - -#define TEMP_LIMIT_TO_REG(val) SENSORS_LIMIT(((val)<0?(((val)-5)/10):\ - ((val)+5)/10), \ - 0,255) - -#define ALARMS_FROM_REG(val) (val) - -#define DIV_FROM_REG(val) (1 << (val)) -#define DIV_TO_REG(val) ((val)==1?0:((val)==8?3:((val)==4?2:1))) - -#define VID_FROM_REG(val) ((val)==0x1f?0:(val)>=0x10?510-(val)*10:\ - 205-(val)*5) - -/* For each registered ADM1024, we need to keep some data in memory. It is - dynamically allocated, at the same time when a new adm1024 client is - allocated. */ -struct adm1024_data { - struct i2c_client client; - int sysctl_id; - enum chips type; - - struct semaphore update_lock; - char valid; /* !=0 if following fields are valid */ - unsigned long last_updated; /* In jiffies */ - - u8 in[6]; /* Register value */ - u8 in_max[6]; /* Register value */ - u8 in_min[6]; /* Register value */ - u8 fan[2]; /* Register value */ - u8 fan_min[2]; /* Register value */ - u8 fan_div[2]; /* Register encoding, shifted right */ - int temp; /* Temp, shifted right */ - u8 temp_os_max; /* Register value */ - u8 temp_os_hyst; /* Register value */ - int temp1; /* Ext Temp 1 */ - u8 temp1_os_max; - u8 temp1_os_hyst; - int temp2; /* Ext Temp 2 */ - u8 temp2_os_max; - u8 temp2_os_hyst; - u16 alarms; /* Register encoding, combined */ - u8 analog_out; /* Register value */ - u8 vid; /* Register value combined */ -}; - - - -static int adm1024_attach_adapter(struct i2c_adapter *adapter); -static int adm1024_detect(struct i2c_adapter *adapter, int address, - unsigned short flags, int kind); -static int adm1024_detach_client(struct i2c_client *client); - -static int adm1024_read_value(struct i2c_client *client, u8 register); -static int adm1024_write_value(struct i2c_client *client, u8 register, - u8 value); -static void adm1024_update_client(struct i2c_client *client); -static void adm1024_init_client(struct i2c_client *client); - - -static void adm1024_in(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void adm1024_fan(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void adm1024_temp(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void adm1024_temp1(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void adm1024_temp2(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void adm1024_alarms(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void adm1024_fan_div(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void adm1024_analog_out(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, - long *results); -static void adm1024_vid(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); - -static struct i2c_driver adm1024_driver = { - .name = "ADM1024 sensor driver", - .id = I2C_DRIVERID_ADM1024, - .flags = I2C_DF_NOTIFY, - .attach_adapter = adm1024_attach_adapter, - .detach_client = adm1024_detach_client, -}; - -/* The /proc/sys entries */ -/* -- SENSORS SYSCTL START -- */ - -#define ADM1024_SYSCTL_IN0 1000 /* Volts * 100 */ -#define ADM1024_SYSCTL_IN1 1001 -#define ADM1024_SYSCTL_IN2 1002 -#define ADM1024_SYSCTL_IN3 1003 -#define ADM1024_SYSCTL_IN4 1004 -#define ADM1024_SYSCTL_IN5 1005 -#define ADM1024_SYSCTL_FAN1 1101 /* Rotations/min */ -#define ADM1024_SYSCTL_FAN2 1102 -#define ADM1024_SYSCTL_TEMP 1250 /* Degrees Celsius * 100 */ -#define ADM1024_SYSCTL_TEMP1 1290 /* Degrees Celsius */ -#define ADM1024_SYSCTL_TEMP2 1295 /* Degrees Celsius */ -#define ADM1024_SYSCTL_FAN_DIV 2000 /* 1, 2, 4 or 8 */ -#define ADM1024_SYSCTL_ALARMS 2001 /* bitvector */ -#define ADM1024_SYSCTL_ANALOG_OUT 2002 -#define ADM1024_SYSCTL_VID 2003 - -#define ADM1024_ALARM_IN0 0x0001 -#define ADM1024_ALARM_IN1 0x0002 -#define ADM1024_ALARM_IN2 0x0004 -#define ADM1024_ALARM_IN3 0x0008 -#define ADM1024_ALARM_IN4 0x0100 -#define ADM1024_ALARM_IN5 0x0200 -#define ADM1024_ALARM_FAN1 0x0040 -#define ADM1024_ALARM_FAN2 0x0080 -#define ADM1024_ALARM_TEMP 0x0010 -#define ADM1024_ALARM_TEMP1 0x0020 -#define ADM1024_ALARM_TEMP2 0x0001 -#define ADM1024_ALARM_CHAS 0x1000 - -/* -- SENSORS SYSCTL END -- */ - -/* These files are created for each detected ADM1024. This is just a template; - though at first sight, you might think we could use a statically - allocated list, we need some way to get back to the parent - which - is done through one of the 'extra' fields which are initialized - when a new copy is allocated. */ -static ctl_table adm1024_dir_table_template[] = { - {ADM1024_SYSCTL_IN0, "in0", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &adm1024_in}, - {ADM1024_SYSCTL_IN1, "in1", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &adm1024_in}, - {ADM1024_SYSCTL_IN2, "in2", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &adm1024_in}, - {ADM1024_SYSCTL_IN3, "in3", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &adm1024_in}, - {ADM1024_SYSCTL_IN4, "in4", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &adm1024_in}, - {ADM1024_SYSCTL_IN5, "in5", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &adm1024_in}, - {ADM1024_SYSCTL_FAN1, "fan1", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &adm1024_fan}, - {ADM1024_SYSCTL_FAN2, "fan2", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &adm1024_fan}, - {ADM1024_SYSCTL_TEMP, "temp1", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &adm1024_temp}, - {ADM1024_SYSCTL_TEMP1, "temp2", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &adm1024_temp1}, - {ADM1024_SYSCTL_TEMP2, "temp3", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &adm1024_temp2}, - {ADM1024_SYSCTL_FAN_DIV, "fan_div", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &adm1024_fan_div}, - {ADM1024_SYSCTL_ALARMS, "alarms", NULL, 0, 0444, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &adm1024_alarms}, - {ADM1024_SYSCTL_ANALOG_OUT, "analog_out", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &adm1024_analog_out}, - {ADM1024_SYSCTL_VID, "vid", NULL, 0, 0444, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &adm1024_vid}, - {0} -}; - -static int adm1024_attach_adapter(struct i2c_adapter *adapter) -{ - return i2c_detect(adapter, &addr_data, adm1024_detect); -} - -static int adm1024_detect(struct i2c_adapter *adapter, int address, - unsigned short flags, int kind) -{ - int i; - struct i2c_client *new_client; - struct adm1024_data *data; - int err = 0; - const char *type_name = ""; - const char *client_name = ""; - - /* Make sure we aren't probing the ISA bus!! This is just a safety check - at this moment; i2c_detect really won't call us. */ -#ifdef DEBUG - if (i2c_is_isa_adapter(adapter)) { - printk - ("adm1024.o: adm1024_detect called for an ISA bus adapter?!?\n"); - return 0; - } -#endif - - if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) - goto ERROR0; - - /* OK. For now, we presume we have a valid client. We now create the - client structure, even though we cannot fill it completely yet. - But it allows us to access adm1024_{read,write}_value. */ - - if (!(data = kmalloc(sizeof(struct adm1024_data), GFP_KERNEL))) { - err = -ENOMEM; - goto ERROR0; - } - - new_client = &data->client; - new_client->addr = address; - new_client->data = data; - new_client->adapter = adapter; - new_client->driver = &adm1024_driver; - new_client->flags = 0; - - /* Now, we do the remaining detection. */ - - if (kind < 0) { - if((adm1024_read_value(new_client, ADM1024_REG_CONFIG) & 0x80) != 0x00) - goto ERROR1; - } - - /* Determine the chip type. */ - if (kind <= 0) { - i = adm1024_read_value(new_client, ADM1024_REG_COMPANY_ID); - if (i == 0x41) - kind = adm1024; - else { - if (kind == 0) - printk - ("adm1024.o: Ignoring 'force' parameter for unknown chip at " - "adapter %d, address 0x%02x\n", - i2c_adapter_id(adapter), address); - goto ERROR1; - } - } - - if (kind == adm1024) { - type_name = "adm1024"; - client_name = "ADM1024 chip"; - } else { -#ifdef DEBUG - printk("adm1024.o: Internal error: unknown kind (%d)\n", - kind); -#endif - goto ERROR1; - } - - /* Fill in the remaining client fields and put it into the global list */ - strcpy(new_client->name, client_name); - data->type = kind; - data->valid = 0; - init_MUTEX(&data->update_lock); - - /* Tell the I2C layer a new client has arrived */ - if ((err = i2c_attach_client(new_client))) - goto ERROR3; - - /* Register a new directory entry with module sensors */ - if ((i = i2c_register_entry(new_client, - type_name, - adm1024_dir_table_template, - THIS_MODULE)) < 0) { - err = i; - goto ERROR4; - } - data->sysctl_id = i; - - /* Initialize the ADM1024 chip */ - adm1024_init_client(new_client); - return 0; - -/* OK, this is not exactly good programming practice, usually. But it is - very code-efficient in this case. */ - - ERROR4: - i2c_detach_client(new_client); - ERROR3: - ERROR1: - kfree(data); - ERROR0: - return err; -} - -static int adm1024_detach_client(struct i2c_client *client) -{ - int err; - - i2c_deregister_entry(((struct adm1024_data *) (client->data))-> - sysctl_id); - - if ((err = i2c_detach_client(client))) { - printk - ("adm1024.o: Client deregistration failed, client not detached.\n"); - return err; - } - - kfree(client->data); - - return 0; -} - -static int adm1024_read_value(struct i2c_client *client, u8 reg) -{ - return 0xFF & i2c_smbus_read_byte_data(client, reg); -} - -static int adm1024_write_value(struct i2c_client *client, u8 reg, u8 value) -{ - return i2c_smbus_write_byte_data(client, reg, value); -} - -static void adm1024_init_client(struct i2c_client *client) -{ - /* Enable temperature channel 2 */ - adm1024_write_value(client, ADM1024_REG_CHANNEL_MODE, adm1024_read_value(client, ADM1024_REG_CHANNEL_MODE) | 0x04); - - /* Start monitoring */ - adm1024_write_value(client, ADM1024_REG_CONFIG, 0x07); -} - -static void adm1024_update_client(struct i2c_client *client) -{ - struct adm1024_data *data = client->data; - u8 i; - - down(&data->update_lock); - - if ( - (jiffies - data->last_updated > - (data->type == adm1024 ? HZ / 2 : HZ * 2)) - || (jiffies < data->last_updated) || !data->valid) { - -#ifdef DEBUG - printk("Starting adm1024 update\n"); -#endif - for (i = 0; i <= 5; i++) { - data->in[i] = - adm1024_read_value(client, ADM1024_REG_IN(i)); - data->in_min[i] = - adm1024_read_value(client, - ADM1024_REG_IN_MIN(i)); - data->in_max[i] = - adm1024_read_value(client, - ADM1024_REG_IN_MAX(i)); - } - data->fan[0] = - adm1024_read_value(client, ADM1024_REG_FAN1); - data->fan_min[0] = - adm1024_read_value(client, ADM1024_REG_FAN1_MIN); - data->fan[1] = - adm1024_read_value(client, ADM1024_REG_FAN2); - data->fan_min[1] = - adm1024_read_value(client, ADM1024_REG_FAN2_MIN); - data->temp = - (adm1024_read_value(client, ADM1024_REG_TEMP) << 1) + - ((adm1024_read_value - (client, ADM1024_REG_TEMP_CONFIG) & 0x80) >> 7); - data->temp_os_max = - adm1024_read_value(client, ADM1024_REG_TOS); - data->temp_os_hyst = - adm1024_read_value(client, ADM1024_REG_THYST); - data->temp1 = - adm1024_read_value(client, ADM1024_REG_EXT_TEMP1); - data->temp1_os_max = - adm1024_read_value(client, ADM1024_REG_EXT_TEMP1_HIGH); - data->temp1_os_hyst = - adm1024_read_value(client, ADM1024_REG_EXT_TEMP1_LOW); - data->temp2 = - adm1024_read_value(client, ADM1024_REG_2_5V); - data->temp2_os_max = - adm1024_read_value(client, ADM1024_REG_2_5V_HIGH); - data->temp2_os_hyst = - adm1024_read_value(client, ADM1024_REG_2_5V_LOW); - - i = adm1024_read_value(client, ADM1024_REG_VID_FAN_DIV); - data->fan_div[0] = (i >> 4) & 0x03; - data->fan_div[1] = (i >> 6) & 0x03; - data->vid = i & 0x0f; - data->vid |= - (adm1024_read_value(client, ADM1024_REG_VID4) & 0x01) - << 4; - - data->alarms = - adm1024_read_value(client, - ADM1024_REG_INT1_STAT) + - (adm1024_read_value(client, ADM1024_REG_INT2_STAT) << - 8); - data->analog_out = - adm1024_read_value(client, ADM1024_REG_ANALOG_OUT); - data->last_updated = jiffies; - data->valid = 1; - } - - up(&data->update_lock); -} - - -/* The next few functions are the call-back functions of the /proc/sys and - sysctl files. Which function is used is defined in the ctl_table in - the extra1 field. - Each function must return the magnitude (power of 10 to divide the date - with) if it is called with operation==SENSORS_PROC_REAL_INFO. It must - put a maximum of *nrels elements in results reflecting the data of this - file, and set *nrels to the number it actually put in it, if operation== - SENSORS_PROC_REAL_READ. Finally, it must get upto *nrels elements from - results and write them to the chip, if operations==SENSORS_PROC_REAL_WRITE. - Note that on SENSORS_PROC_REAL_READ, I do not check whether results is - large enough (by checking the incoming value of *nrels). This is not very - good practice, but as long as you put less than about 5 values in results, - you can assume it is large enough. */ -void adm1024_in(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - - int scales[6] = { 250, 225, 330, 500, 1200, 270 }; - - struct adm1024_data *data = client->data; - int nr = ctl_name - ADM1024_SYSCTL_IN0; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 2; - else if (operation == SENSORS_PROC_REAL_READ) { - adm1024_update_client(client); - results[0] = - IN_FROM_REG(data->in_min[nr], nr) * scales[nr] / 192; - results[1] = - IN_FROM_REG(data->in_max[nr], nr) * scales[nr] / 192; - results[2] = - IN_FROM_REG(data->in[nr], nr) * scales[nr] / 192; - *nrels_mag = 3; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag >= 1) { - data->in_min[nr] = - IN_TO_REG((results[0] * 192) / scales[nr], nr); - adm1024_write_value(client, ADM1024_REG_IN_MIN(nr), - data->in_min[nr]); - } - if (*nrels_mag >= 2) { - data->in_max[nr] = - IN_TO_REG((results[1] * 192) / scales[nr], nr); - adm1024_write_value(client, ADM1024_REG_IN_MAX(nr), - data->in_max[nr]); - } - } -} - -void adm1024_fan(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct adm1024_data *data = client->data; - int nr = ctl_name - ADM1024_SYSCTL_FAN1 + 1; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - adm1024_update_client(client); - results[0] = FAN_FROM_REG(data->fan_min[nr - 1], - DIV_FROM_REG(data-> - fan_div[nr - 1])); - results[1] = - FAN_FROM_REG(data->fan[nr - 1], - DIV_FROM_REG(data->fan_div[nr - 1])); - *nrels_mag = 2; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag >= 1) { - data->fan_min[nr - 1] = FAN_TO_REG(results[0], - DIV_FROM_REG - (data-> - fan_div[nr - - 1])); - adm1024_write_value(client, - nr == - 1 ? ADM1024_REG_FAN1_MIN : - ADM1024_REG_FAN2_MIN, - data->fan_min[nr - 1]); - } - } -} - - -void adm1024_temp(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct adm1024_data *data = client->data; - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 1; - else if (operation == SENSORS_PROC_REAL_READ) { - adm1024_update_client(client); - results[0] = TEMP_LIMIT_FROM_REG(data->temp_os_max); - results[1] = TEMP_LIMIT_FROM_REG(data->temp_os_hyst); - results[2] = TEMP_FROM_REG(data->temp); - *nrels_mag = 3; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag >= 1) { - data->temp_os_max = TEMP_LIMIT_TO_REG(results[0]); - adm1024_write_value(client, ADM1024_REG_TOS, - data->temp_os_max); - } - if (*nrels_mag >= 2) { - data->temp_os_hyst = TEMP_LIMIT_TO_REG(results[1]); - adm1024_write_value(client, ADM1024_REG_THYST, - data->temp_os_hyst); - } - } -} - -void adm1024_temp1(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct adm1024_data *data = client->data; - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 1; - else if (operation == SENSORS_PROC_REAL_READ) { - adm1024_update_client(client); - results[0] = TEMP_LIMIT_FROM_REG(data->temp1_os_max); - results[1] = TEMP_LIMIT_FROM_REG(data->temp1_os_hyst); - results[2] = EXT_TEMP_FROM_REG(data->temp1); - *nrels_mag = 3; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag >= 1) { - data->temp1_os_max = TEMP_LIMIT_TO_REG(results[0]); - adm1024_write_value(client, ADM1024_REG_EXT_TEMP1_HIGH, - data->temp1_os_max); - } - if (*nrels_mag >= 2) { - data->temp1_os_hyst = TEMP_LIMIT_TO_REG(results[1]); - adm1024_write_value(client, ADM1024_REG_EXT_TEMP1_LOW, - data->temp1_os_hyst); - } - } -} - -void adm1024_temp2(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct adm1024_data *data = client->data; - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 1; - else if (operation == SENSORS_PROC_REAL_READ) { - adm1024_update_client(client); - results[0] = TEMP_LIMIT_FROM_REG(data->temp2_os_max); - results[1] = TEMP_LIMIT_FROM_REG(data->temp2_os_hyst); - results[2] = EXT_TEMP_FROM_REG(data->temp2); - *nrels_mag = 3; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag >= 1) { - data->temp2_os_max = TEMP_LIMIT_TO_REG(results[0]); - adm1024_write_value(client, ADM1024_REG_2_5V_HIGH, - data->temp2_os_max); - } - if (*nrels_mag >= 2) { - data->temp2_os_hyst = TEMP_LIMIT_TO_REG(results[1]); - adm1024_write_value(client, ADM1024_REG_2_5V_LOW, - data->temp2_os_hyst); - } - } -} - -void adm1024_alarms(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct adm1024_data *data = client->data; - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - adm1024_update_client(client); - results[0] = ALARMS_FROM_REG(data->alarms); - *nrels_mag = 1; - } -} - -void adm1024_fan_div(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results) -{ - struct adm1024_data *data = client->data; - int old; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - adm1024_update_client(client); - results[0] = DIV_FROM_REG(data->fan_div[0]); - results[1] = DIV_FROM_REG(data->fan_div[1]); - *nrels_mag = 2; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - old = adm1024_read_value(client, ADM1024_REG_VID_FAN_DIV); - if (*nrels_mag >= 2) { - data->fan_div[1] = DIV_TO_REG(results[1]); - old = (old & 0x3f) | (data->fan_div[1] << 6); - } - if (*nrels_mag >= 1) { - data->fan_div[0] = DIV_TO_REG(results[0]); - old = (old & 0xcf) | (data->fan_div[0] << 4); - adm1024_write_value(client, - ADM1024_REG_VID_FAN_DIV, old); - } - } -} - -void adm1024_analog_out(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results) -{ - struct adm1024_data *data = client->data; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - adm1024_update_client(client); - results[0] = data->analog_out; - *nrels_mag = 1; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag >= 1) { - data->analog_out = results[0]; - adm1024_write_value(client, ADM1024_REG_ANALOG_OUT, - data->analog_out); - } - } -} - -void adm1024_vid(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct adm1024_data *data = client->data; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 2; - else if (operation == SENSORS_PROC_REAL_READ) { - adm1024_update_client(client); - results[0] = VID_FROM_REG(data->vid); - *nrels_mag = 1; - } -} - -static int __init sm_adm1024_init(void) -{ - printk("adm1024.o version %s (%s)\n", LM_VERSION, LM_DATE); - return i2c_add_driver(&adm1024_driver); -} - -static void __exit sm_adm1024_exit(void) -{ - i2c_del_driver(&adm1024_driver); -} - - - -MODULE_AUTHOR - ("Frodo Looijaard and Philip Edelbrock "); -MODULE_DESCRIPTION("ADM1024 driver"); - -MODULE_LICENSE("GPL"); - -module_init(sm_adm1024_init); -module_exit(sm_adm1024_exit); diff --git a/kernel/chips/adm1025.c b/kernel/chips/adm1025.c deleted file mode 100644 index 61c2aa7b..00000000 --- a/kernel/chips/adm1025.c +++ /dev/null @@ -1,588 +0,0 @@ -/* - adm1025.c - Part of lm_sensors, Linux kernel modules for hardware - monitoring - Copyright (c) 2000 Chen-Yuan Wu - Copyright (c) 2003-2004 Jean Delvare - - Based on the adm9240 driver. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -/* Supports the Analog Devices ADM1025 and the Philips NE1619. - See doc/chips/adm1025 for details */ - -#include -#include -#include -#include -#include -#include "version.h" -#include "sensors_vid.h" - -MODULE_LICENSE("GPL"); - -/* Addresses to scan */ -static unsigned short normal_i2c[] = { SENSORS_I2C_END }; -static unsigned short normal_i2c_range[] = { 0x2c, 0x2e, SENSORS_I2C_END }; -static unsigned int normal_isa[] = { SENSORS_ISA_END }; -static unsigned int normal_isa_range[] = { SENSORS_ISA_END }; - -/* Insmod parameters */ -SENSORS_INSMOD_2(adm1025, ne1619); - -/* Many ADM1025 constants specified below */ - - -/* The ADM1025 registers */ - -/* These are all read-only */ -#define ADM1025_REG_2_5V 0x20 /* not used directly, see */ -#define ADM1025_REG_VCCP1 0x21 /* ADM1025_REG_IN(nr) below */ -#define ADM1025_REG_3_3V 0x22 -#define ADM1025_REG_5V 0x23 -#define ADM1025_REG_12V 0x24 -#define ADM1025_REG_VCC 0x25 - -#define ADM1025_REG_RTEMP 0x26 /* not used directly, see */ -#define ADM1025_REG_LTEMP 0x27 /* ADM1025_REG_TEMP(nr) below */ - -#define ADM1025_REG_COMPANY_ID 0x3E /* 0x41 for Analog Devices, - 0xA1 for Philips */ -#define ADM1025_REG_DIE_REV 0x3F /* 0x20-0x2F for ADM1025 and compatible */ - -#define ADM1025_REG_STATUS1 0x41 -#define ADM1025_REG_STATUS2 0x42 - -#define ADM1025_REG_VID 0x47 -#define ADM1025_REG_VID4 0x49 /* actually R/W - but we don't write to it */ - -/* These are read/write */ -#define ADM1025_REG_2_5V_HIGH 0x2B /* not used directly, see */ -#define ADM1025_REG_2_5V_LOW 0x2C /* ADM1025_REG_IN_MAX(nr) and */ -#define ADM1025_REG_VCCP1_HIGH 0x2D /* ADM1025_REG_IN_MIN(nr) below */ -#define ADM1025_REG_VCCP1_LOW 0x2E -#define ADM1025_REG_3_3V_HIGH 0x2F -#define ADM1025_REG_3_3V_LOW 0x30 -#define ADM1025_REG_5V_HIGH 0x31 -#define ADM1025_REG_5V_LOW 0x32 -#define ADM1025_REG_12V_HIGH 0x33 -#define ADM1025_REG_12V_LOW 0x34 -#define ADM1025_REG_VCC_HIGH 0x35 -#define ADM1025_REG_VCC_LOW 0x36 - -#define ADM1025_REG_RTEMP_HIGH 0x37 /* not used directly, see */ -#define ADM1025_REG_RTEMP_LOW 0x38 /* ADM1025_REG_TEMP_MAX(nr) and */ -#define ADM1025_REG_LTEMP_HIGH 0x39 /* ADM1025_REG_TEMP_MIN(nr) below */ -#define ADM1025_REG_LTEMP_LOW 0x3A - -#define ADM1025_REG_CONFIG 0x40 - -/* Useful macros */ -#define ADM1025_REG_IN(nr) (ADM1025_REG_2_5V + (nr)) -#define ADM1025_REG_IN_MAX(nr) (ADM1025_REG_2_5V_HIGH + (nr) * 2) -#define ADM1025_REG_IN_MIN(nr) (ADM1025_REG_2_5V_LOW + (nr) * 2) -#define ADM1025_REG_TEMP(nr) (ADM1025_REG_RTEMP + (nr)) -#define ADM1025_REG_TEMP_HIGH(nr) (ADM1025_REG_RTEMP_HIGH + (nr) * 2) -#define ADM1025_REG_TEMP_LOW(nr) (ADM1025_REG_RTEMP_LOW + (nr) * 2) - -/* Conversions. Rounding and limit checking is only done on the TO_REG - variants. Note that you should be a bit careful with which arguments - these macros are called: arguments may be evaluated more than once. - Fixing this is just not worth it. */ -#define IN_TO_REG(val) SENSORS_LIMIT(val, 0, 255) -#define IN_FROM_REG(val) (val) - -#define TEMP_FROM_REG(val) (((val)>=0x80?(val)-0x100:(val))*10) -#define TEMP_TO_REG(val) SENSORS_LIMIT(((val)<0?(((val)-5)/10):\ - ((val)+5)/10),-128,127) - -#define ALARMS_FROM_REG(val) (val) - -/* For each registered ADM1025, we need to keep some data in memory. It is - dynamically allocated, at the same time when a new adm1025 client is - allocated. */ -struct adm1025_data { - struct i2c_client client; - int sysctl_id; - enum chips type; - - struct semaphore update_lock; - char valid; /* !=0 if following fields are valid */ - unsigned long last_updated; /* In jiffies */ - - u8 in[6]; /* Register value */ - u8 in_max[6]; /* Register value */ - u8 in_min[6]; /* Register value */ - u8 temp[2]; /* Register value */ - u8 temp_high[2]; /* Register value */ - u8 temp_low[2]; /* Register value */ - u16 alarms; /* Register encoding, combined */ - u8 vid; /* Register value combined */ - u8 vrm; -}; - - -static int adm1025_attach_adapter(struct i2c_adapter *adapter); -static int adm1025_detect(struct i2c_adapter *adapter, int address, - unsigned short flags, int kind); -static int adm1025_detach_client(struct i2c_client *client); -static void adm1025_update_client(struct i2c_client *client); -static void adm1025_init_client(struct i2c_client *client); - - -static void adm1025_in(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void adm1025_temp(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void adm1025_alarms(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void adm1025_vid(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void adm1025_vrm(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); - -static struct i2c_driver adm1025_driver = { - .name = "ADM1025 sensor driver", - .id = I2C_DRIVERID_ADM1025, - .flags = I2C_DF_NOTIFY, - .attach_adapter = adm1025_attach_adapter, - .detach_client = adm1025_detach_client, -}; - -/* The /proc/sys entries */ -/* -- SENSORS SYSCTL START -- */ - -#define ADM1025_SYSCTL_IN0 1000 /* Volts * 100 */ -#define ADM1025_SYSCTL_IN1 1001 -#define ADM1025_SYSCTL_IN2 1002 -#define ADM1025_SYSCTL_IN3 1003 -#define ADM1025_SYSCTL_IN4 1004 -#define ADM1025_SYSCTL_IN5 1005 - -#define ADM1025_SYSCTL_RTEMP 1250 /* Degrees Celsius * 10 */ -#define ADM1025_SYSCTL_TEMP 1251 - -#define ADM1025_SYSCTL_ALARMS 2001 /* bitvector */ -#define ADM1025_SYSCTL_VID 2003 /* Volts * 1000 */ -#define ADM1025_SYSCTL_VRM 2004 - -#define ADM1025_ALARM_IN0 0x0001 -#define ADM1025_ALARM_IN1 0x0002 -#define ADM1025_ALARM_IN2 0x0004 -#define ADM1025_ALARM_IN3 0x0008 -#define ADM1025_ALARM_IN4 0x0100 -#define ADM1025_ALARM_IN5 0x0200 -#define ADM1025_ALARM_RTEMP 0x0020 -#define ADM1025_ALARM_TEMP 0x0010 -#define ADM1025_ALARM_RFAULT 0x4000 - -/* -- SENSORS SYSCTL END -- */ - -/* These files are created for each detected ADM1025. This is just a template; - though at first sight, you might think we could use a statically - allocated list, we need some way to get back to the parent - which - is done through one of the 'extra' fields which are initialized - when a new copy is allocated. */ -static ctl_table adm1025_dir_table_template[] = { - {ADM1025_SYSCTL_IN0, "in0", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &adm1025_in}, - {ADM1025_SYSCTL_IN1, "in1", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &adm1025_in}, - {ADM1025_SYSCTL_IN2, "in2", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &adm1025_in}, - {ADM1025_SYSCTL_IN3, "in3", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &adm1025_in}, - {ADM1025_SYSCTL_IN4, "in4", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &adm1025_in}, - {ADM1025_SYSCTL_IN5, "in5", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &adm1025_in}, - {ADM1025_SYSCTL_RTEMP, "temp1", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &adm1025_temp}, - {ADM1025_SYSCTL_TEMP, "temp2", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &adm1025_temp}, - {ADM1025_SYSCTL_ALARMS, "alarms", NULL, 0, 0444, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &adm1025_alarms}, - {ADM1025_SYSCTL_VID, "vid", NULL, 0, 0444, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &adm1025_vid}, - {ADM1025_SYSCTL_VRM, "vrm", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &adm1025_vrm}, - {0} -}; - -static int adm1025_attach_adapter(struct i2c_adapter *adapter) -{ - return i2c_detect(adapter, &addr_data, adm1025_detect); -} - -static int adm1025_detect(struct i2c_adapter *adapter, int address, - unsigned short flags, int kind) -{ - int i; - struct i2c_client *new_client; - struct adm1025_data *data; - int err = 0; - const char *type_name = ""; - const char *client_name = ""; - - /* Make sure we aren't probing the ISA bus!! This is just a safety check - at this moment; i2c_detect really won't call us. */ -#ifdef DEBUG - if (i2c_is_isa_adapter(adapter)) { - printk - ("adm1025.o: adm1025_detect called for an ISA bus adapter?!?\n"); - return 0; - } -#endif - - if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) - goto ERROR0; - - /* OK. For now, we presume we have a valid client. We now create the - client structure, even though we cannot fill it completely yet. - But it allows us to access adm1025_{read,write}_value. */ - - if (!(data = kmalloc(sizeof(struct adm1025_data), GFP_KERNEL))) { - err = -ENOMEM; - goto ERROR0; - } - - new_client = &data->client; - new_client->addr = address; - new_client->data = data; - new_client->adapter = adapter; - new_client->driver = &adm1025_driver; - new_client->flags = 0; - - /* Now, we do the remaining detection. */ - - if (kind < 0) { - if ((i2c_smbus_read_byte_data(new_client, - ADM1025_REG_CONFIG) & 0x80) != 0x00 - || (i2c_smbus_read_byte_data(new_client, - ADM1025_REG_STATUS1) & 0xC0) != 0x00 - || (i2c_smbus_read_byte_data(new_client, - ADM1025_REG_STATUS2) & 0xBC) != 0x00) - goto ERROR1; - } - - /* Determine the chip type. */ - if (kind <= 0) { - u8 man_id, chip_id; - - man_id = i2c_smbus_read_byte_data(new_client, - ADM1025_REG_COMPANY_ID); - chip_id = i2c_smbus_read_byte_data(new_client, - ADM1025_REG_DIE_REV); - - if (man_id == 0x41) { /* Analog Devices */ - if ((chip_id & 0xF0) == 0x20) /* ADM1025 */ - kind = adm1025; - } else if (man_id == 0xA1) { /* Philips */ - if (address != 0x2E - && (chip_id & 0xF0) == 0x20) /* NE1619 */ - kind = ne1619; - } - } - - if (kind <= 0) { /* Identification failed */ - printk("adm1025.o: Unsupported chip.\n"); - goto ERROR1; - } - - if (kind == adm1025) { - type_name = "adm1025"; - client_name = "ADM1025 chip"; - } else if (kind == ne1619) { - type_name = "ne1619"; - client_name = "NE1619 chip"; - } else { -#ifdef DEBUG - printk("adm1025.o: Internal error: unknown kind (%d)\n", - kind); -#endif - goto ERROR1; - } - - /* Fill in the remaining client fields and put it into the global list */ - strcpy(new_client->name, client_name); - data->type = kind; - data->valid = 0; - init_MUTEX(&data->update_lock); - - /* Tell the I2C layer a new client has arrived */ - if ((err = i2c_attach_client(new_client))) - goto ERROR3; - - /* Register a new directory entry with module sensors */ - if ((i = i2c_register_entry(new_client, - type_name, - adm1025_dir_table_template, - THIS_MODULE)) < 0) { - err = i; - goto ERROR4; - } - data->sysctl_id = i; - - /* Initialize the ADM1025 chip */ - adm1025_init_client(new_client); - return 0; - -/* OK, this is not exactly good programming practice, usually. But it is - very code-efficient in this case. */ - - ERROR4: - i2c_detach_client(new_client); - ERROR3: - ERROR1: - kfree(data); - ERROR0: - return err; -} - -static int adm1025_detach_client(struct i2c_client *client) -{ - int err; - - i2c_deregister_entry(((struct adm1025_data *) (client->data))-> - sysctl_id); - - if ((err = i2c_detach_client(client))) { - printk - ("adm1025.o: Client deregistration failed, client not detached.\n"); - return err; - } - - kfree(client->data); - - return 0; -} - -/* Called when we have found a new ADM1025. */ -static void adm1025_init_client(struct i2c_client *client) -{ - struct adm1025_data *data = client->data; - u8 reg; - int i; - - data->vrm = 82; - - /* Set high limits - Usually we avoid setting limits on driver init, but it happens - that the ADM1025 comes with stupid default limits (all registers - set to 0). In case the chip has not gone through any limit - setting yet, we better set the high limits to the max so that - no alarm triggers. */ - for (i=0; i<6; i++) { - reg = i2c_smbus_read_byte_data(client, - ADM1025_REG_IN_MAX(i)); - if (reg == 0) - i2c_smbus_write_byte_data(client, - ADM1025_REG_IN_MAX(i), - 0xFF); - } - for (i=0; i<2; i++) { - reg = i2c_smbus_read_byte_data(client, - ADM1025_REG_TEMP_HIGH(i)); - if (reg == 0) - i2c_smbus_write_byte_data(client, - ADM1025_REG_TEMP_HIGH(i), - 0x7F); - } - - /* Start monitoring */ - reg = i2c_smbus_read_byte_data(client, ADM1025_REG_CONFIG); - i2c_smbus_write_byte_data(client, ADM1025_REG_CONFIG, (reg|0x01)&0x7F); -} - -static void adm1025_update_client(struct i2c_client *client) -{ - struct adm1025_data *data = client->data; - u8 nr; - - down(&data->update_lock); - - if ((jiffies - data->last_updated > 2 * HZ) - || (jiffies < data->last_updated) || !data->valid) { -#ifdef DEBUG - printk("Starting adm1025 update\n"); -#endif - - /* Voltages */ - for (nr = 0; nr < 6; nr++) { - data->in[nr] = i2c_smbus_read_byte_data(client, ADM1025_REG_IN(nr)); - data->in_min[nr] = i2c_smbus_read_byte_data(client, ADM1025_REG_IN_MIN(nr)); - data->in_max[nr] = i2c_smbus_read_byte_data(client, ADM1025_REG_IN_MAX(nr)); - } - - /* Temperatures */ - for (nr = 0; nr < 2; nr++) { - data->temp[nr] = i2c_smbus_read_byte_data(client, ADM1025_REG_TEMP(nr)); - data->temp_high[nr] = i2c_smbus_read_byte_data(client, ADM1025_REG_TEMP_HIGH(nr)); - data->temp_low[nr] = i2c_smbus_read_byte_data(client, ADM1025_REG_TEMP_LOW(nr)); - } - - /* VID */ - data->vid = (i2c_smbus_read_byte_data(client, ADM1025_REG_VID) & 0x0f) - + ((i2c_smbus_read_byte_data(client, ADM1025_REG_VID4) & 0x01) << 4); - - /* Alarms */ - data->alarms = (i2c_smbus_read_byte_data(client, ADM1025_REG_STATUS1) & 0x3f) - + ((i2c_smbus_read_byte_data(client, ADM1025_REG_STATUS2) & 0x43) << 8); - - data->last_updated = jiffies; - data->valid = 1; - } - - up(&data->update_lock); -} - - -/* The next few functions are the call-back functions of the /proc/sys and - sysctl files. Which function is used is defined in the ctl_table in - the extra1 field. - Each function must return the magnitude (power of 10 to divide the data - with) if it is called with operation==SENSORS_PROC_REAL_INFO. It must - put a maximum of *nrels elements in results reflecting the data of this - file, and set *nrels to the number it actually put in it, if operation== - SENSORS_PROC_REAL_READ. Finally, it must get upto *nrels elements from - results and write them to the chip, if operations==SENSORS_PROC_REAL_WRITE. - Note that on SENSORS_PROC_REAL_READ, I do not check whether results is - large enough (by checking the incoming value of *nrels). This is not very - good practice, but as long as you put less than about 5 values in results, - you can assume it is large enough. */ -void adm1025_in(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - int scales[6] = { 250, 225, 330, 500, 1200, 330 }; - - struct adm1025_data *data = client->data; - int nr = ctl_name - ADM1025_SYSCTL_IN0; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 2; - else if (operation == SENSORS_PROC_REAL_READ) { - adm1025_update_client(client); - results[0] = (IN_FROM_REG(data->in_min[nr]) * scales[nr] + 96) / 192; - results[1] = (IN_FROM_REG(data->in_max[nr]) * scales[nr] + 96) / 192; - results[2] = (IN_FROM_REG(data->in[nr]) * scales[nr] + 96) / 192; - *nrels_mag = 3; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag >= 1) { - data->in_min[nr] = IN_TO_REG((results[0] * 192 + scales[nr] / 2) - / scales[nr]); - i2c_smbus_write_byte_data(client, ADM1025_REG_IN_MIN(nr), - data->in_min[nr]); - } - if (*nrels_mag >= 2) { - data->in_max[nr] = IN_TO_REG((results[1] * 192 + scales[nr] / 2) - / scales[nr]); - i2c_smbus_write_byte_data(client, ADM1025_REG_IN_MAX(nr), - data->in_max[nr]); - } - } -} - -void adm1025_temp(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct adm1025_data *data = client->data; - int nr = ctl_name - ADM1025_SYSCTL_RTEMP; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 1; - else if (operation == SENSORS_PROC_REAL_READ) { - adm1025_update_client(client); - results[0] = TEMP_FROM_REG(data->temp_high[nr]); - results[1] = TEMP_FROM_REG(data->temp_low[nr]); - results[2] = TEMP_FROM_REG(data->temp[nr]); - *nrels_mag = 3; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag >= 1) { - data->temp_high[nr] = TEMP_TO_REG(results[0]); - i2c_smbus_write_byte_data(client, ADM1025_REG_TEMP_HIGH(nr), - data->temp_high[nr]); - } - if (*nrels_mag >= 2) { - data->temp_low[nr] = TEMP_TO_REG(results[1]); - i2c_smbus_write_byte_data(client, ADM1025_REG_TEMP_LOW(nr), - data->temp_low[nr]); - } - } -} - -void adm1025_alarms(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct adm1025_data *data = client->data; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - adm1025_update_client(client); - results[0] = ALARMS_FROM_REG(data->alarms); - *nrels_mag = 1; - } -} - -void adm1025_vid(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct adm1025_data *data = client->data; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 3; - else if (operation == SENSORS_PROC_REAL_READ) { - adm1025_update_client(client); - results[0] = vid_from_reg(data->vid, data->vrm); - *nrels_mag = 1; - } -} - -void adm1025_vrm(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct adm1025_data *data = client->data; - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 1; - else if (operation == SENSORS_PROC_REAL_READ) { - results[0] = data->vrm; - *nrels_mag = 1; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag >= 1) - data->vrm = results[0]; - } -} - -static int __init sm_adm1025_init(void) -{ - printk("adm1025.o version %s (%s)\n", LM_VERSION, LM_DATE); - return i2c_add_driver(&adm1025_driver); -} - -static void __exit sm_adm1025_exit(void) -{ - i2c_del_driver(&adm1025_driver); -} - - - -MODULE_AUTHOR("Chen-Yuan Wu " - " and Jean Delvare "); -MODULE_DESCRIPTION("ADM1025 driver"); - -module_init(sm_adm1025_init); -module_exit(sm_adm1025_exit); diff --git a/kernel/chips/adm1026.c b/kernel/chips/adm1026.c deleted file mode 100644 index cce55faf..00000000 --- a/kernel/chips/adm1026.c +++ /dev/null @@ -1,1733 +0,0 @@ -/* - adm1026.c - Part of lm_sensors, Linux kernel modules for hardware - monitoring - Copyright (c) 2002, 2003 Philip Pokorny - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - - CHANGELOG - - 2003-03-13 Initial development - 2003-05-07 First Release. Includes GPIO fixup and full - functionality. - 2003-05-18 Minor fixups and tweaks. - Print GPIO config after fixup. - Adjust fan MIN if DIV changes. - 2003-05-21 Fix printing of FAN/GPIO config - Fix silly bug in fan_div logic - Fix fan_min handling so that 0xff is 0 is 0xff - 2003-05-25 Fix more silly typos... - 2003-06-11 Change FAN_xx_REG macros to use different scaling - Most (all?) drivers assume two pulses per rev fans - and the old scaling was producing double the RPM's - Thanks to Jerome Hsiao @ Arima for pointing this out. - 2004-01-27 Remove use of temporary ID. - Define addresses as a range. -*/ - -#include -#include -#include -#include -#include -#include "version.h" -#include "sensors_vid.h" - -#ifndef I2C_DRIVERID_ADM1026 -#define I2C_DRIVERID_ADM1026 1048 -#endif - -/* Addresses to scan */ -static unsigned short normal_i2c[] = { SENSORS_I2C_END }; -static unsigned short normal_i2c_range[] = { 0x2c, 0x2e, SENSORS_I2C_END }; -static unsigned int normal_isa[] = { SENSORS_ISA_END }; -static unsigned int normal_isa_range[] = { SENSORS_ISA_END }; - -/* Insmod parameters */ -SENSORS_INSMOD_1(adm1026); - -static int gpio_input[17] = { -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1 }; -static int gpio_output[17] = { -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1 }; -static int gpio_inverted[17] = { -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1 }; -static int gpio_normal[17] = { -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1 }; -static int gpio_fan[8] = { -1, -1, -1, -1, -1, -1, -1, -1 }; -MODULE_PARM(gpio_input,"1-17i"); -MODULE_PARM_DESC(gpio_input,"List of GPIO pins (0-16) to program as inputs"); -MODULE_PARM(gpio_output,"1-17i"); -MODULE_PARM_DESC(gpio_output,"List of GPIO pins (0-16) to program as outputs"); -MODULE_PARM(gpio_inverted,"1-17i"); -MODULE_PARM_DESC(gpio_inverted,"List of GPIO pins (0-16) to program as inverted"); -MODULE_PARM(gpio_normal,"1-17i"); -MODULE_PARM_DESC(gpio_normal,"List of GPIO pins (0-16) to program as normal/non-inverted"); -MODULE_PARM(gpio_fan,"1-8i"); -MODULE_PARM_DESC(gpio_fan,"List of GPIO pins (0-7) to program as fan tachs"); - -/* Many ADM1026 constants specified below */ - -/* The ADM1026 registers */ -#define ADM1026_REG_CONFIG1 (0x00) -#define CFG1_MONITOR (0x01) -#define CFG1_INT_ENABLE (0x02) -#define CFG1_INT_CLEAR (0x04) -#define CFG1_AIN8_9 (0x08) -#define CFG1_THERM_HOT (0x10) -#define CFG1_DAC_AFC (0x20) -#define CFG1_PWM_AFC (0x40) -#define CFG1_RESET (0x80) -#define ADM1026_REG_CONFIG2 (0x01) -/* CONFIG2 controls FAN0/GPIO0 through FAN7/GPIO7 */ -#define ADM1026_REG_CONFIG3 (0x07) -#define CFG3_GPIO16_ENABLE (0x01) -#define CFG3_CI_CLEAR (0x02) -#define CFG3_VREF_250 (0x04) -#define CFG3_GPIO16_DIR (0x40) -#define CFG3_GPIO16_POL (0x80) -#define ADM1026_REG_E2CONFIG (0x13) -#define E2CFG_READ (0x01) -#define E2CFG_WRITE (0x02) -#define E2CFG_ERASE (0x04) -#define E2CFG_ROM (0x08) -#define E2CFG_CLK_EXT (0x80) - -/* There are 10 general analog inputs and 7 dedicated inputs - * They are: - * 0 - 9 = AIN0 - AIN9 - * 10 = Vbat - * 11 = 3.3V Standby - * 12 = 3.3V Main - * 13 = +5V - * 14 = Vccp (CPU core voltage) - * 15 = +12V - * 16 = -12V - */ -static u16 REG_IN[] = { - 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, - 0x36, 0x37, 0x27, 0x29, 0x26, 0x2a, - 0x2b, 0x2c, 0x2d, 0x2e, 0x2f - }; -static u16 REG_IN_MIN[] = { - 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, - 0x5e, 0x5f, 0x6d, 0x49, 0x6b, 0x4a, - 0x4b, 0x4c, 0x4d, 0x4e, 0x4f - }; -static u16 REG_IN_MAX[] = { - 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, - 0x56, 0x57, 0x6c, 0x41, 0x6a, 0x42, - 0x43, 0x44, 0x45, 0x46, 0x47 - }; -#define ADM1026_REG_IN(nr) (REG_IN[(nr)]) -#define ADM1026_REG_IN_MIN(nr) (REG_IN_MIN[(nr)]) -#define ADM1026_REG_IN_MAX(nr) (REG_IN_MAX[(nr)]) - -/* Temperatures are: - * 0 - Internal - * 1 - External 1 - * 2 - External 2 - */ -static u16 REG_TEMP[] = { 0x1f, 0x28, 0x29 }; -static u16 REG_TEMP_MIN[] = { 0x69, 0x48, 0x49 }; -static u16 REG_TEMP_MAX[] = { 0x68, 0x40, 0x41 }; -static u16 REG_TEMP_TMIN[] = { 0x10, 0x11, 0x12 }; -static u16 REG_TEMP_THERM[] = { 0x0d, 0x0e, 0x0f }; -static u16 REG_TEMP_OFFSET[] = { 0x1e, 0x6e, 0x6f }; -#define ADM1026_REG_TEMP(nr) (REG_TEMP[(nr)]) -#define ADM1026_REG_TEMP_MIN(nr) (REG_TEMP_MIN[(nr)]) -#define ADM1026_REG_TEMP_MAX(nr) (REG_TEMP_MAX[(nr)]) -#define ADM1026_REG_TEMP_TMIN(nr) (REG_TEMP_TMIN[(nr)]) -#define ADM1026_REG_TEMP_THERM(nr) (REG_TEMP_THERM[(nr)]) -#define ADM1026_REG_TEMP_OFFSET(nr) (REG_TEMP_OFFSET[(nr)]) - -#define ADM1026_REG_FAN(nr) (0x38 + (nr)) -#define ADM1026_REG_FAN_MIN(nr) (0x60 + (nr)) -#define ADM1026_REG_FAN_DIV_0_3 (0x02) -#define ADM1026_REG_FAN_DIV_4_7 (0x03) - -#define ADM1026_REG_DAC (0x04) -#define ADM1026_REG_PWM (0x05) - -#define ADM1026_REG_GPIO_CFG_0_3 (0x08) -#define ADM1026_REG_GPIO_CFG_4_7 (0x09) -#define ADM1026_REG_GPIO_CFG_8_11 (0x0a) -#define ADM1026_REG_GPIO_CFG_12_15 (0x0b) -/* CFG_16 in REG_CFG3 */ -#define ADM1026_REG_GPIO_STATUS_0_7 (0x24) -#define ADM1026_REG_GPIO_STATUS_8_15 (0x25) -/* STATUS_16 in REG_STATUS4 */ -#define ADM1026_REG_GPIO_MASK_0_7 (0x1c) -#define ADM1026_REG_GPIO_MASK_8_15 (0x1d) -/* MASK_16 in REG_MASK4 */ - -#define ADM1026_REG_COMPANY 0x16 -#define ADM1026_REG_VERSTEP 0x17 -/* These are the recognized values for the above regs */ -#define ADM1026_COMPANY_ANALOG_DEV 0x41 -#define ADM1026_VERSTEP_GENERIC 0x40 -#define ADM1026_VERSTEP_ADM1026 0x44 - -#define ADM1026_REG_MASK1 0x18 -#define ADM1026_REG_MASK2 0x19 -#define ADM1026_REG_MASK3 0x1a -#define ADM1026_REG_MASK4 0x1b - -#define ADM1026_REG_STATUS1 0x20 -#define ADM1026_REG_STATUS2 0x21 -#define ADM1026_REG_STATUS3 0x22 -#define ADM1026_REG_STATUS4 0x23 - -/* Conversions. Rounding and limit checking is only done on the TO_REG - variants. Note that you should be a bit careful with which arguments - these macros are called: arguments may be evaluated more than once. - */ - -/* IN are scaled acording to built-in resistors. These are the - * voltages corresponding to 3/4 of full scale (192 or 0xc0) - * NOTE: The -12V input needs an additional factor to account - * for the Vref pullup resistor. - * NEG12_OFFSET = SCALE * Vref / V-192 - Vref - * = 13875 * 2.50 / 1.875 - 2500 - * = 16000 - */ -#if 1 -/* The values in this table are based on Table II, page 15 of the - * datasheet. - */ -static int adm1026_scaling[] = { /* .001 Volts */ - 2250, 2250, 2250, 2250, 2250, 2250, - 1875, 1875, 1875, 1875, 3000, 3330, - 3330, 4995, 2250, 12000, 13875 - }; -#define NEG12_OFFSET 16000 -#else -/* The values in this table are based on the resistors in - * Figure 5 on page 16. But the 3.3V inputs are not in - * the figure and the values for the 5V input are wrong. - * For 5V, I'm guessing that R2 at 55.2k is right, but - * the total resistance should be 1400 or 1449 like the - * other inputs. Using 1449, gives 4.922V at 192. - */ -static int adm1026_scaling[] = { /* .001 Volts */ - 2249, 2249, 2249, 2249, 2249, 2249, - 1875, 1875, 1875, 1875, 3329, 3329, - 3329, 4922, 2249, 11969, 13889 - }; -#define NEG12_OFFSET 16019 -#endif - -#define SCALE(val,from,to) (((val)*(to) + ((from)/2))/(from)) -#define INS_TO_REG(n,val) (SENSORS_LIMIT(SCALE(val,adm1026_scaling[n],192),0,255)) -#if 0 /* If we have extended A/D bits */ -#define INSEXT_FROM_REG(n,val,ext) (SCALE((val)*4 + (ext),192*4,adm1026_scaling[n])) -#define INS_FROM_REG(n,val) (INSEXT_FROM_REG(n,val,0)) -#else -#define INS_FROM_REG(n,val) (SCALE(val,192,adm1026_scaling[n])) -#endif - -/* FAN speed is measured using 22.5kHz clock and counts for 2 pulses - * and we assume a 2 pulse-per-rev fan tach signal - * 22500 kHz * 60 (sec/min) * 2 (pulse) / 2 (pulse/rev) == 1350000 - */ -#define FAN_TO_REG(val,div) ((val)<=0 ? 0xff : SENSORS_LIMIT(1350000/((val)*(div)),1,254)) -#define FAN_FROM_REG(val,div) ((val)==0?-1:(val)==0xff ? 0 : 1350000/((val)*(div))) -#define DIV_FROM_REG(val) (1<<(val)) -#define DIV_TO_REG(val) ((val)>=8 ? 3 : (val)>=4 ? 2 : (val)>=2 ? 1 : 0) - -/* Temperature is reported in 1 degC increments */ -#define TEMP_TO_REG(val) (SENSORS_LIMIT(val,-127,127)) -#define TEMP_FROM_REG(val) (val) -#define OFFSET_TO_REG(val) (SENSORS_LIMIT(val,-127,127)) -#define OFFSET_FROM_REG(val) (val) - -#define PWM_TO_REG(val) (SENSORS_LIMIT(val,0,255)) -#define PWM_FROM_REG(val) (val) - -/* Analog output is a voltage, but it's used like a PWM - * Seems like this should be scaled, but to be consistent - * with other drivers, we do it this way. - */ -#define DAC_TO_REG(val) (SENSORS_LIMIT(val,0,255)) -#define DAC_FROM_REG(val) (val) - -#define ALARMS_FROM_REG(val) (val) - -/* Unlike some other drivers we DO NOT set initial limits. Use - * the config file to set limits. - */ - -/* Typically used with systems using a v9.1 VRM spec ? */ -#define ADM1026_INIT_VRM 91 -#define ADM1026_INIT_VID -1 - -/* Chip sampling rates - * - * Some sensors are not updated more frequently than once per second - * so it doesn't make sense to read them more often than that. - * We cache the results and return the saved data if the driver - * is called again before a second has elapsed. - * - * Also, there is significant configuration data for this chip - * So, we keep the config data up to date in the cache - * when it is written and only sample it once every 5 *minutes* - */ -#define ADM1026_DATA_INTERVAL (1 * HZ) -#define ADM1026_CONFIG_INTERVAL (5 * 60 * HZ) - -/* We allow for multiple chips in a single system. - * - * For each registered ADM1026, we need to keep state information - * at client->data. The adm1026_data structure is dynamically - * allocated, when a new client structure is allocated. */ - -struct adm1026_data { - struct i2c_client client; - int sysctl_id; - - struct semaphore update_lock; - int valid; /* !=0 if following fields are valid */ - unsigned long last_reading; /* In jiffies */ - unsigned long last_config; /* In jiffies */ - - u8 in[17]; /* Register value */ - u8 in_max[17]; /* Register value */ - u8 in_min[17]; /* Register value */ - s8 temp[3]; /* Register value */ - s8 temp_min[3]; /* Register value */ - s8 temp_max[3]; /* Register value */ - s8 temp_tmin[3]; /* Register value */ - s8 temp_therm[3]; /* Register value */ - s8 temp_offset[3]; /* Register value */ - u8 fan[8]; /* Register value */ - u8 fan_min[8]; /* Register value */ - u8 fan_div[8]; /* Decoded value */ - u8 pwm; /* Register value */ - u8 analog_out; /* Register value */ - int vid; /* Decoded value */ - u8 vrm; /* VRM version */ - long alarms; /* Register encoding, combined */ - long alarm_mask; /* Register encoding, combined */ - long gpio; /* Register encoding, combined */ - long gpio_mask; /* Register encoding, combined */ - u8 gpio_config[17]; /* Decoded value */ - u8 config1; /* Register value */ - u8 config2; /* Register value */ - u8 config3; /* Register value */ -}; - -static int adm1026_attach_adapter(struct i2c_adapter *adapter); -static int adm1026_detect(struct i2c_adapter *adapter, int address, - unsigned short flags, int kind); -static int adm1026_detach_client(struct i2c_client *client); - -static int adm1026_read_value(struct i2c_client *client, u8 register); -static int adm1026_write_value(struct i2c_client *client, u8 register, int value); -static void adm1026_print_gpio(struct i2c_client *client); -static void adm1026_fixup_gpio(struct i2c_client *client); -static void adm1026_update_client(struct i2c_client *client); -static void adm1026_init_client(struct i2c_client *client); - - -static void adm1026_in(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results); -static void adm1026_in16(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results); -static void adm1026_fan(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void adm1026_fixup_fan_min(struct i2c_client *client, - int fan, int old_div); -static void adm1026_fan_div(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void adm1026_temp(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void adm1026_temp_offset(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void adm1026_temp_tmin(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void adm1026_temp_therm(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void adm1026_vid(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void adm1026_vrm(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void adm1026_alarms(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void adm1026_alarm_mask(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void adm1026_gpio(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void adm1026_gpio_mask(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void adm1026_pwm(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void adm1026_analog_out(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void adm1026_afc(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); - -static struct i2c_driver adm1026_driver = { - .name = "ADM1026 compatible sensor driver", - .id = I2C_DRIVERID_ADM1026, - .flags = I2C_DF_NOTIFY, - .attach_adapter = &adm1026_attach_adapter, - .detach_client = &adm1026_detach_client, -}; - -/* Unique ID assigned to each ADM1026 detected */ -static int adm1026_id = 0; - -/* -- SENSORS SYSCTL START -- */ -#define ADM1026_SYSCTL_FAN0 1000 -#define ADM1026_SYSCTL_FAN1 1001 -#define ADM1026_SYSCTL_FAN2 1002 -#define ADM1026_SYSCTL_FAN3 1003 -#define ADM1026_SYSCTL_FAN4 1004 -#define ADM1026_SYSCTL_FAN5 1005 -#define ADM1026_SYSCTL_FAN6 1006 -#define ADM1026_SYSCTL_FAN7 1007 -#define ADM1026_SYSCTL_FAN_DIV 1008 -#define ADM1026_SYSCTL_GPIO 1009 -#define ADM1026_SYSCTL_GPIO_MASK 1010 -#define ADM1026_SYSCTL_ALARMS 1011 -#define ADM1026_SYSCTL_ALARM_MASK 1012 -#define ADM1026_SYSCTL_IN0 1013 -#define ADM1026_SYSCTL_IN1 1014 -#define ADM1026_SYSCTL_IN2 1015 -#define ADM1026_SYSCTL_IN3 1016 -#define ADM1026_SYSCTL_IN4 1017 -#define ADM1026_SYSCTL_IN5 1018 -#define ADM1026_SYSCTL_IN6 1019 -#define ADM1026_SYSCTL_IN7 1020 -#define ADM1026_SYSCTL_IN8 1021 -#define ADM1026_SYSCTL_IN9 1022 -#define ADM1026_SYSCTL_IN10 1023 -#define ADM1026_SYSCTL_IN11 1024 -#define ADM1026_SYSCTL_IN12 1025 -#define ADM1026_SYSCTL_IN13 1026 -#define ADM1026_SYSCTL_IN14 1027 -#define ADM1026_SYSCTL_IN15 1028 -#define ADM1026_SYSCTL_IN16 1029 -#define ADM1026_SYSCTL_PWM 1030 -#define ADM1026_SYSCTL_ANALOG_OUT 1031 -#define ADM1026_SYSCTL_AFC 1032 -#define ADM1026_SYSCTL_TEMP1 1033 -#define ADM1026_SYSCTL_TEMP2 1034 -#define ADM1026_SYSCTL_TEMP3 1035 -#define ADM1026_SYSCTL_TEMP_OFFSET1 1036 -#define ADM1026_SYSCTL_TEMP_OFFSET2 1037 -#define ADM1026_SYSCTL_TEMP_OFFSET3 1038 -#define ADM1026_SYSCTL_TEMP_THERM1 1039 -#define ADM1026_SYSCTL_TEMP_THERM2 1040 -#define ADM1026_SYSCTL_TEMP_THERM3 1041 -#define ADM1026_SYSCTL_TEMP_TMIN1 1042 -#define ADM1026_SYSCTL_TEMP_TMIN2 1043 -#define ADM1026_SYSCTL_TEMP_TMIN3 1044 -#define ADM1026_SYSCTL_VID 1045 -#define ADM1026_SYSCTL_VRM 1046 - -#define ADM1026_ALARM_TEMP2 (1L << 0) -#define ADM1026_ALARM_TEMP3 (1L << 1) -#define ADM1026_ALARM_IN9 (1L << 1) -#define ADM1026_ALARM_IN11 (1L << 2) -#define ADM1026_ALARM_IN12 (1L << 3) -#define ADM1026_ALARM_IN13 (1L << 4) -#define ADM1026_ALARM_IN14 (1L << 5) -#define ADM1026_ALARM_IN15 (1L << 6) -#define ADM1026_ALARM_IN16 (1L << 7) -#define ADM1026_ALARM_IN0 (1L << 8) -#define ADM1026_ALARM_IN1 (1L << 9) -#define ADM1026_ALARM_IN2 (1L << 10) -#define ADM1026_ALARM_IN3 (1L << 11) -#define ADM1026_ALARM_IN4 (1L << 12) -#define ADM1026_ALARM_IN5 (1L << 13) -#define ADM1026_ALARM_IN6 (1L << 14) -#define ADM1026_ALARM_IN7 (1L << 15) -#define ADM1026_ALARM_FAN0 (1L << 16) -#define ADM1026_ALARM_FAN1 (1L << 17) -#define ADM1026_ALARM_FAN2 (1L << 18) -#define ADM1026_ALARM_FAN3 (1L << 19) -#define ADM1026_ALARM_FAN4 (1L << 20) -#define ADM1026_ALARM_FAN5 (1L << 21) -#define ADM1026_ALARM_FAN6 (1L << 22) -#define ADM1026_ALARM_FAN7 (1L << 23) -#define ADM1026_ALARM_TEMP1 (1L << 24) -#define ADM1026_ALARM_IN10 (1L << 25) -#define ADM1026_ALARM_IN8 (1L << 26) -#define ADM1026_ALARM_THERM (1L << 27) -#define ADM1026_ALARM_AFC_FAN (1L << 28) -#define ADM1026_ALARM_CI (1L << 30) -/* -- SENSORS SYSCTL END -- */ - -/* The /proc/sys entries */ -/* These files are created for each detected ADM1026. This is just a template; - * The actual list is built from this and additional per-chip - * custom lists below. Note the XXX_LEN macros. These must be - * compile time constants because they will be used to allocate - * space for the final template passed to i2c_register_entry. - * We depend on the ability of GCC to evaluate expressions at - * compile time to turn these expressions into compile time - * constants, but this can generate a warning. - */ -static ctl_table adm1026_common[] = { - {ADM1026_SYSCTL_IN0, "in0", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &adm1026_in}, - {ADM1026_SYSCTL_IN1, "in1", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &adm1026_in}, - {ADM1026_SYSCTL_IN2, "in2", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &adm1026_in}, - {ADM1026_SYSCTL_IN3, "in3", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &adm1026_in}, - {ADM1026_SYSCTL_IN4, "in4", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &adm1026_in}, - {ADM1026_SYSCTL_IN5, "in5", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &adm1026_in}, - {ADM1026_SYSCTL_IN6, "in6", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &adm1026_in}, - {ADM1026_SYSCTL_IN7, "in7", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &adm1026_in}, - {ADM1026_SYSCTL_IN8, "in8", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &adm1026_in}, - {ADM1026_SYSCTL_IN9, "in9", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &adm1026_in}, - {ADM1026_SYSCTL_IN10, "in10", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &adm1026_in}, - {ADM1026_SYSCTL_IN11, "in11", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &adm1026_in}, - {ADM1026_SYSCTL_IN12, "in12", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &adm1026_in}, - {ADM1026_SYSCTL_IN13, "in13", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &adm1026_in}, - {ADM1026_SYSCTL_IN14, "in14", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &adm1026_in}, - {ADM1026_SYSCTL_IN15, "in15", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &adm1026_in}, - {ADM1026_SYSCTL_IN16, "in16", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &adm1026_in16}, - - {ADM1026_SYSCTL_FAN0, "fan0", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &adm1026_fan}, - {ADM1026_SYSCTL_FAN1, "fan1", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &adm1026_fan}, - {ADM1026_SYSCTL_FAN2, "fan2", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &adm1026_fan}, - {ADM1026_SYSCTL_FAN3, "fan3", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &adm1026_fan}, - {ADM1026_SYSCTL_FAN4, "fan4", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &adm1026_fan}, - {ADM1026_SYSCTL_FAN5, "fan5", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &adm1026_fan}, - {ADM1026_SYSCTL_FAN6, "fan6", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &adm1026_fan}, - {ADM1026_SYSCTL_FAN7, "fan7", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &adm1026_fan}, - {ADM1026_SYSCTL_FAN_DIV, "fan_div", NULL, 0, 0644, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &adm1026_fan_div}, - - {ADM1026_SYSCTL_TEMP1, "temp1", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &adm1026_temp}, - {ADM1026_SYSCTL_TEMP2, "temp2", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &adm1026_temp}, - {ADM1026_SYSCTL_TEMP3, "temp3", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &adm1026_temp}, - {ADM1026_SYSCTL_TEMP_OFFSET1, "temp1_offset", NULL, 0, 0644, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &adm1026_temp_offset}, - {ADM1026_SYSCTL_TEMP_OFFSET2, "temp2_offset", NULL, 0, 0644, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &adm1026_temp_offset}, - {ADM1026_SYSCTL_TEMP_OFFSET3, "temp3_offset", NULL, 0, 0644, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &adm1026_temp_offset}, - {ADM1026_SYSCTL_TEMP_TMIN1, "temp1_tmin", NULL, 0, 0644, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &adm1026_temp_tmin}, - {ADM1026_SYSCTL_TEMP_TMIN2, "temp2_tmin", NULL, 0, 0644, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &adm1026_temp_tmin}, - {ADM1026_SYSCTL_TEMP_TMIN3, "temp3_tmin", NULL, 0, 0644, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &adm1026_temp_tmin}, - {ADM1026_SYSCTL_TEMP_THERM1, "temp1_therm", NULL, 0, 0644, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &adm1026_temp_therm}, - {ADM1026_SYSCTL_TEMP_THERM2, "temp2_therm", NULL, 0, 0644, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &adm1026_temp_therm}, - {ADM1026_SYSCTL_TEMP_THERM3, "temp3_therm", NULL, 0, 0644, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &adm1026_temp_therm}, - - {ADM1026_SYSCTL_VID, "vid", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &adm1026_vid}, - {ADM1026_SYSCTL_VRM, "vrm", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &adm1026_vrm}, - - {ADM1026_SYSCTL_ALARMS, "alarms", NULL, 0, 0444, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &adm1026_alarms}, - {ADM1026_SYSCTL_ALARM_MASK, "alarm_mask", NULL, 0, 0644, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &adm1026_alarm_mask}, - - {ADM1026_SYSCTL_GPIO, "gpio", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &adm1026_gpio}, - {ADM1026_SYSCTL_GPIO_MASK, "gpio_mask", NULL, 0, 0644, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &adm1026_gpio_mask}, - - {ADM1026_SYSCTL_PWM, "pwm", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &adm1026_pwm}, - {ADM1026_SYSCTL_ANALOG_OUT, "analog_out", NULL, 0, 0644, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &adm1026_analog_out}, - {ADM1026_SYSCTL_AFC, "afc", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &adm1026_afc}, - - {0} -}; -#define CTLTBL_COMMON (sizeof(adm1026_common)/sizeof(adm1026_common[0])) - -#define MAX2(a,b) ((a)>(b)?(a):(b)) -#define MAX3(a,b,c) ((a)>(b)?MAX2((a),(c)):MAX2((b),(c))) -#define MAX4(a,b,c,d) ((a)>(b)?MAX3((a),(c),(d)):MAX3((b),(c),(d))) - -#define CTLTBL_MAX (CTLTBL_COMMON) - -/* This function is called when: - * the module is loaded - * a new adapter is loaded - */ -static int adm1026_attach_adapter(struct i2c_adapter *adapter) -{ - return i2c_detect(adapter, &addr_data, adm1026_detect); -} - -/* This function is called by i2c_detect */ -static int adm1026_detect(struct i2c_adapter *adapter, int address, - unsigned short flags, int kind) -{ - int i; - int company, verstep ; - struct i2c_client *new_client; - struct adm1026_data *data; - int err = 0; - const char *type_name = ""; - struct ctl_table template[CTLTBL_MAX] ; - struct ctl_table * template_next = template ; - - if (i2c_is_isa_adapter(adapter)) { - /* This chip has no ISA interface */ - goto ERROR0 ; - } - - if (!i2c_check_functionality(adapter, - I2C_FUNC_SMBUS_BYTE_DATA)) { - /* We need to be able to do byte I/O */ - goto ERROR0 ; - } - - /* OK. For now, we presume we have a valid client. We now create the - client structure, even though we cannot fill it completely yet. - But it allows us to access adm1026_{read,write}_value. */ - - if (!(data = kmalloc(sizeof(struct adm1026_data), GFP_KERNEL))) { - err = -ENOMEM; - goto ERROR0; - } - - new_client = &data->client; - new_client->addr = address; - new_client->data = data; - new_client->adapter = adapter; - new_client->driver = &adm1026_driver; - new_client->flags = 0; - - /* Now, we do the remaining detection. */ - - company = adm1026_read_value(new_client, ADM1026_REG_COMPANY); - verstep = adm1026_read_value(new_client, ADM1026_REG_VERSTEP); - -#ifdef DEBUG - printk("adm1026: Detecting device at %d,0x%02x with" - " COMPANY: 0x%02x and VERSTEP: 0x%02x\n", - i2c_adapter_id(new_client->adapter), new_client->addr, - company, verstep - ); -#endif - - /* If auto-detecting, Determine the chip type. */ - if (kind <= 0) { -#ifdef DEBUG - printk("adm1026: Autodetecting device at %d,0x%02x ...\n", - i2c_adapter_id(adapter), address ); -#endif - if( company == ADM1026_COMPANY_ANALOG_DEV - && verstep == ADM1026_VERSTEP_ADM1026 ) { - kind = adm1026 ; - } else if( company == ADM1026_COMPANY_ANALOG_DEV - && (verstep & 0xf0) == ADM1026_VERSTEP_GENERIC ) { - printk("adm1026: Unrecognized stepping 0x%02x" - " Defaulting to ADM1026.\n", verstep ); - kind = adm1026 ; - } else if( (verstep & 0xf0) == ADM1026_VERSTEP_GENERIC ) { - printk("adm1026: Found version/stepping 0x%02x" - " Assuming generic ADM1026.\n", verstep ); - kind = any_chip ; - } else { -#ifdef DEBUG - printk("adm1026: Autodetection failed\n"); -#endif - /* Not an ADM1026 ... */ - if( kind == 0 ) { /* User used force=x,y */ - printk("adm1026: Generic ADM1026 Version 6 not" - " found at %d,0x%02x. Try force_adm1026.\n", - i2c_adapter_id(adapter), address ); - } - goto ERROR1; - } - } - - /* Fill in the chip specific driver values */ - switch (kind) { - case any_chip : - type_name = "adm1026"; - strcpy(new_client->name, "Generic ADM1026"); - template_next = template ; /* None used */ - break ; - case adm1026 : - type_name = "adm1026"; - strcpy(new_client->name, "Analog Devices ADM1026"); - template_next = template ; - break ; -#if 0 - /* Example of another adm1026 "compatible" device */ - case adx1000 : - type_name = "adx1000"; - strcpy(new_client->name, "Compatible ADX1000"); - memcpy( template, adx_specific, sizeof(adx_specific) ); - template_next = template + CTLTBL_ADX1000 ; - break ; -#endif - default : - printk("adm1026: Internal error, invalid kind (%d)!\n", kind); - err = -EFAULT ; - goto ERROR1; - } - - /* Fill in the remaining client fields */ - new_client->id = adm1026_id++; - printk("adm1026(%d): Assigning ID %d to %s at %d,0x%02x\n", - new_client->id, new_client->id, new_client->name, - i2c_adapter_id(new_client->adapter), - new_client->addr - ); - - /* Housekeeping values */ - data->valid = 0; - - /* Set the VRM version */ - data->vrm = ADM1026_INIT_VRM ; - data->vid = ADM1026_INIT_VID ; - - init_MUTEX(&data->update_lock); - - /* Initialize the ADM1026 chip */ - adm1026_init_client(new_client); - - /* Tell the I2C layer a new client has arrived */ - if ((err = i2c_attach_client(new_client))) - goto ERROR1; - - /* Finish out the template */ - memcpy(template_next, adm1026_common, sizeof(adm1026_common)); - - /* Register a new directory entry with module sensors */ - if ((i = i2c_register_entry(new_client, - type_name, - template, - THIS_MODULE)) < 0) { - err = i; - goto ERROR2; - } - data->sysctl_id = i; - - return 0; - - /* Error out and cleanup code */ - ERROR2: - i2c_detach_client(new_client); - ERROR1: - kfree(data); - ERROR0: - return err; -} - -static int adm1026_detach_client(struct i2c_client *client) -{ - int err; - int id ; - - id = client->id; - i2c_deregister_entry(((struct adm1026_data *)(client->data))->sysctl_id); - - if ((err = i2c_detach_client(client))) { - printk("adm1026(%d): Client deregistration failed," - " client not detached.\n", id ); - return err; - } - - kfree(client->data); - - return 0; -} - -static int adm1026_read_value(struct i2c_client *client, u8 reg) -{ - int res; - - if( reg < 0x80 ) { - /* "RAM" locations */ - res = i2c_smbus_read_byte_data(client, reg) & 0xff ; - } else { - /* EEPROM, do nothing */ - res = 0 ; - } - - return res ; -} - -static int adm1026_write_value(struct i2c_client *client, u8 reg, int value) -{ - int res ; - - if( reg < 0x80 ) { - /* "RAM" locations */ - res = i2c_smbus_write_byte_data(client, reg, value); - } else { - /* EEPROM, do nothing */ - res = 0 ; - } - - return res ; -} - -/* Called when we have found a new ADM1026. */ -static void adm1026_init_client(struct i2c_client *client) -{ - int value ; - int i; - struct adm1026_data *data = client->data; - -#ifdef DEBUG - printk("adm1026(%d): Initializing device\n", client->id); -#endif - - /* Read chip config */ - data->config1 = adm1026_read_value(client, ADM1026_REG_CONFIG1); - data->config2 = adm1026_read_value(client, ADM1026_REG_CONFIG2); - data->config3 = adm1026_read_value(client, ADM1026_REG_CONFIG3); - - /* Inform user of chip config */ -#ifdef DEBUG - printk("adm1026(%d): ADM1026_REG_CONFIG1 is: 0x%02x\n", - client->id, data->config1 ); -#endif - if( (data->config1 & CFG1_MONITOR) == 0 ) { - printk("adm1026(%d): Monitoring not currently enabled.\n", - client->id ); - } - if( data->config1 & CFG1_INT_ENABLE ) { - printk("adm1026(%d): SMBALERT interrupts are enabled.\n", - client->id ); - } - if( data->config1 & CFG1_AIN8_9 ) { - printk("adm1026(%d): in8 and in9 enabled. temp3 disabled.\n", - client->id ); - } else { - printk("adm1026(%d): temp3 enabled. in8 and in9 disabled.\n", - client->id ); - } - if( data->config1 & CFG1_THERM_HOT ) { - printk("adm1026(%d): Automatic THERM, PWM, and temp limits enabled.\n", - client->id ); - } - - if( data->config3 & CFG3_GPIO16_ENABLE ) { - printk("adm1026(%d): GPIO16 enabled. THERM pin disabled.\n", - client->id ); - } else { - printk("adm1026(%d): THERM pin enabled. GPIO16 disabled.\n", - client->id ); - } - if( data->config3 & CFG3_VREF_250 ) { - printk("adm1026(%d): Vref is 2.50 Volts.\n", client->id ); - } else { - printk("adm1026(%d): Vref is 1.82 Volts.\n", client->id ); - } - - /* Read and pick apart the existing GPIO configuration */ - value = 0 ; - for( i = 0 ; i <= 15 ; ++i ) { - if( (i & 0x03) == 0 ) { - value = adm1026_read_value(client, - ADM1026_REG_GPIO_CFG_0_3 + i/4 ); - } - data->gpio_config[i] = value & 0x03 ; - value >>= 2 ; - } - data->gpio_config[16] = (data->config3 >> 6) & 0x03 ; - - /* ... and then print it */ - adm1026_print_gpio(client); - - /* If the user asks us to reprogram the GPIO config, then - * do it now. But only if this is the first ADM1026. - */ - if( client->id == 0 - && (gpio_input[0] != -1 || gpio_output[0] != -1 - || gpio_inverted[0] != -1 || gpio_normal[0] != -1 - || gpio_fan[0] != -1 ) ) { - adm1026_fixup_gpio(client); - } - - /* WE INTENTIONALLY make no changes to the limits, - * offsets, pwms and fans. If they were - * configured, we don't want to mess with them. - * If they weren't, the default is generally safe - * and will suffice until 'sensors -s' can be run. - */ - - /* Start monitoring */ - value = adm1026_read_value(client, ADM1026_REG_CONFIG1); - - /* Set MONITOR, clear interrupt acknowledge and s/w reset */ - value = (value | CFG1_MONITOR) & (~CFG1_INT_CLEAR & ~CFG1_RESET) ; -#ifdef DEBUG - printk("adm1026(%d): Setting CONFIG to: 0x%02x\n", client->id, value ); -#endif - data->config1 = value ; - adm1026_write_value(client, ADM1026_REG_CONFIG1, value); - -} - -static void adm1026_print_gpio(struct i2c_client *client) -{ - struct adm1026_data *data = client->data; - int i ; - - printk("adm1026(%d): GPIO config is:\nadm1026(%d):", - client->id, client->id ); - for( i = 0 ; i <= 7 ; ++i ) { - if( data->config2 & (1 << i) ) { - printk( " %sGP%s%d", - data->gpio_config[i] & 0x02 ? "" : "!", - data->gpio_config[i] & 0x01 ? "OUT" : "IN", - i ); - } else { - printk( " FAN%d", i ); - } - } - printk( "\nadm1026(%d):", client->id ); - for( i = 8 ; i <= 15 ; ++i ) { - printk( " %sGP%s%d", - data->gpio_config[i] & 0x02 ? "" : "!", - data->gpio_config[i] & 0x01 ? "OUT" : "IN", - i ); - } - if( data->config3 & CFG3_GPIO16_ENABLE ) { - printk( " %sGP%s16\n", - data->gpio_config[16] & 0x02 ? "" : "!", - data->gpio_config[16] & 0x01 ? "OUT" : "IN" ); - } else { - /* GPIO16 is THERM */ - printk( " THERM\n" ); - } -} - -static void adm1026_fixup_gpio(struct i2c_client *client) -{ - struct adm1026_data *data = client->data; - int i ; - int value ; - - /* Make the changes requested. */ - /* We may need to unlock/stop monitoring or soft-reset the - * chip before we can make changes. This hasn't been - * tested much. FIXME - */ - - /* Make outputs */ - for( i = 0 ; i <= 16 ; ++i ) { - if( gpio_output[i] >= 0 && gpio_output[i] <= 16 ) { - data->gpio_config[gpio_output[i]] |= 0x01 ; - } - /* if GPIO0-7 is output, it isn't a FAN tach */ - if( gpio_output[i] >= 0 && gpio_output[i] <= 7 ) { - data->config2 |= 1 << gpio_output[i] ; - } - } - - /* Input overrides output */ - for( i = 0 ; i <= 16 ; ++i ) { - if( gpio_input[i] >= 0 && gpio_input[i] <= 16 ) { - data->gpio_config[gpio_input[i]] &= ~ 0x01 ; - } - /* if GPIO0-7 is input, it isn't a FAN tach */ - if( gpio_input[i] >= 0 && gpio_input[i] <= 7 ) { - data->config2 |= 1 << gpio_input[i] ; - } - } - - /* Inverted */ - for( i = 0 ; i <= 16 ; ++i ) { - if( gpio_inverted[i] >= 0 && gpio_inverted[i] <= 16 ) { - data->gpio_config[gpio_inverted[i]] &= ~ 0x02 ; - } - } - - /* Normal overrides inverted */ - for( i = 0 ; i <= 16 ; ++i ) { - if( gpio_normal[i] >= 0 && gpio_normal[i] <= 16 ) { - data->gpio_config[gpio_normal[i]] |= 0x02 ; - } - } - - /* Fan overrides input and output */ - for( i = 0 ; i <= 7 ; ++i ) { - if( gpio_fan[i] >= 0 && gpio_fan[i] <= 7 ) { - data->config2 &= ~( 1 << gpio_fan[i] ); - } - } - - /* Write new configs to registers */ - adm1026_write_value(client, ADM1026_REG_CONFIG2, data->config2); - data->config3 = (data->config3 & 0x3f) - | ((data->gpio_config[16] & 0x03) << 6) ; - adm1026_write_value(client, ADM1026_REG_CONFIG3, data->config3); - for( i = 15, value = 0 ; i >= 0 ; --i ) { - value <<= 2 ; - value |= data->gpio_config[i] & 0x03 ; - if( (i & 0x03) == 0 ) { - adm1026_write_value(client, - ADM1026_REG_GPIO_CFG_0_3 + i/4, - value ); - value = 0 ; - } - } - - /* Print the new config */ - adm1026_print_gpio(client); -} - -static void adm1026_update_client(struct i2c_client *client) -{ - struct adm1026_data *data = client->data; - int i; - long value, alarms, gpio ; - - down(&data->update_lock); - - if (!data->valid - || (jiffies - data->last_reading > ADM1026_DATA_INTERVAL )) { - /* Things that change quickly */ - -#ifdef DEBUG - printk("adm1026(%d): Reading sensor values\n", client->id); -#endif - for (i = 0 ; i <= 16 ; ++i) { - data->in[i] = - adm1026_read_value(client, ADM1026_REG_IN(i)); - } - - for (i = 0 ; i <= 7 ; ++i) { - data->fan[i] = - adm1026_read_value(client, ADM1026_REG_FAN(i)); - } - - for (i = 0 ; i <= 2 ; ++i) { - /* NOTE: temp[] is s8 and we assume 2's complement - * "conversion" in the assignment */ - data->temp[i] = - adm1026_read_value(client, ADM1026_REG_TEMP(i)); - } - - data->pwm = adm1026_read_value(client, ADM1026_REG_PWM); - data->analog_out = adm1026_read_value(client, ADM1026_REG_DAC); - - /* GPIO16 is MSbit of alarms, move it to gpio */ - alarms = adm1026_read_value(client, ADM1026_REG_STATUS4); - gpio = alarms & 0x80 ? 0x0100 : 0 ; /* GPIO16 */ - alarms &= 0x7f ; - alarms <<= 8 ; - alarms |= adm1026_read_value(client, ADM1026_REG_STATUS3); - alarms <<= 8 ; - alarms |= adm1026_read_value(client, ADM1026_REG_STATUS2); - alarms <<= 8 ; - alarms |= adm1026_read_value(client, ADM1026_REG_STATUS1); - data->alarms = alarms ; - - /* Read the GPIO values */ - gpio |= adm1026_read_value(client, ADM1026_REG_GPIO_STATUS_8_15); - gpio <<= 8 ; - gpio |= adm1026_read_value(client, ADM1026_REG_GPIO_STATUS_0_7); - data->gpio = gpio ; - - data->last_reading = jiffies ; - }; /* last_reading */ - - if (!data->valid - || (jiffies - data->last_config > ADM1026_CONFIG_INTERVAL) ) { - /* Things that don't change often */ - -#ifdef DEBUG - printk("adm1026(%d): Reading config values\n", client->id); -#endif - for (i = 0 ; i <= 16 ; ++i) { - data->in_min[i] = - adm1026_read_value(client, ADM1026_REG_IN_MIN(i)); - data->in_max[i] = - adm1026_read_value(client, ADM1026_REG_IN_MAX(i)); - } - - value = adm1026_read_value(client, ADM1026_REG_FAN_DIV_0_3) - | (adm1026_read_value(client, ADM1026_REG_FAN_DIV_4_7) << 8); - for (i = 0 ; i <= 7 ; ++i) { - data->fan_min[i] = - adm1026_read_value(client, ADM1026_REG_FAN_MIN(i)); - data->fan_div[i] = DIV_FROM_REG(value & 0x03); - value >>= 2 ; - } - - for (i = 0; i <= 2; ++i) { - /* NOTE: temp_xxx[] are s8 and we assume 2's complement - * "conversion" in the assignment */ - data->temp_min[i] = - adm1026_read_value(client, ADM1026_REG_TEMP_MIN(i)); - data->temp_max[i] = - adm1026_read_value(client, ADM1026_REG_TEMP_MAX(i)); - data->temp_tmin[i] = - adm1026_read_value(client, ADM1026_REG_TEMP_TMIN(i)); - data->temp_therm[i] = - adm1026_read_value(client, ADM1026_REG_TEMP_THERM(i)); - data->temp_offset[i] = - adm1026_read_value(client, ADM1026_REG_TEMP_OFFSET(i)); - } - - /* Read the STATUS/alarm masks */ - alarms = adm1026_read_value(client, ADM1026_REG_MASK4); - gpio = alarms & 0x80 ? 0x0100 : 0 ; /* GPIO16 */ - alarms = (alarms & 0x7f) << 8 ; - alarms |= adm1026_read_value(client, ADM1026_REG_MASK3); - alarms <<= 8 ; - alarms |= adm1026_read_value(client, ADM1026_REG_MASK2); - alarms <<= 8 ; - alarms |= adm1026_read_value(client, ADM1026_REG_MASK1); - data->alarm_mask = alarms ; - - /* Read the GPIO values */ - gpio |= adm1026_read_value(client, ADM1026_REG_GPIO_MASK_8_15); - gpio <<= 8 ; - gpio |= adm1026_read_value(client, ADM1026_REG_GPIO_MASK_0_7); - data->gpio_mask = gpio ; - - /* Read the GPIO config */ - data->config2 = adm1026_read_value(client, ADM1026_REG_CONFIG2); - data->config3 = adm1026_read_value(client, ADM1026_REG_CONFIG3); - data->gpio_config[16] = (data->config3 >> 6) & 0x03 ; - - value = 0 ; - for( i = 0 ; i <= 15 ; ++i ) { - if( (i & 0x03) == 0 ) { - value = adm1026_read_value(client, - ADM1026_REG_GPIO_CFG_0_3 + i/4 ); - } - data->gpio_config[i] = value & 0x03 ; - value >>= 2 ; - } - - data->last_config = jiffies; - }; /* last_config */ - - /* We don't know where or even _if_ the VID might be on the GPIO - * pins. But the datasheet gives an example config showing - * GPIO11-15 being used to monitor VID0-4, so we go with that - * but make the vid WRITEABLE so if it's wrong, the user can - * set it in /etc/sensors.conf perhaps using an expression or - * 0 to trigger a re-read from the GPIO pins. - */ - if( data->vid == ADM1026_INIT_VID ) { - /* Hasn't been set yet, make a bold assumption */ - printk("adm1026(%d): Setting VID from GPIO11-15.\n", - client->id ); - data->vid = (data->gpio >> 11) & 0x1f ; - } - - data->valid = 1; - - up(&data->update_lock); -} - - -/* The following functions are the call-back functions of the /proc/sys and - sysctl files. The appropriate function is referenced in the ctl_table - extra1 field. - - Each function must return the magnitude (power of 10 to divide the - data with) if it is called with operation set to SENSORS_PROC_REAL_INFO. - It must put a maximum of *nrels elements in results reflecting the - data of this file, and set *nrels to the number it actually put in - it, if operation is SENSORS_PROC_REAL_READ. Finally, it must get - up to *nrels elements from results and write them to the chip, if - operations is SENSORS_PROC_REAL_WRITE. - */ -void adm1026_in(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct adm1026_data *data = client->data; - int nr = ctl_name - ADM1026_SYSCTL_IN0; - - /* We handle in0 - in15 here. in16 (-12V) is handled below */ - if (nr < 0 || nr > 15) - return ; /* ERROR */ - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 3; /* 1.000 */ - else if (operation == SENSORS_PROC_REAL_READ) { - adm1026_update_client(client); - results[0] = INS_FROM_REG(nr,data->in_min[nr]); - results[1] = INS_FROM_REG(nr,data->in_max[nr]); - results[2] = INS_FROM_REG(nr,data->in[nr]); - *nrels_mag = 3; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - down(&data->update_lock); - if (*nrels_mag > 1) { - data->in_max[nr] = INS_TO_REG(nr,results[1]); - adm1026_write_value(client, ADM1026_REG_IN_MAX(nr), - data->in_max[nr]); - } - if (*nrels_mag > 0) { - data->in_min[nr] = INS_TO_REG(nr,results[0]); - adm1026_write_value(client, ADM1026_REG_IN_MIN(nr), - data->in_min[nr]); - } - up(&data->update_lock); - } -} - -void adm1026_in16(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct adm1026_data *data = client->data; - int nr = ctl_name - ADM1026_SYSCTL_IN0; - - /* We handle in16 (-12V) here */ - if (nr != 16) - return ; /* ERROR */ - - /* Apply offset and swap min/max so that min is 90% of - * target and max is 110% of target. - */ - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 3; /* 1.000 */ - else if (operation == SENSORS_PROC_REAL_READ) { - adm1026_update_client(client); - results[0] = INS_FROM_REG(nr,data->in_max[nr])-NEG12_OFFSET ; - results[1] = INS_FROM_REG(nr,data->in_min[nr])-NEG12_OFFSET ; - results[2] = INS_FROM_REG(nr,data->in[nr])-NEG12_OFFSET ; - *nrels_mag = 3; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - down(&data->update_lock); - if (*nrels_mag > 1) { - data->in_min[nr] = INS_TO_REG(nr,results[1]+NEG12_OFFSET); - adm1026_write_value(client, ADM1026_REG_IN_MIN(nr), - data->in_min[nr]); - } - if (*nrels_mag > 0) { - data->in_max[nr] = INS_TO_REG(nr,results[0]+NEG12_OFFSET); - adm1026_write_value(client, ADM1026_REG_IN_MAX(nr), - data->in_max[nr]); - } - up(&data->update_lock); - } -} - -void adm1026_fan(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct adm1026_data *data = client->data; - int nr = ctl_name - ADM1026_SYSCTL_FAN0 ; - - if (nr < 0 || nr > 7) - return ; /* ERROR */ - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - adm1026_update_client(client); - results[0] = FAN_FROM_REG(data->fan_min[nr], data->fan_div[nr]); - results[1] = FAN_FROM_REG(data->fan[nr], data->fan_div[nr]); - *nrels_mag = 2; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - down(&data->update_lock); - if (*nrels_mag > 0) { - data->fan_min[nr] = FAN_TO_REG(results[0], - data->fan_div[nr]); - adm1026_write_value(client, ADM1026_REG_FAN_MIN(nr), - data->fan_min[nr]); - } - up(&data->update_lock); - } -} - -/* Adjust fan_min to account for new fan divisor */ -void adm1026_fixup_fan_min(struct i2c_client *client, int fan, int old_div) -{ - struct adm1026_data *data = client->data; - int new_div = data->fan_div[fan] ; - int new_min; - - /* 0 and 0xff are special. Don't adjust them */ - if( data->fan_min[fan] == 0 || data->fan_min[fan] == 0xff ) { - return ; - } - - new_min = data->fan_min[fan] * old_div / new_div ; - new_min = SENSORS_LIMIT(new_min, 1, 254); - data->fan_min[fan] = new_min ; - adm1026_write_value(client, ADM1026_REG_FAN_MIN(fan), new_min); -} - -void adm1026_fan_div(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct adm1026_data *data = client->data; - int i ; - int value, div, old ; - - if (ctl_name != ADM1026_SYSCTL_FAN_DIV) - return ; /* ERROR */ - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - adm1026_update_client(client); - for( i = 0 ; i <= 7 ; ++i ) { - results[i] = data->fan_div[i] ; - } - *nrels_mag = 8; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - down(&data->update_lock); - value = 0 ; - for( i = 7 ; i >= 0 ; --i ) { - value <<= 2 ; - if (*nrels_mag > i) { - old = data->fan_div[i] ; - div = DIV_TO_REG(results[i]) ; - data->fan_div[i] = DIV_FROM_REG(div) ; - if( data->fan_div[i] != old ) { - adm1026_fixup_fan_min(client,i,old); - } - } else { - div = DIV_TO_REG(data->fan_div[i]) ; - } - value |= div ; - } - adm1026_write_value(client, ADM1026_REG_FAN_DIV_0_3, - value & 0xff); - adm1026_write_value(client, ADM1026_REG_FAN_DIV_4_7, - (value >> 8) & 0xff); - up(&data->update_lock); - } -} - -void adm1026_temp(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct adm1026_data *data = client->data; - int nr = ctl_name - ADM1026_SYSCTL_TEMP1 ; - - if (nr < 0 || nr > 2) - return ; /* ERROR */ - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - adm1026_update_client(client); - results[0] = TEMP_FROM_REG(data->temp_min[nr]); - results[1] = TEMP_FROM_REG(data->temp_max[nr]); - results[2] = TEMP_FROM_REG(data->temp[nr]); - *nrels_mag = 3; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - down(&data->update_lock); - if (*nrels_mag > 1) { - data->temp_max[nr] = TEMP_TO_REG(results[1]); - adm1026_write_value(client, ADM1026_REG_TEMP_MAX(nr), - data->temp_max[nr]); - } - if (*nrels_mag > 0) { - data->temp_min[nr] = TEMP_TO_REG(results[0]); - adm1026_write_value(client, ADM1026_REG_TEMP_MIN(nr), - data->temp_min[nr]); - } - up(&data->update_lock); - } -} - -void adm1026_temp_offset(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct adm1026_data *data = client->data; - int nr = ctl_name - ADM1026_SYSCTL_TEMP_OFFSET1 ; - - if (nr < 0 || nr > 2) - return ; /* ERROR */ - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - adm1026_update_client(client); - results[0] = TEMP_FROM_REG(data->temp_offset[nr]); - *nrels_mag = 1; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - down(&data->update_lock); - if (*nrels_mag > 0) { - data->temp_offset[nr] = TEMP_TO_REG(results[0]); - adm1026_write_value(client, ADM1026_REG_TEMP_OFFSET(nr), - data->temp_offset[nr]); - } - up(&data->update_lock); - } -} - -void adm1026_temp_tmin(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct adm1026_data *data = client->data; - int nr = ctl_name - ADM1026_SYSCTL_TEMP_TMIN1 ; - - if (nr < 0 || nr > 2) - return ; /* ERROR */ - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - adm1026_update_client(client); - results[0] = TEMP_FROM_REG(data->temp_tmin[nr]); - *nrels_mag = 1; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - down(&data->update_lock); - if (*nrels_mag > 0) { - data->temp_tmin[nr] = TEMP_TO_REG(results[0]); - adm1026_write_value(client, ADM1026_REG_TEMP_TMIN(nr), - data->temp_tmin[nr]); - } - up(&data->update_lock); - } -} - -void adm1026_temp_therm(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct adm1026_data *data = client->data; - int nr = ctl_name - ADM1026_SYSCTL_TEMP_THERM1 ; - - if (nr < 0 || nr > 2) - return ; /* ERROR */ - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - adm1026_update_client(client); - results[0] = TEMP_FROM_REG(data->temp_therm[nr]); - *nrels_mag = 1; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - down(&data->update_lock); - if (*nrels_mag > 0) { - data->temp_therm[nr] = TEMP_TO_REG(results[0]); - adm1026_write_value(client, ADM1026_REG_TEMP_THERM(nr), - data->temp_therm[nr]); - } - up(&data->update_lock); - } -} - -void adm1026_pwm(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct adm1026_data *data = client->data; - - if (ctl_name != ADM1026_SYSCTL_PWM) - return ; /* ERROR */ - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - adm1026_update_client(client); - results[0] = PWM_FROM_REG(data->pwm); - results[1] = 1 ; /* Always enabled */ - *nrels_mag = 2; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - down(&data->update_lock); - /* PWM enable is read-only */ - if (*nrels_mag > 0) { - data->pwm = PWM_TO_REG(results[0]); - adm1026_write_value(client, ADM1026_REG_PWM, - data->pwm); - } - up(&data->update_lock); - } -} - -void adm1026_analog_out(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct adm1026_data *data = client->data; - - if (ctl_name != ADM1026_SYSCTL_ANALOG_OUT) - return ; /* ERROR */ - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; /* 0 - 255 */ - else if (operation == SENSORS_PROC_REAL_READ) { - adm1026_update_client(client); - results[0] = DAC_FROM_REG(data->analog_out); - *nrels_mag = 1; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - down(&data->update_lock); - if (*nrels_mag > 0) { - data->analog_out = DAC_TO_REG(results[0]); - adm1026_write_value(client, ADM1026_REG_DAC, - data->analog_out); - } - up(&data->update_lock); - } -} - -void adm1026_afc(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct adm1026_data *data = client->data; - - if (ctl_name != ADM1026_SYSCTL_AFC) - return ; /* ERROR */ - - /* PWM auto fan control, DAC auto fan control */ - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - adm1026_update_client(client); - results[0] = (data->config1 & CFG1_PWM_AFC) != 0 ; - results[1] = (data->config1 & CFG1_DAC_AFC) != 0 ; - *nrels_mag = 2; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - down(&data->update_lock); - if (*nrels_mag > 1) { - data->config1 = (data->config1 & ~CFG1_DAC_AFC) - | (results[1] ? CFG1_DAC_AFC : 0) ; - } - if (*nrels_mag > 0) { - data->config1 = (data->config1 & ~CFG1_PWM_AFC) - | (results[0] ? CFG1_PWM_AFC : 0) ; - adm1026_write_value(client, ADM1026_REG_CONFIG1, - data->config1); - } - up(&data->update_lock); - } -} - -void adm1026_vid(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct adm1026_data *data = client->data; - - if( ctl_name != ADM1026_SYSCTL_VID ) - return ; /* ERROR */ - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 3; - else if (operation == SENSORS_PROC_REAL_READ) { - adm1026_update_client(client); - results[0] = vid_from_reg((data->vid)&0x3f,data->vrm); - *nrels_mag = 1; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - down(&data->update_lock); - /* Hmmm... There isn't a VID_TO_REG mapping */ - if (*nrels_mag > 0) { - if( results[0] >= 0 ) { - data->vid = results[0] & 0x3f ; - } else { - data->vid = ADM1026_INIT_VID ; - } - } - up(&data->update_lock); - } - -} - -void adm1026_vrm(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct adm1026_data *data = client->data; - - if( ctl_name != ADM1026_SYSCTL_VRM ) - return ; /* ERROR */ - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 1; - else if (operation == SENSORS_PROC_REAL_READ) { - results[0] = data->vrm ; - *nrels_mag = 1; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag > 0) { - data->vrm = results[0] ; - } - } -} - -void adm1026_alarms(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct adm1026_data *data = client->data; - - if( ctl_name != ADM1026_SYSCTL_ALARMS ) - return ; /* ERROR */ - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - adm1026_update_client(client); - results[0] = data->alarms ; - *nrels_mag = 1; - } - /* FIXME: Perhaps we should implement a write function - * to clear an alarm? - */ -} - -void adm1026_alarm_mask(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results) -{ - struct adm1026_data *data = client->data; - unsigned long mask ; - - if( ctl_name != ADM1026_SYSCTL_ALARM_MASK ) - return ; /* ERROR */ - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - adm1026_update_client(client); - results[0] = data->alarm_mask ; - *nrels_mag = 1; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - down(&data->update_lock); - if (*nrels_mag > 0) { - data->alarm_mask = results[0] & 0x7fffffff ; - mask = data->alarm_mask - | (data->gpio_mask & 0x10000 ? 0x80000000 : 0) ; - adm1026_write_value(client, ADM1026_REG_MASK1, - mask & 0xff); - mask >>= 8 ; - adm1026_write_value(client, ADM1026_REG_MASK2, - mask & 0xff); - mask >>= 8 ; - adm1026_write_value(client, ADM1026_REG_MASK3, - mask & 0xff); - mask >>= 8 ; - adm1026_write_value(client, ADM1026_REG_MASK4, - mask & 0xff); - } - up(&data->update_lock); - } -} - -void adm1026_gpio(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct adm1026_data *data = client->data; - long gpio ; - - if( ctl_name != ADM1026_SYSCTL_GPIO ) - return ; /* ERROR */ - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - adm1026_update_client(client); - results[0] = data->gpio ; - *nrels_mag = 1; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - down(&data->update_lock); - if (*nrels_mag > 0) { - data->gpio = results[0] & 0x1ffff ; - gpio = data->gpio ; - adm1026_write_value(client, - ADM1026_REG_GPIO_STATUS_0_7, - gpio & 0xff ); - gpio >>= 8 ; - adm1026_write_value(client, - ADM1026_REG_GPIO_STATUS_8_15, - gpio & 0xff ); - gpio = ((gpio >> 1) & 0x80) - | (data->alarms >> 24 & 0x7f); - adm1026_write_value(client, - ADM1026_REG_STATUS4, - gpio & 0xff ); - } - up(&data->update_lock); - } -} - -void adm1026_gpio_mask(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results) -{ - struct adm1026_data *data = client->data; - long mask ; - - if( ctl_name != ADM1026_SYSCTL_GPIO_MASK ) - return ; /* ERROR */ - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - adm1026_update_client(client); - results[0] = data->gpio_mask ; - *nrels_mag = 1; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - down(&data->update_lock); - if (*nrels_mag > 0) { - data->gpio_mask = results[0] & 0x1ffff ; - mask = data->gpio_mask ; - adm1026_write_value(client, ADM1026_REG_GPIO_MASK_0_7, - mask & 0xff); - mask >>= 8 ; - adm1026_write_value(client, ADM1026_REG_GPIO_MASK_8_15, - mask & 0xff); - mask = ((mask >> 1) & 0x80) - | (data->alarm_mask >> 24 & 0x7f); - adm1026_write_value(client, ADM1026_REG_MASK1, - mask & 0xff); - } - up(&data->update_lock); - } -} - -static int __init sm_adm1026_init(void) -{ - printk("adm1026: Version %s (%s)\n", LM_VERSION, LM_DATE); - return i2c_add_driver(&adm1026_driver); -} - -static void __exit sm_adm1026_exit(void) -{ - i2c_del_driver(&adm1026_driver); -} - -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Philip Pokorny and - Jean Delvare - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#include -#include -#include -#include -#include -#include "version.h" - -/* Following macros take channel parameter starting from 0 */ -#define ADM1031_REG_FAN_SPEED(nr) (0x08 + (nr)) - -#define ADM1031_REG_FAN_DIV(nr) (0x20 + (nr)) -#define ADM1031_REG_FAN_MIN(nr) (0x10 + (nr)) - -#define ADM1031_REG_TEMP_MAX(nr) (0x14 + 4 * (nr)) -#define ADM1031_REG_TEMP_MIN(nr) (0x15 + 4 * (nr)) -#define ADM1031_REG_TEMP_CRIT(nr) (0x16 + 4 * (nr)) - -#define ADM1031_REG_TEMP(nr) (0x0a + (nr)) -#define ADM1031_REG_AUTO_TEMP(nr) (0x24 + (nr)) - -#define ADM1031_REG_STATUS(nr) (0x02 + (nr)) -#define ADM1031_REG_FAN_PWM 0x22 - -#define ADM1031_REG_CONF1 0x00 -#define ADM1031_REG_CONF2 0x01 -#define ADM1031_REG_EXT_TEMP 0x06 - -#define ADM1031_CONF1_MONITOR_ENABLE 0x01 /* Monitoring enable */ -#define ADM1031_CONF1_PWM_INVERT 0x08 /* PWM Invert (unused) */ -#define ADM1031_CONF1_AUTO_MODE 0x80 /* Auto fan mode */ - -#define ADM1031_CONF2_PWM1_ENABLE 0x01 -#define ADM1031_CONF2_PWM2_ENABLE 0x02 -#define ADM1031_CONF2_TACH1_ENABLE 0x04 -#define ADM1031_CONF2_TACH2_ENABLE 0x08 -#define ADM1031_CONF2_TEMP_ENABLE(chan) (0x10 << (chan)) - -/* Addresses to scan */ -static unsigned short normal_i2c[] = { SENSORS_I2C_END }; -static unsigned short normal_i2c_range[] = { 0x2c, 0x2e, SENSORS_I2C_END }; -static unsigned int normal_isa[] = { SENSORS_ISA_END }; -static unsigned int normal_isa_range[] = { SENSORS_ISA_END }; - -/* Insmod parameters */ -SENSORS_INSMOD_2(adm1030, adm1031); - -/* - * Proc entries - * These files are created for each detected ADM1031. - */ - -/* -- SENSORS SYSCTL START -- */ - -#define ADM1031_SYSCTL_TEMP1 1200 -#define ADM1031_SYSCTL_TEMP2 1201 -#define ADM1031_SYSCTL_TEMP3 1202 - -#define ADM1031_SYSCTL_FAN1 1210 -#define ADM1031_SYSCTL_FAN2 1211 - -#define ADM1031_SYSCTL_FAN_DIV 1220 - -#define ADM1031_SYSCTL_ALARMS 1250 - -#define ADM1031_ALARM_FAN1_MIN 0x0001 -#define ADM1031_ALARM_FAN1_FLT 0x0002 -#define ADM1031_ALARM_TEMP2_HIGH 0x0004 -#define ADM1031_ALARM_TEMP2_LOW 0x0008 -#define ADM1031_ALARM_TEMP2_CRIT 0x0010 -#define ADM1031_ALARM_TEMP2_DIODE 0x0020 -#define ADM1031_ALARM_TEMP1_HIGH 0x0040 -#define ADM1031_ALARM_TEMP1_LOW 0x0080 -#define ADM1031_ALARM_FAN2_MIN 0x0100 -#define ADM1031_ALARM_FAN2_FLT 0x0200 -#define ADM1031_ALARM_TEMP3_HIGH 0x0400 -#define ADM1031_ALARM_TEMP3_LOW 0x0800 -#define ADM1031_ALARM_TEMP3_CRIT 0x1000 -#define ADM1031_ALARM_TEMP3_DIODE 0x2000 -#define ADM1031_ALARM_TEMP1_CRIT 0x4000 -#define ADM1031_ALARM_THERMAL 0x8000 - - -/* -- SENSORS SYSCTL END -- */ -static void adm1031_alarms(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void adm1031_temp(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void adm1031_fan(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void adm1031_fan_div(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); - -static ctl_table adm1031_dir_table_template[] = { - {ADM1031_SYSCTL_TEMP1, "temp1", NULL, 0, 0644, NULL, - &i2c_proc_real, - &i2c_sysctl_real, NULL, &adm1031_temp}, - {ADM1031_SYSCTL_TEMP2, "temp2", NULL, 0, 0644, NULL, - &i2c_proc_real, - &i2c_sysctl_real, NULL, &adm1031_temp}, - {ADM1031_SYSCTL_TEMP3, "temp3", NULL, 0, 0644, NULL, - &i2c_proc_real, - &i2c_sysctl_real, NULL, &adm1031_temp}, - {ADM1031_SYSCTL_FAN1, "fan1", NULL, 0, 0644, NULL, - &i2c_proc_real, - &i2c_sysctl_real, NULL, &adm1031_fan}, - {ADM1031_SYSCTL_FAN_DIV, "fan_div", NULL, 0, 0644, NULL, - &i2c_proc_real, - &i2c_sysctl_real, NULL, &adm1031_fan_div}, - {ADM1031_SYSCTL_FAN2, "fan2", NULL, 0, 0644, NULL, - &i2c_proc_real, - &i2c_sysctl_real, NULL, &adm1031_fan}, - {ADM1031_SYSCTL_ALARMS, "alarms", NULL, 0, 0444, NULL, - &i2c_proc_real, - &i2c_sysctl_real, NULL, &adm1031_alarms}, - {0} -}; - -static ctl_table adm1030_dir_table_template[] = { - {ADM1031_SYSCTL_TEMP1, "temp1", NULL, 0, 0644, NULL, - &i2c_proc_real, - &i2c_sysctl_real, NULL, &adm1031_temp}, - {ADM1031_SYSCTL_TEMP2, "temp2", NULL, 0, 0644, NULL, - &i2c_proc_real, - &i2c_sysctl_real, NULL, &adm1031_temp}, - {ADM1031_SYSCTL_FAN1, "fan1", NULL, 0, 0644, NULL, - &i2c_proc_real, - &i2c_sysctl_real, NULL, &adm1031_fan}, - {ADM1031_SYSCTL_FAN_DIV, "fan_div", NULL, 0, 0644, NULL, - &i2c_proc_real, - &i2c_sysctl_real, NULL, &adm1031_fan_div}, - {ADM1031_SYSCTL_ALARMS, "alarms", NULL, 0, 0444, NULL, - &i2c_proc_real, - &i2c_sysctl_real, NULL, &adm1031_alarms}, - {0} -}; - - -/* Each client has this additional data */ -struct adm1031_data { - struct i2c_client client; - int sysctl_id; - struct semaphore update_lock; - int chip_type; - char valid; /* !=0 if following fields are valid */ - unsigned long last_updated; /* In jiffies */ - - u16 alarms; - u8 conf1; - u8 conf2; - u8 fan[2]; - u8 fan_min[2]; - u8 fan_pwm[2]; - u8 fan_div[2]; - s8 temp[3]; - u8 auto_temp[3]; - u8 ext_temp[3]; - s8 temp_min[3]; - s8 temp_max[3]; - s8 temp_crit[3]; -}; - -static int adm1031_attach_adapter(struct i2c_adapter *adapter); -static int adm1031_detect(struct i2c_adapter *adapter, int address, - unsigned short flags, int kind); -static void adm1031_init_client(struct i2c_client *client); -static int adm1031_detach_client(struct i2c_client *client); - -static inline u8 adm1031_read_value(struct i2c_client *client, u8 reg); -static inline int adm1031_write_value(struct i2c_client *client, u8 reg, - unsigned int value); - -static void adm1031_update_client(struct i2c_client *client); - -/* This is the driver that will be inserted */ -static struct i2c_driver adm1031_driver = { - .name = "ADM1031/ADM1030 sensor driver", - .flags = I2C_DF_NOTIFY, - .attach_adapter = adm1031_attach_adapter, - .detach_client = adm1031_detach_client, -}; - -#define TEMP_TO_REG(val) ((val) < 0 ? (((val) - 500) / 1000) : \ - (((val) + 500) / 1000)) - -#define TEMP_FROM_REG(reg) ((reg) * 1000) - -#define TEMP_FROM_REG_EXT(val,ext) (TEMP_FROM_REG(val) + (ext) * 125) - -#define FAN_FROM_REG(reg,div) ((reg) ? 675000 / ((reg) * (div)) : 0) - -#define FAN_TO_REG(val,div) ((val) <= 0 ? 0 : \ - (val) * (div) >= 675000 ? 1 : \ - (val) * (div) <= 2647 ? 255 : \ - 675000 / ((val) * (div))) - -#define FAN_DIV_TO_REG(val) ((val) == 8 ? 0xc0 : \ - (val) == 4 ? 0x80 : \ - (val) == 1 ? 0x00 : 0x40) - -#define FAN_DIV_FROM_REG(reg) (1 << (((reg)&0xc0) >> 6)) - -#define AUTO_TEMP_MIN_FROM_REG(reg) (((reg) >> 3) * 4) - - -static int adm1031_attach_adapter(struct i2c_adapter *adapter) -{ - return i2c_detect(adapter, &addr_data, adm1031_detect); -} - -/* This function is called by i2c_detect */ -static int -adm1031_detect(struct i2c_adapter *adapter, int address, - unsigned short flags, int kind) -{ - struct i2c_client *new_client; - struct adm1031_data *data; - int err = 0; - const char *type_name = ""; - const char *client_name = ""; - - if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) - goto exit; - - if (!(data = kmalloc(sizeof(struct adm1031_data), GFP_KERNEL))) { - err = -ENOMEM; - goto exit; - } - memset(data, 0, sizeof(struct adm1031_data)); - - new_client = &data->client; - new_client->data = data; - new_client->addr = address; - new_client->adapter = adapter; - new_client->driver = &adm1031_driver; - new_client->flags = 0; - - if (kind < 0) { - int id, co; - id = i2c_smbus_read_byte_data(new_client, 0x3d); - co = i2c_smbus_read_byte_data(new_client, 0x3e); - - if (((id != 0x31) || (id != 0x30)) && (co != 0x41)) - goto exit_free; - kind = (id == 0x30) ? adm1030 : adm1031; - } - - if (kind <= 0) - kind = adm1031; - - /* Given the detected chip type, set the chip name and the - * auto fan control helper table. */ - if (kind == adm1030) { - type_name = "adm1030"; - client_name = "ADM1030 chip"; - - } else if (kind == adm1031) { - type_name = "adm1031"; - client_name = "ADM1031 chip"; - } - data->chip_type = kind; - - strcpy(new_client->name, client_name); - data->valid = 0; - init_MUTEX(&data->update_lock); - - /* Tell the I2C layer a new client has arrived */ - if ((err = i2c_attach_client(new_client))) - goto exit_free; - - - if (kind == adm1030) { - if ((err = i2c_register_entry(new_client, type_name, - adm1030_dir_table_template, - THIS_MODULE)) < 0) - goto exit_detach; - } else if (kind == adm1031) { - if ((err = i2c_register_entry(new_client, type_name, - adm1031_dir_table_template, - THIS_MODULE)) < 0) - goto exit_detach; - } - - data->sysctl_id = err; - - /* Initialize the ADM1031 chip */ - adm1031_init_client(new_client); - - return 0; - -exit_detach: - i2c_detach_client(new_client); -exit_free: - kfree(data); -exit: - return err; -} - -static int adm1031_detach_client(struct i2c_client *client) -{ - int ret; - struct adm1031_data *data = client->data; - - i2c_deregister_entry(data->sysctl_id); - if ((ret = i2c_detach_client(client)) != 0) { - return ret; - } - - kfree(data); - return 0; -} - -static inline u8 adm1031_read_value(struct i2c_client *client, u8 reg) -{ - return i2c_smbus_read_byte_data(client, reg); -} - -static inline int adm1031_write_value(struct i2c_client *client, u8 reg, - unsigned int value) -{ - return i2c_smbus_write_byte_data(client, reg, value); -} - -static void adm1031_init_client(struct i2c_client *client) -{ - unsigned int read_val; - unsigned int mask; - struct adm1031_data *data = client->data; - - mask = (ADM1031_CONF2_PWM1_ENABLE | ADM1031_CONF2_TACH1_ENABLE); - if (data->chip_type == adm1031) { - mask |= (ADM1031_CONF2_PWM2_ENABLE | - ADM1031_CONF2_TACH2_ENABLE); - } - /* Initialize the ADM1031 chip (enable fan speed reading) */ - read_val = adm1031_read_value(client, ADM1031_REG_CONF2); - if ((read_val | mask) != read_val) { - adm1031_write_value(client, ADM1031_REG_CONF2, - read_val | mask); - } - - read_val = adm1031_read_value(client, ADM1031_REG_CONF1); - if ((read_val | ADM1031_CONF1_MONITOR_ENABLE) != read_val) { - adm1031_write_value(client, ADM1031_REG_CONF1, read_val | - ADM1031_CONF1_MONITOR_ENABLE); - } -} - -static void adm1031_update_client(struct i2c_client *client) -{ - struct adm1031_data *data = client->data; - int chan; - - down(&data->update_lock); - - if ((jiffies - data->last_updated > HZ + HZ / 2) || - (jiffies < data->last_updated) || !data->valid) { -#ifdef DEBUG - printk(KERN_INFO "adm1031.o: Starting chip update\n"); -#endif - for (chan = 0; - chan < ((data->chip_type == adm1031) ? 3 : 2); - chan++) { - u8 oldh, newh; - - oldh = adm1031_read_value(client, - ADM1031_REG_TEMP(chan)); - data->ext_temp[chan] = adm1031_read_value(client, - ADM1031_REG_EXT_TEMP); - newh = adm1031_read_value(client, - ADM1031_REG_TEMP(chan)); - if (newh != oldh) { - data->ext_temp[chan] = adm1031_read_value(client, - ADM1031_REG_EXT_TEMP); -#ifdef DEBUG - oldh = adm1031_read_value(client, - ADM1031_REG_TEMP(chan)); - - /* oldh is actually newer */ - if (newh != oldh) - printk(KERN_INFO "adm1031.o: Remote " - "temperature may be wrong.\n"); -#endif - } - data->temp[chan] = newh; - - data->temp_min[chan] = adm1031_read_value(client, - ADM1031_REG_TEMP_MIN(chan)); - data->temp_max[chan] = adm1031_read_value(client, - ADM1031_REG_TEMP_MAX(chan)); - data->temp_crit[chan] = adm1031_read_value(client, - ADM1031_REG_TEMP_CRIT(chan)); - data->auto_temp[chan] = adm1031_read_value(client, - ADM1031_REG_AUTO_TEMP(chan)); - } - - data->conf1 = adm1031_read_value(client, ADM1031_REG_CONF1); - - data->alarms = adm1031_read_value(client, ADM1031_REG_STATUS(0)) - | (adm1031_read_value(client, ADM1031_REG_STATUS(1)) - << 8); - if (data->chip_type == adm1030) { - data->alarms &= 0xc0ff; - } - - for (chan = 0; - chan < (data->chip_type == adm1030 ? 1 : 2); - chan++) { - data->fan_div[chan] = adm1031_read_value(client, - ADM1031_REG_FAN_DIV(chan)); - data->fan_min[chan] = adm1031_read_value(client, - ADM1031_REG_FAN_MIN(chan)); - data->fan[chan] = adm1031_read_value(client, - ADM1031_REG_FAN_SPEED(chan)); - data->fan_pwm[chan] = (adm1031_read_value(client, - ADM1031_REG_FAN_PWM) >> (4 * chan)) - & 0x0f; - } - - data->conf1 = adm1031_read_value(client, ADM1031_REG_CONF1); - data->conf2 = adm1031_read_value(client, ADM1031_REG_CONF2); - - data->last_updated = jiffies; - data->valid = 1; - } - - up(&data->update_lock); -} - -static int __init sensors_adm1031_init(void) -{ - printk(KERN_INFO "adm1031.o version %s (%s)\n", LM_VERSION, LM_DATE); - return i2c_add_driver(&adm1031_driver); -} - -static void __exit sensors_adm1031_exit(void) -{ - i2c_del_driver(&adm1031_driver); -} - - -static void -adm1031_temp(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - int ext; - struct adm1031_data *data = client->data; - int tmp; - int nr = ctl_name - ADM1031_SYSCTL_TEMP1; - - ext = nr == 0 ? - ((data->ext_temp[nr] >> 6) & 0x3) * 2 : - (((data->ext_temp[nr] >> ((nr - 1) * 3)) & 7)); - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 3; - else if (operation == SENSORS_PROC_REAL_READ) { - adm1031_update_client(client); - results[0] = TEMP_FROM_REG(data->temp_max[nr]); - results[1] = TEMP_FROM_REG(data->temp_min[nr]); - results[2] = TEMP_FROM_REG(data->temp_crit[nr]); - results[3] = TEMP_FROM_REG_EXT(data->temp[nr], ext); - *nrels_mag = 4; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag >= 1) { - tmp = SENSORS_LIMIT(results[0], -55000, 127000); - data->temp_max[nr] = TEMP_TO_REG(tmp); - adm1031_write_value(client, - ADM1031_REG_TEMP_MAX(nr), - data->temp_max[nr]); - } - if (*nrels_mag >= 2) { - tmp = SENSORS_LIMIT(results[1], -55000, 127000); - data->temp_min[nr] = TEMP_TO_REG(tmp); - adm1031_write_value(client, - ADM1031_REG_TEMP_MIN(nr), - data->temp_min[nr]); - } - if (*nrels_mag >= 3) { - tmp = SENSORS_LIMIT(results[2], -55000, 127000); - data->temp_crit[nr] = TEMP_TO_REG(tmp); - adm1031_write_value(client, - ADM1031_REG_TEMP_CRIT(nr), - data->temp_crit[nr]); - } - } -} - -/* - * That function checks the cases where the fan reading is not - * relevant. It is used to provide 0 as fan reading when the fan is - * not supposed to run. - */ -static int trust_fan_readings(struct adm1031_data * data, int chan) -{ - int res = 0; - - if (data->conf1 & ADM1031_CONF1_AUTO_MODE) { - switch(data->conf1 & 0x60) { - case 0x00: /* temp2 controls fan1, temp3 controls fan2 */ - res = data->temp[chan+1] >= - AUTO_TEMP_MIN_FROM_REG(data->auto_temp[chan+1]); - break; - case 0x20: /* temp2 controls both fans */ - res = data->temp[1] >= - AUTO_TEMP_MIN_FROM_REG(data->auto_temp[1]); - break; - case 0x40: /* temp3 controls both fans */ - res = data->temp[2] >= - AUTO_TEMP_MIN_FROM_REG(data->auto_temp[2]); - break; - case 0x60: /* max of temp1, temp2 and temp3 controls both - fans */ - res = data->temp[0] >= - AUTO_TEMP_MIN_FROM_REG(data->auto_temp[0]) - || data->temp[1] >= - AUTO_TEMP_MIN_FROM_REG(data->auto_temp[1]) - || (data->chip_type == adm1031 - && data->temp[2] >= - AUTO_TEMP_MIN_FROM_REG(data->auto_temp[2])); - break; - } - } else { - res = data->fan_pwm[chan] > 0; - } - - return res; -} - -static void adm1031_fan(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results) -{ - struct adm1031_data *data = client->data; - int nr = ctl_name - ADM1031_SYSCTL_FAN1; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - adm1031_update_client(client); - results[0] = FAN_FROM_REG(data->fan_min[nr], - FAN_DIV_FROM_REG(data->fan_div[nr])); - results[1] = trust_fan_readings(data, nr) ? - FAN_FROM_REG(data->fan[nr], - FAN_DIV_FROM_REG(data->fan_div[nr])) : 0; - *nrels_mag = 2; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag >= 1) { - data->fan_min[nr] = FAN_TO_REG(results[0], - FAN_DIV_FROM_REG(data->fan_div[nr])); - adm1031_write_value(client, - ADM1031_REG_FAN_MIN(nr), - data->fan_min[nr]); - } - } -} - -static void adm1031_fan_div(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results) -{ - struct adm1031_data *data = client->data; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - adm1031_update_client(client); - results[0] = FAN_DIV_FROM_REG(data->fan_div[0]); - *nrels_mag = 1; - if(data->chip_type == adm1031) { - results[1] = FAN_DIV_FROM_REG(data->fan_div[1]); - *nrels_mag = 2; - } - } else if (operation == SENSORS_PROC_REAL_WRITE) { - int old_div, new_min; - if (*nrels_mag >= 1) { - old_div = FAN_DIV_FROM_REG(data->fan_div[0]); - data->fan_div[0] = FAN_DIV_TO_REG(results[0]); - adm1031_write_value(client, - ADM1031_REG_FAN_DIV(0), - data->fan_div[0]); - new_min = data->fan_min[0] * old_div / - FAN_DIV_FROM_REG(data->fan_div[0]); - data->fan_min[0] = new_min > 0xff ? 0xff : new_min; - adm1031_write_value(client, - ADM1031_REG_FAN_MIN(0), - data->fan_min[0]); - } - if (*nrels_mag >= 2) { - old_div = FAN_DIV_FROM_REG(data->fan_div[1]); - data->fan_div[1] = FAN_DIV_TO_REG(results[1]); - adm1031_write_value(client, - ADM1031_REG_FAN_DIV(1), - data->fan_div[1]); - new_min = data->fan_min[1] * old_div / - FAN_DIV_FROM_REG(data->fan_div[1]); - data->fan_min[1] = new_min > 0xff ? 0xff : new_min; - adm1031_write_value(client, - ADM1031_REG_FAN_MIN(1), - data->fan_min[1]); - } - } -} - -static void adm1031_alarms(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results) -{ - struct adm1031_data *data = client->data; - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - adm1031_update_client(client); - results[0] = data->alarms; - *nrels_mag = 1; - } -} - -MODULE_AUTHOR("Alexandre d'Alton "); -MODULE_DESCRIPTION("ADM1031/ADM1030 driver"); -MODULE_LICENSE("GPL"); - -module_init(sensors_adm1031_init); -module_exit(sensors_adm1031_exit); diff --git a/kernel/chips/adm9240.c b/kernel/chips/adm9240.c deleted file mode 100644 index e603091f..00000000 --- a/kernel/chips/adm9240.c +++ /dev/null @@ -1,700 +0,0 @@ -/* - adm9240.c - Part of lm_sensors, Linux kernel modules for hardware - monitoring - Copyright (C) 1999 Frodo Looijaard - and Philip Edelbrock - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -/* Supports ADM9240, DS1780, and LM81. See doc/chips/adm9240 for details */ - -/* - A couple notes about the ADM9240: - -* It claims to be 'LM7x' register compatible. This must be in reference - to only the LM78, because it is missing stuff to emulate LM75's as well. - (like the Winbond W83781 does) - -* This driver was written from rev. 0 of the PDF, but it seems well - written and complete (unlike the W83781 which is horrible and has - supposedly gone through a few revisions.. rev 0 of that one must - have been in crayon on construction paper...) - -* All analog inputs can range from 0 to 2.5, eventhough some inputs are - marked as being 5V, 12V, etc. I don't have any real voltages going - into my prototype, so I'm not sure that things are computed right, - but at least the limits seem to be working OK. - -* Another curiousity is that the fan_div seems to be read-only. I.e., - any written value to it doesn't seem to make any difference. The - fan_div seems to be 'stuck' at 2 (which isn't a bad value in most cases). - - --Phil -*/ - -#include -#include -#include -#include -#include -#include "version.h" - -/* Addresses to scan */ -static unsigned short normal_i2c[] = { SENSORS_I2C_END }; -static unsigned short normal_i2c_range[] = { 0x2c, 0x2f, SENSORS_I2C_END }; -static unsigned int normal_isa[] = { SENSORS_ISA_END }; -static unsigned int normal_isa_range[] = { SENSORS_ISA_END }; - -/* Insmod parameters */ -SENSORS_INSMOD_3(adm9240, ds1780, lm81); - -/* Many ADM9240 constants specified below */ - -#define ADM9240_REG_IN_MAX(nr) (0x2b + (nr) * 2) -#define ADM9240_REG_IN_MIN(nr) (0x2c + (nr) * 2) -#define ADM9240_REG_IN(nr) (0x20 + (nr)) - -/* The ADM9240 registers */ -#define ADM9240_REG_TEST 0x15 -#define ADM9240_REG_ANALOG_OUT 0x19 -/* These are all read-only */ -#define ADM9240_REG_2_5V 0x20 -#define ADM9240_REG_VCCP1 0x21 -#define ADM9240_REG_3_3V 0x22 -#define ADM9240_REG_5V 0x23 -#define ADM9240_REG_12V 0x24 -#define ADM9240_REG_VCCP2 0x25 -#define ADM9240_REG_TEMP 0x27 -#define ADM9240_REG_FAN1 0x28 -#define ADM9240_REG_FAN2 0x29 -#define ADM9240_REG_COMPANY_ID 0x3E /* 0x23 for ADM9240; 0xDA for DS1780 */ - /* 0x01 for LM81 */ -#define ADM9240_REG_DIE_REV 0x3F -/* These are read/write */ -#define ADM9240_REG_2_5V_HIGH 0x2B -#define ADM9240_REG_2_5V_LOW 0x2C -#define ADM9240_REG_VCCP1_HIGH 0x2D -#define ADM9240_REG_VCCP1_LOW 0x2E -#define ADM9240_REG_3_3V_HIGH 0x2F -#define ADM9240_REG_3_3V_LOW 0x30 -#define ADM9240_REG_5V_HIGH 0x31 -#define ADM9240_REG_5V_LOW 0x32 -#define ADM9240_REG_12V_HIGH 0x33 -#define ADM9240_REG_12V_LOW 0x34 -#define ADM9240_REG_VCCP2_HIGH 0x35 -#define ADM9240_REG_VCCP2_LOW 0x36 -#define ADM9240_REG_TCRIT_LIMIT 0x37 /* LM81 only - not supported */ -#define ADM9240_REG_LOW_LIMIT 0x38 /* LM81 only - not supported */ -#define ADM9240_REG_TOS 0x39 -#define ADM9240_REG_THYST 0x3A -#define ADM9240_REG_FAN1_MIN 0x3B -#define ADM9240_REG_FAN2_MIN 0x3C - -#define ADM9240_REG_CONFIG 0x40 -#define ADM9240_REG_INT1_STAT 0x41 -#define ADM9240_REG_INT2_STAT 0x42 -#define ADM9240_REG_INT1_MASK 0x43 -#define ADM9240_REG_INT2_MASK 0x44 - -#define ADM9240_REG_COMPAT 0x45 /* dummy compat. register for other drivers? */ -#define ADM9240_REG_CHASSIS_CLEAR 0x46 -#define ADM9240_REG_VID_FAN_DIV 0x47 -#define ADM9240_REG_I2C_ADDR 0x48 -#define ADM9240_REG_VID4 0x49 -#define ADM9240_REG_TEMP_CONFIG 0x4B -#define ADM9240_REG_EXTMODE1 0x4C /* LM81 only - not supported */ -#define ADM9240_REG_EXTMODE2 0x4D /* LM81 only - not supported */ - -/* Conversions. Rounding and limit checking is only done on the TO_REG - variants. Note that you should be a bit careful with which arguments - these macros are called: arguments may be evaluated more than once. - Fixing this is just not worth it. */ -#define IN_TO_REG(val,nr) (SENSORS_LIMIT((val), 0, 255)) -#define IN_FROM_REG(val,nr) (val) - -static inline u8 FAN_TO_REG(long rpm, int div) -{ - if (rpm == 0) - return 255; - rpm = SENSORS_LIMIT(rpm, 1, 1000000); - return SENSORS_LIMIT((1350000 + rpm * div / 2) / (rpm * div), 1, - 254); -} - -#define FAN_FROM_REG(val,div) ((val)==0?-1:\ - (val)==255?0:1350000/((div)*(val))) - -#define TEMP_FROM_REG(temp) ((temp)<256 ? (temp) * 5 : \ - ((temp) - 512) * 5) - -#define TEMP_LIMIT_FROM_REG(val) (((val)>=0x80?(val)-0x100:(val))*10) - -#define TEMP_LIMIT_TO_REG(val) SENSORS_LIMIT(((val)<0?(((val)-5)/10)+256:\ - ((val)+5)/10), \ - 0,255) - -#define ALARMS_FROM_REG(val) (val) - -#define DIV_FROM_REG(val) (1 << (val)) -#define DIV_TO_REG(val) ((val)==1?0:((val)==8?3:((val)==4?2:1))) - -#define VID_FROM_REG(val) ((val)==0x1f?0:(val)>=0x10?510-(val)*10:\ - 205-(val)*5) - -/* For each registered ADM9240, we need to keep some data in memory. */ -struct adm9240_data { - struct i2c_client client; - int sysctl_id; - enum chips type; - - struct semaphore update_lock; - char valid; /* !=0 if following fields are valid */ - unsigned long last_updated; /* In jiffies */ - - u8 in[6]; /* Register value */ - u8 in_max[6]; /* Register value */ - u8 in_min[6]; /* Register value */ - u8 fan[2]; /* Register value */ - u8 fan_min[2]; /* Register value */ - u8 fan_div[2]; /* Register encoding, shifted right */ - int temp; /* Temp, shifted right */ - u8 temp_os_max; /* Register value */ - u8 temp_os_hyst; /* Register value */ - u16 alarms; /* Register encoding, combined */ - u8 analog_out; /* Register value */ - u8 vid; /* Register value combined */ -}; - - -static int adm9240_attach_adapter(struct i2c_adapter *adapter); -static int adm9240_detect(struct i2c_adapter *adapter, int address, - unsigned short flags, int kind); -static int adm9240_detach_client(struct i2c_client *client); - -static void adm9240_update_client(struct i2c_client *client); -static void adm9240_init_client(struct i2c_client *client); - - -static void adm9240_in(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void adm9240_fan(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void adm9240_temp(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void adm9240_alarms(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void adm9240_fan_div(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void adm9240_analog_out(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, - long *results); -static void adm9240_vid(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); - -static struct i2c_driver adm9240_driver = { - .name = "ADM9240 sensor driver", - .id = I2C_DRIVERID_ADM9240, - .flags = I2C_DF_NOTIFY, - .attach_adapter = adm9240_attach_adapter, - .detach_client = adm9240_detach_client, -}; - -/* The /proc/sys entries */ - -/* -- SENSORS SYSCTL START -- */ - -#define ADM9240_SYSCTL_IN0 1000 /* Volts * 100 */ -#define ADM9240_SYSCTL_IN1 1001 -#define ADM9240_SYSCTL_IN2 1002 -#define ADM9240_SYSCTL_IN3 1003 -#define ADM9240_SYSCTL_IN4 1004 -#define ADM9240_SYSCTL_IN5 1005 -#define ADM9240_SYSCTL_FAN1 1101 /* Rotations/min */ -#define ADM9240_SYSCTL_FAN2 1102 -#define ADM9240_SYSCTL_TEMP 1250 /* Degrees Celsius * 100 */ -#define ADM9240_SYSCTL_FAN_DIV 2000 /* 1, 2, 4 or 8 */ -#define ADM9240_SYSCTL_ALARMS 2001 /* bitvector */ -#define ADM9240_SYSCTL_ANALOG_OUT 2002 -#define ADM9240_SYSCTL_VID 2003 - -#define ADM9240_ALARM_IN0 0x0001 -#define ADM9240_ALARM_IN1 0x0002 -#define ADM9240_ALARM_IN2 0x0004 -#define ADM9240_ALARM_IN3 0x0008 -#define ADM9240_ALARM_IN4 0x0100 -#define ADM9240_ALARM_IN5 0x0200 -#define ADM9240_ALARM_FAN1 0x0040 -#define ADM9240_ALARM_FAN2 0x0080 -#define ADM9240_ALARM_TEMP 0x0010 -#define ADM9240_ALARM_CHAS 0x1000 - -/* -- SENSORS SYSCTL END -- */ - -/* These files are created for each detected ADM9240. This is just a template; - though at first sight, you might think we could use a statically - allocated list, we need some way to get back to the parent - which - is done through one of the 'extra' fields which are initialized - when a new copy is allocated. */ -static ctl_table adm9240_dir_table_template[] = { - {ADM9240_SYSCTL_IN0, "in0", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &adm9240_in}, - {ADM9240_SYSCTL_IN1, "in1", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &adm9240_in}, - {ADM9240_SYSCTL_IN2, "in2", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &adm9240_in}, - {ADM9240_SYSCTL_IN3, "in3", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &adm9240_in}, - {ADM9240_SYSCTL_IN4, "in4", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &adm9240_in}, - {ADM9240_SYSCTL_IN5, "in5", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &adm9240_in}, - {ADM9240_SYSCTL_FAN1, "fan1", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &adm9240_fan}, - {ADM9240_SYSCTL_FAN2, "fan2", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &adm9240_fan}, - {ADM9240_SYSCTL_TEMP, "temp", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &adm9240_temp}, - {ADM9240_SYSCTL_FAN_DIV, "fan_div", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &adm9240_fan_div}, - {ADM9240_SYSCTL_ALARMS, "alarms", NULL, 0, 0444, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &adm9240_alarms}, - {ADM9240_SYSCTL_ANALOG_OUT, "analog_out", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &adm9240_analog_out}, - {ADM9240_SYSCTL_VID, "vid", NULL, 0, 0444, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &adm9240_vid}, - {0} -}; - -static int adm9240_attach_adapter(struct i2c_adapter *adapter) -{ - return i2c_detect(adapter, &addr_data, adm9240_detect); -} - -static int adm9240_detect(struct i2c_adapter *adapter, int address, - unsigned short flags, int kind) -{ - int i; - struct i2c_client *new_client; - struct adm9240_data *data; - int err = 0; - const char *type_name = ""; - const char *client_name = ""; - - if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) - goto ERROR0; - - /* OK. For now, we presume we have a valid client. We now create the - client structure, even though we cannot fill it completely yet. - But it allows us to access adm9240_{read,write}_value. */ - - if (!(data = kmalloc(sizeof(struct adm9240_data), GFP_KERNEL))) { - err = -ENOMEM; - goto ERROR0; - } - - - new_client = &data->client; - new_client->addr = address; - new_client->data = data; - new_client->adapter = adapter; - new_client->driver = &adm9240_driver; - new_client->flags = 0; - - /* Now, we do the remaining detection. */ - - if (kind < 0) { - if ( - ((i2c_smbus_read_byte_data - (new_client, ADM9240_REG_CONFIG) & 0x80) != 0x00) - || - (i2c_smbus_read_byte_data(new_client, ADM9240_REG_I2C_ADDR) - != address)) - goto ERROR1; - } - - /* Determine the chip type. */ - if (kind <= 0) { - i = i2c_smbus_read_byte_data(new_client, - ADM9240_REG_COMPANY_ID); - if (i == 0x23) - kind = adm9240; - else if (i == 0xda) - kind = ds1780; - else if (i == 0x01) - kind = lm81; - else { - if (kind == 0) - printk("adm9240.o: Ignoring 'force' " - "parameter for unknown chip at " - "adapter %d, address 0x%02x\n", - i2c_adapter_id(adapter), address); - goto ERROR1; - } - } - - if (kind == adm9240) { - type_name = "adm9240"; - client_name = "ADM9240 chip"; - } else if (kind == ds1780) { - type_name = "ds1780"; - client_name = "DS1780 chip"; - } else if (kind == lm81) { - type_name = "lm81"; - client_name = "LM81 chip"; - } else { -#ifdef DEBUG - printk("adm9240.o: Internal error: unknown kind (%d)\n", - kind); -#endif - goto ERROR1; - } - - /* Fill in the remaining client fields and put it into the global - list */ - strcpy(new_client->name, client_name); - data->type = kind; - data->valid = 0; - init_MUTEX(&data->update_lock); - - /* Tell the I2C layer a new client has arrived */ - if ((err = i2c_attach_client(new_client))) - goto ERROR3; - - /* Register a new directory entry with module sensors */ - if ((i = i2c_register_entry(new_client, - type_name, - adm9240_dir_table_template, - THIS_MODULE)) < 0) { - err = i; - goto ERROR4; - } - data->sysctl_id = i; - - /* Initialize the ADM9240 chip */ - adm9240_init_client(new_client); - return 0; - -/* OK, this is not exactly good programming practice, usually. But it is - very code-efficient in this case. */ - - ERROR4: - i2c_detach_client(new_client); - ERROR3: - ERROR1: - kfree(data); - ERROR0: - return err; -} - -static int adm9240_detach_client(struct i2c_client *client) -{ - int err; - - i2c_deregister_entry(((struct adm9240_data *) (client->data))-> - sysctl_id); - - if ((err = i2c_detach_client(client))) { - printk("adm9240.o: Client deregistration failed, " - "client not detached\n"); - return err; - } - - kfree(client->data); - - return 0; -} - - -/* Called when we have found a new ADM9240. */ -static void adm9240_init_client(struct i2c_client *client) -{ - /* Start monitoring */ - i2c_smbus_write_byte_data(client, ADM9240_REG_CONFIG, 0x01); -} - -static void adm9240_update_client(struct i2c_client *client) -{ - struct adm9240_data *data = client->data; - u8 i; - - down(&data->update_lock); - - if ( - (jiffies - data->last_updated > - (data->type == adm9240 ? HZ / 2 : HZ * 2)) - || (jiffies < data->last_updated) || !data->valid) { - -#ifdef DEBUG - printk("Starting adm9240 update\n"); -#endif - for (i = 0; i <= 5; i++) { - data->in[i] = - i2c_smbus_read_byte_data(client, - ADM9240_REG_IN(i)); - data->in_min[i] = - i2c_smbus_read_byte_data(client, - ADM9240_REG_IN_MIN(i)); - data->in_max[i] = - i2c_smbus_read_byte_data(client, - ADM9240_REG_IN_MAX(i)); - } - data->fan[0] = - i2c_smbus_read_byte_data(client, ADM9240_REG_FAN1); - data->fan_min[0] = - i2c_smbus_read_byte_data(client, ADM9240_REG_FAN1_MIN); - data->fan[1] = - i2c_smbus_read_byte_data(client, ADM9240_REG_FAN2); - data->fan_min[1] = - i2c_smbus_read_byte_data(client, ADM9240_REG_FAN2_MIN); - data->temp = - (i2c_smbus_read_byte_data(client, ADM9240_REG_TEMP) << 1) + - ((i2c_smbus_read_byte_data - (client, ADM9240_REG_TEMP_CONFIG) & 0x80) >> 7); - data->temp_os_max = - i2c_smbus_read_byte_data(client, ADM9240_REG_TOS); - data->temp_os_hyst = - i2c_smbus_read_byte_data(client, ADM9240_REG_THYST); - - i = i2c_smbus_read_byte_data(client, ADM9240_REG_VID_FAN_DIV); - data->fan_div[0] = (i >> 4) & 0x03; - data->fan_div[1] = (i >> 6) & 0x03; - data->vid = i & 0x0f; - data->vid |= - (i2c_smbus_read_byte_data(client, ADM9240_REG_VID4) & 0x01) - << 4; - - data->alarms = - i2c_smbus_read_byte_data(client, - ADM9240_REG_INT1_STAT) + - (i2c_smbus_read_byte_data(client, ADM9240_REG_INT2_STAT) << - 8); - data->analog_out = - i2c_smbus_read_byte_data(client, ADM9240_REG_ANALOG_OUT); - data->last_updated = jiffies; - data->valid = 1; - } - - up(&data->update_lock); -} - - -/* The next few functions are the call-back functions of the /proc/sys and - sysctl files. Which function is used is defined in the ctl_table in - the extra1 field. - Each function must return the magnitude (power of 10 to divide the date - with) if it is called with operation==SENSORS_PROC_REAL_INFO. It must - put a maximum of *nrels elements in results reflecting the data of this - file, and set *nrels to the number it actually put in it, if operation== - SENSORS_PROC_REAL_READ. Finally, it must get upto *nrels elements from - results and write them to the chip, if operations==SENSORS_PROC_REAL_WRITE. - Note that on SENSORS_PROC_REAL_READ, I do not check whether results is - large enough (by checking the incoming value of *nrels). This is not very - good practice, but as long as you put less than about 5 values in results, - you can assume it is large enough. */ -void adm9240_in(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - - int scales[6] = { 250, 270, 330, 500, 1200, 270 }; - - struct adm9240_data *data = client->data; - int nr = ctl_name - ADM9240_SYSCTL_IN0; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 2; - else if (operation == SENSORS_PROC_REAL_READ) { - adm9240_update_client(client); - results[0] = - IN_FROM_REG(data->in_min[nr], nr) * scales[nr] / 192; - results[1] = - IN_FROM_REG(data->in_max[nr], nr) * scales[nr] / 192; - results[2] = - IN_FROM_REG(data->in[nr], nr) * scales[nr] / 192; - *nrels_mag = 3; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag >= 1) { - data->in_min[nr] = - IN_TO_REG((results[0] * 192) / scales[nr], nr); - i2c_smbus_write_byte_data(client, - ADM9240_REG_IN_MIN(nr), - data->in_min[nr]); - } - if (*nrels_mag >= 2) { - data->in_max[nr] = - IN_TO_REG((results[1] * 192) / scales[nr], nr); - i2c_smbus_write_byte_data(client, - ADM9240_REG_IN_MAX(nr), - data->in_max[nr]); - } - } -} - -void adm9240_fan(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct adm9240_data *data = client->data; - int nr = ctl_name - ADM9240_SYSCTL_FAN1 + 1; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - adm9240_update_client(client); - results[0] = FAN_FROM_REG(data->fan_min[nr - 1], - DIV_FROM_REG(data-> - fan_div[nr - 1])); - results[1] = - FAN_FROM_REG(data->fan[nr - 1], - DIV_FROM_REG(data->fan_div[nr - 1])); - *nrels_mag = 2; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag >= 1) { - data->fan_min[nr - 1] = FAN_TO_REG(results[0], - DIV_FROM_REG - (data-> - fan_div[nr - - 1])); - i2c_smbus_write_byte_data(client, nr == 1 ? - ADM9240_REG_FAN1_MIN : - ADM9240_REG_FAN2_MIN, - data->fan_min[nr - 1]); - } - } -} - - -void adm9240_temp(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct adm9240_data *data = client->data; - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 1; - else if (operation == SENSORS_PROC_REAL_READ) { - adm9240_update_client(client); - results[0] = TEMP_LIMIT_FROM_REG(data->temp_os_max); - results[1] = TEMP_LIMIT_FROM_REG(data->temp_os_hyst); - results[2] = TEMP_FROM_REG(data->temp); - *nrels_mag = 3; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag >= 1) { - data->temp_os_max = TEMP_LIMIT_TO_REG(results[0]); - i2c_smbus_write_byte_data(client, ADM9240_REG_TOS, - data->temp_os_max); - } - if (*nrels_mag >= 2) { - data->temp_os_hyst = TEMP_LIMIT_TO_REG(results[1]); - i2c_smbus_write_byte_data(client, ADM9240_REG_THYST, - data->temp_os_hyst); - } - } -} - -void adm9240_alarms(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct adm9240_data *data = client->data; - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - adm9240_update_client(client); - results[0] = ALARMS_FROM_REG(data->alarms); - *nrels_mag = 1; - } -} - -void adm9240_fan_div(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results) -{ - struct adm9240_data *data = client->data; - int old; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - adm9240_update_client(client); - results[0] = DIV_FROM_REG(data->fan_div[0]); - results[1] = DIV_FROM_REG(data->fan_div[1]); - *nrels_mag = 2; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - old = i2c_smbus_read_byte_data(client, - ADM9240_REG_VID_FAN_DIV); - if (*nrels_mag >= 2) { - data->fan_div[1] = DIV_TO_REG(results[1]); - old = (old & 0x3f) | (data->fan_div[1] << 6); - } - if (*nrels_mag >= 1) { - data->fan_div[0] = DIV_TO_REG(results[0]); - old = (old & 0xcf) | (data->fan_div[0] << 4); - i2c_smbus_write_byte_data(client, - ADM9240_REG_VID_FAN_DIV, - old); - } - } -} - -void adm9240_analog_out(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results) -{ - struct adm9240_data *data = client->data; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - adm9240_update_client(client); - results[0] = data->analog_out; - *nrels_mag = 1; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag >= 1) { - data->analog_out = results[0]; - i2c_smbus_write_byte_data(client, - ADM9240_REG_ANALOG_OUT, - data->analog_out); - } - } -} - -void adm9240_vid(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct adm9240_data *data = client->data; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 2; - else if (operation == SENSORS_PROC_REAL_READ) { - adm9240_update_client(client); - results[0] = VID_FROM_REG(data->vid); - *nrels_mag = 1; - } -} - -static int __init sm_adm9240_init(void) -{ - printk("adm9240.o version %s (%s)\n", LM_VERSION, LM_DATE); - return i2c_add_driver(&adm9240_driver); -} - -static void __exit sm_adm9240_exit(void) -{ - i2c_del_driver(&adm9240_driver); -} - - -MODULE_AUTHOR("Frodo Looijaard " - "and Philip Edelbrock "); -MODULE_LICENSE("GPL"); -MODULE_DESCRIPTION("ADM9240 driver"); - -module_init(sm_adm9240_init); -module_exit(sm_adm9240_exit); diff --git a/kernel/chips/asb100.c b/kernel/chips/asb100.c deleted file mode 100644 index 993cb7db..00000000 --- a/kernel/chips/asb100.c +++ /dev/null @@ -1,1010 +0,0 @@ -/* - asb100.c - Part of lm_sensors, Linux kernel modules for hardware - monitoring - - Copyright (c) 2003 Mark M. Hoffman - - (derived from w83781d.c) - - Copyright (c) 1998 - 2003 Frodo Looijaard , - Philip Edelbrock , and - Mark Studebaker - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -/* - This driver supports the hardware sensor chips: Asus ASB100 and - ASB100-A "BACH". - - ASB100-A supports pwm1, while plain ASB100 does not. There is no known - way for the driver to tell which one is there. - - Chip #vin #fanin #pwm #temp wchipid vendid i2c ISA - asb100 7 3 1 4 0x31 0x0694 yes no -*/ - -//#define DEBUG 1 - -#include -#include -#include -#include -#include -#include "version.h" -#include "sensors_vid.h" -#include "lm75.h" - -#ifndef I2C_DRIVERID_ASB100 -#define I2C_DRIVERID_ASB100 1043 -#endif - -/* I2C addresses to scan */ -static unsigned short normal_i2c[] = { 0x2d, SENSORS_I2C_END }; -static unsigned short normal_i2c_range[] = { SENSORS_I2C_END }; - -/* ISA addresses to scan (none) */ -static unsigned int normal_isa[] = { SENSORS_ISA_END }; -static unsigned int normal_isa_range[] = { SENSORS_ISA_END }; - -/* default VRM to 9.0 */ -#define ASB100_DEFAULT_VRM 90 - -/* Insmod parameters */ -SENSORS_INSMOD_1(asb100); -SENSORS_MODULE_PARM(force_subclients, "List of subclient addresses: " \ - "{bus, clientaddr, subclientaddr1, subclientaddr2}"); - -/* Voltage IN registers 0-6 */ -#define ASB100_REG_IN(nr) (0x20 + (nr)) -#define ASB100_REG_IN_MAX(nr) (0x2b + (nr * 2)) -#define ASB100_REG_IN_MIN(nr) (0x2c + (nr * 2)) - -/* FAN IN registers 1-3 */ -#define ASB100_REG_FAN(nr) (0x27 + (nr)) -#define ASB100_REG_FAN_MIN(nr) (0x3a + (nr)) - -/* TEMPERATURE registers 1-4 */ -static const u16 asb100_reg_temp[] = {0, 0x27, 0x150, 0x250, 0x17}; -static const u16 asb100_reg_temp_max[] = {0, 0x39, 0x155, 0x255, 0x18}; -static const u16 asb100_reg_temp_hyst[] = {0, 0x3a, 0x153, 0x253, 0x19}; - -#define ASB100_REG_TEMP(nr) (asb100_reg_temp[nr]) -#define ASB100_REG_TEMP_MAX(nr) (asb100_reg_temp_max[nr]) -#define ASB100_REG_TEMP_HYST(nr) (asb100_reg_temp_hyst[nr]) - -#define ASB100_REG_TEMP2_CONFIG 0x0152 -#define ASB100_REG_TEMP3_CONFIG 0x0252 - - -#define ASB100_REG_CONFIG 0x40 -#define ASB100_REG_ALARM1 0x41 -#define ASB100_REG_ALARM2 0x42 -#define ASB100_REG_SMIM1 0x43 -#define ASB100_REG_SMIM2 0x44 -#define ASB100_REG_VID_FANDIV 0x47 -#define ASB100_REG_I2C_ADDR 0x48 -#define ASB100_REG_CHIPID 0x49 -#define ASB100_REG_I2C_SUBADDR 0x4a -#define ASB100_REG_PIN 0x4b -#define ASB100_REG_IRQ 0x4c -#define ASB100_REG_BANK 0x4e -#define ASB100_REG_CHIPMAN 0x4f - -#define ASB100_REG_WCHIPID 0x58 - -/* bit 7 -> enable, bits 0-3 -> duty cycle */ -#define ASB100_REG_PWM1 0x59 - -/* CONVERSIONS - Rounding and limit checking is only done on the TO_REG variants. */ - -/* These constants are a guess, consistent w/ w83781d */ -#define ASB100_IN_MIN ( 0) -#define ASB100_IN_MAX (408) - -/* IN: 1/100 V (0V to 4.08V) - REG: 16mV/bit */ -static u8 IN_TO_REG(unsigned val) -{ - unsigned nval = SENSORS_LIMIT(val, ASB100_IN_MIN, ASB100_IN_MAX); - return (nval * 10 + 8) / 16; -} - -static unsigned IN_FROM_REG(u8 reg) -{ - return (reg * 16 + 5) / 10; -} - -static u8 FAN_TO_REG(long rpm, int div) -{ - if (rpm == 0) - return 255; - rpm = SENSORS_LIMIT(rpm, 1, 1000000); - return SENSORS_LIMIT((1350000 + rpm * div / 2) / (rpm * div), 1, 254); -} - -static int FAN_FROM_REG(u8 val, int div) -{ - return val==0 ? -1 : val==255 ? 0 : 1350000/(val*div); -} - -/* These constants are a guess, consistent w/ w83781d */ -#define ASB100_TEMP_MIN (-1280) -#define ASB100_TEMP_MAX ( 1270) - -/* TEMP: 1/10 degrees C (-128C to +127C) - REG: 1C/bit, two's complement */ -static u8 TEMP_TO_REG(int temp) -{ - int ntemp = SENSORS_LIMIT(temp, ASB100_TEMP_MIN, ASB100_TEMP_MAX); - ntemp += (ntemp<0 ? -5 : 5); - return (u8)(ntemp / 10); -} - -static int TEMP_FROM_REG(u8 reg) -{ - return (s8)reg * 10; -} - -/* PWM: 0 - 255 per sensors documentation - REG: (6.25% duty cycle per bit) */ -static u8 ASB100_PWM_TO_REG(int pwm) -{ - pwm = SENSORS_LIMIT(pwm, 0, 255); - return (u8)(pwm / 16); -} - -static int ASB100_PWM_FROM_REG(u8 reg) -{ - return reg * 16; -} - -#define ALARMS_FROM_REG(val) (val) - -#define DIV_FROM_REG(val) (1 << (val)) - -/* FAN DIV: 1, 2, 4, or 8 (defaults to 2) - REG: 0, 1, 2, or 3 (respectively) (defaults to 1) */ -static u8 DIV_TO_REG(long val) -{ - return val==8 ? 3 : val==4 ? 2 : val==1 ? 0 : 1; -} - -/* For each registered client, we need to keep some data in memory. That - data is pointed to by client->data. The structure itself is - dynamically allocated, at the same time the client itself is allocated. */ -struct asb100_data { - struct i2c_client client; - struct semaphore lock; - int sysctl_id; - enum chips type; - - struct semaphore update_lock; - unsigned long last_updated; /* In jiffies */ - - /* array of 2 pointers to subclients */ - struct i2c_client *lm75[2]; - - char valid; /* !=0 if following fields are valid */ - u8 in[7]; /* Register value */ - u8 in_max[7]; /* Register value */ - u8 in_min[7]; /* Register value */ - u8 fan[3]; /* Register value */ - u8 fan_min[3]; /* Register value */ - u16 temp[4]; /* Register value (0 and 3 are u8 only) */ - u16 temp_max[4]; /* Register value (0 and 3 are u8 only) */ - u16 temp_hyst[4]; /* Register value (0 and 3 are u8 only) */ - u8 fan_div[3]; /* Register encoding, right justified */ - u8 pwm; /* Register encoding */ - u8 vid; /* Register encoding, combined */ - u32 alarms; /* Register encoding, combined */ - u8 vrm; -}; - -static int asb100_attach_adapter(struct i2c_adapter *adapter); -static int asb100_detect(struct i2c_adapter *adapter, int address, - unsigned short flags, int kind); -static int asb100_detach_client(struct i2c_client *client); - -static int asb100_read_value(struct i2c_client *client, u16 reg); -static void asb100_write_value(struct i2c_client *client, u16 reg, u16 val); -static void asb100_update_client(struct i2c_client *client); -static void asb100_init_client(struct i2c_client *client); - -static void asb100_in(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void asb100_fan(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void asb100_temp(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void asb100_temp_add(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void asb100_vid(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void asb100_vrm(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void asb100_alarms(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void asb100_fan_div(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void asb100_pwm(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); - -static struct i2c_driver asb100_driver = { - .name = "asb100", - .id = I2C_DRIVERID_ASB100, - .flags = I2C_DF_NOTIFY, - .attach_adapter = asb100_attach_adapter, - .detach_client = asb100_detach_client, -}; - -/* The /proc/sys entries */ -/* -- SENSORS SYSCTL START -- */ - -#define ASB100_SYSCTL_IN0 1000 /* Volts * 100 */ -#define ASB100_SYSCTL_IN1 1001 -#define ASB100_SYSCTL_IN2 1002 -#define ASB100_SYSCTL_IN3 1003 -#define ASB100_SYSCTL_IN4 1004 -#define ASB100_SYSCTL_IN5 1005 -#define ASB100_SYSCTL_IN6 1006 - -#define ASB100_SYSCTL_FAN1 1101 /* Rotations/min */ -#define ASB100_SYSCTL_FAN2 1102 -#define ASB100_SYSCTL_FAN3 1103 - -#define ASB100_SYSCTL_TEMP1 1200 /* Degrees Celsius * 10 */ -#define ASB100_SYSCTL_TEMP2 1201 -#define ASB100_SYSCTL_TEMP3 1202 -#define ASB100_SYSCTL_TEMP4 1203 - -#define ASB100_SYSCTL_VID 1300 /* Volts * 1000 */ -#define ASB100_SYSCTL_VRM 1301 - -#define ASB100_SYSCTL_PWM1 1401 /* 0-255 => 0-100% duty cycle */ - -#define ASB100_SYSCTL_FAN_DIV 2000 /* 1, 2, 4 or 8 */ -#define ASB100_SYSCTL_ALARMS 2001 /* bitvector */ - -#define ASB100_ALARM_IN0 0x0001 /* ? */ -#define ASB100_ALARM_IN1 0x0002 /* ? */ -#define ASB100_ALARM_IN2 0x0004 -#define ASB100_ALARM_IN3 0x0008 -#define ASB100_ALARM_TEMP1 0x0010 -#define ASB100_ALARM_TEMP2 0x0020 -#define ASB100_ALARM_FAN1 0x0040 -#define ASB100_ALARM_FAN2 0x0080 -#define ASB100_ALARM_IN4 0x0100 -#define ASB100_ALARM_IN5 0x0200 /* ? */ -#define ASB100_ALARM_IN6 0x0400 /* ? */ -#define ASB100_ALARM_FAN3 0x0800 -#define ASB100_ALARM_CHAS 0x1000 -#define ASB100_ALARM_TEMP3 0x2000 - -/* -- SENSORS SYSCTL END -- */ - -/* These files are created for each detected chip. This is just a template; - though at first sight, you might think we could use a statically - allocated list, we need some way to get back to the parent - which - is done through one of the 'extra' fields which are initialized - when a new copy is allocated. */ - -/* no datasheet - but we did get some hints from someone who - claimed to have the datasheet */ -#define ASB100_SYSCTL_IN(nr) {ASB100_SYSCTL_IN##nr, "in" #nr, NULL, 0, \ - 0644, NULL, &i2c_proc_real, &i2c_sysctl_real, NULL, &asb100_in} -#define ASB100_SYSCTL_FAN(nr) {ASB100_SYSCTL_FAN##nr, "fan" #nr, NULL, 0, \ - 0644, NULL, &i2c_proc_real, &i2c_sysctl_real, NULL, &asb100_fan} -#define ASB100_SYSCTL_TEMP(nr, func) {ASB100_SYSCTL_TEMP##nr, "temp" #nr, \ - NULL, 0, 0644, NULL, &i2c_proc_real, &i2c_sysctl_real, NULL, func} -static ctl_table asb100_dir_table_template[] = { - ASB100_SYSCTL_IN(0), - ASB100_SYSCTL_IN(1), - ASB100_SYSCTL_IN(2), - ASB100_SYSCTL_IN(3), - ASB100_SYSCTL_IN(4), - ASB100_SYSCTL_IN(5), - ASB100_SYSCTL_IN(6), - - ASB100_SYSCTL_FAN(1), - ASB100_SYSCTL_FAN(2), - ASB100_SYSCTL_FAN(3), - - ASB100_SYSCTL_TEMP(1, &asb100_temp), - ASB100_SYSCTL_TEMP(2, &asb100_temp_add), - ASB100_SYSCTL_TEMP(3, &asb100_temp_add), - ASB100_SYSCTL_TEMP(4, &asb100_temp), - - {ASB100_SYSCTL_VID, "vid", NULL, 0, 0444, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &asb100_vid}, - {ASB100_SYSCTL_VRM, "vrm", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &asb100_vrm}, - {ASB100_SYSCTL_FAN_DIV, "fan_div", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &asb100_fan_div}, - {ASB100_SYSCTL_ALARMS, "alarms", NULL, 0, 0444, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &asb100_alarms}, - {ASB100_SYSCTL_PWM1, "pwm1", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &asb100_pwm}, - {0} -}; - -/* This function is called when: - asb100_driver is inserted (when this module is loaded), for each - available adapter - when a new adapter is inserted (and asb100_driver is still present) - */ -static int asb100_attach_adapter(struct i2c_adapter *adapter) -{ - return i2c_detect(adapter, &addr_data, asb100_detect); -} - -static int asb100_detect_subclients(struct i2c_adapter *adapter, int address, - int kind, struct i2c_client *new_client) -{ - int i, id, err = 0; - struct asb100_data *data = new_client->data; - - data->lm75[0] = kmalloc(sizeof(struct i2c_client), GFP_KERNEL); - if (!(data->lm75[0])) { - err = -ENOMEM; - goto ERROR_SC_0; - } - memset(data->lm75[0], 0x00, sizeof(struct i2c_client)); - - data->lm75[1] = kmalloc(sizeof(struct i2c_client), GFP_KERNEL); - if (!(data->lm75[1])) { - err = -ENOMEM; - goto ERROR_SC_1; - } - memset(data->lm75[1], 0x00, sizeof(struct i2c_client)); - - id = i2c_adapter_id(adapter); - - if (force_subclients[0] == id && force_subclients[1] == address) { - for (i = 2; i <= 3; i++) { - if (force_subclients[i] < 0x48 || - force_subclients[i] > 0x4f) { - printk(KERN_ERR "asb100.o: invalid subclient " - "address %d; must be 0x48-0x4f\n", - force_subclients[i]); - goto ERROR_SC_2; - } - } - asb100_write_value(new_client, ASB100_REG_I2C_SUBADDR, - (force_subclients[2] & 0x07) | - ((force_subclients[3] & 0x07) <<4)); - data->lm75[0]->addr = force_subclients[2]; - data->lm75[1]->addr = force_subclients[3]; - } else { - int val = asb100_read_value(new_client, ASB100_REG_I2C_SUBADDR); - data->lm75[0]->addr = 0x48 + (val & 0x07); - data->lm75[1]->addr = 0x48 + ((val >> 4) & 0x07); - } - - if(data->lm75[0]->addr == data->lm75[1]->addr) { - printk(KERN_ERR "asb100.o: duplicate addresses 0x%x " - "for subclients\n", data->lm75[0]->addr); - goto ERROR_SC_2; - } - - for (i = 0; i <= 1; i++) { - data->lm75[i]->data = NULL; - data->lm75[i]->adapter = adapter; - data->lm75[i]->driver = &asb100_driver; - data->lm75[i]->flags = 0; - strcpy(data->lm75[i]->name, "asb100 subclient"); - } - - if ((err = i2c_attach_client(data->lm75[0]))) { - printk(KERN_ERR "asb100.o: Subclient %d registration " - "at address 0x%x failed.\n", i, data->lm75[0]->addr); - goto ERROR_SC_2; - } - - if ((err = i2c_attach_client(data->lm75[1]))) { - printk(KERN_ERR "asb100.o: Subclient %d registration " - "at address 0x%x failed.\n", i, data->lm75[1]->addr); - goto ERROR_SC_3; - } - - return 0; - -/* Undo inits in case of errors */ -ERROR_SC_3: - i2c_detach_client(data->lm75[0]); -ERROR_SC_2: - kfree(data->lm75[1]); -ERROR_SC_1: - kfree(data->lm75[0]); -ERROR_SC_0: - return err; -} - -static int asb100_detect(struct i2c_adapter *adapter, int address, - unsigned short flags, int kind) -{ - int err = 0; - struct i2c_client *new_client; - struct asb100_data *data; - - /* asb100 is SMBus only */ - if (i2c_is_isa_adapter(adapter)) { - pr_debug("asb100.o: detect failed, " - "cannot attach to legacy adapter!\n"); - goto ERROR0; - } - - if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) { - pr_debug("asb100.o: detect failed, " - "smbus byte data not supported!\n"); - goto ERROR0; - } - - /* OK. For now, we presume we have a valid client. We now create the - client structure, even though we cannot fill it completely yet. - But it allows us to access asb100_{read,write}_value. */ - - if (!(data = kmalloc(sizeof(struct asb100_data), GFP_KERNEL))) { - pr_debug("asb100.o: detect failed, kmalloc failed!\n"); - err = -ENOMEM; - goto ERROR0; - } - - new_client = &data->client; - new_client->addr = address; - init_MUTEX(&data->lock); - new_client->data = data; - new_client->adapter = adapter; - new_client->driver = &asb100_driver; - new_client->flags = 0; - - /* Now, we do the remaining detection. */ - - /* The chip may be stuck in some other bank than bank 0. This may - make reading other information impossible. Specify a force=... or - force_*=... parameter, and the chip will be reset to the right - bank. */ - if (kind < 0) { - - int val1 = asb100_read_value(new_client, ASB100_REG_BANK); - int val2 = asb100_read_value(new_client, ASB100_REG_CHIPMAN); - - /* If we're in bank 0 */ - if ( (!(val1 & 0x07)) && - /* Check for ASB100 ID (low byte) */ - ( ((!(val1 & 0x80)) && (val2 != 0x94)) || - /* Check for ASB100 ID (high byte ) */ - ((val1 & 0x80) && (val2 != 0x06)) ) ) { - pr_debug("asb100.o: detect failed, " - "bad chip id 0x%02x!\n", val2); - goto ERROR1; - } - - } /* kind < 0 */ - - /* We have either had a force parameter, or we have already detected - Winbond. Put it now into bank 0 and Vendor ID High Byte */ - asb100_write_value(new_client, ASB100_REG_BANK, - (asb100_read_value(new_client, ASB100_REG_BANK) & 0x78) | 0x80); - - /* Determine the chip type. */ - if (kind <= 0) { - int val1 = asb100_read_value(new_client, ASB100_REG_WCHIPID); - int val2 = asb100_read_value(new_client, ASB100_REG_CHIPMAN); - - if ((val1 == 0x31) && (val2 == 0x06)) - kind = asb100; - else { - if (kind == 0) - printk (KERN_WARNING "asb100.o: Ignoring " - "'force' parameter for unknown chip " - "at adapter %d, address 0x%02x.\n", - i2c_adapter_id(adapter), address); - goto ERROR1; - } - } - - /* Fill in remaining client fields and put it into the global list */ - strcpy(new_client->name, "ASB100 chip"); - data->type = kind; - - data->valid = 0; - init_MUTEX(&data->update_lock); - - /* Tell the I2C layer a new client has arrived */ - if ((err = i2c_attach_client(new_client))) - goto ERROR1; - - /* Attach secondary lm75 clients */ - if ((err = asb100_detect_subclients(adapter, address, kind, - new_client))) - goto ERROR2; - - /* Initialize the chip */ - asb100_init_client(new_client); - - /* Register a new directory entry with module sensors */ - if ((data->sysctl_id = i2c_register_entry(new_client, "asb100", - asb100_dir_table_template, THIS_MODULE)) < 0) { - err = data->sysctl_id; - goto ERROR3; - } - - return 0; - -ERROR3: - i2c_detach_client(data->lm75[0]); - kfree(data->lm75[1]); - kfree(data->lm75[0]); -ERROR2: - i2c_detach_client(new_client); -ERROR1: - kfree(data); -ERROR0: - return err; -} - -static int asb100_detach_client(struct i2c_client *client) -{ - int err; - struct asb100_data *data = client->data; - - /* remove sysctl table (primary client only) */ - if ((data)) - i2c_deregister_entry(data->sysctl_id); - - if ((err = i2c_detach_client(client))) { - printk (KERN_ERR "asb100.o: Client deregistration failed; " - "client not detached.\n"); - return err; - } - - if (data) { - /* primary client */ - kfree(data); - } else { - /* subclients */ - kfree(client); - } - - return 0; -} - -/* The SMBus locks itself, usually, but nothing may access the Winbond between - bank switches. ISA access must always be locked explicitly! - We ignore the W83781D BUSY flag at this moment - it could lead to deadlocks, - would slow down the W83781D access and should not be necessary. - There are some ugly typecasts here, but the good news is - they should - nowhere else be necessary! */ -static int asb100_read_value(struct i2c_client *client, u16 reg) -{ - struct asb100_data *data = client->data; - struct i2c_client *cl; - int res, bank; - - down(&data->lock); - - bank = (reg >> 8) & 0x0f; - if (bank > 2) - /* switch banks */ - i2c_smbus_write_byte_data(client, ASB100_REG_BANK, bank); - - if (bank == 0 || bank > 2) { - res = i2c_smbus_read_byte_data(client, reg & 0xff); - } else { - /* switch to subclient */ - cl = data->lm75[bank - 1]; - - /* convert from ISA to LM75 I2C addresses */ - switch (reg & 0xff) { - case 0x50: /* TEMP */ - res = swab16(i2c_smbus_read_word_data (cl, 0)); - break; - case 0x52: /* CONFIG */ - res = i2c_smbus_read_byte_data(cl, 1); - break; - case 0x53: /* HYST */ - res = swab16(i2c_smbus_read_word_data (cl, 2)); - break; - case 0x55: /* MAX */ - default: - res = swab16(i2c_smbus_read_word_data (cl, 3)); - break; - } - } - - if (bank > 2) - i2c_smbus_write_byte_data(client, ASB100_REG_BANK, 0); - - up(&data->lock); - - return res; -} - -static void asb100_write_value(struct i2c_client *client, u16 reg, u16 value) -{ - struct asb100_data *data = client->data; - struct i2c_client *cl; - int bank; - - down(&data->lock); - - bank = (reg >> 8) & 0x0f; - if (bank > 2) - /* switch banks */ - i2c_smbus_write_byte_data(client, ASB100_REG_BANK, bank); - - if (bank == 0 || bank > 2) { - i2c_smbus_write_byte_data(client, reg & 0xff, value & 0xff); - } else { - /* switch to subclient */ - cl = data->lm75[bank - 1]; - - /* convert from ISA to LM75 I2C addresses */ - switch (reg & 0xff) { - case 0x52: /* CONFIG */ - i2c_smbus_write_byte_data(cl, 1, value & 0xff); - break; - case 0x53: /* HYST */ - i2c_smbus_write_word_data(cl, 2, swab16(value)); - break; - case 0x55: /* MAX */ - i2c_smbus_write_word_data(cl, 3, swab16(value)); - break; - } - } - - if (bank > 2) - i2c_smbus_write_byte_data(client, ASB100_REG_BANK, 0); - - up(&data->lock); -} - -static void asb100_init_client(struct i2c_client *client) -{ - struct asb100_data *data = client->data; - - data->vrm = ASB100_DEFAULT_VRM; - - /* Start monitoring */ - asb100_write_value(client, ASB100_REG_CONFIG, - (asb100_read_value(client, ASB100_REG_CONFIG) & 0xf7) | 0x01); -} - -static void asb100_update_client(struct i2c_client *client) -{ - struct asb100_data *data = client->data; - int i; - - down(&data->update_lock); - - if (time_after(jiffies - data->last_updated, HZ + HZ / 2) || - time_before(jiffies, data->last_updated) || !data->valid) { - - pr_debug("asb100.o: starting device update...\n"); - - /* 7 voltage inputs */ - for (i = 0; i < 7; i++) { - data->in[i] = asb100_read_value(client, - ASB100_REG_IN(i)); - data->in_min[i] = asb100_read_value(client, - ASB100_REG_IN_MIN(i)); - data->in_max[i] = asb100_read_value(client, - ASB100_REG_IN_MAX(i)); - } - - /* 3 fan inputs */ - for (i = 1; i <= 3; i++) { - data->fan[i-1] = asb100_read_value(client, - ASB100_REG_FAN(i)); - data->fan_min[i-1] = asb100_read_value(client, - ASB100_REG_FAN_MIN(i)); - } - - /* 4 temperature inputs */ - for (i = 1; i <= 4; i++) { - data->temp[i-1] = asb100_read_value(client, - ASB100_REG_TEMP(i)); - data->temp_max[i-1] = asb100_read_value(client, - ASB100_REG_TEMP_MAX(i)); - data->temp_hyst[i-1] = asb100_read_value(client, - ASB100_REG_TEMP_HYST(i)); - } - - /* VID and fan divisors */ - i = asb100_read_value(client, ASB100_REG_VID_FANDIV); - data->vid = i & 0x0f; - data->vid |= (asb100_read_value(client, - ASB100_REG_CHIPID) & 0x01) << 4; - data->fan_div[0] = (i >> 4) & 0x03; - data->fan_div[1] = (i >> 6) & 0x03; - data->fan_div[2] = (asb100_read_value(client, - ASB100_REG_PIN) >> 6) & 0x03; - - /* PWM */ - data->pwm = asb100_read_value(client, ASB100_REG_PWM1); - - /* alarms */ - data->alarms = asb100_read_value(client, ASB100_REG_ALARM1) + - (asb100_read_value(client, ASB100_REG_ALARM2) << 8); - - data->last_updated = jiffies; - data->valid = 1; - - pr_debug("asb100.o: ... update complete.\n"); - } - - up(&data->update_lock); -} - - -/* The next few functions are the call-back functions of the /proc/sys and - sysctl files. Which function is used is defined in the ctl_table in - the extra1 field. - Each function must return the magnitude (power of 10 to divide the date - with) if it is called with operation==SENSORS_PROC_REAL_INFO. It must - put a maximum of *nrels elements in results reflecting the data of this - file, and set *nrels to the number it actually put in it, if operation== - SENSORS_PROC_REAL_READ. Finally, it must get upto *nrels elements from - results and write them to the chip, if operations==SENSORS_PROC_REAL_WRITE. - Note that on SENSORS_PROC_REAL_READ, I do not check whether results is - large enough (by checking the incoming value of *nrels). This is not very - good practice, but as long as you put less than about 5 values in results, - you can assume it is large enough. */ -static void asb100_in(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct asb100_data *data = client->data; - int nr = ctl_name - ASB100_SYSCTL_IN0; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 2; - else if (operation == SENSORS_PROC_REAL_READ) { - asb100_update_client(client); - results[0] = IN_FROM_REG(data->in_min[nr]); - results[1] = IN_FROM_REG(data->in_max[nr]); - results[2] = IN_FROM_REG(data->in[nr]); - *nrels_mag = 3; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag >= 1) { - data->in_min[nr] = IN_TO_REG(results[0]); - asb100_write_value(client, ASB100_REG_IN_MIN(nr), - data->in_min[nr]); - } - if (*nrels_mag >= 2) { - data->in_max[nr] = IN_TO_REG(results[1]); - asb100_write_value(client, ASB100_REG_IN_MAX(nr), - data->in_max[nr]); - } - } -} - -void asb100_fan(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct asb100_data *data = client->data; - int nr = ctl_name - ASB100_SYSCTL_FAN1 + 1; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - asb100_update_client(client); - results[0] = FAN_FROM_REG(data->fan_min[nr - 1], - DIV_FROM_REG(data->fan_div[nr - 1])); - results[1] = FAN_FROM_REG(data->fan[nr - 1], - DIV_FROM_REG(data->fan_div[nr - 1])); - *nrels_mag = 2; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag >= 1) { - data->fan_min[nr - 1] = - FAN_TO_REG(results[0], - DIV_FROM_REG(data->fan_div[nr-1])); - asb100_write_value(client, - ASB100_REG_FAN_MIN(nr), - data->fan_min[nr - 1]); - } - } -} - -void asb100_temp(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct asb100_data *data = client->data; - int nr = ctl_name - ASB100_SYSCTL_TEMP1; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 1; - - else if (operation == SENSORS_PROC_REAL_READ) { - asb100_update_client(client); - results[0] = TEMP_FROM_REG(data->temp_max[nr]); - results[1] = TEMP_FROM_REG(data->temp_hyst[nr]); - results[2] = TEMP_FROM_REG(data->temp[nr]); - *nrels_mag = 3; - - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag >= 1) { - data->temp_max[nr] = TEMP_TO_REG(results[0]); - asb100_write_value(client, ASB100_REG_TEMP_MAX(nr+1), - data->temp_max[nr]); - } - if (*nrels_mag >= 2) { - data->temp_hyst[nr] = TEMP_TO_REG(results[1]); - asb100_write_value(client, ASB100_REG_TEMP_HYST(nr+1), - data->temp_hyst[nr]); - } - } -} - -void asb100_temp_add(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results) -{ - struct asb100_data *data = client->data; - int nr = ctl_name - ASB100_SYSCTL_TEMP1; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 1; - - else if (operation == SENSORS_PROC_REAL_READ) { - asb100_update_client(client); - - results[0] = LM75_TEMP_FROM_REG(data->temp_max[nr]); - results[1] = LM75_TEMP_FROM_REG(data->temp_hyst[nr]); - results[2] = LM75_TEMP_FROM_REG(data->temp[nr]); - *nrels_mag = 3; - - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag >= 1) { - data->temp_max[nr] = - LM75_TEMP_TO_REG(results[0]); - asb100_write_value(client, ASB100_REG_TEMP_MAX(nr+1), - data->temp_max[nr]); - } - if (*nrels_mag >= 2) { - data->temp_hyst[nr] = - LM75_TEMP_TO_REG(results[1]); - asb100_write_value(client, ASB100_REG_TEMP_HYST(nr+1), - data->temp_hyst[nr]); - } - } -} - -void asb100_vid(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct asb100_data *data = client->data; - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 3; - else if (operation == SENSORS_PROC_REAL_READ) { - asb100_update_client(client); - results[0] = vid_from_reg(data->vid, data->vrm); - *nrels_mag = 1; - } -} - -void asb100_vrm(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct asb100_data *data = client->data; - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 1; - else if (operation == SENSORS_PROC_REAL_READ) { - results[0] = data->vrm; - *nrels_mag = 1; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag >= 1) - data->vrm = results[0]; - } -} - -void asb100_alarms(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct asb100_data *data = client->data; - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - asb100_update_client(client); - results[0] = ALARMS_FROM_REG(data->alarms); - *nrels_mag = 1; - } -} - -void asb100_fan_div(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results) -{ - struct asb100_data *data = client->data; - int old, old2; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - - else if (operation == SENSORS_PROC_REAL_READ) { - asb100_update_client(client); - results[0] = DIV_FROM_REG(data->fan_div[0]); - results[1] = DIV_FROM_REG(data->fan_div[1]); - results[2] = DIV_FROM_REG(data->fan_div[2]); - *nrels_mag = 3; - - } else if (operation == SENSORS_PROC_REAL_WRITE) { - old = asb100_read_value(client, ASB100_REG_VID_FANDIV); - if (*nrels_mag >= 3) { - data->fan_div[2] = DIV_TO_REG(results[2]); - old2 = asb100_read_value(client, ASB100_REG_PIN); - old2 = (old2 & 0x3f) | ((data->fan_div[2] & 0x03) << 6); - asb100_write_value(client, ASB100_REG_PIN, old2); - } - if (*nrels_mag >= 2) { - data->fan_div[1] = DIV_TO_REG(results[1]); - old = (old & 0x3f) | ((data->fan_div[1] & 0x03) << 6); - } - if (*nrels_mag >= 1) { - data->fan_div[0] = DIV_TO_REG(results[0]); - old = (old & 0xcf) | ((data->fan_div[0] & 0x03) << 4); - asb100_write_value(client, ASB100_REG_VID_FANDIV, old); - } - } -} - -void asb100_pwm(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct asb100_data *data = client->data; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - asb100_update_client(client); - results[0] = ASB100_PWM_FROM_REG(data->pwm & 0x0f); - results[1] = (data->pwm & 0x80) ? 1 : 0; - *nrels_mag = 2; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - u8 val = data->pwm; - if (*nrels_mag >= 1) { - val = 0x0f & ASB100_PWM_TO_REG(results[0]); - if (*nrels_mag >= 2) { - if (results[1]) - val |= 0x80; - else - val &= ~0x80; - } - asb100_write_value(client, ASB100_REG_PWM1, val); - } - } -} - -static int __init asb100_init(void) -{ - printk(KERN_INFO "asb100.o version %s (%s)\n", LM_VERSION, LM_DATE); - return i2c_add_driver(&asb100_driver); -} - -static void __exit asb100_exit(void) -{ - i2c_del_driver(&asb100_driver); -} - -MODULE_AUTHOR( "Mark M. Hoffman , " - "Frodo Looijaard , " - "Philip Edelbrock , and " - "Mark Studebaker "); - -MODULE_DESCRIPTION("ASB100 'Bach' driver"); -MODULE_LICENSE("GPL"); - -module_init(asb100_init); -module_exit(asb100_exit); - diff --git a/kernel/chips/bmcsensors.c b/kernel/chips/bmcsensors.c deleted file mode 100644 index 6cac49d5..00000000 --- a/kernel/chips/bmcsensors.c +++ /dev/null @@ -1,1133 +0,0 @@ -/* - bmcsensors.c - Part of lm_sensors, Linux kernel modules - for hardware monitoring - - Copyright (c) 2002 Mark D. Studebaker - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#include -#include -#include -#include -#include -#include -#include -/* for kernel thread ... */ -#include -#include -#include -#include -#include "version.h" - -/* -#define DEBUG 1 -*/ - -struct bmcsensors_data { - int sysctl_id; - - struct semaphore update_lock; - char valid; /* !=0 if following fields are valid */ - unsigned long last_updated; /* In jiffies */ - - u8 alarms; -}; - - -static int bmcsensors_attach_adapter(struct i2c_adapter *adapter); -static int bmcsensors_detect(struct i2c_adapter *adapter, int address, - unsigned short flags, int kind); -static int bmcsensors_detach_client(struct i2c_client *client); -static int bmcsensors_command(struct i2c_client *client, unsigned int cmd, - void *arg); - -static void bmcsensors_update_client(struct i2c_client *client); -static void bmcsensors_reserve_sdr(void); -static void bmc_do_pause(unsigned int amount); /* YJ for debug */ - - -static void bmcsensors_all(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -#if 0 -static void bmcsensors_alarms(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void bmcsensors_fan_div(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void bmcsensors_pwm(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -#endif -static void bmcsensors_get_sdr(u16 resid, u16 record, u8 offset); -static void bmcsensors_get_reading(struct i2c_client *client, int i); - -static struct i2c_driver bmcsensors_driver = { - .name = "BMC Sensors driver", - .id = I2C_DRIVERID_BMCSENSORS, - .flags = I2C_DF_NOTIFY, - .attach_adapter = bmcsensors_attach_adapter, - .detach_client = bmcsensors_detach_client, - .command = bmcsensors_command, -}; - -static struct bmcsensors_data bmc_data; -static struct i2c_client bmc_client = { - .name = "BMC Sensors", - .id = 1, /* fake should be 0 */ - .driver = &bmcsensors_driver, - .data = &bmc_data, -}; - -static int bmcsensors_initialized; - -#define MAX_SDR_ENTRIES 100 -#define SDR_LIMITS 8 -#define SDR_MAX_ID_LENGTH 16 -#define SDR_MAX_UNPACKED_ID_LENGTH ((SDR_MAX_ID_LENGTH * 4 / 3) + 2) -struct sdrdata { - /* reverse lookup from sysctl */ - int sysctl; - /* retrieved from SDR, not expected to change */ - u8 stype; - u8 number; - u8 capab; - u16 thresh_mask; - u8 format; - u8 linear; - s16 m; - s16 b; - u8 k; - u8 nominal; - u8 limits[SDR_LIMITS]; - int lim1, lim2; /* index into limits for reported upper and lower limit */ - u8 lim1_write, lim2_write; - u8 string_type; - u8 id_length; - u8 id[SDR_MAX_ID_LENGTH]; - /* retrieved from reading */ - u8 reading; - u8 status; - u8 thresholds; -}; -static struct sdrdata sdrd[MAX_SDR_ENTRIES]; -static int sdrd_count; - - -/* -- SENSORS SYSCTL START -- */ -#define BMC_SYSCTL_IN1 1000 -#define BMC_SYSCTL_TEMP1 1100 -#define BMC_SYSCTL_CURR1 1200 -#define BMC_SYSCTL_FAN1 1300 -#define BMC_SYSCTL_ALARMS 5000 - -/* -- SENSORS SYSCTL END -- */ - -#define MAX_PROC_ENTRIES (MAX_SDR_ENTRIES + 5) -#define MAX_PROCNAME_SIZE 8 -static ctl_table *bmcsensors_dir_table; -static char *bmcsensors_proc_name_pool; - -#define IPMI_SDR_SIZE 67 -#define IPMI_CHUNK_SIZE 16 -static int ipmi_sdr_partial_size = IPMI_CHUNK_SIZE; -static struct ipmi_msg tx_message; /* send message */ -static unsigned char tx_msg_data[IPMI_MAX_MSG_LENGTH + 50]; -static unsigned char rx_msg_data[IPMI_MAX_MSG_LENGTH + 50]; /* sloppy */ -static int rx_msg_data_offset; -static int msgid; /* API to IPMI is long but we'll let i2c-ipmi convert */ -static u16 resid; -static u16 nextrecord; -static int errorcount; - -enum states {STATE_INIT, STATE_RESERVE, STATE_SDR, STATE_SDRPARTIAL, - STATE_READING, STATE_UNCANCEL, STATE_PROCTABLE, STATE_DONE}; -/* YJ : added extra state STATE_PROCTABLE for thread activity */ -static int state; -static int receive_counter; - - -/* IPMI Message defs */ -/* Network Function Codes */ -#define IPMI_NETFN_SENSOR 0x04 -#define IPMI_NETFN_STORAGE 0x0A -/* Commands */ -#define IPMI_RESERVE_SDR 0x22 -#define IPMI_GET_SDR 0x23 -#define IPMI_GET_SENSOR_STATE_READING 0x2D - -/* SDR defs */ -#define STYPE_TEMP 0x01 -#define STYPE_VOLT 0x02 -#define STYPE_CURR 0x03 -#define STYPE_FAN 0x04 - -/* do we really need maximums per-type? */ -#define STYPE_MAX 4 /* the last sensor type we are interested in */ -static u8 bmcs_count[STYPE_MAX + 1]; -static const u8 bmcs_max[STYPE_MAX + 1] = {0, 20, 40, 20, 20}; -/* YJ: on poweredge 1750, we need ^^ */ - -/************************************/ -/* YJ ... */ -static int thread_pid= 0; -static DECLARE_MUTEX_LOCKED(bmc_sem); -/* ... YJ */ -/************************************/ - -/* unpack based on string type, convert to normal, null terminate */ -static void ipmi_sprintf(u8 * to, u8 * from, u8 type, u8 length) -{ - static const u8 *bcdplus = "0123456789 -.:,_"; - int i; - - switch (type) { - case 0: /* unicode */ - for(i = 0; i < length; i++) - *to++ = *from++ & 0x7f; - *to = 0; - break; - case 1: /* BCD Plus */ - for(i = 0; i < length; i++) - *to++ = bcdplus[*from++ & 0x0f]; - *to = 0; - break; - case 2: /* packed ascii */ /* if not a mult. of 3 this will run over */ - for(i = 0; i < length; i += 3) { - *to++ = *from & 0x3f; - *to++ = *from >> 6 | ((*(from+1) & 0xf) << 2); - from++; - *to++ = *from >> 4 | ((*(from+1) & 0x3) << 4); - from++; - *to++ = (*from++ >> 2) & 0x3f; - } - *to = 0; - break; - case 3: /* normal */ - if(length > 1) - memcpy(to, from, length); - to[length] = 0; - break; - } -} - -static const char * threshold_text[] = { - "upper non-recoverable threshold", - "upper critical threshold", - "upper non-critical threshold", - "lower non-recoverable threshold", - "lower critical threshold", - "lower non-critical threshold", - "positive-going hysteresis", - "negative-going hysteresis" /* unused */ -}; - -/* select two out of the 8 possible readable thresholds, and place indexes into the limits - array into lim1 and lim2. Set writable flags */ -static void bmcsensors_select_thresholds(struct sdrdata * sd) -{ - u8 capab = sd->capab; - u16 mask = sd->thresh_mask; - int tmp; - - sd->lim1 = -1; - sd->lim2 = -1; - sd->lim1_write = 0; - sd->lim2_write = 0; - - if(((capab & 0x0c) == 0x04) || /* readable thresholds ? */ - ((capab & 0x0c) == 0x08)) { - /* select upper threshold */ - if(mask & 0x10) { /* upper crit */ - sd->lim1 = 1; - if((capab & 0x0c) == 0x08 && (mask & 0x1000)) - sd->lim1_write = 1; - } - else if(mask & 0x20) { /* upper non-recov */ - sd->lim1 = 0; - if((capab & 0x0c) == 0x08 && (mask & 0x2000)) - sd->lim1_write = 1; - } - else if(mask & 0x08) { /* upper non-crit */ - sd->lim1 = 2; - if((capab & 0x0c) == 0x08 && (mask & 0x0800)) - sd->lim1_write = 1; - } - - /* select lower threshold */ - if((((capab & 0x30) == 0x10) || /* readable ? */ - ((capab & 0x30) == 0x20)) && /* pos hyst */ - sd->stype == STYPE_TEMP) - sd->lim2 = 6; - else if(mask & 0x02) { /* lower crit */ - sd->lim2 = 4; - if((capab & 0x0c) == 0x08 && (mask & 0x0200)) - sd->lim2_write = 1; - } - else if(mask & 0x04) { /* lower non-recov */ - sd->lim2 = 3; - if((capab & 0x0c) == 0x08 && (mask & 0x0400)) - sd->lim2_write = 1; - } - else if(mask & 0x01) { /* lower non-crit */ - sd->lim2 = 5; - if((capab & 0x0c) == 0x08 && (mask & 0x0100)) - sd->lim2_write = 1; - } - } - - /* swap lim1/lim2 if m < 0 or function is 1/x (but not both!) */ - if((sd->m < 0 && sd->linear != 7) || (sd->m >= 0 && sd->linear == 7)) { - tmp = sd->lim1; - sd->lim1 = sd->lim2; - sd->lim2 = tmp; - } - - if(sd->lim1 >= 0) - printk(KERN_INFO "bmcsensors.o: using %s for upper limit\n", - threshold_text[sd->lim1]); -#ifdef DEBUG - else - printk(KERN_INFO "bmcsensors.o: no readable upper limit\n"); -#endif - if(sd->lim2 >= 0) - printk(KERN_INFO "bmcsensors.o: using %s for lower limit\n", - threshold_text[sd->lim2]); -#ifdef DEBUG - else - printk(KERN_INFO "bmcsensors.o: no readable lower limit\n"); -#endif -} - -/* After we have received all the SDR entries and picked out the ones - we are interested in, build a table of the /proc entries and register with i2c. -*/ -static void bmcsensors_build_proc_table(void) -{ - int i; - int temps = 0, volts = 0, currs = 0, fans = 0; - u8 id[SDR_MAX_UNPACKED_ID_LENGTH]; - - - printk(KERN_INFO "bmcsensors.o: building proc table\n"); - if(!(bmcsensors_dir_table = kmalloc((sdrd_count + 1) * sizeof(struct ctl_table), GFP_KERNEL))) { - printk(KERN_ERR "bmcsensors.o: no memory\n"); - return; /* do more than this */ /* ^^ add 1 or more for alarms, etc. */ - } - if(!(bmcsensors_proc_name_pool = kmalloc((sdrd_count + 0) * MAX_PROCNAME_SIZE, GFP_KERNEL))) { - kfree(bmcsensors_dir_table); - printk(KERN_ERR "bmcsensors.o: no memory\n"); - return; /* do more than this */ /* ^^ add 1 or more for alarms, etc. */ - } - - for(i = 0; i < sdrd_count; i++) { - bmcsensors_dir_table[i].procname = bmcsensors_proc_name_pool + (i * MAX_PROCNAME_SIZE); - bmcsensors_dir_table[i].data = NULL; - bmcsensors_dir_table[i].maxlen = 0; - bmcsensors_dir_table[i].child = NULL; - bmcsensors_dir_table[i].proc_handler = &i2c_proc_real; - bmcsensors_dir_table[i].strategy = &i2c_sysctl_real; - bmcsensors_dir_table[i].de = NULL; - - switch(sdrd[i].stype) { - case(STYPE_TEMP) : - bmcsensors_dir_table[i].ctl_name = BMC_SYSCTL_TEMP1 + temps; - sprintf((char *)bmcsensors_dir_table[i].procname, "temp%d", ++temps); - bmcsensors_dir_table[i].extra1 = &bmcsensors_all; - break; - case(STYPE_VOLT) : - bmcsensors_dir_table[i].ctl_name = BMC_SYSCTL_IN1 + volts; - sprintf((char *)bmcsensors_dir_table[i].procname, "in%d", ++volts); - bmcsensors_dir_table[i].extra1 = &bmcsensors_all; - break; - case(STYPE_CURR) : - bmcsensors_dir_table[i].ctl_name = BMC_SYSCTL_CURR1 + currs; - sprintf((char *)bmcsensors_dir_table[i].procname, "curr%d", ++currs); - bmcsensors_dir_table[i].extra1 = &bmcsensors_all; - break; - case(STYPE_FAN) : - bmcsensors_dir_table[i].ctl_name = BMC_SYSCTL_FAN1 + fans; - sprintf((char *)bmcsensors_dir_table[i].procname, "fan%d", ++fans); - bmcsensors_dir_table[i].extra1 = &bmcsensors_all; - break; - default: /* ?? */ - printk(KERN_INFO "bmcsensors.o: unk stype\n"); - continue; - } - sdrd[i].sysctl = bmcsensors_dir_table[i].ctl_name; - printk(KERN_INFO "bmcsensors.o: registering sensor %d: (type 0x%.2x) " - "(fmt=%d; m=%d; b=%d; k1=%d; k2=%d; cap=0x%.2x; mask=0x%.4x)\n", - i, sdrd[i].stype, sdrd[i].format, - sdrd[i].m, sdrd[i].b,sdrd[i].k & 0xf, sdrd[i].k >> 4, - sdrd[i].capab, sdrd[i].thresh_mask); - if(sdrd[i].id_length > 0) { - ipmi_sprintf(id, sdrd[i].id, sdrd[i].string_type, sdrd[i].id_length); - printk(KERN_INFO "bmcsensors.o: sensors.conf: label %s \"%s\"\n", - bmcsensors_dir_table[i].procname, id); - } - bmcsensors_select_thresholds(sdrd + i); - if(sdrd[i].linear != 0 && sdrd[i].linear != 7) { - printk(KERN_INFO - "bmcsensors.o: sensor %d: nonlinear function 0x%.2x unsupported, expect bad results\n", - i, sdrd[i].linear); - } - if((sdrd[i].format & 0x03) == 0x02) { - printk(KERN_INFO - "bmcsensors.o: sensor %d: 1's complement format unsupported, expect bad results\n", - i); - } else if((sdrd[i].format & 0x03) == 0x03) { - printk(KERN_INFO - "bmcsensors.o: sensor %d: threshold sensor only, no readings available", - i); - } - if(sdrd[i].lim1_write || sdrd[i].lim2_write) - bmcsensors_dir_table[i].mode = 0644; - else - bmcsensors_dir_table[i].mode = 0444; - } - bmcsensors_dir_table[sdrd_count].ctl_name = 0; - - if ((i = i2c_register_entry(&bmc_client, "bmc", - bmcsensors_dir_table, - THIS_MODULE)) < 0) { - printk(KERN_INFO "bmcsensors.o: i2c registration failed.\n"); - kfree(bmcsensors_dir_table); - kfree(bmcsensors_proc_name_pool); - return; - } - bmcsensors_initialized = 3; - bmc_data.sysctl_id = i; - - printk(KERN_INFO "bmcsensors.o: %d reservations cancelled\n", errorcount); - printk(KERN_INFO "bmcsensors.o: registered %d temp, %d volt, %d current, %d fan sensors\n", - temps, volts, currs, fans); -/* - This completes the initialization. The first userspace read - of a /proc value will force the first - bmcsensors_update_client() which starts the - reading of the sensors themselves via IPMI messages. -*/ -} - - -/* Process a sensor reading response */ -static int bmcsensors_rcv_reading_msg(struct ipmi_msg *msg) -{ - if(receive_counter >= sdrd_count) { - /* shouldn't happen */ - receive_counter = 0; - return STATE_DONE; - } - sdrd[receive_counter].reading = msg->data[1]; - sdrd[receive_counter].status = msg->data[2]; - sdrd[receive_counter].thresholds = msg->data[3]; -#ifdef DEBUG - printk(KERN_DEBUG "bmcsensors.o: sensor %d (type %d) reading %d\n", - receive_counter, sdrd[receive_counter].stype, msg->data[1]); -#endif - if(++receive_counter >= sdrd_count) { - receive_counter = 0; - return STATE_DONE; - } - /* don't really need to pass client */ - bmcsensors_get_reading(&bmc_client, receive_counter); - return STATE_READING; -} - -/* Process an SDR response, save the SDR's we like in the sdrd table */ -static int bmcsensors_rcv_sdr_msg(struct ipmi_msg *msg, int state) -{ - u16 record; - int type; - int stype; - int id_length; - int i; - int rstate = STATE_SDR; - int ipmi_ver = 0; - unsigned char * data; - u8 id[SDR_MAX_UNPACKED_ID_LENGTH]; - - - if(msg->data[0] != 0) { - /* cut request in half and try again */ - ipmi_sdr_partial_size /= 2; - if(ipmi_sdr_partial_size < 8) { - printk(KERN_INFO "bmcsensors.o: IPMI buffers too small, giving up\n"); - up (&bmc_sem); /* should wait for thread exit ! */ - return STATE_DONE; - } -#ifdef DEBUG - printk(KERN_INFO "bmcsensors.o: Reducing SDR request size to %d\n", ipmi_sdr_partial_size); -#endif - bmcsensors_get_sdr(0, 0, 0); - return STATE_SDR; - } - if(ipmi_sdr_partial_size < IPMI_SDR_SIZE) { - if(rx_msg_data_offset == 0) { - memcpy(rx_msg_data, msg->data, ipmi_sdr_partial_size + 3); - rx_msg_data_offset = ipmi_sdr_partial_size + 3; - } else { - memcpy(rx_msg_data + rx_msg_data_offset, msg->data + 3, ipmi_sdr_partial_size); - rx_msg_data_offset += ipmi_sdr_partial_size; - } - if(rx_msg_data_offset > rx_msg_data[7] + 7) { - /* got last chunk */ - rx_msg_data_offset = 0; - data = rx_msg_data; - } else { - /* get more */ - record = (rx_msg_data[4] << 8) | rx_msg_data[3]; - bmcsensors_get_sdr(resid, record, rx_msg_data_offset - 3); - return STATE_SDR; - } - } else { - data = msg->data; /* got it in one chunk */ - } - - nextrecord = (data[2] << 8) | data[1]; - /* printk(KERN_INFO "bmcsensors.o: nextrecord %d\n", nextrecord); */ - - - type = data[6]; - if(type == 1 || type == 2) { /* known SDR type */ -/* - version = data[5]; - owner = data[8]; - lun = data[9]; - entity = data[11]; - init = data[13]; -*/ - stype = data[(ipmi_ver == 0x90?16:15)]; - if(stype <= STYPE_MAX) { /* known sensor type */ - if(bmcs_count[stype] >= bmcs_max[stype]) { - if(bmcs_max[stype] > 0) - printk(KERN_INFO - "bmcsensors.o: Limit of %d exceeded for sensor type 0x%x\n", - bmcs_max[stype], stype); -#ifdef DEBUG - else - printk(KERN_INFO - "bmcsensors.o: Ignoring unsupported sensor type 0x%x\n", - stype); -#endif - } else if(sdrd_count >= MAX_SDR_ENTRIES) { - printk(KERN_INFO - "bmcsensors.o: Limit of %d exceeded for total sensors\n", - MAX_SDR_ENTRIES); - nextrecord = 0xffff; - } else if(data[(ipmi_ver == 0x90?17:16)] != 0x01) { - if(type == 1) - ipmi_sprintf(id, &data[51], data[50] >> 6, data[50] & 0x1f); - else - ipmi_sprintf(id, &data[(ipmi_ver == 0x90?30:35)], data[(ipmi_ver == 0x90?29:34)] >> 6, data[(ipmi_ver == 0x90?29:34)] & 0x1f); - printk(KERN_INFO - "bmcsensors.o: skipping non-threshold sensor \"%s\"\n", - id); - } else { - /* add entry to sdrd table */ - sdrd[sdrd_count].stype = stype; - sdrd[sdrd_count].number = data[10]; - sdrd[sdrd_count].capab = data[(ipmi_ver == 0x90?15:14)]; - sdrd[sdrd_count].thresh_mask = (((u16) data[(ipmi_ver == 0x90?21:22)]) << 8) | data[21]; - if(type == 1) { - sdrd[sdrd_count].format = data[(ipmi_ver == 0x90?22:24)] >> 6; - sdrd[sdrd_count].linear = data[(ipmi_ver == 0x90?25:26)] & 0x7f; - sdrd[sdrd_count].m = data[(ipmi_ver == 0x90?26:27)]; - sdrd[sdrd_count].m |= ((u16) (data[(ipmi_ver == 0x90?27:28)] & 0xc0)) << 2; - if(sdrd[sdrd_count].m & 0x0200) - sdrd[sdrd_count].m |= 0xfc00; /* sign extend */ - sdrd[sdrd_count].b = data[(ipmi_ver == 0x90?28:29)]; - sdrd[sdrd_count].b |= ((u16) (data[(ipmi_ver == 0x90?29:30)] & 0xc0)) << 2; - if(sdrd[sdrd_count].b & 0x0200) - sdrd[sdrd_count].b |= 0xfc00; /* sign extend */ - sdrd[sdrd_count].k = data[(ipmi_ver == 0x90?31:32)]; - sdrd[sdrd_count].nominal = data[(ipmi_ver == 0x90?33:34)]; - for(i = 0; i < SDR_LIMITS; i++) /* assume readable */ - sdrd[sdrd_count].limits[i] = data[(ipmi_ver == 0x90?40:39) + i]; - sdrd[sdrd_count].string_type = data[50] >> 6; - id_length = data[50] & 0x1f; - memcpy(sdrd[sdrd_count].id, &data[51], id_length); - sdrd[sdrd_count].id_length = id_length; - } else { - sdrd[sdrd_count].m = 1; - sdrd[sdrd_count].b = 0; - sdrd[sdrd_count].k = 0; - sdrd[sdrd_count].string_type = data[(ipmi_ver == 0x90?29:34)] >> 6; - id_length = data[34] & 0x1f; - if(id_length > 0) - memcpy(sdrd[sdrd_count].id, &data[(ipmi_ver == 0x90?30:35)], id_length); - sdrd[sdrd_count].id_length = id_length; - /* limits?? */ - if(ipmi_ver == 0x90){ - memcpy(sdrd[sdrd_count].id, &data[30], id_length); - sdrd[sdrd_count].id_length = id_length; - } - } - bmcs_count[stype]++; - sdrd_count++; - if (sdrd_count>=MAX_SDR_ENTRIES) nextrecord = 0xffff; /*YJ*/ - - } - } -#ifdef DEBUG - /* peek at the other SDR types */ - } else if(type == 0x10 || type == 0x11 || type == 0x12) { - ipmi_sprintf(id, data + 19, data[18]>>6, data[18] & 0x1f); - if(type == 0x10) { - printk(KERN_INFO "bmcsensors.o: Generic Device acc=0x%x; slv=0x%x; lun=0x%x; type=0x%x; \"%s\"\n", - data[8], data[9], data[10], data[13], id); - } else if(type == 0x11) { - printk(KERN_INFO "bmcsensors.o: FRU Device acc=0x%x; slv=0x%x; log=0x%x; ch=0x%x; type=0x%x; \"%s\"\n", - data[8], data[9], data[10], data[11], data[13], id); - } else { - printk(KERN_INFO "bmcsensors.o: Mgmt Ctllr Device slv=0x%x; \"%s\"\n", - data[8], id); - } - } else if(type == 0x14) { - printk(KERN_INFO "bmcsensors.o: Message Channel Info Records:\n"); - for(i = 0; i < 8; i++) { - printk(KERN_INFO "bmcsensors.o: Channel %d info 0x%x\n", - i, data[9 + i]); - } - } else { - printk(KERN_INFO "bmcsensors.o: Skipping SDR type 0x%x\n", type); -#endif - } - if (nextrecord>=6224) { - nextrecord = 0xffff; /*YJ stop sensor scan on poweredge 1750 */ - } - if (ipmi_ver != 0x90) { - if (nextrecord>=6224) { - nextrecord = 0xffff; /*YJ stop sensor scan on poweredge 1750 */ - } - } - - if(nextrecord == 0xFFFF) { - if(sdrd_count == 0) { - printk(KERN_INFO "bmcsensors.o: No recognized sensors found.\n"); - /* unregister?? */ - rstate = STATE_DONE; - up (&bmc_sem); /* should wait for thread exit !!! */ - } else { - /* YJ ...*/ - printk(KERN_INFO "bmcsensors.o: all sensors detected\n"); - rstate = STATE_PROCTABLE; - /* YJ bmcsensors_build_proc_table() call by thread */ - /* ... YJ */ - } - - } else { - - bmcsensors_get_sdr(0, nextrecord, 0); - } - return rstate; -} - -/* Process incoming messages based on internal state */ -static void bmcsensors_rcv_msg(struct ipmi_msg *msg) -{ - - switch(state) { - case STATE_INIT: - case STATE_RESERVE: - resid = (((u16)msg->data[2]) << 8) | msg->data[1]; -#ifdef DEBUG - printk(KERN_DEBUG "bmcsensors.o: Got first resid 0x%.4x\n", resid); -#endif - bmcsensors_get_sdr(0, 0, 0); - state = STATE_SDR; - break; - - case STATE_SDR: - case STATE_SDRPARTIAL: - state = bmcsensors_rcv_sdr_msg(msg, state); - /*YJ ...*/ - if (state==STATE_PROCTABLE){ - -#ifdef DEBUG - printk(KERN_DEBUG "releasing thread\n"); -#endif - - up (&bmc_sem); - } - /*YJ bmcsensors_build_proc_table() called by thread */ - /* ... YJ */ - break; - - case STATE_READING: - state = bmcsensors_rcv_reading_msg(msg); - break; - - case STATE_UNCANCEL: - resid = (((u16)msg->data[2]) << 8) | msg->data[1]; -#ifdef DEBUG - printk(KERN_DEBUG "bmcsensors.o: Got new resid 0x%.4x\n", resid); -#endif - rx_msg_data_offset = 0; - bmcsensors_get_sdr(0, nextrecord, 0); - state = STATE_SDR; - break; - - case STATE_DONE: - case STATE_PROCTABLE: - break; - - default: - state = STATE_INIT; - } -} - - -/* Incoming message handler */ -static void bmcsensors_msg_handler(struct ipmi_recv_msg *msg, - void * handler_data) -{ - if(state == STATE_SDR && msg->msg.data[0] == 0xc5) { - /* )(*&@(*&#@$ reservation cancelled, get new resid */ - if(++errorcount > 275) { - printk(KERN_ERR - "bmcsensors.o: Too many reservations cancelled, giving up\n"); - state = STATE_DONE; - up (&bmc_sem); /* YJ : should make sure thread exited ! */ - } else { -#ifdef DEBUG - printk(KERN_DEBUG - "bmcsensors.o: resid 0x%04x cancelled, getting new one\n", resid); -#endif - bmcsensors_reserve_sdr(); - state = STATE_UNCANCEL; - } - } else if (msg->msg.data[0] != 0 && msg->msg.data[0] != 0xca && - msg->msg.data[0] != 0xce) { - /* YJ : accept 0xce */ - printk(KERN_ERR - "bmcsensors.o: Error 0x%x on cmd 0x%x/0x%x; state = %d; probably fatal.\n", - msg->msg.data[0], msg->msg.netfn & 0xfe, msg->msg.cmd, state); - } else { - bmcsensors_rcv_msg(&(msg->msg)); - } - ipmi_free_recv_msg(msg); -} - -/* callback from i2c-ipmi */ -static int bmcsensors_command(struct i2c_client *client, unsigned int cmd, void *arg) -{ - bmcsensors_msg_handler((struct ipmi_recv_msg *) arg, NULL); - return 0; -} - -/************** Message Sending **************/ - -/* Send an IPMI message */ -static void bmcsensors_send_message(struct ipmi_msg * msg) -{ -#ifdef DEBUG - printk(KERN_INFO "bmcsensors.o: Send BMC msg, cmd: 0x%x\n", - msg->cmd); -#endif - bmc_client.adapter->algo->slave_send((struct i2c_adapter *) &bmc_client, - (char *) msg, msgid++); - -} - -/* Compose and send a "reserve SDR" message */ -static void bmcsensors_reserve_sdr(void) -{ - tx_message.netfn = IPMI_NETFN_STORAGE; - tx_message.cmd = IPMI_RESERVE_SDR; - tx_message.data_len = 0; - tx_message.data = NULL; - printk(KERN_INFO "bmcsensors.o: reserve_sdr...\n"); - bmcsensors_send_message(&tx_message); -} - -/* Componse and send a "get SDR" message */ -static void bmcsensors_get_sdr(u16 res_id, u16 record, u8 offset) -{ -#ifdef DEBUG - printk(KERN_DEBUG "bmcsensors.o: Get SDR 0x%x 0x%x 0x%x\n", - res_id, record, offset); -#endif - tx_message.netfn = IPMI_NETFN_STORAGE; - tx_message.cmd = IPMI_GET_SDR; - tx_message.data_len = 6; - tx_message.data = tx_msg_data; - tx_msg_data[0] = res_id & 0xff; - tx_msg_data[1] = res_id >> 8; - tx_msg_data[2] = record & 0xff; - tx_msg_data[3] = record >> 8; - tx_msg_data[4] = offset; - tx_msg_data[5] = ipmi_sdr_partial_size; - bmcsensors_send_message(&tx_message); -} - -/* Compose and send a "get sensor reading" message */ -static void bmcsensors_get_reading(struct i2c_client *client, int i) -{ - tx_message.netfn = IPMI_NETFN_SENSOR; - tx_message.cmd = IPMI_GET_SENSOR_STATE_READING; - tx_message.data_len = 1; - tx_message.data = tx_msg_data; - tx_msg_data[0] = sdrd[i].number; - bmcsensors_send_message(&tx_message); -} - -/**************** Initialization ****************/ - -static int bmcsensors_attach_adapter(struct i2c_adapter *adapter) -{ - printk(KERN_INFO "bmcsensors.o: attach_adapter...\n"); - - if(adapter->algo->id != I2C_ALGO_IPMI){ - printk(KERN_INFO "bmcsensors.o: attach_adapter, expected 0x%x, got 0x%x\n", I2C_ALGO_IPMI, adapter->algo->id); - return 0; - } - - if(bmcsensors_initialized >= 2) { - printk(KERN_INFO "bmcsensors.o: Additional IPMI adapter not supported\n"); - return 0; - } - - return bmcsensors_detect(adapter, 0, 0, 0); -} - -static int bmcsensors_detect(struct i2c_adapter *adapter, int address, - unsigned short flags, int kind) -{ - int err, i; - - bmc_client.id = 0; - bmc_client.adapter = adapter; - bmc_data.valid = 0; - - if ((err = i2c_attach_client(&bmc_client))) { - printk(KERN_ERR "attach client error in bmcsensors_detect()\n"); - return err; - } - bmcsensors_initialized = 2; - - state = STATE_INIT; - sdrd_count = 0; - receive_counter = 0; - rx_msg_data_offset = 0; - errorcount = 0; - ipmi_sdr_partial_size = IPMI_CHUNK_SIZE; - for(i = 0; i <= STYPE_MAX; i++) - bmcs_count[i] = 0; - - /* send our first message, which kicks things off */ - printk(KERN_INFO "bmcsensors.o: Registered client, scanning for sensors...\n"); - bmcsensors_reserve_sdr(); - /* don't call i2c_register_entry until we scan the SDR's */ - return 0; -} - -static int bmcsensors_detach_client(struct i2c_client *client) -{ - int err; - - if(bmcsensors_initialized >= 3) { - kfree(bmcsensors_dir_table); - kfree(bmcsensors_proc_name_pool); - i2c_deregister_entry(((struct bmcsensors_data *) (client->data))-> - sysctl_id); - } - - if ((err = i2c_detach_client(client))) { -/* - printk - ("bmcsensors.o: Client deregistration failed, client not detached.\n"); -*/ - return err; - } - - bmcsensors_initialized = 1; - return 0; -} - - -static void bmc_do_pause(unsigned int amount) -{ - current->state = TASK_INTERRUPTIBLE; - schedule_timeout(amount); -} - -static void bmcsensors_update_client(struct i2c_client *client) -{ - struct bmcsensors_data *data = client->data; - int j = 0; - -/* - down(&data->update_lock); -*/ - - /* if within 3 seconds you get old data */ - if ((jiffies - data->last_updated > 3 * HZ) || - (jiffies < data->last_updated) || !data->valid) { - /* don't start an update cycle if one already in progress */ - if(state != STATE_READING) { - state = STATE_READING; -#ifdef DEBUG - printk(KERN_DEBUG "bmcsensors.o: starting update\n"); -#endif - bmcsensors_get_reading(client, 0); - } - /* wait 4 seconds max */ - while(state == STATE_READING && j++ < 100) - bmc_do_pause(HZ / 25); -#ifdef DEBUG - printk(KERN_DEBUG "bmcsensors.o: update complete; j = %d\n", j); -#endif - data->last_updated = jiffies; - data->valid = 1; - } - -/* - up(&data->update_lock); -*/ -} - - -/************* /proc callback helper functions *********/ - -/* need better way to map from sysctl to sdrd record number */ -static struct sdrdata * find_sdrd(int sysctl) -{ - int i; - - for(i = 0; i < sdrd_count; i++) - if(sdrd[i].sysctl == sysctl) - return sdrd + i; - return NULL; -} - -/* IPMI V1.5 Section 30 */ -static const int exps[] = {1, 10, 100, 1000, 10000, 100000, 1000000, 10000000}; - -/* Return 0 for fan, 2 for temp, 3 for voltage - We could make it variable based on the accuracy (= log10(m * 10**k2)); - this would work for /proc output, however libsensors resolution - is statically set in lib/chips.c */ -static int decplaces(struct sdrdata *sd) -{ - switch(sd->stype) { - case STYPE_TEMP: - return 2; - case STYPE_CURR: - case STYPE_VOLT: - return 3; - case STYPE_FAN: - default: - return 0; - } -} - -/* convert a raw value to a reading. IMPI V1.5 Section 30 */ -/* 1/x is the only "linearization function" supported */ -static long conv_val(int value, struct sdrdata *sd) -{ - u8 k1, k2; - long r; - - r = value * sd->m; - k1 = sd->k & 0x0f; - k2 = sd->k >> 4; - if(k1 < 8) - r += sd->b * exps[k1]; - else - r += sd->b / exps[16 - k1]; - r *= exps[decplaces(sd)]; - if(k2 < 8) { - if(sd->linear != 7) - r *= exps[k2]; - else - // this will always truncate to 0: r = 1 / (exps[k2] * r); - r = 0; - } else { - if(sd->linear != 7) - r /= exps[16 - k2]; - else { - if(r != 0) - // 1 / x * 10 ** (-m) == 10 ** m / x - r = exps[16 - k2] / r; - else - r = 0; - } - } - return r; -} - - -/************** /proc callbacks *****************/ - -static void bmcsensors_all(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct sdrdata *sd; -/* - struct bmcsensors_data *data = client->data; -*/ - - if((sd = find_sdrd(ctl_name)) == NULL) { - *nrels_mag = 0; - return; - } - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = decplaces(sd); - else if (operation == SENSORS_PROC_REAL_READ) { - bmcsensors_update_client(client); - if(sd->lim2 >= 0) { - if(sd->stype == STYPE_TEMP) /* upper limit first */ - results[0] = - conv_val(sd->limits[sd->lim1], sd); - else /* lower limit first */ - results[0] = - conv_val(sd->limits[sd->lim2], sd); - } else - results[0] = 0; - if(sd->stype == STYPE_FAN) { /* lower limit only */ - results[1] = conv_val(sd->reading, sd); - *nrels_mag = 2; - } else { - if(sd->lim1 >= 0) { - if(sd->stype == STYPE_TEMP) { /* lower 2nd */ - results[1] = - conv_val(sd->limits[sd->lim2], sd); - if(sd->lim2 == 6) /* pos. thresh. */ - results[1] = results[0] - - results[1]; - } else /* upper 2nd */ - results[1] = - conv_val(sd->limits[sd->lim1], sd); - } else - results[1] = 0; - results[2] = conv_val(sd->reading, sd); - *nrels_mag = 3; - } - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag >= 1) { - /* unimplemented */ - } - } -} - -#if 0 -static void bmcsensors_alarms(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct bmcsensors_data *data = client->data; - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - bmcsensors_update_client(client); - results[0] = data->alarms; - *nrels_mag = 1; - } -} -#endif - -/* YJ ... */ -static int bmc_thread(void *dummy){ - - lock_kernel(); - daemonize(); - unlock_kernel(); - - strcpy(current->comm, "bmc-sensors"); - - if(down_interruptible(&bmc_sem)) { - - printk("exiting..."); - - thread_pid= 0; - up (&bmc_sem); - - return 0; - } - - if (state == STATE_PROCTABLE){ - - bmcsensors_build_proc_table(); - - state = STATE_DONE; - - printk(KERN_INFO "bmcsensors.o: bmcsensor thread done\n" ); - - } - - thread_pid= 0; - - up (&bmc_sem); - - return 0; -} -/* ... YJ */ - -static int __init sm_bmcsensors_init(void) -{ - printk(KERN_INFO "bmcsensors.o version %s (%s)\n", LM_VERSION, LM_DATE); - /* YJ ... */ - init_MUTEX_LOCKED(&bmc_sem); - - thread_pid= kernel_thread(bmc_thread, NULL, 0); - - if (thread_pid<0){ - printk(KERN_ERR "bmcsensors.o : Could not initialize bmc thread. Aborting\n"); - return 0; - } - /* ... YJ */ - - return i2c_add_driver(&bmcsensors_driver); -} - -static void __exit sm_bmcsensors_exit(void) -{ - int j; - j= 0; - /* YJ ... */ - printk(KERN_INFO "bmcsensors.o sleeping a while\n"); - while( (j++ < 50)){ - bmc_do_pause(HZ / 25); - } - if (thread_pid > 0){ - printk(KERN_INFO "bmcsensors.o stopping kernel thread\n"); - state= STATE_DONE; - j= 0; - up (&bmc_sem); - printk(KERN_INFO "bmcsensors.o waiting...\n"); - /* make sure kernel thread does not access driver memory any more */ - while((thread_pid > 0)&& (j++ < 100)){ - bmc_do_pause(HZ / 25); - } - printk(KERN_INFO "bmcsensors.o OK\n"); - } - j= 0; - /* sleep for debug... not necessary ? */ - printk(KERN_INFO "bmcsensors.o sleeping again\n"); - while( (j++ < 50)){ - bmc_do_pause(HZ / 25); - } - /* ...YJ */ - printk(KERN_INFO "bmcsensors.o i2c cleanup\n"); - i2c_del_driver(&bmcsensors_driver); -} - - - -MODULE_AUTHOR("Mark D. Studebaker "); -MODULE_DESCRIPTION("IPMI BMC sensors"); -MODULE_LICENSE("GPL"); - -module_init(sm_bmcsensors_init); -module_exit(sm_bmcsensors_exit); diff --git a/kernel/chips/bt869.c b/kernel/chips/bt869.c deleted file mode 100644 index aceea8d0..00000000 --- a/kernel/chips/bt869.c +++ /dev/null @@ -1,886 +0,0 @@ -/* - bt869.c - Part of lm_sensors, Linux kernel modules for hardware - monitoring - - Copyright (c) 1998, 1999 Frodo Looijaard - Copyright (c) 2001, 2002 Stephen Davies - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - - -#define DEBUG 1 - -#include -#include -#include -#include -#include -#include "version.h" - -MODULE_LICENSE("GPL"); - -/* Addresses to scan */ -static unsigned short normal_i2c[] = { SENSORS_I2C_END }; - -/* found only at 0x44 or 0x45 */ -static unsigned short normal_i2c_range[] = { 0x44, 0x45, SENSORS_I2C_END }; -static unsigned int normal_isa[] = { SENSORS_ISA_END }; -static unsigned int normal_isa_range[] = { SENSORS_ISA_END }; - -/* Insmod parameters */ -SENSORS_INSMOD_1(bt869); - -/* Many bt869 constants specified below */ - -/* The bt869 registers */ -/* Coming soon: Many, many registers */ - -/* Conversions. Rounding and limit checking is only done on the TO_REG - variants. Note that you should be a bit careful with which arguments - these macros are called: arguments may be evaluated more than once. - Fixing this is just not worth it. */ - - /*none */ - -/* Initial values */ -/*none*/ - -/* Each client has this additional data */ -struct bt869_data { - struct i2c_client client; - int sysctl_id; - - struct semaphore update_lock; - char valid; /* !=0 if following fields are valid */ - unsigned long last_updated; /* In jiffies */ - - u8 status[3]; /* Register values */ - u16 res[2]; /* Resolution XxY */ - u8 ntsc; /* 1=NTSC, 0=PAL */ - u8 half; /* go half res */ - u8 depth; /* screen depth */ - u8 colorbars; /* turn on/off colorbar calibration screen */ - u8 svideo; /* output format: (2=RGB) 1=SVIDEO, 0=Composite */ -}; - -static int bt869_attach_adapter(struct i2c_adapter *adapter); -static int bt869_detect(struct i2c_adapter *adapter, int address, - unsigned short flags, int kind); -static void bt869_init_client(struct i2c_client *client); -static int bt869_detach_client(struct i2c_client *client); -static int bt869_read_value(struct i2c_client *client, u8 reg); -static int bt869_write_value(struct i2c_client *client, u8 reg, u16 value); -static void bt869_write_values(struct i2c_client *client, u16 *values); -static void bt869_status(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void bt869_ntsc(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void bt869_res(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void bt869_half(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void bt869_colorbars(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void bt869_svideo(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void bt869_depth(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void bt869_update_client(struct i2c_client *client); - - -/* This is the driver that will be inserted */ -static struct i2c_driver bt869_driver = { - .name = "BT869 video-output chip driver", - .id = I2C_DRIVERID_BT869, - .flags = I2C_DF_NOTIFY, - .attach_adapter = bt869_attach_adapter, - .detach_client = bt869_detach_client, -}; - -/* -- SENSORS SYSCTL START -- */ -#define BT869_SYSCTL_STATUS 1000 -#define BT869_SYSCTL_NTSC 1001 -#define BT869_SYSCTL_HALF 1002 -#define BT869_SYSCTL_RES 1003 -#define BT869_SYSCTL_COLORBARS 1004 -#define BT869_SYSCTL_DEPTH 1005 -#define BT869_SYSCTL_SVIDEO 1006 - -/* -- SENSORS SYSCTL END -- */ - -/* These files are created for each detected bt869. This is just a template; - though at first sight, you might think we could use a statically - allocated list, we need some way to get back to the parent - which - is done through one of the 'extra' fields which are initialized - when a new copy is allocated. */ -static ctl_table bt869_dir_table_template[] = { - {BT869_SYSCTL_STATUS, "status", NULL, 0, 0444, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &bt869_status}, - {BT869_SYSCTL_NTSC, "ntsc", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &bt869_ntsc}, - {BT869_SYSCTL_RES, "res", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &bt869_res}, - {BT869_SYSCTL_HALF, "half", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &bt869_half}, - {BT869_SYSCTL_COLORBARS, "colorbars", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &bt869_colorbars}, - {BT869_SYSCTL_DEPTH, "depth", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &bt869_depth}, - {BT869_SYSCTL_SVIDEO, "svideo", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &bt869_svideo}, - {0} -}; - -/* ****************** - -720x576, 27.5MHz, PAL, no overscan compensation. - -This mode should be use for digital video, DVD playback etc. - -NOTE: This mode for PAL, see 720x480 for an equivalent NTSC mode -NOTE: -- Steve Davies - - -Compatible X modeline: - - Mode "720x576-BT869" - DotClock 27.5 - HTimings 720 744 800 880 - VTimings 576 581 583 625 - EndMode - - -625LINE=1 625 line output format -BST_AMP[7:0]=x57 87 Burst ampl. multiplication factor (PAL std??) -BY_PLL=0 Use the PLL -CATTENUATE[2:0]=0 No chroma attenuation -CCF1B1[7:0]=0 close caption stuff -CCF1B2[7:0]=0 close caption stuff -CCF2B1[7:0]=0 close caption stuff -CCF2B2[7:0]=0 close caption stuff -CCORING[2:0]=0 Bypass chroma coring -CCR_START[8:0]=0 [CCR_START[8]=0; CCR_START[7:0]=0] Close-caption clock runin start from hsync -CC_ADD[11:0]=xD2 210 [CC_ADD[11:8]=0; CC_ADD[7:0]=xD2] Close-caption DTO increment -CHECK_STAT=0 Don't check monitor status -CLPF[1:0]=0 Hoz chroma lowpass filter=Bypass -DACDISA=1 Disable DACA -DACDISB=0 Don't disable DACB -DACDISC=0 Don't disable DACC -DACOFF=0 Don't disable the DACs -DATDLY = 0 normal -DATSWP=0 normal -DCHROMA=0 Don't blank chroma -DIS_FFILT=1 Disable flickerfilter -DIS_GMSHC=1 Disable chroma psuedo-gamma removal -DIS_GMSHY=1 Disable luma pseudo gamma removal -DIS_GMUSHC=1 Disable chroma anti-pseudo gamma removal -DIS_GMUSHY=1 Disable luma anti-pseudo gamma removal -DIS_SCRESET=0 Normal subcarrier phase resets -DIS_YFLPF=0 Disable Luma initial hoz low pass filter -DIV2=0 Input pixel rate not divided by 2 -ECBAR=0 No colour bars -ECCF1=0 Disable closed caption -ECCF2=0 Disable closed caption -ECCGATE=0 Normal close caption encoding -ECLIP=0 0=disable clipping -EN_ASYNC=0 set to 0 for normal operation -EN_BLANKO=0 BLANK is an input -EN_DOT=0 Disables dot clock sync on BLANK pin -EN_OUT=1 Allows outputs to be enabled -EN_XCLK=1 Use CLKI pin as clock source -ESTATUS[1:0]=0 Used to select readback register -FIELDI=0 Logical 1 on FIELD indicates even field -F_SELC[2:0]=0 5 line chroma flickerfilter -F_SELY[2:0]=0 5 line luma flickerfilter -HBURST_BEGIN[7:0]=x98 152 Chroma burst start point in clocks -HBURST_END[7:0]=x58 88 Chroma burst end point in clocks - 128 -HSYNCI=0 Active low HSYNC -HSYNC_WIDTH[7:0]=x80 128 Analogue sync width in clocks -HSYNOFFSET[9:0]=0 [HSYNOFFSET[9:8]=0; HSYNOFFSET[7:0]=0] hsync in "standard position" -HSYNWIDTH[5:0]=2 2 pixel hsync width -H_ACTIVE[9:0]=x2D0 720 [H_ACTIVE[9:8]=2; H_ACTIVE[7:0]=xD0] Active pixels per line -H_BLANKI[8:0]=x84 132 [H_BLANKI[8]=0; H_BLANKI[7:0]=x84] End of blanking of input video -H_BLANKO[9:0]=x120 288 [H_BLANKO[9:8]=1; H_BLANKO[7:0]=x20] End of blanking from hoz sync leading edge -H_CLKI[10:0]=x378 888 [H_CLKI[10:8]=3; H_CLKI[7:0]=x78] Input line length total in clocks -H_CLKO[11:0]=x6e0 1760 [H_CLKO[11:8]=6; H_CLKO[7:0]=xe0] Output clocks per line -H_FRACT[7:0]=0 0 fractional input clocks per line -IN_MODE[2:0]=0 24Bit RGB muxed -LUMADLY[1:0]=0 0 pixel delay on Y_DLY luma -MCB[7:0]=x49 73 Mult factor for CB prior to subcarrier mod. -MCR[7:0]=x82 130 Mult factor for CR prior to subcarrier mod. -MODE2X=0 Don't divide clock input by 2 -MSC[31:0]=x2945E0B4 692445365 [MSC[31:24]=x29; MSC[23:16]=x45; MSC[15:8]=xE0; MSC[7:0]=xB4] Subcarrier incr. -MY[7:0]=x8C 140 Mult factor for Y -NI_OUT=0 Normal interlaced output -OUT_MODE[1:0]=0 video0-3 is CVBS, Y, C, Y_DLY -OUT_MUXA[1:0]=0 Don't care as DACA is disabled -OUT_MUXB[1:0]=1 Output video[1] (Y) on DACB -OUT_MUXC[1:0]=2 Output video[2] (C) on DACC -PAL_MD=1 Video output in PAL mode -PHASE_OFF[7:0]=0 Subcarrier phase offset -PLL_FRACT[15:0]=x30 48 [PLL_FRACT[15:8]=0x0; PLL_FRACT[7:0]=x30] frac portion of pll multiplier -PLL_INT[5:0]=0x0C 12 Int portion of pll multiplier -SETUP=0 7.5-IRE setup disabled -SLAVER=1 -SRESET=0 Don't do a software reset -SYNC_AMP[7:0]=xF0 240 Sync amp mult. factor (PAL std???) -VBLANKDLY=0 Extra line of blanking in 2nd field? -VSYNCI=0 Active low VSYNC -VSYNC_DUR=0 2.5line VSYNC duration on output -VSYNCOFFSET[10:0]=0 [VSYNOFFSET[10:8]=0; VSYNOFFSET[7:0]=0] VSYNC in standard position -VSYNWIDTH[2:0]=1 1 line of vsync width -V_ACTIVEI[9:0]=x240 576 [V_ACTIVEI[9:0]=2; V_ACTIVEI[7:0]=x40] Active input lines -V_ACTIVEO[8:0]=x122 290 [V_ACTIVE0[8]=1; V_ACTIVEO[7:0]=x22] -V_BLANKI[7:0]=x2A 42 Input lines from vsync to first active line -V_BLANKO[7:0]=x16 22 -V_LINESI[9:0]=x271 625 [V_LINESI[9:8]=2; V_LINESI[7:0]=x71] Number of input lines -V_SCALE[13:0]=x1000 4096 [V_SCALE[13:8]=x10; V_SCALE[7:0]=0] Vert scale coefficient="none"? -YATTENUATE[2:0]=0 no luma attenuation -YCORING[2:0]=0 Luma-coring bypass -YLPF[1:0]=0 Luma hoz low pass filter=bypass - -***************** */ - -static u16 registers_720_576[] = - { - 0x6e, 0x00, /* HSYNOFFSET[7:0]=0 */ - 0x70, 0x02, /* HSYNOFFSET[9:8]=0; HSYNWIDTH[5:0]=2 */ - 0x72, 0x00, /* VSYNOFFSET[7:0]=0 */ - 0x74, 0x01, /* DATDLY = 0; DATSWP=0; VSYNOFFSET[10:8]=0; VSYNWIDTH[2:0]=1 */ - 0x76, 0xe0, /* H_CLKO[7:0]=xe0 */ - 0x78, 0xd0, /* H_ACTIVE[7:0]=xD0 */ - 0x7a, 0x80, /* HSYNC_WIDTH[7:0]=x80 */ - 0x7c, 0x98, /* HBURST_BEGIN[7:0]=x98 */ - 0x7e, 0x58, /* HBURST_END[7:0]=x58 */ - 0x80, 0x20, /* H_BLANKO[7:0]=x20 */ - 0x82, 0x16, /* V_BLANKO[7:0]=x16 */ - 0x84, 0x22, /* V_ACTIVEO[7:0]=x22 */ - 0x86, 0xa6, /* V_ACTIVE0[8]=1; H_ACTIVE[9:8]=2; H_CLKO[11:8]=6 */ - 0x88, 0x00, /* H_FRACT[7:0]=0 */ - 0x8a, 0x78, /* H_CLKI[7:0]=x78 */ - 0x8c, 0x80, /* H_BLANKI[7:0]=x84 */ - 0x8e, 0x03, /* VBLANKDLY=0; H_BLANKI[8]=0; H_CLKI[10:8]=3 */ - 0x90, 0x71, /* V_LINESI[7:0]=x71 */ - 0x92, 0x2a, /* V_BLANKI[7:0]=x2A */ - 0x94, 0x40, /* V_ACTIVEI[7:0]=x40 */ - 0x96, 0x0a, /* CLPF[1:0]=0; YLPF[1:0]=0; V_ACTIVEI[9:0]=2; V_LINESI[9:8]=2 */ - 0x98, 0x00, /* V_SCALE[7:0]=0 */ - 0x9a, 0x50, /* H_BLANKO[9:8]=1; V_SCALE[13:8]=x10 */ - 0x9c, 0x30, /* PLL_FRACT[7:0]=x30 */ - 0x9e, 0x0, /* PLL_FRACT[15:8]=0x0 */ - 0xa0, 0x8c, /* EN_XCLK=1; BY_PLL=0; PLL_INT[5:0]=0x0C */ - 0xa2, 0x24, /* ECLIP=0; PAL_MD=1; DIS_SCRESET=0; VSYNC_DUR=0; 625LINE=1; SETUP=0; NI_OUT=0 */ - 0xa4, 0xf0, /* SYNC_AMP[7:0]=xF0 */ - 0xa6, 0x57, /* BST_AMP[7:0]=x57 */ - 0xa8, 0x82, /* MCR[7:0]=x82 */ - 0xaa, 0x49, /* MCB[7:0]=x49 */ - 0xac, 0x8c, /* MY[7:0]=x8C */ - 0xae, 0xb4, /* MSC[7:0]=xb4 */ - 0xb0, 0xe0, /* MSC[15:8]=xe0 */ - 0xb2, 0x45, /* MSC[23:16]=x45 */ - 0xb4, 0x29, /* MSC[31:24]=x29 */ - 0xb6, 0x00, /* PHASE_OFF[7:0]=0 */ - //0xba, 0x21, /* SRESET=0; CHECK_STAT=0; SLAVER=1; DACOFF=0; DACDISC=0; DACDISB=0; DACDISA=1 */ - 0xc4, 0x01, /* ESTATUS[1:0]=0; ECCF2=0; ECCF1=0; ECCGATE=0; ECBAR=0; DCHROMA=0; EN_OUT=1 */ - 0xc6, 0x00, /* EN_BLANKO=0; EN_DOT=0; FIELDI=0; VSYNCI=0; HSYNCI=0; IN_MODE[2:0]=0(24bRGB) */ - 0xc8, 0x40, /* DIS_YFLPF=0; DIS_FFILT=1; F_SELC[2:0]=0; F_SELY[2:0]=0 */ - 0xca, 0xc0, /* DIS_GMUSHY=1; DIS_GMSHY=1; YCORING[2:0]=0; YATTENUATE[2:0]=0 */ - 0xcc, 0xc0, /* DIS_GMUSHC=1; DIS_GMSHC=1; CCORING[2:0]=0; CATTENUATE[2:0]=0 */ - //0xce, 0x24, /* OUT_MUXC=2 [C]; OUT_MUXB=1 [Y]; OUT_MUXA=0 [CVBS, but disabled]*/ - //0xce, 0x04, /* OUT_MUXC=0 [CVBS]; OUT_MUXB=1 [Y]; OUT_MUXA=0 [CVBS, but disabled]*/ - 0xd6, 0x00, /* OUT_MODE[1:0]=0; LUMADLY[1:0]=0 */ - 0, 0 - }; - - -/* ****************** - -720x480, 27.5MHz, NTSC no overscan compensation. - -This mode should be use for digital video, DVD playback etc. - -NOTE: This mode for NTSC, see 720x576 for an equivalent PAL mode -NOTE: -- Steve Davies - -Compatible X modeline: - - Mode "720x480-BT869" - DotClock 27.5 - HTimings 720 744 800 872 - VTimings 480 483 485 525 - EndMode - - -625LINE=0 not 625 line output format -BST_AMP[7:0]=x74 116 Burst ampl. multiplication factor (NTSC std??) -BY_PLL=0 Use the PLL -CATTENUATE[2:0]=0 No chroma attenuation -CCF1B1[7:0]=0 close caption stuff -CCF1B2[7:0]=0 close caption stuff -CCF2B1[7:0]=0 close caption stuff -CCF2B2[7:0]=0 close caption stuff -CCORING[2:0]=0 Bypass chroma coring -CCR_START[8:0]=0 [CCR_START[8]=0; CCR_START[7:0]=0] Close-caption clock runin start from hsync -CC_ADD[11:0]=xD2 210 [CC_ADD[11:8]=0; CC_ADD[7:0]=xD2] Close-caption DTO increment -CHECK_STAT=0 Don't check monitor status -CLPF[1:0]=0 Hoz chroma lowpass filter=Bypass -DACDISA=1 Disable DACA -DACDISB=0 Don't disable DACB -DACDISC=0 Don't disable DACC -DACOFF=0 Don't disable the DACs -DATDLY = 0 normal -DATSWP=0 normal -DCHROMA=0 Don't blank chroma -DIS_FFILT=1 Disable flickerfilter -DIS_GMSHC=1 Disable chroma psuedo-gamma removal -DIS_GMSHY=1 Disable luma pseudo gamma removal -DIS_GMUSHC=1 Disable chroma anti-pseudo gamma removal -DIS_GMUSHY=1 Disable luma anti-pseudo gamma removal -DIS_SCRESET=0 Normal subcarrier phase resets -DIS_YFLPF=0 Disable Luma initial hoz low pass filter -DIV2=0 Input pixel rate not divided by 2 -ECBAR=0 No colour bars -ECCF1=0 Disable closed caption -ECCF2=0 Disable closed caption -ECCGATE=0 Normal close caption encoding -ECLIP=0 0=disable clipping -EN_ASYNC=0 set to 0 for normal operation -EN_BLANKO=0 BLANK is an input -EN_DOT=0 Disables dot clock sync on BLANK pin -EN_OUT=1 Allows outputs to be enabled -EN_XCLK=1 Use CLKI pin as clock source -ESTATUS[1:0]=0 Used to select readback register -FIELDI=0 Logical 1 on FIELD indicates even field -F_SELC[2:0]=0 5 line chroma flickerfilter -F_SELY[2:0]=0 5 line luma flickerfilter -HBURST_BEGIN[7:0]=x92 146 Chroma burst start point in clocks -HBURST_END[7:0]=x57 87 Chroma burst end point in clocks - 128 -HSYNCI=0 Active low HSYNC -HSYNC_WIDTH[7:0]=x80 128 Analogue sync width in clocks -HSYNOFFSET[9:0]=0 [HSYNOFFSET[9:8]=0; HSYNOFFSET[7:0]=0] hsync in "standard position" -HSYNWIDTH[5:0]=2 2 pixel hsync width -H_ACTIVE[9:0]=x2D0 720 [H_ACTIVE[9:8]=2; H_ACTIVE[7:0]=xD0] Active pixels per line -H_BLANKI[8:0]=x80 128 [H_BLANKI[8]=0; H_BLANKI[7:0]=x80] End of blanking of input video -H_BLANKO[9:0]=x102 258 [H_BLANKO[9:8]=1; H_BLANKO[7:0]=x2] End of blanking from hoz sync leading edge -H_CLKI[10:0]=x368 872 [H_CLKI[10:8]=3; H_CLKI[7:0]=x68] Input line length total in clocks -H_CLKO[11:0]=x6d0 1744 [H_CLKO[11:8]=6; H_CLKO[7:0]=xD0] Output clocks per line -H_FRACT[7:0]=0 0 fractional input clocks per line -IN_MODE[2:0]=0 24Bit RGB muxed -LUMADLY[1:0]=0 0 pixel delay on Y_DLY luma -MCB[7:0]=x43 67 Mult factor for CB prior to subcarrier mod. -MCR[7:0]=x77 119 Mult factor for CR prior to subcarrier mod. -MODE2X=0 Don't divide clock input by 2 -MSC[31:0]=x215282E5 559055589 [MSC[31:24]=x21; MSC[23:16]=x52; MSC[15:8]=x82; MSC[7:0]=xE5] Subcarrier incr. -MY[7:0]=x85 133 Mult factor for Y -NI_OUT=0 Normal interlaced output -OUT_MODE[1:0]=0 video0-3 is CVBS, Y, C, Y_DLY -OUT_MUXA[1:0]=0 Don't care as DACA is disabled -OUT_MUXB[1:0]=1 Output video[1] (Y) on DACB -OUT_MUXC[1:0]=2 Output video[2] (C) on DACC -PAL_MD=0 Video output in PAL mode? No. -PHASE_OFF[7:0]=0 Subcarrier phase offset -PLL_FRACT[15:0]=x30 48 [PLL_FRACT[15:8]=0x0; PLL_FRACT[7:0]=x30] frac portion of pll multiplier -PLL_INT[5:0]=0x0C 12 Int portion of pll multiplier -SETUP=1 7.5-IRE enabled for NTSC -SLAVER=1 -SRESET=0 Don't do a software reset -SYNC_AMP[7:0]=xE5 229 Sync amp mult. factor (PAL std???) -VBLANKDLY=0 Extra line of blanking in 2nd field? -VSYNCI=0 Active low VSYNC -VSYNC_DUR=1 2.5line VSYNC duration on output (Yes for NTSC) -VSYNCOFFSET[10:0]=0 [VSYNOFFSET[10:8]=0; VSYNOFFSET[7:0]=0] VSYNC in standard position -VSYNWIDTH[2:0]=1 1 line of vsync width -V_ACTIVEI[9:0]=x1E0 480 [V_ACTIVEI[9:0]=1; V_ACTIVEI[7:0]=xE0] Active input lines -V_ACTIVEO[8:0]=xF0 240 [V_ACTIVE0[8]=0; V_ACTIVEO[7:0]=xF0] -V_BLANKI[7:0]=x2A 42 Input lines from vsync to first active line -V_BLANKO[7:0]=x16 22 -V_LINESI[9:0]=x20D 525 [V_LINESI[9:8]=2; V_LINESI[7:0]=x0D] Number of input lines -V_SCALE[13:0]=x1000 4096 [V_SCALE[13:8]=x10; V_SCALE[7:0]=0] Vert scale coefficient="none"? -YATTENUATE[2:0]=0 no luma attenuation -YCORING[2:0]=0 Luma-coring bypass -YLPF[1:0]=0 Luma hoz low pass filter=bypass - -***************** */ - -static u16 registers_720_480[] = - { - 0x6e, 0x00, /* HSYNOFFSET[7:0]=0 */ - 0x70, 0x02, /* HSYNOFFSET[9:8]=0; HSYNWIDTH[5:0]=2 */ - 0x72, 0x00, /* VSYNOFFSET[7:0]=0 */ - 0x74, 0x01, /* DATDLY = 0; DATSWP=0; VSYNOFFSET[10:8]=0; VSYNWIDTH[2:0]=1 */ - 0x76, 0xD0, /* H_CLKO[7:0]=xD0 */ - 0x78, 0xD0, /* H_ACTIVE[7:0]=xD0 */ - 0x7a, 0x80, /* HSYNC_WIDTH[7:0]=x80 */ - 0x7c, 0x92, /* HBURST_BEGIN[7:0]=x92 */ - 0x7e, 0x57, /* HBURST_END[7:0]=x57 */ - 0x80, 0x02, /* H_BLANKO[7:0]=x2 */ - 0x82, 0x16, /* V_BLANKO[7:0]=x16 */ - 0x84, 0xF0, /* V_ACTIVEO[7:0]=xF0 */ - 0x86, 0x26, /* V_ACTIVE0[8]=0; H_ACTIVE[9:8]=2; H_CLKO[11:8]=6 */ - 0x88, 0x00, /* H_FRACT[7:0]=0 */ - 0x8a, 0xD0, /* H_CLKI[7:0]=xD0 */ - 0x8c, 0x80, /* H_BLANKI[7:0]=x80 */ - 0x8e, 0x03, /* VBLANKDLY=0; H_BLANKI[8]=0; H_CLKI[10:8]=3 */ - 0x90, 0x0D, /* V_LINESI[7:0]=x0D */ - 0x92, 0x2A, /* V_BLANKI[7:0]=x2A */ - 0x94, 0xE0, /* V_ACTIVEI[7:0]=xE0 */ - 0x96, 0x06, /* CLPF[1:0]=0; YLPF[1:0]=0; V_ACTIVEI[9:8]=1; V_LINESI[9:8]=2 */ - 0x98, 0x00, /* V_SCALE[7:0]=0 */ - 0x9a, 0x50, /* H_BLANKO[9:8]=1; V_SCALE[13:8]=x10 */ - 0x9c, 0x30, /* PLL_FRACT[7:0]=x30 */ - 0x9e, 0x0, /* PLL_FRACT[15:8]=0x0 */ - 0xa0, 0x8c, /* EN_XCLK=1; BY_PLL=0; PLL_INT[5:0]=0x0C */ - 0xa2, 0x0A, /* ECLIP=0; PAL_MD=0; DIS_SCRESET=0; VSYNC_DUR=1; 625LINE=0; SETUP=1; NI_OUT=0 */ - 0xa4, 0xE5, /* SYNC_AMP[7:0]=xE5 */ - 0xa6, 0x74, /* BST_AMP[7:0]=x74 */ - 0xa8, 0x77, /* MCR[7:0]=x77 */ - 0xaa, 0x43, /* MCB[7:0]=x43 */ - 0xac, 0x85, /* MY[7:0]=x85 */ - 0xae, 0xE5, /* MSC[7:0]=xE5 */ - 0xb0, 0x82, /* MSC[15:8]=x82 */ - 0xb2, 0x52, /* MSC[23:16]=x52 */ - 0xb4, 0x21, /* MSC[31:24]=x21 */ - 0xb6, 0x00, /* PHASE_OFF[7:0]=0 */ - //0xba, 0x21, /* SRESET=0; CHECK_STAT=0; SLAVER=1; DACOFF=0; DACDISC=0; DACDISB=0; DACDISA=1 */ - 0xc4, 0x01, /* ESTATUS[1:0]=0; ECCF2=0; ECCF1=0; ECCGATE=0; ECBAR=0; DCHROMA=0; EN_OUT=1 */ - 0xc6, 0x00, /* EN_BLANKO=0; EN_DOT=0; FIELDI=0; VSYNCI=0; HSYNCI=0; IN_MODE[2:0]=0(24bRGB) */ - 0xc8, 0x40, /* DIS_YFLPF=0; DIS_FFILT=1; F_SELC[2:0]=0; F_SELY[2:0]=0 */ - 0xca, 0xc0, /* DIS_GMUSHY=1; DIS_GMSHY=1; YCORING[2:0]=0; YATTENUATE[2:0]=0 */ - 0xcc, 0xc0, /* DIS_GMUSHC=1; DIS_GMSHC=1; CCORING[2:0]=0; CATTENUATE[2:0]=0 */ - //0xce, 0x24, /* OUT_MUXC=2 [C]; OUT_MUXB=1 [Y]; OUT_MUXA=0 [CVBS, but disabled]*/ - //0xce, 0x04, /* OUT_MUXC=0 [CVBS]; OUT_MUXB=1 [Y]; OUT_MUXA=0 [CVBS, but disabled]*/ - 0xd6, 0x00, /* OUT_MODE[1:0]=0; LUMADLY[1:0]=0 */ - 0, 0 - }; - - -static int bt869_attach_adapter(struct i2c_adapter *adapter) -{ - return i2c_detect(adapter, &addr_data, bt869_detect); -} - -/* This function is called by i2c_detect */ -int bt869_detect(struct i2c_adapter *adapter, int address, - unsigned short flags, int kind) -{ - int i, cur; - struct i2c_client *new_client; - struct bt869_data *data; - int err = 0; - const char *type_name, *client_name; - - - printk("bt869.o: probing address %d .\n", address); - /* Make sure we aren't probing the ISA bus!! This is just a safety check - at this moment; i2c_detect really won't call us. */ -#ifdef DEBUG - if (i2c_is_isa_adapter(adapter)) { - printk - ("bt869.o: bt869_detect called for an ISA bus adapter?!?\n"); - return 0; - } -#endif - - if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_READ_BYTE | - I2C_FUNC_SMBUS_WRITE_BYTE_DATA)) - goto ERROR0; - - /* OK. For now, we presume we have a valid client. We now create the - client structure, even though we cannot fill it completely yet. - But it allows us to access bt869_{read,write}_value. */ - if (!(data = kmalloc(sizeof(struct bt869_data), GFP_KERNEL))) { - err = -ENOMEM; - goto ERROR0; - } - - new_client = &data->client; - new_client->addr = address; - new_client->data = data; - new_client->adapter = adapter; - new_client->driver = &bt869_driver; - new_client->flags = 0; - - /* Now, we do the remaining detection. It is lousy. */ - i2c_smbus_write_byte_data(new_client, 0xC4, 0); /* set status bank 0 */ - cur = i2c_smbus_read_byte(new_client); - printk("bt869.o: address 0x%X testing-->0x%X\n", address, cur); - if ((cur & 0xE0) != 0x20) - goto ERROR1; - - /* Determine the chip type */ - kind = ((cur & 0x20) >> 5); - - if (kind) { - type_name = "bt869"; - client_name = "bt869 chip"; - printk("bt869.o: BT869 detected\n"); - } else { - type_name = "bt868"; - client_name = "bt868 chip"; - printk("bt869.o: BT868 detected\n"); - } - - /* Fill in the remaining client fields and put it into the global list */ - strcpy(new_client->name, client_name); - data->valid = 0; - init_MUTEX(&data->update_lock); - - /* Tell the I2C layer a new client has arrived */ - if ((err = i2c_attach_client(new_client))) - goto ERROR3; - - /* Register a new directory entry with module sensors */ - if ((i = i2c_register_entry(new_client, type_name, - bt869_dir_table_template, - THIS_MODULE)) < 0) { - err = i; - goto ERROR4; - } - data->sysctl_id = i; - - bt869_init_client((struct i2c_client *) new_client); - return 0; - -/* OK, this is not exactly good programming practice, usually. But it is - very code-efficient in this case. */ - - ERROR4: - i2c_detach_client(new_client); - ERROR3: - ERROR1: - kfree(data); - ERROR0: - return err; -} - -static int bt869_detach_client(struct i2c_client *client) -{ - int err; - - i2c_deregister_entry(((struct bt869_data *) (client->data))-> - sysctl_id); - - if ((err = i2c_detach_client(client))) { - printk - ("bt869.o: Client deregistration failed, client not detached.\n"); - return err; - } - - kfree(client->data); - - return 0; -} - - -/* All registers are byte-sized. - bt869 uses a high-byte first convention, which is exactly opposite to - the usual practice. */ -static int bt869_read_value(struct i2c_client *client, u8 reg) -{ - return i2c_smbus_read_byte(client); -} - -/* All registers are byte-sized. - bt869 uses a high-byte first convention, which is exactly opposite to - the usual practice. */ -static int bt869_write_value(struct i2c_client *client, u8 reg, u16 value) -{ -#ifdef DEBUG - printk("bt869.o: write_value(0x%X, 0x%X)\n", reg, value); -#endif - return i2c_smbus_write_byte_data(client, reg, value); -} - -static void bt869_write_values(struct i2c_client *client, u16 *values) -{ - /* writes set of registers from array. 0,0 marks end of table */ - while (*values) { - bt869_write_value(client, values[0], values[1]); - values += 2; - } -} - -static void bt869_init_client(struct i2c_client *client) -{ - struct bt869_data *data = client->data; - - /* Initialize the bt869 chip */ - bt869_write_value(client, 0x0ba, 0x80); - // bt869_write_value(client,0x0D6, 0x00); - /* Be a slave to the clock on the Voodoo3 */ - bt869_write_value(client, 0xa0, 0x80); - bt869_write_value(client, 0xba, 0x20); - /* depth =16bpp */ - bt869_write_value(client, 0x0C6, 0x001); - bt869_write_value(client, 0xC4, 1); - /* Flicker free enable and config */ - bt869_write_value(client, 0xC8, 0); - data->res[0] = 640; - data->res[1] = 480; - data->ntsc = 1; - data->half = 0; - data->colorbars = 0; - data->svideo = 0; - data->depth = 16; - -} - -static void bt869_update_client(struct i2c_client *client) -{ - struct bt869_data *data = client->data; - - down(&data->update_lock); - - if ((jiffies - data->last_updated > HZ + HZ / 2) || - (jiffies < data->last_updated) || !data->valid) { -#ifdef DEBUG - printk("Starting bt869 update\n"); -#endif - if ((data->res[0] == 800) && (data->res[1] == 600)) { - /* 800x600 built-in mode */ - bt869_write_value(client, 0xB8, - (2 + (!data->ntsc))); - bt869_write_value(client, 0xa0, 0x80 + 0x11); - printk("bt869.o: writing into config -->0x%X\n", - (2 + (!data->ntsc))); - } - else if ((data->res[0] == 720) && (data->res[1] == 576)) { - /* 720x576 no-overscan-compensation mode suitable for PAL DVD playback */ - data->ntsc = 0; /* This mode always PAL */ - bt869_write_values(client, registers_720_576); - } - else if ((data->res[0] == 720) && (data->res[1] == 480)) { - /* 720x480 no-overscan-compensation mode suitable for NTSC DVD playback */ - data->ntsc = 1; /* This mode always NTSC */ - bt869_write_values(client, registers_720_480); - } - else { - /* 640x480 built-in mode */ - bt869_write_value(client, 0xB8, (!data->ntsc)); - bt869_write_value(client, 0xa0, 0x80 + 0x0C); - printk("bt869.o: writing into config -->0x%X\n", - (0 + (!data->ntsc))); - if ((data->res[0] != 640) || (data->res[1] != 480)) { - printk - ("bt869.o: Warning: arbitrary resolutions not supported yet. Using 640x480.\n"); - data->res[0] = 640; - data->res[1] = 480; - } - } - /* Set colour depth */ - if ((data->depth != 24) && (data->depth != 16)) - data->depth = 16; - if (data->depth == 16) - bt869_write_value(client, 0x0C6, 0x001); - if (data->depth == 24) - bt869_write_value(client, 0x0C6, 0x000); - /* set "half" resolution mode */ - bt869_write_value(client, 0xd4, data->half << 6); - /* Set composite/svideo mode, also enable the right dacs */ - switch (data->svideo) { - case 2: /* RGB */ - /* requires hardware mod on Voodoo3 to get all outputs, - untested in practice... Feedback to steve@daviesfam.org please */ - bt869_write_value(client, 0xd6, 0x0c); - bt869_write_value(client, 0xce, 0x24); - bt869_write_value(client, 0xba, 0x20); - break; - case 1: /* Svideo*/ - bt869_write_value(client, 0xce, 0x24); - bt869_write_value(client, 0xba, 0x21); - break; - default: /* Composite */ - bt869_write_value(client, 0xce, 0x0); - bt869_write_value(client, 0xba, 0x21); - break; - } - /* Enable outputs */ - bt869_write_value(client, 0xC4, 1); - /* Issue timing reset */ - bt869_write_value(client, 0x6c, 0x80); - -/* Read back status registers */ - bt869_write_value(client, 0xC4, - 1 | (data->colorbars << 2)); - data->status[0] = bt869_read_value(client, 1); - bt869_write_value(client, 0xC4, - 0x41 | (data->colorbars << 2)); - data->status[1] = bt869_read_value(client, 1); - bt869_write_value(client, 0xC4, - 0x81 | (data->colorbars << 2)); - data->status[2] = bt869_read_value(client, 1); - bt869_write_value(client, 0xC4, - 0x0C1 | (data->colorbars << 2)); - data->last_updated = jiffies; - data->valid = 1; - } - up(&data->update_lock); -} - - -void bt869_status(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct bt869_data *data = client->data; - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - bt869_update_client(client); - results[0] = data->status[0]; - results[1] = data->status[1]; - results[2] = data->status[2]; - *nrels_mag = 3; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - printk - ("bt869.o: Warning: write was requested on read-only proc file: status\n"); - } -} - - -void bt869_ntsc(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct bt869_data *data = client->data; - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - bt869_update_client(client); - results[0] = data->ntsc; - *nrels_mag = 1; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag >= 1) { - data->ntsc = (results[0] > 0); - } - bt869_update_client(client); - } -} - - -void bt869_svideo(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct bt869_data *data = client->data; - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - bt869_update_client(client); - results[0] = data->svideo; - *nrels_mag = 1; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag >= 1) { - data->svideo = results[0]; - } - bt869_update_client(client); - } -} - - -void bt869_res(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct bt869_data *data = client->data; - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - bt869_update_client(client); - results[0] = data->res[0]; - results[1] = data->res[1]; - *nrels_mag = 2; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag >= 1) { - data->res[0] = results[0]; - } - if (*nrels_mag >= 2) { - data->res[1] = results[1]; - } - bt869_update_client(client); - } -} - - -void bt869_half(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct bt869_data *data = client->data; - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - bt869_update_client(client); - results[0] = data->half; - *nrels_mag = 1; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag >= 1) { - data->half = (results[0] > 0); - bt869_update_client(client); - } - } -} - -void bt869_colorbars(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results) -{ - struct bt869_data *data = client->data; - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - bt869_update_client(client); - results[0] = data->colorbars; - *nrels_mag = 1; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag >= 1) { - data->colorbars = (results[0] > 0); - bt869_update_client(client); - } - } -} - -void bt869_depth(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct bt869_data *data = client->data; - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - bt869_update_client(client); - results[0] = data->depth; - *nrels_mag = 1; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag >= 1) { - data->depth = results[0]; - bt869_update_client(client); - } - } -} - -static int __init sm_bt869_init(void) -{ - printk("bt869.o version %s (%s)\n", LM_VERSION, LM_DATE); - return i2c_add_driver(&bt869_driver); -} - -static void __exit sm_bt869_exit(void) -{ - i2c_del_driver(&bt869_driver); -} - - - -MODULE_AUTHOR - ("Frodo Looijaard , Philip Edelbrock , Stephen Davies "); -MODULE_DESCRIPTION("bt869 driver"); - -module_init(sm_bt869_init); -module_exit(sm_bt869_exit); diff --git a/kernel/chips/ddcmon.c b/kernel/chips/ddcmon.c deleted file mode 100644 index 45303f4b..00000000 --- a/kernel/chips/ddcmon.c +++ /dev/null @@ -1,586 +0,0 @@ -/* - ddcmon.c - Part of lm_sensors, Linux kernel modules for hardware - monitoring - Copyright (c) 1998, 1999, 2000 Frodo Looijaard , - Philip Edelbrock , - and Mark Studebaker - Copyright (c) 2003 Jean Delvare - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#include -#include -#include -#include -#include -#include "version.h" - -MODULE_LICENSE("GPL"); - -/* Addresses to scan */ -static unsigned short normal_i2c[] = { 0x50, SENSORS_I2C_END }; -static unsigned short normal_i2c_range[] = { SENSORS_I2C_END }; -static unsigned int normal_isa[] = { SENSORS_ISA_END }; -static unsigned int normal_isa_range[] = { SENSORS_ISA_END }; - -/* Insmod parameters */ -SENSORS_INSMOD_1(ddcmon); - -static int checksum = 0; -MODULE_PARM(checksum, "i"); -MODULE_PARM_DESC(checksum, "Only accept eeproms whose checksum is correct"); - -/* Many constants specified below */ - -/* DDCMON registers */ -/* vendor section */ -#define DDCMON_REG_MAN_ID 0x08 -#define DDCMON_REG_PROD_ID 0x0A -#define DDCMON_REG_SERIAL 0x0C -#define DDCMON_REG_WEEK 0x10 -#define DDCMON_REG_YEAR 0x11 -/* EDID version */ -#define DDCMON_REG_EDID_VER 0x12 -#define DDCMON_REG_EDID_REV 0x13 -/* display information */ -#define DDCMON_REG_HORSIZE 0x15 -#define DDCMON_REG_VERSIZE 0x16 -#define DDCMON_REG_GAMMA 0x17 -#define DDCMON_REG_DPMS_FLAGS 0x18 -/* supported timings */ -#define DDCMON_REG_ESTABLISHED_TIMINGS 0x23 -#define DDCMON_REG_STANDARD_TIMINGS 0x26 -#define DDCMON_REG_TIMBASE 0x36 -#define DDCMON_REG_TIMINCR 18 -#define DDCMON_REG_TIMNUM 4 - -#define DDCMON_REG_CHECKSUM 0x7f - -/* Size of DDCMON in bytes */ -#define DDCMON_SIZE 128 - -/* Each client has this additional data */ -struct ddcmon_data { - struct i2c_client client; - int sysctl_id; - - struct semaphore update_lock; - char valid; /* !=0 if following fields are valid */ - unsigned long last_updated; /* In jiffies */ - - u8 data[DDCMON_SIZE]; /* Register values */ -}; - - -static int ddcmon_attach_adapter(struct i2c_adapter *adapter); -static int ddcmon_detect(struct i2c_adapter *adapter, int address, - unsigned short flags, int kind); -static int ddcmon_detach_client(struct i2c_client *client); - -static void ddcmon_idcall(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void ddcmon_size(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void ddcmon_sync(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void ddcmon_maxclock(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void ddcmon_timings(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void ddcmon_serial(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void ddcmon_time(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void ddcmon_edid(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void ddcmon_gamma(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void ddcmon_dpms(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void ddcmon_standard_timing(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void ddcmon_update_client(struct i2c_client *client); - - -/* This is the driver that will be inserted */ -static struct i2c_driver ddcmon_driver = { - .name = "DDCMON READER", - .id = I2C_DRIVERID_DDCMON, - .flags = I2C_DF_NOTIFY, - .attach_adapter = ddcmon_attach_adapter, - .detach_client = ddcmon_detach_client, -}; - -/* -- SENSORS SYSCTL START -- */ - -#define DDCMON_SYSCTL_ID 1010 -#define DDCMON_SYSCTL_SIZE 1011 -#define DDCMON_SYSCTL_SYNC 1012 -#define DDCMON_SYSCTL_TIMINGS 1013 -#define DDCMON_SYSCTL_SERIAL 1014 -#define DDCMON_SYSCTL_TIME 1015 -#define DDCMON_SYSCTL_EDID 1016 -#define DDCMON_SYSCTL_GAMMA 1017 -#define DDCMON_SYSCTL_DPMS 1018 -#define DDCMON_SYSCTL_TIMING1 1021 -#define DDCMON_SYSCTL_TIMING2 1022 -#define DDCMON_SYSCTL_TIMING3 1023 -#define DDCMON_SYSCTL_TIMING4 1024 -#define DDCMON_SYSCTL_TIMING5 1025 -#define DDCMON_SYSCTL_TIMING6 1026 -#define DDCMON_SYSCTL_TIMING7 1027 -#define DDCMON_SYSCTL_TIMING8 1028 -#define DDCMON_SYSCTL_MAXCLOCK 1029 - -/* -- SENSORS SYSCTL END -- */ - -/* These files are created for each detected DDCMON. This is just a template; - though at first sight, you might think we could use a statically - allocated list, we need some way to get back to the parent - which - is done through one of the 'extra' fields which are initialized - when a new copy is allocated. */ -static ctl_table ddcmon_dir_table_template[] = { - {DDCMON_SYSCTL_ID, "id", NULL, 0, 0444, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &ddcmon_idcall}, - {DDCMON_SYSCTL_SIZE, "size", NULL, 0, 0444, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &ddcmon_size}, - {DDCMON_SYSCTL_SYNC, "sync", NULL, 0, 0444, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &ddcmon_sync}, - {DDCMON_SYSCTL_TIMINGS, "timings", NULL, 0, 0444, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &ddcmon_timings}, - {DDCMON_SYSCTL_SERIAL, "serial", NULL, 0, 0444, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &ddcmon_serial}, - {DDCMON_SYSCTL_TIME, "time", NULL, 0, 0444, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &ddcmon_time}, - {DDCMON_SYSCTL_EDID, "edid", NULL, 0, 0444, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &ddcmon_edid}, - {DDCMON_SYSCTL_GAMMA, "gamma", NULL, 0, 0444, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &ddcmon_gamma}, - {DDCMON_SYSCTL_DPMS, "dpms", NULL, 0, 0444, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &ddcmon_dpms}, - {DDCMON_SYSCTL_TIMING1, "timing1", NULL, 0, 0444, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &ddcmon_standard_timing}, - {DDCMON_SYSCTL_TIMING2, "timing2", NULL, 0, 0444, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &ddcmon_standard_timing}, - {DDCMON_SYSCTL_TIMING3, "timing3", NULL, 0, 0444, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &ddcmon_standard_timing}, - {DDCMON_SYSCTL_TIMING4, "timing4", NULL, 0, 0444, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &ddcmon_standard_timing}, - {DDCMON_SYSCTL_TIMING5, "timing5", NULL, 0, 0444, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &ddcmon_standard_timing}, - {DDCMON_SYSCTL_TIMING6, "timing6", NULL, 0, 0444, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &ddcmon_standard_timing}, - {DDCMON_SYSCTL_TIMING7, "timing7", NULL, 0, 0444, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &ddcmon_standard_timing}, - {DDCMON_SYSCTL_TIMING8, "timing8", NULL, 0, 0444, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &ddcmon_standard_timing}, - {DDCMON_SYSCTL_MAXCLOCK, "maxclock", NULL, 0, 0444, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &ddcmon_maxclock}, - {0} -}; - -static int ddcmon_attach_adapter(struct i2c_adapter *adapter) -{ - return i2c_detect(adapter, &addr_data, ddcmon_detect); -} - -/* This function is called by i2c_detect */ -int ddcmon_detect(struct i2c_adapter *adapter, int address, - unsigned short flags, int kind) -{ - int i, cs; - struct i2c_client *new_client; - struct ddcmon_data *data; - int err = 0; - const char *type_name, *client_name; - - if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) - goto ERROR0; - - /* OK. For now, we presume we have a valid client. We now create the - client structure, even though we cannot fill it completely yet. - But it allows us to access ddcmon_{read,write}_value. */ - if (!(data = kmalloc(sizeof(struct ddcmon_data), GFP_KERNEL))) { - err = -ENOMEM; - goto ERROR0; - } - - new_client = &data->client; - memset(data->data, 0xff, DDCMON_SIZE); - new_client->addr = address; - new_client->data = data; - new_client->adapter = adapter; - new_client->driver = &ddcmon_driver; - new_client->flags = 0; - - /* prevent 24RF08 corruption (just in case) */ - i2c_smbus_write_quick(new_client, 0); - - /* Now, we do the remaining detection. */ - if (checksum) { - int cs = 0; - for (i = 0; i < 0x80; i++) - cs += i2c_smbus_read_byte_data(new_client, i); - if ((cs & 0xff) != 0) - goto ERROR1; - } - - /* Verify the first 8 locations 0x00FFFFFFFFFFFF00 */ - /* Allow force and force_ddcmon arguments */ - if(kind < 0) - { - for(i = 0; i < 8; i++) { - cs = i2c_smbus_read_byte_data(new_client, i); - if(i == 0 || i == 7) { - if(cs != 0) - goto ERROR1; - } else if(cs != 0xff) - goto ERROR1; - } - } - - type_name = "ddcmon"; - client_name = "DDC Monitor"; - - /* Fill in the remaining client fields and put it in the global list */ - strcpy(new_client->name, client_name); - data->valid = 0; - init_MUTEX(&data->update_lock); - - /* Tell the I2C layer a new client has arrived */ - if ((err = i2c_attach_client(new_client))) - goto ERROR3; - - /* Register a new directory entry with module sensors */ - if ((i = i2c_register_entry(new_client, type_name, - ddcmon_dir_table_template, - THIS_MODULE)) < 0) { - err = i; - goto ERROR4; - } - data->sysctl_id = i; - - return 0; - - ERROR4: - i2c_detach_client(new_client); - ERROR3: - ERROR1: - kfree(data); - ERROR0: - return err; -} - -static int ddcmon_detach_client(struct i2c_client *client) -{ - int err; - - i2c_deregister_entry(((struct ddcmon_data *) (client->data))-> - sysctl_id); - if ((err = i2c_detach_client(client))) { - printk - ("ddcmon.o: Client deregistration failed, client not detached.\n"); - return err; - } - kfree(client->data); - return 0; -} - -static void ddcmon_update_client(struct i2c_client *client) -{ - struct ddcmon_data *data = client->data; - int i, j; - - down(&data->update_lock); - - if ((jiffies - data->last_updated > 300 * HZ) || - (jiffies < data->last_updated) || !data->valid) { - if (i2c_check_functionality(client->adapter, - I2C_FUNC_SMBUS_READ_I2C_BLOCK)) - { - for (i=0; idata + i) - != I2C_SMBUS_I2C_BLOCK_MAX) { - printk(KERN_WARNING "ddcmon.o: block read fail at 0x%.2x!\n", i); - goto DONE; - } - } else { - if (i2c_smbus_write_byte(client, 0)) { - printk(KERN_WARNING "ddcmon.o: read start fail at 0!\n"); - goto DONE; - } - for (i = 0; i < DDCMON_SIZE; i++) { - j = i2c_smbus_read_byte(client); - if (j < 0) { - printk(KERN_WARNING "eeprom.o: read fail at 0x%.2x!\n", i); - goto DONE; - } - data->data[i] = (u8) j; - } - } - data->last_updated = jiffies; - data->valid = 1; - } -DONE: - up(&data->update_lock); -} - - -void ddcmon_idcall(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results) -{ - struct ddcmon_data *data = client->data; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - ddcmon_update_client(client); - results[0] = data->data[DDCMON_REG_MAN_ID + 1] | - (data->data[DDCMON_REG_MAN_ID] << 8); - results[1] = data->data[DDCMON_REG_PROD_ID + 1] | - (data->data[DDCMON_REG_PROD_ID] << 8); - *nrels_mag = 2; - } -} - -void ddcmon_size(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results) -{ - struct ddcmon_data *data = client->data; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - ddcmon_update_client(client); - results[0] = data->data[DDCMON_REG_VERSIZE]; - results[1] = data->data[DDCMON_REG_HORSIZE]; - *nrels_mag = 2; - } -} - -void ddcmon_sync(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results) -{ - int i, j; - struct ddcmon_data *data = client->data; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - ddcmon_update_client(client); - *nrels_mag = 4; - /* look for monitor limits entry */ - for(i = DDCMON_REG_TIMBASE; - i < DDCMON_REG_TIMBASE + - (DDCMON_REG_TIMNUM * DDCMON_REG_TIMINCR); - i += DDCMON_REG_TIMINCR) { - if (data->data[i] == 0x00 - && data->data[i + 1] == 0x00 - && data->data[i + 2] == 0x00 - && data->data[i + 3] == 0xfd) { - for(j = 0; j < 4; j++) - results[j] = data->data[i + j + 5]; - return; - } - } - for(j = 0; j < 4; j++) - results[j] = 0; - } -} - -void ddcmon_maxclock(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results) -{ - int i; - struct ddcmon_data *data = client->data; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - ddcmon_update_client(client); - *nrels_mag = 1; - /* look for monitor limits entry */ - for(i = DDCMON_REG_TIMBASE; - i < DDCMON_REG_TIMBASE + - (DDCMON_REG_TIMNUM * DDCMON_REG_TIMINCR); - i += DDCMON_REG_TIMINCR) { - if (data->data[i] == 0x00 - && data->data[i + 1] == 0x00 - && data->data[i + 2] == 0x00 - && data->data[i + 3] == 0xfd) { - results[0] = (data->data[i + 9] == 0xff ? - 0 : data->data[i + 9] * 10); - return; - } - } - results[0] = 0; - } -} - -void ddcmon_timings(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results) -{ - struct ddcmon_data *data = client->data; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - ddcmon_update_client(client); - results[0] = data->data[DDCMON_REG_ESTABLISHED_TIMINGS] | - (data->data[DDCMON_REG_ESTABLISHED_TIMINGS + 1] << 8) | - (data->data[DDCMON_REG_ESTABLISHED_TIMINGS + 2] << 16); - *nrels_mag = 1; - } -} - -void ddcmon_serial(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results) -{ - struct ddcmon_data *data = client->data; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - ddcmon_update_client(client); - results[0] = data->data[DDCMON_REG_SERIAL] | - (data->data[DDCMON_REG_SERIAL + 1] << 8) | - (data->data[DDCMON_REG_SERIAL + 2] << 16) | - (data->data[DDCMON_REG_SERIAL + 3] << 24); - *nrels_mag = 1; - } -} - -void ddcmon_time(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results) -{ - struct ddcmon_data *data = client->data; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - ddcmon_update_client(client); - results[0] = data->data[DDCMON_REG_YEAR] + 1990; - results[1] = data->data[DDCMON_REG_WEEK]; - *nrels_mag = 2; - } -} - -void ddcmon_edid(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results) -{ - struct ddcmon_data *data = client->data; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - ddcmon_update_client(client); - results[0] = data->data[DDCMON_REG_EDID_VER]; - results[1] = data->data[DDCMON_REG_EDID_REV]; - *nrels_mag = 2; - } -} - -void ddcmon_gamma(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results) -{ - struct ddcmon_data *data = client->data; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 2; - else if (operation == SENSORS_PROC_REAL_READ) { - ddcmon_update_client(client); - results[0] = 100 + data->data[DDCMON_REG_GAMMA]; - *nrels_mag = 1; - } -} - -void ddcmon_dpms(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results) -{ - struct ddcmon_data *data = client->data; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - ddcmon_update_client(client); - results[0] = data->data[DDCMON_REG_DPMS_FLAGS]; - *nrels_mag = 1; - } -} - -void ddcmon_standard_timing(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results) -{ - struct ddcmon_data *data = client->data; - int nr = ctl_name - DDCMON_SYSCTL_TIMING1; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - ddcmon_update_client(client); - /* If both bytes of the timing are 0x00 or 0x01, then the timing - slot is unused. */ - if ((data->data[DDCMON_REG_STANDARD_TIMINGS + nr * 2] - | data->data[DDCMON_REG_STANDARD_TIMINGS + nr * 2 + 1]) & 0xfe) { - results[0] = (data->data[DDCMON_REG_STANDARD_TIMINGS + nr * 2] + 31) * 8; - switch (data->data[DDCMON_REG_STANDARD_TIMINGS + nr * 2 + 1] >> 6) { - /* We don't care about rounding issues there, it really - should be OK without it. */ - case 0x00: - results[1] = results[0]; /* unconfirmed */ - break; - case 0x01: - results[1] = results[0] * 3 / 4; - break; - case 0x02: - results[1] = results[0] * 4 / 5; - break; - case 0x03: - results[1] = results[0] * 9 / 16; - break; - } - results[2] = (data->data[DDCMON_REG_STANDARD_TIMINGS + nr * 2 + 1] & 0x3f) + 60; - } else { - results[0] = 0; - results[1] = 0; - results[2] = 0; - } - *nrels_mag = 3; - } -} - -static int __init sm_ddcmon_init(void) -{ - printk("ddcmon.o version %s (%s)\n", LM_VERSION, LM_DATE); - return i2c_add_driver(&ddcmon_driver); -} - -static void __exit sm_ddcmon_exit(void) -{ - i2c_del_driver(&ddcmon_driver); -} - - - -MODULE_AUTHOR("Frodo Looijaard , " - "Philip Edelbrock , " - "Mark Studebaker " - "and Jean Delvare "); -MODULE_DESCRIPTION("DDCMON driver"); - -module_init(sm_ddcmon_init); -module_exit(sm_ddcmon_exit); diff --git a/kernel/chips/ds1307.c b/kernel/chips/ds1307.c deleted file mode 100644 index 028e6ceb..00000000 --- a/kernel/chips/ds1307.c +++ /dev/null @@ -1,345 +0,0 @@ - -/* - * linux/drivers/i2c/ds1307.c - * - * Author: Abraham van der Merwe - * - * Linux support for the Dallas Semiconductor DS1307 Serial Real-Time - * Clock. - * - * Based on code from the lm-sensors project which is available - * at http://www.lm-sensors.org/ and Russell King's PCF8583 Real-Time - * Clock driver (linux/drivers/acorn/char/pcf8583.c). - * - * This source code is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * version 2 as published by the Free Software Foundation. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "version.h" -#include "ds1307.h" - -#define BCD_TO_BIN(x) (((x) & 15) + ((x) >> 4) * 10) -#define BIN_TO_BCD(x) ((((x) / 10) << 4) + (x) % 10) - -static struct i2c_driver ds1307; -static DECLARE_MUTEX (mutex); - -/* - * The DS1307 Real-Time Clock wants the address in a different - * message, so we can't use the normal i2c_master_recv() routine - * for receiving data. - */ -static int ds1307_i2c_recv (struct i2c_client *client,char *buf,char addr,int count) -{ - struct i2c_msg msg[] = { - { addr: client->addr, flags: 0, len: 1, buf: &addr }, - { addr: client->addr, flags: I2C_M_RD, len: count, buf: buf } - }; - int result = 0; - - if (down_interruptible (&mutex)) - return (-ERESTARTSYS); - - if (i2c_transfer (client->adapter,msg,2) != 2) - result = -EIO; - - up (&mutex); - - return (result); -} - -/* - * Would've been nice to specify the address to this as well, but then we - * would need to copy the buffer twice - not worth it... - */ -static int ds1307_i2c_send (struct i2c_client *client,const char *buf,int count) -{ - int result = 0; - - if (down_interruptible (&mutex)) - return (-ERESTARTSYS); - - if (i2c_master_send (client,(const char *) buf,count) != count) - result = -EIO; - - up (&mutex); - - return (result); -} - -static int ds1307_attach (struct i2c_adapter *adapter,int addr,unsigned short flags,int kind) -{ - struct i2c_client *client; - int result; - - if ((client = (struct i2c_client *) kmalloc (sizeof (struct i2c_client),GFP_KERNEL)) == NULL) - return (-ENOMEM); - - strcpy (client->name,ds1307.name); - client->flags = I2C_CLIENT_ALLOW_USE | I2C_CLIENT_ALLOW_MULTIPLE_USE; - client->addr = addr; - client->adapter = adapter; - client->driver = &ds1307; - client->data = NULL; - - if ((result = i2c_attach_client (client))) { - kfree (client); - return (result); - } - - return (0); -} - -static int ds1307_attach_adapter (struct i2c_adapter *adapter) -{ - static unsigned short ignore[] = { I2C_CLIENT_END }; - static unsigned short addr[] = { 0x68, I2C_CLIENT_END }; - static struct i2c_client_address_data ds1307_addr_data = { - normal_i2c: addr, - normal_i2c_range: ignore, - probe: ignore, - probe_range: ignore, - ignore: ignore, - ignore_range: ignore, - force: ignore - }; - - return (i2c_probe (adapter,&ds1307_addr_data,ds1307_attach)); -} - -static int ds1307_detach_client (struct i2c_client *client) -{ - int result; - - if ((result = i2c_detach_client (client))) - return (result); - - kfree (client); - - return (0); -} - -static int ds1307_getdate (struct i2c_client *client,void *arg) -{ - struct ds1307_date *date = (struct ds1307_date *) arg; - u8 buf[7]; - - /* this also enables the oscillator */ - memset (buf,0,7); - - /* enable 24-hour mode */ - buf[2] = 0x40; - - if (ds1307_i2c_recv (client,(char *) buf,0,7) < 0) - return (-EIO); - - date->tm_sec = BCD_TO_BIN (buf[0] & ~0x80); - date->tm_min = BCD_TO_BIN (buf[1]); - date->tm_hour = BCD_TO_BIN (buf[2] & 0x3f); - date->tm_wday = BCD_TO_BIN (buf[3]) - 1; - date->tm_mday = BCD_TO_BIN (buf[4]); - date->tm_mon = BCD_TO_BIN (buf[5]) - 1; - date->tm_year = BCD_TO_BIN (buf[6]) + 100; - - return (0); -} - -static int ds1307_setdate (struct i2c_client *client,void *arg) -{ - struct ds1307_date *date = (struct ds1307_date *) arg; - u8 buf[8]; - - /* select address 0 */ - buf[0] = 0; - - buf[1] = BIN_TO_BCD (date->tm_sec); - buf[2] = BIN_TO_BCD (date->tm_min); - buf[3] = BIN_TO_BCD (date->tm_hour) | 0x40; - buf[4] = BIN_TO_BCD (date->tm_wday + 1); - buf[5] = BIN_TO_BCD (date->tm_mday); - buf[6] = BIN_TO_BCD (date->tm_mon + 1); - buf[7] = BIN_TO_BCD (date->tm_year - 100); - - return (ds1307_i2c_send (client,(const char *) buf,8)); -} - -static int ds1307_enable (struct i2c_client *client,void *arg) -{ - u8 buf[2]; - - if (ds1307_i2c_recv (client,(char *) buf + 1,0,1) < 0) - return (-EIO); - - if ((buf[1] & 0x80)) { - buf[0] = 0, buf[1] &= ~0x80; - return (ds1307_i2c_send (client,(const char *) buf,2)); - } - - return (0); -} - -static int ds1307_irqon (struct i2c_client *client,void *arg) -{ - u8 buf[2]; - - if (ds1307_i2c_recv (client,(char *) buf + 1,7,1) < 0) - return (-EIO); - - buf[0] = 7; - buf[1] |= 0x10; - - return (ds1307_i2c_send (client,(const char *) buf,2)); -} - -static int ds1307_irqoff (struct i2c_client *client,void *arg) -{ - u8 buf[2]; - - if (ds1307_i2c_recv (client,(char *) buf + 1,7,1) < 0) - return (-EIO); - - buf[0] = 7; - buf[1] &= ~0x10; - - return (ds1307_i2c_send (client,(const char *) buf,2)); -} - -static int ds1307_getfreq (struct i2c_client *client,void *arg) -{ - u16 *freq = (u16 *) arg; - u8 buf; - static const u16 table[] = { - DS1307_FREQ_1HZ, - DS1307_FREQ_4KHZ, - DS1307_FREQ_8KHZ, - DS1307_FREQ_32KHZ - }; - - if (ds1307_i2c_recv (client,(char *) &buf,7,1) < 0) - return (-EIO); - - *freq = table[buf & 3]; - - return (0); -} - -static int ds1307_setfreq (struct i2c_client *client,void *arg) -{ - u16 *freq = (u16 *) arg; - u8 buf[2]; - - /* select address 7 */ - buf[0] = 7; - - /* default to 1HZ */ - buf[1] = 0; - - switch (*freq) { - case DS1307_FREQ_32KHZ: buf[1]++; - case DS1307_FREQ_8KHZ: buf[1]++; - case DS1307_FREQ_4KHZ: buf[1]++; - case DS1307_FREQ_1HZ: break; - default: - return (-EINVAL); - } - - return (ds1307_i2c_send (client,(const char *) buf,2)); -} - -static int ds1307_read (struct i2c_client *client,void *arg) -{ - struct ds1307_memory *mem = (struct ds1307_memory *) arg; - u8 buf[DS1307_SIZE]; - - if (mem->offset >= DS1307_SIZE || mem->offset + mem->length > DS1307_SIZE) - return (-EINVAL); - - if (ds1307_i2c_recv (client,(char *) buf,mem->offset + 8,mem->length) < 0) - return (-EIO); - - memcpy (mem->buf,buf,mem->length); - - return (0); -} - -static int ds1307_write (struct i2c_client *client,void *arg) -{ - struct ds1307_memory *mem = (struct ds1307_memory *) arg; - u8 buf[DS1307_SIZE + 1]; - - if (mem->offset >= DS1307_SIZE || mem->offset + mem->length > DS1307_SIZE) - return (-EINVAL); - - buf[0] = mem->offset + 8; - - memcpy (buf + 1,mem->buf,mem->length); - - return (ds1307_i2c_send (client,(const char *) buf,mem->length + 1)); -} - -static int ds1307_command (struct i2c_client *client,unsigned int cmd,void *arg) -{ - static const struct { - int cmd; - int (*function) (struct i2c_client *,void *arg); - } ioctl[] = { - { DS1307_ENABLE, ds1307_enable }, - { DS1307_GET_DATE, ds1307_getdate }, - { DS1307_SET_DATE, ds1307_setdate }, - { DS1307_IRQ_ON, ds1307_irqon }, - { DS1307_IRQ_OFF, ds1307_irqoff }, - { DS1307_GET_FREQ, ds1307_getfreq }, - { DS1307_SET_FREQ, ds1307_setfreq }, - { DS1307_READ, ds1307_read }, - { DS1307_WRITE, ds1307_write } - }; - int i; - - for (i = 0; i < sizeof (ioctl) / sizeof (ioctl[0]); i++) - if (ioctl[i].cmd == cmd) - return (ioctl[i].function (client,arg)); - - return (-EINVAL); -} - - -static struct i2c_driver ds1307 = { - .name = "ds1307", - .id = I2C_DRIVERID_DS1307, - .flags = I2C_DF_NOTIFY, - .attach_adapter = ds1307_attach_adapter, - .detach_client = ds1307_detach_client, - .command = ds1307_command, -}; - -static int __init sm_ds1307_init(void) -{ - printk("ds1307.o version %s (%s)\n", LM_VERSION, LM_DATE); - return i2c_add_driver(&ds1307); -} - -static void __exit sm_ds1307_exit(void) -{ - i2c_del_driver(&ds1307); -} - - - -MODULE_AUTHOR ("Abraham van der Merwe "); -MODULE_DESCRIPTION ("Linux support for DS1307 Real-Time Clock"); - -MODULE_LICENSE ("GPL"); - -module_init(sm_ds1307_init); -module_exit(sm_ds1307_exit); - diff --git a/kernel/chips/ds1621.c b/kernel/chips/ds1621.c deleted file mode 100644 index e1a1fbba..00000000 --- a/kernel/chips/ds1621.c +++ /dev/null @@ -1,537 +0,0 @@ -/* - ds1621.c - Part of lm_sensors, Linux kernel modules for hardware - monitoring - Christian W. Zuckschwerdt 2000-11-23 - based on lm75.c by Frodo Looijaard - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -/* Supports DS1621. See doc/chips/ds1621 for details */ - -#include -#include -#include -#include -#include -#include "version.h" - -MODULE_LICENSE("GPL"); - -/* Addresses to scan */ -static unsigned short normal_i2c[] = { SENSORS_I2C_END }; -static unsigned short normal_i2c_range[] = { 0x48, 0x4f, SENSORS_I2C_END }; -static unsigned int normal_isa[] = { SENSORS_ISA_END }; -static unsigned int normal_isa_range[] = { SENSORS_ISA_END }; - -/* Insmod parameters */ -SENSORS_INSMOD_1(ds1621); - -/* Many DS1621 constants specified below */ - -/* Config register used for detection */ -/* 7 6 5 4 3 2 1 0 */ -/* |Done|THF |TLF |NVB | X | X |POL |1SHOT| */ -#define DS1621_REG_CONFIG_NVB 0x10 -#define DS1621_REG_CONFIG_POLARITY 0x02 -#define DS1621_REG_CONFIG_1SHOT 0x01 -#define DS1621_REG_CONFIG_DONE 0x80 - -/* Note: the done bit is always unset if continuous conversion is in progress. - We need to stop the continuous conversion or switch to single shot - before this bit becomes available! - */ - -/* The DS1621 registers */ -#define DS1621_REG_TEMP 0xAA /* word, RO */ -#define DS1621_REG_TEMP_OVER 0xA1 /* word, RW */ -#define DS1621_REG_TEMP_HYST 0xA2 /* word, RW -- it's a low temp trigger */ -#define DS1621_REG_CONF 0xAC /* byte, RW */ -#define DS1621_REG_TEMP_COUNTER 0xA8 /* byte, RO */ -#define DS1621_REG_TEMP_SLOPE 0xA9 /* byte, RO */ -#define DS1621_COM_START 0xEE /* no data */ -#define DS1621_COM_STOP 0x22 /* no data */ - -/* Conversions. Rounding and limit checking is only done on the TO_REG - variants. Note that you should be a bit careful with which arguments - these macros are called: arguments may be evaluated more than once. - Fixing this is just not worth it. */ -#define TEMP_FROM_REG(val) ((((val & 0x7fff) >> 7) * 5) | \ - ((val & 0x8000)?-256:0)) -#define TEMP_TO_REG(val) (SENSORS_LIMIT((val<0 ? (0x200+((val)/5))<<7 : \ - (((val) + 2) / 5) << 7),0,0xffff)) -#define ALARMS_FROM_REG(val) ((val) & \ - (DS1621_ALARM_TEMP_HIGH | DS1621_ALARM_TEMP_LOW)) -#define ITEMP_FROM_REG(val) ((((val & 0x7fff) >> 8)) | \ - ((val & 0x8000)?-256:0)) - -/* Each client has this additional data */ -struct ds1621_data { - struct i2c_client client; - int sysctl_id; - - struct semaphore update_lock; - char valid; /* !=0 if following fields are valid */ - unsigned long last_updated; /* In jiffies */ - - u16 temp, temp_over, temp_hyst; /* Register values, word */ - u8 conf; /* Register encoding, combined */ - - char enable; /* !=0 if we're expected to restart the conversion */ - u8 temp_int, temp_counter, temp_slope; /* Register values, byte */ -}; - -static int ds1621_attach_adapter(struct i2c_adapter *adapter); -static int ds1621_detect(struct i2c_adapter *adapter, int address, - unsigned short flags, int kind); -static void ds1621_init_client(struct i2c_client *client); -static int ds1621_detach_client(struct i2c_client *client); - -static int ds1621_read_value(struct i2c_client *client, u8 reg); -static int ds1621_write_value(struct i2c_client *client, u8 reg, u16 value); -static void ds1621_temp(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void ds1621_alarms(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void ds1621_enable(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void ds1621_continuous(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void ds1621_polarity(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void ds1621_update_client(struct i2c_client *client); - - -/* This is the driver that will be inserted */ -static struct i2c_driver ds1621_driver = { - .name = "DS1621 sensor driver", - .id = I2C_DRIVERID_DS1621, - .flags = I2C_DF_NOTIFY, - .attach_adapter = ds1621_attach_adapter, - .detach_client = ds1621_detach_client, -}; - -/* -- SENSORS SYSCTL START -- */ -#define DS1621_SYSCTL_TEMP 1200 /* Degrees Celsius * 10 */ -#define DS1621_SYSCTL_ALARMS 2001 /* bitvector */ -#define DS1621_ALARM_TEMP_HIGH 0x40 -#define DS1621_ALARM_TEMP_LOW 0x20 -#define DS1621_SYSCTL_ENABLE 2002 -#define DS1621_SYSCTL_CONTINUOUS 2003 -#define DS1621_SYSCTL_POLARITY 2004 - -/* -- SENSORS SYSCTL END -- */ - -/* These files are created for each detected DS1621. This is just a template; - though at first sight, you might think we could use a statically - allocated list, we need some way to get back to the parent - which - is done through one of the 'extra' fields which are initialized - when a new copy is allocated. */ -static ctl_table ds1621_dir_table_template[] = { - {DS1621_SYSCTL_TEMP, "temp", NULL, 0, 0644, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &ds1621_temp}, - {DS1621_SYSCTL_ALARMS, "alarms", NULL, 0, 0444, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &ds1621_alarms}, - {DS1621_SYSCTL_ENABLE, "enable", NULL, 0, 0644, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &ds1621_enable}, - {DS1621_SYSCTL_CONTINUOUS, "continuous", NULL, 0, 0644, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &ds1621_continuous}, - {DS1621_SYSCTL_POLARITY, "polarity", NULL, 0, 0644, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &ds1621_polarity}, - {0} -}; - -static int ds1621_attach_adapter(struct i2c_adapter *adapter) -{ - return i2c_detect(adapter, &addr_data, ds1621_detect); -} - -/* This function is called by i2c_detect */ -static int ds1621_detect(struct i2c_adapter *adapter, int address, - unsigned short flags, int kind) -{ - int i, conf, temp; - struct i2c_client *new_client; - struct ds1621_data *data; - int err = 0; - const char *type_name, *client_name; - - /* Make sure we aren't probing the ISA bus!! This is just a safety check - at this moment; i2c_detect really won't call us. */ -#ifdef DEBUG - if (i2c_is_isa_adapter(adapter)) { - printk - ("ds1621.o: ds1621_detect called for an ISA bus adapter?!?\n"); - return 0; - } -#endif - - if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA | - I2C_FUNC_SMBUS_WORD_DATA | - I2C_FUNC_SMBUS_WRITE_BYTE)) - goto ERROR0; - - /* OK. For now, we presume we have a valid client. We now create the - client structure, even though we cannot fill it completely yet. - But it allows us to access ds1621_{read,write}_value. */ - if (!(data = kmalloc(sizeof(struct ds1621_data), GFP_KERNEL))) { - err = -ENOMEM; - goto ERROR0; - } - - new_client = &data->client; - new_client->addr = address; - new_client->data = data; - new_client->adapter = adapter; - new_client->driver = &ds1621_driver; - new_client->flags = 0; - - /* Now, we do the remaining detection. It is lousy. */ - if (kind < 0) { - /* The NVB bit should be low if no EEPROM write has been - requested during the latest 10ms, which is highly - improbable in our case. */ - conf = i2c_smbus_read_byte_data(new_client, - DS1621_REG_CONF); - if (conf & DS1621_REG_CONFIG_NVB) - goto ERROR1; - /* The 7 lowest bits of a temperature should always be 0. */ - temp = ds1621_read_value(new_client, - DS1621_REG_TEMP); - if (temp & 0x007f) - goto ERROR1; - temp = ds1621_read_value(new_client, - DS1621_REG_TEMP_HYST); - if (temp & 0x007f) - goto ERROR1; - temp = ds1621_read_value(new_client, - DS1621_REG_TEMP_OVER); - if (temp & 0x007f) - goto ERROR1; - } - - /* Determine the chip type - only one kind supported! */ - if (kind <= 0) - kind = ds1621; - - if (kind == ds1621) { - type_name = "ds1621"; - client_name = "DS1621 chip"; - } else { -#ifdef DEBUG - printk("ds1621.o: Internal error: unknown kind (%d)\n", - kind); -#endif - goto ERROR1; - } - - /* Fill in remaining client fields and put it into the global list */ - strcpy(new_client->name, client_name); - data->valid = 0; - init_MUTEX(&data->update_lock); - - /* Tell the I2C layer a new client has arrived */ - if ((err = i2c_attach_client(new_client))) - goto ERROR3; - - /* Register a new directory entry with module sensors */ - if ((i = i2c_register_entry(new_client, type_name, - ds1621_dir_table_template, - THIS_MODULE)) < 0) { - err = i; - goto ERROR4; - } - data->sysctl_id = i; - - ds1621_init_client(new_client); - return 0; - -/* OK, this is not exactly good programming practice, usually. But it is - very code-efficient in this case. */ - - ERROR4: - i2c_detach_client(new_client); - ERROR3: - ERROR1: - kfree(data); - ERROR0: - return err; -} - -static int ds1621_detach_client(struct i2c_client *client) -{ - int err; - - i2c_deregister_entry(((struct ds1621_data *) (client->data))-> - sysctl_id); - - if ((err = i2c_detach_client(client))) { - printk - ("ds1621.o: Client deregistration failed, client not detached.\n"); - return err; - } - - kfree(client->data); - - return 0; -} - - -/* All registers are word-sized, except for the configuration register. - DS1621 uses a high-byte first convention, which is exactly opposite to - the usual practice. */ -static int ds1621_read_value(struct i2c_client *client, u8 reg) -{ - if ((reg == DS1621_REG_CONF) || (reg == DS1621_REG_TEMP_COUNTER) - || (reg == DS1621_REG_TEMP_SLOPE)) - return i2c_smbus_read_byte_data(client, reg); - else - return swab16(i2c_smbus_read_word_data(client, reg)); -} - -/* All registers are word-sized, except for the configuration register. - DS1621 uses a high-byte first convention, which is exactly opposite to - the usual practice. */ -static int ds1621_write_value(struct i2c_client *client, u8 reg, u16 value) -{ - if ( (reg == DS1621_COM_START) || (reg == DS1621_COM_STOP) ) - return i2c_smbus_write_byte(client, reg); - else - if ((reg == DS1621_REG_CONF) || (reg == DS1621_REG_TEMP_COUNTER) - || (reg == DS1621_REG_TEMP_SLOPE)) - return i2c_smbus_write_byte_data(client, reg, value); - else - return i2c_smbus_write_word_data(client, reg, swab16(value)); -} - -static void ds1621_init_client(struct i2c_client *client) -{ - int reg; - - reg = ds1621_read_value(client, DS1621_REG_CONF); - /* start the continuous conversion */ - if(reg & 0x01) - ds1621_write_value(client, DS1621_REG_CONF, reg & 0xfe); -} - -static void ds1621_update_client(struct i2c_client *client) -{ - struct ds1621_data *data = client->data; - u8 new_conf; - - down(&data->update_lock); - - if ((jiffies - data->last_updated > HZ + HZ / 2) || - (jiffies < data->last_updated) || !data->valid) { - -#ifdef DEBUG - printk("Starting ds1621 update\n"); -#endif - - data->conf = ds1621_read_value(client, DS1621_REG_CONF); - - data->temp = ds1621_read_value(client, - DS1621_REG_TEMP); - data->temp_over = ds1621_read_value(client, - DS1621_REG_TEMP_OVER); - data->temp_hyst = ds1621_read_value(client, - DS1621_REG_TEMP_HYST); - - /* wait for the DONE bit before reading extended values */ - - if (data->conf & DS1621_REG_CONFIG_DONE) { - data->temp_counter = ds1621_read_value(client, - DS1621_REG_TEMP_COUNTER); - data->temp_slope = ds1621_read_value(client, - DS1621_REG_TEMP_SLOPE); - data->temp_int = ITEMP_FROM_REG(data->temp); - /* restart the conversion */ - if (data->enable) - ds1621_write_value(client, DS1621_COM_START, 0); - } - - /* reset alarms if necessary */ - new_conf = data->conf; - if (data->temp < data->temp_over) - new_conf &= ~DS1621_ALARM_TEMP_HIGH; - if (data->temp > data->temp_hyst) - new_conf &= ~DS1621_ALARM_TEMP_LOW; - if (data->conf != new_conf) - ds1621_write_value(client, DS1621_REG_CONF, - new_conf); - - data->last_updated = jiffies; - data->valid = 1; - } - - up(&data->update_lock); -} - - -void ds1621_temp(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct ds1621_data *data = client->data; - if (operation == SENSORS_PROC_REAL_INFO) - if (!(data->conf & DS1621_REG_CONFIG_DONE) || - (data->temp_counter > data->temp_slope) || - (data->temp_slope == 0)) { - *nrels_mag = 1; - } else { - *nrels_mag = 2; - } - else if (operation == SENSORS_PROC_REAL_READ) { - ds1621_update_client(client); - /* decide wether to calculate more precise temp */ - if (!(data->conf & DS1621_REG_CONFIG_DONE) || - (data->temp_counter > data->temp_slope) || - (data->temp_slope == 0)) { - results[0] = TEMP_FROM_REG(data->temp_over); - results[1] = TEMP_FROM_REG(data->temp_hyst); - results[2] = TEMP_FROM_REG(data->temp); - } else { - results[0] = TEMP_FROM_REG(data->temp_over)*10; - results[1] = TEMP_FROM_REG(data->temp_hyst)*10; - results[2] = data->temp_int * 100 - 25 + - ((data->temp_slope - data->temp_counter) * - 100 / data->temp_slope); - } - *nrels_mag = 3; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag >= 1) { - data->temp_over = TEMP_TO_REG(results[0]); - ds1621_write_value(client, DS1621_REG_TEMP_OVER, - data->temp_over); - } - if (*nrels_mag >= 2) { - data->temp_hyst = TEMP_TO_REG(results[1]); - ds1621_write_value(client, DS1621_REG_TEMP_HYST, - data->temp_hyst); - } - } -} - -void ds1621_alarms(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct ds1621_data *data = client->data; - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - ds1621_update_client(client); - results[0] = ALARMS_FROM_REG(data->conf); - *nrels_mag = 1; - } -} - -void ds1621_enable(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - /* If you really screw up your chip (like I did) this is */ - /* sometimes needed to (re)start the continuous conversion */ - /* there is no data to read so this might hang your SMBus! */ - - struct ds1621_data *data = client->data; - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - ds1621_update_client(client); - results[0] = !(data->conf & DS1621_REG_CONFIG_DONE); - *nrels_mag = 1; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag >= 1) { - if (results[0]) { - ds1621_write_value(client, DS1621_COM_START, 0); - data->enable=1; - } else { - ds1621_write_value(client, DS1621_COM_STOP, 0); - data->enable=0; - } - } else { - ds1621_write_value(client, DS1621_COM_START, 0); - data->enable=1; - } - } -} - -void ds1621_continuous(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct ds1621_data *data = client->data; - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - ds1621_update_client(client); - results[0] = !(data->conf & DS1621_REG_CONFIG_1SHOT); - *nrels_mag = 1; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - ds1621_update_client(client); - if (*nrels_mag >= 1) { - if (results[0]) { - ds1621_write_value(client, DS1621_REG_CONF, - data->conf & ~DS1621_REG_CONFIG_1SHOT); - } else { - ds1621_write_value(client, DS1621_REG_CONF, - data->conf | DS1621_REG_CONFIG_1SHOT); - } - } else { - ds1621_write_value(client, DS1621_REG_CONF, - data->conf & ~DS1621_REG_CONFIG_1SHOT); - } - } -} - -void ds1621_polarity(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct ds1621_data *data = client->data; - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - ds1621_update_client(client); - results[0] = !(!(data->conf & DS1621_REG_CONFIG_POLARITY)); - *nrels_mag = 1; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - ds1621_update_client(client); - if (*nrels_mag >= 1) { - if (results[0]) { - ds1621_write_value(client, DS1621_REG_CONF, - data->conf | DS1621_REG_CONFIG_POLARITY); - } else { - ds1621_write_value(client, DS1621_REG_CONF, - data->conf & ~DS1621_REG_CONFIG_POLARITY); - } - } - } -} - -static int __init sm_ds1621_init(void) -{ - printk("ds1621.o version %s (%s)\n", LM_VERSION, LM_DATE); - return i2c_add_driver(&ds1621_driver); -} - -static void __exit sm_ds1621_exit(void) -{ - i2c_del_driver(&ds1621_driver); -} - - - -MODULE_AUTHOR("Christian W. Zuckschwerdt "); -MODULE_DESCRIPTION("DS1621 driver"); - -module_init(sm_ds1621_init); -module_exit(sm_ds1621_exit); diff --git a/kernel/chips/eeprom.c b/kernel/chips/eeprom.c deleted file mode 100644 index 2650dde5..00000000 --- a/kernel/chips/eeprom.c +++ /dev/null @@ -1,350 +0,0 @@ -/* - eeprom.c - Part of lm_sensors, Linux kernel modules for hardware - monitoring - Copyright (c) 1998, 1999 Frodo Looijaard and - Philip Edelbrock - - 2003-08-18 Jean Delvare - Divide the eeprom in 2-row (arbitrary) slices. This significantly - speeds sensors up, as well as various scripts using the eeprom - module. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#include -#include -#include -#include -#include -#include /* for capable() */ -#include "version.h" - -MODULE_LICENSE("GPL"); - -/* Addresses to scan */ -static unsigned short normal_i2c[] = { SENSORS_I2C_END }; -static unsigned short normal_i2c_range[] = { 0x50, 0x57, SENSORS_I2C_END }; -static unsigned int normal_isa[] = { SENSORS_ISA_END }; -static unsigned int normal_isa_range[] = { SENSORS_ISA_END }; - -/* Insmod parameters */ -SENSORS_INSMOD_1(eeprom); - - -/* possible natures */ -#define NATURE_UNKNOWN 0 -#define NATURE_VAIO 1 - -/* Size of EEPROM in bytes */ -#define EEPROM_SIZE 256 - -/* Each client has this additional data */ -struct eeprom_data { - struct i2c_client client; - int sysctl_id; - - struct semaphore update_lock; - u8 valid; /* bitfield, bit!=0 if slice is valid */ - unsigned long last_updated[8]; /* In jiffies, 8 slices */ - - u8 data[EEPROM_SIZE]; /* Register values */ - u8 nature; -}; - - -static int eeprom_attach_adapter(struct i2c_adapter *adapter); -static int eeprom_detect(struct i2c_adapter *adapter, int address, - unsigned short flags, int kind); -static int eeprom_detach_client(struct i2c_client *client); - -static void eeprom_contents(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void eeprom_update_client(struct i2c_client *client, u8 slice); - - -/* This is the driver that will be inserted */ -static struct i2c_driver eeprom_driver = { - .name = "EEPROM READER", - .id = I2C_DRIVERID_EEPROM, - .flags = I2C_DF_NOTIFY, - .attach_adapter = eeprom_attach_adapter, - .detach_client = eeprom_detach_client, -}; - -/* -- SENSORS SYSCTL START -- */ - -#define EEPROM_SYSCTL1 1000 -#define EEPROM_SYSCTL2 1001 -#define EEPROM_SYSCTL3 1002 -#define EEPROM_SYSCTL4 1003 -#define EEPROM_SYSCTL5 1004 -#define EEPROM_SYSCTL6 1005 -#define EEPROM_SYSCTL7 1006 -#define EEPROM_SYSCTL8 1007 -#define EEPROM_SYSCTL9 1008 -#define EEPROM_SYSCTL10 1009 -#define EEPROM_SYSCTL11 1010 -#define EEPROM_SYSCTL12 1011 -#define EEPROM_SYSCTL13 1012 -#define EEPROM_SYSCTL14 1013 -#define EEPROM_SYSCTL15 1014 -#define EEPROM_SYSCTL16 1015 - -/* -- SENSORS SYSCTL END -- */ - -/* These files are created for each detected EEPROM. This is just a template; - though at first sight, you might think we could use a statically - allocated list, we need some way to get back to the parent - which - is done through one of the 'extra' fields which are initialized - when a new copy is allocated. */ -static ctl_table eeprom_dir_table_template[] = { - {EEPROM_SYSCTL1, "00", NULL, 0, 0444, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &eeprom_contents}, - {EEPROM_SYSCTL2, "10", NULL, 0, 0444, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &eeprom_contents}, - {EEPROM_SYSCTL3, "20", NULL, 0, 0444, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &eeprom_contents}, - {EEPROM_SYSCTL4, "30", NULL, 0, 0444, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &eeprom_contents}, - {EEPROM_SYSCTL5, "40", NULL, 0, 0444, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &eeprom_contents}, - {EEPROM_SYSCTL6, "50", NULL, 0, 0444, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &eeprom_contents}, - {EEPROM_SYSCTL7, "60", NULL, 0, 0444, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &eeprom_contents}, - {EEPROM_SYSCTL8, "70", NULL, 0, 0444, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &eeprom_contents}, - {EEPROM_SYSCTL9, "80", NULL, 0, 0444, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &eeprom_contents}, - {EEPROM_SYSCTL10, "90", NULL, 0, 0444, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &eeprom_contents}, - {EEPROM_SYSCTL11, "a0", NULL, 0, 0444, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &eeprom_contents}, - {EEPROM_SYSCTL12, "b0", NULL, 0, 0444, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &eeprom_contents}, - {EEPROM_SYSCTL13, "c0", NULL, 0, 0444, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &eeprom_contents}, - {EEPROM_SYSCTL14, "d0", NULL, 0, 0444, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &eeprom_contents}, - {EEPROM_SYSCTL15, "e0", NULL, 0, 0444, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &eeprom_contents}, - {EEPROM_SYSCTL16, "f0", NULL, 0, 0444, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &eeprom_contents}, - {0} -}; - -static int eeprom_attach_adapter(struct i2c_adapter *adapter) -{ - return i2c_detect(adapter, &addr_data, eeprom_detect); -} - -/* This function is called by i2c_detect */ -static int eeprom_detect(struct i2c_adapter *adapter, int address, - unsigned short flags, int kind) -{ - int i; - struct i2c_client *new_client; - struct eeprom_data *data; - int err = 0; - const char *type_name; - - /* There are three ways we can read the EEPROM data: - (1) I2C block reads (faster, but unsupported by most adapters) - (2) Consecutive byte reads (100% overhead) - (3) Regular byte data reads (200% overhead) - The third method is not implemented by this driver because all - known adapters support at least the second. */ - if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_READ_BYTE_DATA - | I2C_FUNC_SMBUS_BYTE)) - goto ERROR0; - - if (!(data = kmalloc(sizeof(struct eeprom_data), GFP_KERNEL))) { - err = -ENOMEM; - goto ERROR0; - } - - new_client = &data->client; - memset(data->data, 0xff, EEPROM_SIZE); - new_client->addr = address; - new_client->data = data; - new_client->adapter = adapter; - new_client->driver = &eeprom_driver; - new_client->flags = 0; - - /* prevent 24RF08 corruption */ - i2c_smbus_write_quick(new_client, 0); - - type_name = "eeprom"; - - /* Fill in the remaining client fields and put it into the global list */ - strcpy(new_client->name, "EEPROM chip"); - data->valid = 0; - init_MUTEX(&data->update_lock); - data->nature = NATURE_UNKNOWN; - - /* Tell the I2C layer a new client has arrived */ - if ((err = i2c_attach_client(new_client))) - goto ERROR3; - - /* Detect the Vaio nature of EEPROMs. - We use the "PCG-" or "VGN-" prefix as the signature. */ - if (address == 0x57) { - char name[4]; - - name[0] = i2c_smbus_read_byte_data(new_client, 0x80); - name[1] = i2c_smbus_read_byte(new_client); - name[2] = i2c_smbus_read_byte(new_client); - name[3] = i2c_smbus_read_byte(new_client); - - if (!memcmp(name, "PCG-", 4) || !memcmp(name, "VGN-", 4)) { - printk(KERN_INFO "Vaio EEPROM detected, " - "enabling privacy protection\n"); - data->nature = NATURE_VAIO; - } - } - - /* Register a new directory entry with module sensors */ - if ((i = i2c_register_entry(new_client, type_name, - eeprom_dir_table_template, - THIS_MODULE)) < 0) { - err = i; - goto ERROR4; - } - data->sysctl_id = i; - - return 0; - - ERROR4: - i2c_detach_client(new_client); - ERROR3: - kfree(data); - ERROR0: - return err; -} - -static int eeprom_detach_client(struct i2c_client *client) -{ - int err; - - i2c_deregister_entry(((struct eeprom_data *) (client->data))-> - sysctl_id); - - if ((err = i2c_detach_client(client))) { - printk - ("eeprom.o: Client deregistration failed, client not detached.\n"); - return err; - } - - kfree(client->data); - - return 0; -} - -static void eeprom_update_client(struct i2c_client *client, u8 slice) -{ - struct eeprom_data *data = client->data; - int i, j; - - down(&data->update_lock); - - if (!(data->valid & (1 << slice)) - || (jiffies - data->last_updated[slice] > 300 * HZ) - || (jiffies < data->last_updated[slice])) { - -#ifdef DEBUG - printk(KERN_DEBUG "eeprom.o: Starting update, slice %u\n", slice); -#endif - - if (i2c_check_functionality(client->adapter, - I2C_FUNC_SMBUS_READ_I2C_BLOCK)) - { - for (i = slice << 5; i < (slice + 1) << 5; - i += I2C_SMBUS_I2C_BLOCK_MAX) - if (i2c_smbus_read_i2c_block_data(client, - i, data->data + i) - != I2C_SMBUS_I2C_BLOCK_MAX) { - printk(KERN_WARNING "eeprom.o: block read fail at 0x%.2x!\n", i); - goto DONE; - } - } else { - if (i2c_smbus_write_byte(client, slice << 5)) { - printk(KERN_WARNING "eeprom.o: read start fail at 0x%.2x!\n", slice << 5); - goto DONE; - } - for (i = slice << 5; i < (slice + 1) << 5; i++) { - j = i2c_smbus_read_byte(client); - if (j < 0) { - printk(KERN_WARNING "eeprom.o: read fail at 0x%.2x!\n", i); - goto DONE; - } - data->data[i] = (u8) j; - } - } - data->last_updated[slice] = jiffies; - data->valid |= (1 << slice); - } -DONE: - up(&data->update_lock); -} - - -void eeprom_contents(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results) -{ - int i; - int nr = ctl_name - EEPROM_SYSCTL1; - struct eeprom_data *data = client->data; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - eeprom_update_client(client, nr >> 1); - /* Hide Vaio private settings to regular users: - - BIOS passwords: bytes 0x00 to 0x0f (row 0) - - UUID: bytes 0x10 to 0x1f (row 1) - - Serial number: 0xc0 to 0xdf (rows 12 and 13) */ - if (data->nature == NATURE_VAIO - && !capable(CAP_SYS_ADMIN) - && (nr == 0 || nr == 1 || nr == 12 || nr == 13)) - for (i = 0; i < 16; i++) - results[i] = 0; - else - for (i = 0; i < 16; i++) - results[i] = data->data[i + nr * 16]; - - *nrels_mag = 16; - } -} - -static int __init sm_eeprom_init(void) -{ - printk("eeprom.o version %s (%s)\n", LM_VERSION, LM_DATE); - return i2c_add_driver(&eeprom_driver); -} - -static void __exit sm_eeprom_exit(void) -{ - i2c_del_driver(&eeprom_driver); -} - - - -MODULE_AUTHOR - ("Frodo Looijaard and Philip Edelbrock "); -MODULE_DESCRIPTION("EEPROM driver"); - -module_init(sm_eeprom_init); -module_exit(sm_eeprom_exit); diff --git a/kernel/chips/f71805f.c b/kernel/chips/f71805f.c deleted file mode 100644 index 39f8694c..00000000 --- a/kernel/chips/f71805f.c +++ /dev/null @@ -1,757 +0,0 @@ -/* - * f71805f.c - driver for the Fintek F71805F Super-I/O chip integrated - * hardware monitoring features - * Copyright (C) 2005 Jean Delvare - * - * The F71805F is a LPC Super-I/O chip made by Fintek. It integrates - * complete hardware monitoring features: voltage, fan and temperature - * sensors, and manual and automatic fan speed control. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include -#include -#include -#include -#include -#include -#include -#include "version.h" - -/* ISA address is read from Super-I/O configuration space */ -static unsigned short normal_i2c[] = { SENSORS_I2C_END }; -static unsigned short normal_i2c_range[] = { SENSORS_I2C_END }; -static unsigned int normal_isa[] = { 0, SENSORS_ISA_END }; -static unsigned int normal_isa_range[] = { SENSORS_ISA_END }; - -SENSORS_INSMOD_1(f71805f); - -#define DRVNAME "f71805f" - -/* - * Super-I/O constants and functions - */ - -#define F71805F_LD_HWM 0x04 - -#define SIO_REG_LDSEL 0x07 /* Logical device select */ -#define SIO_REG_DEVID 0x20 /* Device ID (2 bytes) */ -#define SIO_REG_DEVREV 0x22 /* Device revision */ -#define SIO_REG_MANID 0x23 /* Fintek ID (2 bytes) */ -#define SIO_REG_ENABLE 0x30 /* Logical device enable */ -#define SIO_REG_ADDR 0x60 /* Logical device address (2 bytes) */ - -#define SIO_FINTEK_ID 0x1934 -#define SIO_F71805F_ID 0x0406 - -static inline int -superio_inb(int base, int reg) -{ - outb(reg, base); - return inb(base + 1); -} - -static int -superio_inw(int base, int reg) -{ - int val; - outb(reg++, base); - val = inb(base + 1) << 8; - outb(reg, base); - val |= inb(base + 1); - return val; -} - -static inline void -superio_select(int base, int ld) -{ - outb(SIO_REG_LDSEL, base); - outb(ld, base + 1); -} - -static inline void -superio_enter(int base) -{ - outb(0x87, base); - outb(0x87, base); -} - -static inline void -superio_exit(int base) -{ - outb(0xaa, base); -} - -/* - * ISA constants - */ - -#define REGION_LENGTH 8 -#define ADDR_REG_OFFSET 5 -#define DATA_REG_OFFSET 6 - -/* - * Registers - */ - -/* in nr from 0 to 8 (8-bit values) */ -#define F71805F_REG_IN(nr) (0x10 + (nr)) -#define F71805F_REG_IN_HIGH(nr) (0x40 + 2 * (nr)) -#define F71805F_REG_IN_LOW(nr) (0x41 + 2 * (nr)) -/* fan nr from 0 to 2 (12-bit values, two registers) */ -#define F71805F_REG_FAN(nr) (0x20 + 2 * (nr)) -#define F71805F_REG_FAN_LOW(nr) (0x28 + 2 * (nr)) -#define F71805F_REG_FAN_CTRL(nr) (0x60 + 16 * (nr)) -/* temp nr from 0 to 2 (8-bit values) */ -#define F71805F_REG_TEMP(nr) (0x1B + (nr)) -#define F71805F_REG_TEMP_HIGH(nr) (0x54 + 2 * (nr)) -#define F71805F_REG_TEMP_HYST(nr) (0x55 + 2 * (nr)) -#define F71805F_REG_TEMP_MODE 0x01 - -#define F71805F_REG_START 0x00 -/* status nr from 0 to 2 */ -#define F71805F_REG_STATUS(nr) (0x36 + (nr)) - -/* - * Data structures and manipulation thereof - */ - -struct f71805f_data { - struct i2c_client client; - struct semaphore lock; - int sysctl_id; - - struct semaphore update_lock; - char valid; /* !=0 if following fields are valid */ - unsigned long last_updated; /* In jiffies */ - unsigned long last_limits; /* In jiffies */ - - /* Register values */ - u8 in[9]; - u8 in_high[9]; - u8 in_low[9]; - u16 fan[3]; - u16 fan_low[3]; - u8 fan_enabled; /* Read once at init time */ - u8 temp[3]; - u8 temp_high[3]; - u8 temp_hyst[3]; - u8 temp_mode; - u8 alarms[3]; -}; - -static inline long in_from_reg(u8 reg) -{ - return (reg * 8); -} - -/* The 2 least significant bits are not used */ -static inline u8 in_to_reg(long val) -{ - if (val <= 0) - return 0; - if (val >= 2016) - return 0xfc; - return (((val + 16) / 32) << 2); -} - -/* in0 is downscaled by a factor 2 internally */ -static inline long in0_from_reg(u8 reg) -{ - return (reg * 16); -} - -static inline u8 in0_to_reg(long val) -{ - if (val <= 0) - return 0; - if (val >= 4032) - return 0xfc; - return (((val + 32) / 64) << 2); -} - -/* The 4 most significant bits are not used */ -static inline long fan_from_reg(u16 reg) -{ - reg &= 0xfff; - if (!reg || reg == 0xfff) - return 0; - return (1500000 / reg); -} - -static inline u16 fan_to_reg(long rpm) -{ - /* If the low limit is set below what the chip can measure, - store the largest possible 12-bit value in the registers, - so that no alarm will ever trigger. */ - if (rpm < 367) - return 0xfff; - return (1500000 / rpm); -} - -static inline u8 temp_to_reg(long val) -{ - if (val < 0) - val = 0; - else if (val > 0xff) - val = 0xff; - return val; -} - -/* - * Driver and client management - */ - -static u8 f71805f_read8(struct i2c_client *client, u8 reg) -{ - struct f71805f_data *data = client->data; - u8 val; - - down(&data->lock); - outb_p(reg, client->addr + ADDR_REG_OFFSET); - val = inb_p(client->addr + DATA_REG_OFFSET); - up(&data->lock); - - return val; -} - -static void f71805f_write8(struct i2c_client *client, u8 reg, u8 val) -{ - struct f71805f_data *data = client->data; - - down(&data->lock); - outb_p(reg, client->addr + ADDR_REG_OFFSET); - outb_p(val, client->addr + DATA_REG_OFFSET); - up(&data->lock); -} - -/* It is important to read the MSB first, because doing so latches the - value of the LSB, so we are sure both bytes belong to the same value. */ -static u16 f71805f_read16(struct i2c_client *client, u8 reg) -{ - struct f71805f_data *data = client->data; - u16 val; - - down(&data->lock); - outb_p(reg, client->addr + ADDR_REG_OFFSET); - val = inb_p(client->addr + DATA_REG_OFFSET) << 8; - outb_p(++reg, client->addr + ADDR_REG_OFFSET); - val |= inb_p(client->addr + DATA_REG_OFFSET); - up(&data->lock); - - return val; -} - -static void f71805f_write16(struct i2c_client *client, u8 reg, u16 val) -{ - struct f71805f_data *data = client->data; - - down(&data->lock); - outb_p(reg, client->addr + ADDR_REG_OFFSET); - outb_p(val >> 8, client->addr + DATA_REG_OFFSET); - outb_p(++reg, client->addr + ADDR_REG_OFFSET); - outb_p(val & 0xff, client->addr + DATA_REG_OFFSET); - up(&data->lock); -} - -static struct i2c_driver f71805f_driver; -static ctl_table f71805f_dir_table_template[]; - -static void f71805f_init_client(struct i2c_client *client) -{ - struct f71805f_data *data = client->data; - u8 reg; - int i; - - reg = f71805f_read8(client, F71805F_REG_START); - if ((reg & 0x41) != 0x01) { - printk(KERN_DEBUG DRVNAME ": Starting monitoring " - "operations\n"); - f71805f_write8(client, - F71805F_REG_START, (reg | 0x01) & ~0x40); - } - - /* Fan monitoring can be disabled. If it is, we won't be polling - the register values, and instead set the cache to return 0 RPM. */ - for (i = 0; i < 3; i++) { - reg = f71805f_read8(client, F71805F_REG_FAN_CTRL(i)); - if (!(reg & 0x80)) - data->fan_enabled |= (1 << i); - else - data->fan[i] = data->fan_low[i] = 0xfff; - } -} - -static int f71805f_detect(struct i2c_adapter *adapter, int address, - unsigned short flags, int kind) -{ - struct i2c_client *client; - struct f71805f_data *data; - int err; - - if (!request_region(address, REGION_LENGTH, f71805f_driver.name)) { - err = -EBUSY; - goto exit; - } - - if (!(data = kmalloc(sizeof(struct f71805f_data), GFP_KERNEL))) { - err = -ENOMEM; - goto exit_release; - } - memset(data, 0, sizeof(struct f71805f_data)); - - /* Fill in the client fields */ - client = &data->client; - client->addr = address; - client->data = data; - client->adapter = adapter; - client->driver = &f71805f_driver; - strcpy(client->name, "F71805F chip"); - - init_MUTEX(&data->lock); - init_MUTEX(&data->update_lock); - - /* Tell the i2c core a new client has arrived */ - if ((err = i2c_attach_client(client))) - goto exit_free; - - /* Initialize the F71805F chip */ - f71805f_init_client(client); - - /* Register a new directory entry in /proc */ - err = i2c_register_entry(client, "f71805f", - f71805f_dir_table_template, THIS_MODULE); - if (err < 0) - goto exit_detach; - data->sysctl_id = err; - - return 0; - -exit_detach: - i2c_detach_client(client); -exit_free: - kfree(data); -exit_release: - release_region(address, REGION_LENGTH); -exit: - return err; -} - -static int f71805f_attach_adapter(struct i2c_adapter *adapter) -{ - return i2c_detect(adapter, &addr_data, f71805f_detect); -} - -static int f71805f_detach_client(struct i2c_client *client) -{ - int err; - struct f71805f_data *data = client->data; - - i2c_deregister_entry(data->sysctl_id); - if ((err = i2c_detach_client(client))) { - printk(KERN_ERR DRVNAME ": Client deregistration failed, " - "client not detached\n"); - return err; - } - - release_region(client->addr, REGION_LENGTH); - kfree(client->data); - - return 0; -} - -static void f71805f_update_client(struct i2c_client *client) -{ - struct f71805f_data *data = client->data; - int nr; - - down(&data->update_lock); - - /* Limit registers cache is refreshed after 60 seconds */ - if ((jiffies - data->last_limits > 60 * HZ) - || (jiffies < data->last_limits) - || !data->valid) { - for (nr = 0; nr < 9; nr++) { - data->in_high[nr] = f71805f_read8(client, - F71805F_REG_IN_HIGH(nr)); - data->in_low[nr] = f71805f_read8(client, - F71805F_REG_IN_LOW(nr)); - } - for (nr = 0; nr < 3; nr++) { - if (data->fan_enabled & (1 << nr)) - data->fan_low[nr] = f71805f_read16(client, - F71805F_REG_FAN_LOW(nr)); - } - for (nr = 0; nr < 3; nr++) { - data->temp_high[nr] = f71805f_read8(client, - F71805F_REG_TEMP_HIGH(nr)); - data->temp_hyst[nr] = f71805f_read8(client, - F71805F_REG_TEMP_HYST(nr)); - } - data->temp_mode = f71805f_read8(client, F71805F_REG_TEMP_MODE); - - data->last_limits = jiffies; - } - - /* Measurement registers cache is refreshed after 1 second */ - if ((jiffies - data->last_updated > HZ) - || (jiffies < data->last_updated) - || !data->valid) { - for (nr = 0; nr < 9; nr++) { - data->in[nr] = f71805f_read8(client, - F71805F_REG_IN(nr)); - } - for (nr = 0; nr < 3; nr++) { - if (data->fan_enabled & (1 << nr)) - data->fan[nr] = f71805f_read16(client, - F71805F_REG_FAN(nr)); - } - for (nr = 0; nr < 3; nr++) { - data->temp[nr] = f71805f_read8(client, - F71805F_REG_TEMP(nr)); - } - for (nr = 0; nr < 3; nr++) { - data->alarms[nr] = f71805f_read8(client, - F71805F_REG_STATUS(nr)); - } - - data->last_updated = jiffies; - data->valid = 1; - } - - up(&data->update_lock); -} - -/* -- SENSORS SYSCTL START -- */ -#define F71805F_SYSCTL_IN0 1000 -#define F71805F_SYSCTL_IN1 1001 -#define F71805F_SYSCTL_IN2 1002 -#define F71805F_SYSCTL_IN3 1003 -#define F71805F_SYSCTL_IN4 1004 -#define F71805F_SYSCTL_IN5 1005 -#define F71805F_SYSCTL_IN6 1006 -#define F71805F_SYSCTL_IN7 1007 -#define F71805F_SYSCTL_IN8 1008 -#define F71805F_SYSCTL_FAN1 1101 -#define F71805F_SYSCTL_FAN2 1102 -#define F71805F_SYSCTL_FAN3 1103 -#define F71805F_SYSCTL_TEMP1 1201 -#define F71805F_SYSCTL_TEMP2 1202 -#define F71805F_SYSCTL_TEMP3 1203 -#define F71805F_SYSCTL_SENSOR1 1211 -#define F71805F_SYSCTL_SENSOR2 1212 -#define F71805F_SYSCTL_SENSOR3 1213 -#define F71805F_SYSCTL_ALARMS_IN 1090 -#define F71805F_SYSCTL_ALARMS_FAN 1190 -#define F71805F_SYSCTL_ALARMS_TEMP 1290 -/* -- SENSORS SYSCTL END -- */ - -static void f71805f_in(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results) -{ - struct f71805f_data *data = client->data; - int nr = ctl_name - F71805F_SYSCTL_IN0; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 3; - else if (operation == SENSORS_PROC_REAL_READ) { - f71805f_update_client(client); - results[0] = in_from_reg(data->in_low[nr]); - results[1] = in_from_reg(data->in_high[nr]); - results[2] = in_from_reg(data->in[nr]); - *nrels_mag = 3; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag < 1) - return; - - down(&data->update_lock); - data->in_low[nr] = in_to_reg(results[0]); - f71805f_write8(client, F71805F_REG_IN_LOW(nr), - data->in_low[nr]); - - if (*nrels_mag >= 2) { - data->in_high[nr] = in_to_reg(results[1]); - f71805f_write8(client, F71805F_REG_IN_HIGH(nr), - data->in_high[nr]); - } - up(&data->update_lock); - } -} - -static void f71805f_in0(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results) -{ - struct f71805f_data *data = client->data; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 3; - else if (operation == SENSORS_PROC_REAL_READ) { - f71805f_update_client(client); - results[0] = in0_from_reg(data->in_low[0]); - results[1] = in0_from_reg(data->in_high[0]); - results[2] = in0_from_reg(data->in[0]); - *nrels_mag = 3; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag < 1) - return; - - down(&data->update_lock); - data->in_low[0] = in0_to_reg(results[0]); - f71805f_write8(client, F71805F_REG_IN_LOW(0), - data->in_low[0]); - - if (*nrels_mag >= 2) { - data->in_high[0] = in0_to_reg(results[1]); - f71805f_write8(client, F71805F_REG_IN_HIGH(0), - data->in_high[0]); - } - up(&data->update_lock); - } -} - -static void f71805f_fan(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results) -{ - struct f71805f_data *data = client->data; - int nr = ctl_name - F71805F_SYSCTL_FAN1; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - f71805f_update_client(client); - results[0] = fan_from_reg(data->fan_low[nr]); - results[1] = fan_from_reg(data->fan[nr]); - *nrels_mag = 2; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag < 1) - return; - - down(&data->update_lock); - data->fan_low[nr] = fan_to_reg(results[0]); - f71805f_write16(client, F71805F_REG_FAN_LOW(nr), - data->fan_low[nr]); - up(&data->update_lock); - } -} - -static void f71805f_temp(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results) -{ - struct f71805f_data *data = client->data; - int nr = ctl_name - F71805F_SYSCTL_TEMP1; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - f71805f_update_client(client); - results[0] = data->temp_high[nr]; - results[1] = data->temp_hyst[nr]; - results[2] = data->temp[nr]; - *nrels_mag = 3; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag < 1) - return; - - down(&data->update_lock); - data->temp_high[nr] = temp_to_reg(results[0]); - f71805f_write8(client, F71805F_REG_TEMP_HIGH(nr), - data->temp_high[nr]); - - if (*nrels_mag >= 2) { - data->temp_hyst[nr] = temp_to_reg(results[1]); - f71805f_write8(client, F71805F_REG_TEMP_HYST(nr), - data->temp_hyst[nr]); - } - up(&data->update_lock); - } -} - -static void f71805f_sensor(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results) -{ - struct f71805f_data *data = client->data; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - int nr = ctl_name - F71805F_SYSCTL_SENSOR1; - - f71805f_update_client(client); - results[0] = (data->temp_mode & (1 << nr)) ? 3 : 4; - *nrels_mag = 1; - } -} - -static void f71805f_alarms_in(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results) -{ - struct f71805f_data *data = client->data; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - f71805f_update_client(client); - results[0] = data->alarms[0] - | ((data->alarms[1] & 0x01) << 8); - *nrels_mag = 1; - } -} - -static void f71805f_alarms_fan(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results) -{ - struct f71805f_data *data = client->data; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - f71805f_update_client(client); - results[0] = data->alarms[2] & 0x07; - *nrels_mag = 1; - } -} - -static void f71805f_alarms_temp(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results) -{ - struct f71805f_data *data = client->data; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - f71805f_update_client(client); - results[0] = (data->alarms[1] >> 3) & 0x07; - *nrels_mag = 1; - } -} - -static ctl_table f71805f_dir_table_template[] = { - { F71805F_SYSCTL_IN0, "in0", NULL, 0, 0644, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &f71805f_in0 }, - { F71805F_SYSCTL_IN1, "in1", NULL, 0, 0644, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &f71805f_in }, - { F71805F_SYSCTL_IN2, "in2", NULL, 0, 0644, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &f71805f_in }, - { F71805F_SYSCTL_IN3, "in3", NULL, 0, 0644, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &f71805f_in }, - { F71805F_SYSCTL_IN4, "in4", NULL, 0, 0644, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &f71805f_in }, - { F71805F_SYSCTL_IN5, "in5", NULL, 0, 0644, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &f71805f_in }, - { F71805F_SYSCTL_IN6, "in6", NULL, 0, 0644, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &f71805f_in }, - { F71805F_SYSCTL_IN7, "in7", NULL, 0, 0644, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &f71805f_in }, - { F71805F_SYSCTL_IN8, "in8", NULL, 0, 0644, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &f71805f_in }, - { F71805F_SYSCTL_FAN1, "fan1", NULL, 0, 0644, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &f71805f_fan }, - { F71805F_SYSCTL_FAN2, "fan2", NULL, 0, 0644, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &f71805f_fan }, - { F71805F_SYSCTL_FAN3, "fan3", NULL, 0, 0644, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &f71805f_fan }, - { F71805F_SYSCTL_TEMP1, "temp1", NULL, 0, 0644, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &f71805f_temp }, - { F71805F_SYSCTL_TEMP2, "temp2", NULL, 0, 0644, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &f71805f_temp }, - { F71805F_SYSCTL_TEMP3, "temp3", NULL, 0, 0644, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &f71805f_temp }, - { F71805F_SYSCTL_SENSOR1, "sensor1", NULL, 0, 0444, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &f71805f_sensor }, - { F71805F_SYSCTL_SENSOR2, "sensor2", NULL, 0, 0444, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &f71805f_sensor }, - { F71805F_SYSCTL_SENSOR3, "sensor3", NULL, 0, 0444, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &f71805f_sensor }, - { F71805F_SYSCTL_ALARMS_IN, "alarms_in", NULL, 0, 0444, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &f71805f_alarms_in }, - { F71805F_SYSCTL_ALARMS_FAN, "alarms_fan", NULL, 0, 0444, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &f71805f_alarms_fan }, - { F71805F_SYSCTL_ALARMS_TEMP, "alarms_temp", NULL, 0, 0444, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &f71805f_alarms_temp }, - { 0 } -}; - -static struct i2c_driver f71805f_driver = { - .name = "F71805F sensor driver", - .flags = I2C_DF_NOTIFY, - .attach_adapter = f71805f_attach_adapter, - .detach_client = f71805f_detach_client, -}; - -static int __init f71805f_find(int sioaddr, unsigned int *address) -{ - int err = -ENODEV; - u16 devid; - - superio_enter(sioaddr); - - devid = superio_inw(sioaddr, SIO_REG_MANID); - if (devid != SIO_FINTEK_ID) - goto exit; - - devid = superio_inw(sioaddr, SIO_REG_DEVID); - if (devid != SIO_F71805F_ID) { - printk(KERN_INFO DRVNAME ": Unsupported Fintek device, " - "skipping\n"); - goto exit; - } - - superio_select(sioaddr, F71805F_LD_HWM); - if (!(superio_inb(sioaddr, SIO_REG_ENABLE) & 0x01)) { - printk(KERN_WARNING DRVNAME ": Device not activated, " - "skipping\n"); - goto exit; - } - - *address = superio_inw(sioaddr, SIO_REG_ADDR); - if (*address == 0) { - printk(KERN_WARNING DRVNAME ": Base address not set, " - "skipping\n"); - goto exit; - } - *address &= ~(REGION_LENGTH - 1); /* Ignore 3 LSB */ - - err = 0; - printk(KERN_INFO DRVNAME ": Found F71805F chip at %#x, revision %u\n", - *address, superio_inb(sioaddr, SIO_REG_DEVREV)); - -exit: - superio_exit(sioaddr); - return err; -} - -static int __init f71805f_init(void) -{ - printk("%s: Driver version %s (%s)\n", DRVNAME, LM_VERSION, LM_DATE); - - if (f71805f_find(0x2e, &normal_isa[0]) - && f71805f_find(0x4e, &normal_isa[0])) - return -ENODEV; - - return i2c_add_driver(&f71805f_driver); -} - -static void __exit f71805f_exit(void) -{ - i2c_del_driver(&f71805f_driver); -} - -MODULE_AUTHOR("Jean Delvare "); -MODULE_LICENSE("GPL"); -MODULE_DESCRIPTION("F71805F hardware monitoring driver"); - -module_init(f71805f_init); -module_exit(f71805f_exit); diff --git a/kernel/chips/fscher.c b/kernel/chips/fscher.c deleted file mode 100644 index 3fabba3a..00000000 --- a/kernel/chips/fscher.c +++ /dev/null @@ -1,730 +0,0 @@ -/* - fscher.c - Part of lm_sensors, Linux kernel modules for hardware - monitoring - Copyright (C) 2003, 2004 Reinhard Nissl - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -/* - fujitsu siemens hermes chip, - module based on fscpos.c - Copyright (C) 2000 Hermann Jung - Copyright (C) 1998, 1999 Frodo Looijaard - and Philip Edelbrock -*/ - -#include -#include -#include -#include -#include -#include "version.h" - -#ifndef I2C_DRIVERID_FSCHER -#define I2C_DRIVERID_FSCHER 1046 -#endif - -/* Addresses to scan */ -static unsigned short normal_i2c[] = { 0x73, SENSORS_I2C_END }; -static unsigned short normal_i2c_range[] = { SENSORS_I2C_END }; -static unsigned int normal_isa[] = { SENSORS_ISA_END }; -static unsigned int normal_isa_range[] = { SENSORS_ISA_END }; - -/* Insmod parameters */ -SENSORS_INSMOD_1(fscher); - -/* The FSCHER registers */ - -/* chip identification */ -#define FSCHER_REG_IDENT_0 0x00 -#define FSCHER_REG_IDENT_1 0x01 -#define FSCHER_REG_IDENT_2 0x02 -#define FSCHER_REG_REVISION 0x03 - -/* global control and status */ -#define FSCHER_REG_EVENT_STATE 0x04 -#define FSCHER_REG_CONTROL 0x05 - -/* watchdog */ -#define FSCHER_REG_WDOG_PRESET 0x28 -#define FSCHER_REG_WDOG_STATE 0x23 -#define FSCHER_REG_WDOG_CONTROL 0x21 - -/* fan 0 */ -#define FSCHER_REG_FAN0_MIN 0x55 -#define FSCHER_REG_FAN0_ACT 0x0e -#define FSCHER_REG_FAN0_STATE 0x0d -#define FSCHER_REG_FAN0_RIPPLE 0x0f - -/* fan 1 */ -#define FSCHER_REG_FAN1_MIN 0x65 -#define FSCHER_REG_FAN1_ACT 0x6b -#define FSCHER_REG_FAN1_STATE 0x62 -#define FSCHER_REG_FAN1_RIPPLE 0x6f - -/* fan 2 */ -#define FSCHER_REG_FAN2_MIN 0xb5 -#define FSCHER_REG_FAN2_ACT 0xbb -#define FSCHER_REG_FAN2_STATE 0xb2 -#define FSCHER_REG_FAN2_RIPPLE 0xbf - -/* voltage supervision */ -#define FSCHER_REG_VOLT_12 0x45 -#define FSCHER_REG_VOLT_5 0x42 -#define FSCHER_REG_VOLT_BATT 0x48 - -/* temperatures */ -/* sensor 0 */ -#define FSCHER_REG_TEMP0_ACT 0x64 -#define FSCHER_REG_TEMP0_STATE 0x71 - -/* sensor 1 */ -#define FSCHER_REG_TEMP1_ACT 0x32 -#define FSCHER_REG_TEMP1_STATE 0x81 - -/* sensor 2 */ -#define FSCHER_REG_TEMP2_ACT 0x35 -#define FSCHER_REG_TEMP2_STATE 0x91 - - - -/* Initial limits */ - -/* For each registered FSCHER, we need to keep some data in memory. It is - dynamically allocated, at the same time when a new fscher client is - allocated. */ -struct fscher_data { - struct i2c_client client; - int sysctl_id; - - struct semaphore update_lock; - char valid; /* !=0 if following fields are valid */ - unsigned long last_updated; /* In jiffies */ - - u8 revision; /* revision of chip */ - u8 global_event; /* global event status */ - u8 global_control; /* global control register */ - u8 watchdog[3]; /* watchdog */ - u8 volt[3]; /* 12, 5, battery current */ - u8 temp_act[3]; /* temperature */ - u8 temp_status[3]; /* status of sensor */ - u8 fan_act[3]; /* fans revolutions per second */ - u8 fan_status[3]; /* fan status */ - u8 fan_min[3]; /* fan min value for rps */ - u8 fan_ripple[3]; /* divider for rps */ -}; - - -static int fscher_attach_adapter(struct i2c_adapter *adapter); -static int fscher_detect(struct i2c_adapter *adapter, int address, - unsigned short flags, int kind); -static int fscher_detach_client(struct i2c_client *client); - -static int fscher_read_value(struct i2c_client *client, u8 register); -static int fscher_write_value(struct i2c_client *client, u8 register, - u8 value); -static void fscher_update_client(struct i2c_client *client); -static void fscher_init_client(struct i2c_client *client); - - -static void fscher_in(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results); -static void fscher_pwm(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void fscher_pwm_internal(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results, - int nr, int reg_min); -static void fscher_fan(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void fscher_fan_internal(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results, - int nr, int reg_state, int res_ripple); -static void fscher_temp(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void fscher_volt(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void fscher_wdog(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); - -static struct i2c_driver fscher_driver = { - .name = "FSCHER sensor driver", - .id = I2C_DRIVERID_FSCHER, - .flags = I2C_DF_NOTIFY, - .attach_adapter = fscher_attach_adapter, - .detach_client = fscher_detach_client, -}; - -/* -- SENSORS SYSCTL START -- */ -#define FSCHER_SYSCTL_VOLT0 1000 /* 12 volt supply */ -#define FSCHER_SYSCTL_VOLT1 1001 /* 5 volt supply */ -#define FSCHER_SYSCTL_VOLT2 1002 /* batterie voltage */ -#define FSCHER_SYSCTL_FAN0 1101 /* state, ripple, actual value - fan 0 */ -#define FSCHER_SYSCTL_FAN1 1102 /* state, ripple, actual value - fan 1 */ -#define FSCHER_SYSCTL_FAN2 1103 /* state, ripple, actual value - fan 2 */ -#define FSCHER_SYSCTL_TEMP0 1201 /* state and value of sensor 0, - cpu die */ -#define FSCHER_SYSCTL_TEMP1 1202 /* state and value of sensor 1, - motherboard */ -#define FSCHER_SYSCTL_TEMP2 1203 /* state and value of sensor 2, - chassis */ -#define FSCHER_SYSCTL_PWM0 1301 /* min fan 0 */ -#define FSCHER_SYSCTL_PWM1 1302 /* min fan 1 */ -#define FSCHER_SYSCTL_PWM2 1303 /* min fan 2 */ -#define FSCHER_SYSCTL_REV 2000 /* revision */ -#define FSCHER_SYSCTL_EVENT 2001 /* global event status */ -#define FSCHER_SYSCTL_CONTROL 2002 /* global control byte */ -#define FSCHER_SYSCTL_WDOG 2003 /* watch dog preset, state and - control */ -/* -- SENSORS SYSCTL END -- */ - -/* These files are created for each detected FSCHER. This is just a template; - though at first sight, you might think we could use a statically - allocated list, we need some way to get back to the parent - which - is done through one of the 'extra' fields which are initialized - when a new copy is allocated. */ -static ctl_table fscher_dir_table_template[] = { - {FSCHER_SYSCTL_REV, "rev", NULL, 0, 0444, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &fscher_in}, - {FSCHER_SYSCTL_EVENT, "alarms", NULL, 0, 0444, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &fscher_in}, - {FSCHER_SYSCTL_CONTROL, "control", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &fscher_in}, - {FSCHER_SYSCTL_TEMP0, "temp1", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &fscher_temp}, - {FSCHER_SYSCTL_TEMP1, "temp2", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &fscher_temp}, - {FSCHER_SYSCTL_TEMP2, "temp3", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &fscher_temp}, - {FSCHER_SYSCTL_VOLT0, "in0", NULL, 0, 0444, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &fscher_volt}, - {FSCHER_SYSCTL_VOLT1, "in1", NULL, 0, 0444, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &fscher_volt}, - {FSCHER_SYSCTL_VOLT2, "in2", NULL, 0, 0444, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &fscher_volt}, - {FSCHER_SYSCTL_FAN0, "fan1", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &fscher_fan}, - {FSCHER_SYSCTL_FAN1, "fan2", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &fscher_fan}, - {FSCHER_SYSCTL_FAN2, "fan3", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &fscher_fan}, - {FSCHER_SYSCTL_PWM0, "pwm1", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &fscher_pwm}, - {FSCHER_SYSCTL_PWM1, "pwm2", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &fscher_pwm}, - {FSCHER_SYSCTL_PWM2, "pwm3", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &fscher_pwm}, - {FSCHER_SYSCTL_WDOG, "wdog", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &fscher_wdog}, - {0} -}; - -static int fscher_attach_adapter(struct i2c_adapter *adapter) -{ - return i2c_detect(adapter, &addr_data, fscher_detect); -} - -int fscher_detect(struct i2c_adapter *adapter, int address, - unsigned short flags, int kind) -{ - int i; - struct i2c_client *new_client; - struct fscher_data *data; - int err = 0; - const char *type_name, *client_name; - - /* Make sure we aren't probing the ISA bus!! This is just a safety - check at this moment; i2c_detect really won't call us. */ -#ifdef DEBUG - if (i2c_is_isa_adapter(adapter)) { - printk("fscher.o: fscher_detect called for an ISA bus adapter?!?\n"); - return 0; - } -#endif - - if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) - goto ERROR0; - - /* OK. For now, we presume we have a valid client. We now create the - client structure, even though we cannot fill it completely yet. - But it allows us to access fscher_{read,write}_value. */ - if (!(data = kmalloc(sizeof(struct fscher_data), GFP_KERNEL))) { - err = -ENOMEM; - goto ERROR0; - } - - new_client = &data->client; - new_client->addr = address; - new_client->data = data; - new_client->adapter = adapter; - new_client->driver = &fscher_driver; - new_client->flags = 0; - - /* Do the remaining detection unless force or force_fscher parameter */ - if (kind < 0) { - if (fscher_read_value(new_client, FSCHER_REG_IDENT_0) != 0x48) /* 'H' */ - goto ERROR1; - if (fscher_read_value(new_client, FSCHER_REG_IDENT_1) != 0x45) /* 'E' */ - goto ERROR1; - if (fscher_read_value(new_client, FSCHER_REG_IDENT_2) != 0x52) /* 'R' */ - goto ERROR1; - } - - kind = fscher; - - type_name = "fscher"; - client_name = "fsc hermes chip"; - - /* Fill in the remaining client fields and put it into the - global list */ - strcpy(new_client->name, client_name); - data->valid = 0; - init_MUTEX(&data->update_lock); - - /* Tell the I2C layer a new client has arrived */ - if ((err = i2c_attach_client(new_client))) - goto ERROR3; - - /* Register a new directory entry with module sensors */ - if ((i = i2c_register_entry(new_client, type_name, - fscher_dir_table_template, - THIS_MODULE)) < 0) { - err = i; - goto ERROR4; - } - data->sysctl_id = i; - - fscher_init_client(new_client); - return 0; - -/* OK, this is not exactly good programming practice, usually. But it is - very code-efficient in this case. */ - ERROR4: - i2c_detach_client(new_client); - ERROR3: - ERROR1: - kfree(data); - ERROR0: - return err; -} - -static int fscher_detach_client(struct i2c_client *client) -{ - int err; - - i2c_deregister_entry(((struct fscher_data *) (client->data))->sysctl_id); - - if ((err = i2c_detach_client(client))) { - printk("fscher.o: Client deregistration failed, client not detached.\n"); - return err; - } - - kfree(client->data); - - return 0; -} - -static int fscher_read_value(struct i2c_client *client, u8 reg) -{ -#ifdef DEBUG - printk("fscher: read reg 0x%02x\n",reg); -#endif - return i2c_smbus_read_byte_data(client, reg); -} - -static int fscher_write_value(struct i2c_client *client, u8 reg, u8 value) -{ -#ifdef DEBUG - printk("fscher: write reg 0x%02x, val 0x%02x\n",reg, value); -#endif - return i2c_smbus_write_byte_data(client, reg, value); -} - -/* Called when we have found a new FSCHER. */ -static void fscher_init_client(struct i2c_client *client) -{ - struct fscher_data *data = client->data; - - /* read revision from chip */ - data->revision = fscher_read_value(client,FSCHER_REG_REVISION); -} - -static void fscher_update_client(struct i2c_client *client) -{ - struct fscher_data *data = client->data; - - down(&data->update_lock); - - if ((jiffies - data->last_updated > 2 * HZ) || - (jiffies < data->last_updated) || !data->valid) { - -#ifdef DEBUG - printk("Starting fscher update\n"); -#endif - data->temp_act[0] = fscher_read_value(client, FSCHER_REG_TEMP0_ACT); - data->temp_act[1] = fscher_read_value(client, FSCHER_REG_TEMP1_ACT); - data->temp_act[2] = fscher_read_value(client, FSCHER_REG_TEMP2_ACT); - data->temp_status[0] = fscher_read_value(client, FSCHER_REG_TEMP0_STATE); - data->temp_status[1] = fscher_read_value(client, FSCHER_REG_TEMP1_STATE); - data->temp_status[2] = fscher_read_value(client, FSCHER_REG_TEMP2_STATE); - - data->volt[0] = fscher_read_value(client, FSCHER_REG_VOLT_12); - data->volt[1] = fscher_read_value(client, FSCHER_REG_VOLT_5); - data->volt[2] = fscher_read_value(client, FSCHER_REG_VOLT_BATT); - - data->fan_act[0] = fscher_read_value(client, FSCHER_REG_FAN0_ACT); - data->fan_act[1] = fscher_read_value(client, FSCHER_REG_FAN1_ACT); - data->fan_act[2] = fscher_read_value(client, FSCHER_REG_FAN2_ACT); - data->fan_status[0] = fscher_read_value(client, FSCHER_REG_FAN0_STATE); - data->fan_status[1] = fscher_read_value(client, FSCHER_REG_FAN1_STATE); - data->fan_status[2] = fscher_read_value(client, FSCHER_REG_FAN2_STATE); - data->fan_min[0] = fscher_read_value(client, FSCHER_REG_FAN0_MIN); - data->fan_min[1] = fscher_read_value(client, FSCHER_REG_FAN1_MIN); - data->fan_min[2] = fscher_read_value(client, FSCHER_REG_FAN2_MIN); - data->fan_ripple[0] = fscher_read_value(client, FSCHER_REG_FAN0_RIPPLE); - data->fan_ripple[1] = fscher_read_value(client, FSCHER_REG_FAN1_RIPPLE); - data->fan_ripple[2] = fscher_read_value(client, FSCHER_REG_FAN2_RIPPLE); - - data->watchdog[0] = fscher_read_value(client, FSCHER_REG_WDOG_PRESET); - data->watchdog[1] = fscher_read_value(client, FSCHER_REG_WDOG_STATE); - data->watchdog[2] = fscher_read_value(client, FSCHER_REG_WDOG_CONTROL); - - data->global_event = fscher_read_value(client, FSCHER_REG_EVENT_STATE); - data->global_control = fscher_read_value(client, FSCHER_REG_CONTROL); - - data->last_updated = jiffies; - data->valid = 1; - } - - up(&data->update_lock); -} - - -/* The next few functions are the call-back functions of the /proc/sys and - sysctl files. Which function is used is defined in the ctl_table in - the extra1 field. - Each function must return the magnitude (power of 10 to divide the date - with) if it is called with operation==SENSORS_PROC_REAL_INFO. It must - put a maximum of *nrels elements in results reflecting the data of this - file, and set *nrels to the number it actually put in it, if operation== - SENSORS_PROC_REAL_READ. Finally, it must get upto *nrels elements from - results and write them to the chip, if operations==SENSORS_PROC_REAL_WRITE. - Note that on SENSORS_PROC_REAL_READ, I do not check whether results is - large enough (by checking the incoming value of *nrels). This is not very - good practice, but as long as you put less than about 5 values in results, - you can assume it is large enough. */ -void fscher_in(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct fscher_data *data = client->data; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - fscher_update_client(client); - switch(ctl_name) { - case FSCHER_SYSCTL_REV: - results[0] = data->revision ; - break; - case FSCHER_SYSCTL_EVENT: - /* bits 6, 5 and 2 are reserved => mask with 0x9b */ - results[0] = data->global_event & 0x9b; - break; - case FSCHER_SYSCTL_CONTROL: - results[0] = data->global_control & 0x01; - break; - default: - printk("fscher: ctl_name %d not supported\n", ctl_name); - *nrels_mag = 0; - return; - } - *nrels_mag = 1; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if((ctl_name == FSCHER_SYSCTL_CONTROL) && (*nrels_mag >= 1)) { - data->global_control = (results[0] & 0x01); - printk("fscher: writing 0x%02x to global_control\n", - data->global_control); - fscher_write_value(client,FSCHER_REG_CONTROL, - data->global_control); - } - else - printk("fscher: writing to chip not supported\n"); - } -} - - -#define TEMP_FROM_REG(val) (val-128) - -void fscher_temp(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct fscher_data *data = client->data; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - fscher_update_client(client); - switch(ctl_name) { - case FSCHER_SYSCTL_TEMP0: - results[0] = data->temp_status[0] & 0x03; - results[1] = TEMP_FROM_REG(data->temp_act[0]); - break; - case FSCHER_SYSCTL_TEMP1: - results[0] = data->temp_status[1] & 0x03; - results[1] = TEMP_FROM_REG(data->temp_act[1]); - break; - case FSCHER_SYSCTL_TEMP2: - results[0] = data->temp_status[2] & 0x03; - results[1] = TEMP_FROM_REG(data->temp_act[2]); - break; - default: - printk("fscher: ctl_name %d not supported\n", ctl_name); - *nrels_mag = 0; - return; - } - *nrels_mag = 2; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if(*nrels_mag >= 1) { - switch(ctl_name) { - case FSCHER_SYSCTL_TEMP0: - data->temp_status[0] = (data->temp_status[0] & ~0x02) - | (results[0] & 0x02); - printk("fscher: writing value 0x%02x to temp0_status\n", - data->temp_status[0]); - fscher_write_value(client, FSCHER_REG_TEMP0_STATE, - data->temp_status[0] & 0x02); - break; - case FSCHER_SYSCTL_TEMP1: - data->temp_status[1] = (data->temp_status[1] & ~0x02) - | (results[0] & 0x02); - printk("fscher: writing value 0x%02x to temp1_status\n", - data->temp_status[1]); - fscher_write_value(client, FSCHER_REG_TEMP1_STATE, - data->temp_status[1] & 0x02); - break; - case FSCHER_SYSCTL_TEMP2: - data->temp_status[2] = (data->temp_status[2] & ~0x02) - | (results[0] & 0x02); - printk("fscher: writing value 0x%02x to temp2_status\n", - data->temp_status[2]); - fscher_write_value(client, FSCHER_REG_TEMP2_STATE, - data->temp_status[2] & 0x02); - break; - default: - printk("fscher: ctl_name %d not supported\n",ctl_name); - } - } - else - printk("fscher: writing to chip not supported\n"); - } -} - -/* - * The final conversion is specified in sensors.conf, as it depends on - * mainboard specific values. We export the registers contents as - * pseudo-hundredths-of-Volts (range 0V - 2.55V). Not that it makes much - * sense per se, but it minimizes the conversions count and keeps the - * values within a usual range. - */ -void fscher_volt(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct fscher_data *data = client->data; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 2; - else if (operation == SENSORS_PROC_REAL_READ) { - fscher_update_client(client); - switch(ctl_name) { - case FSCHER_SYSCTL_VOLT0: - results[0] = data->volt[0]; - break; - case FSCHER_SYSCTL_VOLT1: - results[0] = data->volt[1]; - break; - case FSCHER_SYSCTL_VOLT2: - results[0] = data->volt[2]; - break; - default: - printk("fscher: ctl_name %d not supported\n", ctl_name); - *nrels_mag = 0; - return; - } - *nrels_mag = 1; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - printk("fscher: writing to chip not supported\n"); - } -} - -void fscher_pwm(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - - switch(ctl_name) { - case FSCHER_SYSCTL_PWM0: - fscher_pwm_internal(client,operation,ctl_name,nrels_mag,results, - 0,FSCHER_REG_FAN0_MIN); - break; - case FSCHER_SYSCTL_PWM1: - fscher_pwm_internal(client,operation,ctl_name,nrels_mag,results, - 1,FSCHER_REG_FAN1_MIN); - break; - case FSCHER_SYSCTL_PWM2: - fscher_pwm_internal(client,operation,ctl_name,nrels_mag,results, - 2,FSCHER_REG_FAN2_MIN); - break; - default: - printk("fscher: illegal pwm nr %d\n",ctl_name); - } -} - -void fscher_pwm_internal(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results, - int nr, int reg_min) -{ - struct fscher_data *data = client->data; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - fscher_update_client(client); - results[0] = data->fan_min[nr]; - *nrels_mag = 1; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if(*nrels_mag >= 1) { - data->fan_min[nr] = results[0]; - printk("fscher: writing value 0x%02x to fan%d_min\n", - data->fan_min[nr],nr); - fscher_write_value(client,reg_min,data->fan_min[nr]); - } - } -} - -void fscher_fan(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - switch(ctl_name) { - case FSCHER_SYSCTL_FAN0: - fscher_fan_internal(client,operation,ctl_name,nrels_mag,results, - 0,FSCHER_REG_FAN0_STATE, FSCHER_REG_FAN0_RIPPLE); - break; - case FSCHER_SYSCTL_FAN1: - fscher_fan_internal(client,operation,ctl_name,nrels_mag,results, - 1,FSCHER_REG_FAN1_STATE, FSCHER_REG_FAN1_RIPPLE); - break; - case FSCHER_SYSCTL_FAN2: - fscher_fan_internal(client,operation,ctl_name,nrels_mag,results, - 2,FSCHER_REG_FAN2_STATE, FSCHER_REG_FAN2_RIPPLE); - break; - default: - printk("fscher: illegal fan nr %d\n",ctl_name); - } -} - -#define RPM_FROM_REG(val) (val*60) - -void fscher_fan_internal(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results, - int nr, int reg_state, int reg_ripple) -{ - struct fscher_data *data = client->data; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - fscher_update_client(client); - results[0] = data->fan_status[nr] & 0x04; - results[1] = data->fan_ripple[nr] & 0x03; - results[2] = RPM_FROM_REG(data->fan_act[nr]); - *nrels_mag = 3; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if(*nrels_mag >= 1) { - data->fan_status[nr] = results[0] & 0x04; - printk("fscher: writing value 0x%02x to fan%d_status\n", - data->fan_status[nr],nr); - fscher_write_value(client,reg_state,data->fan_status[nr]); - } - if(*nrels_mag >= 2) { - if((results[1] & 0x03) == 0) { - printk("fscher: fan%d ripple 0 not allowed\n",nr); - return; - } - data->fan_ripple[nr] = results[1] & 0x03; - printk("fscher: writing value 0x%02x to fan%d_ripple\n", - data->fan_ripple[nr],nr); - fscher_write_value(client,reg_ripple,data->fan_ripple[nr]); - } - } -} - -void fscher_wdog(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct fscher_data *data = client->data; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - fscher_update_client(client); - results[0] = data->watchdog[0] ; - results[1] = data->watchdog[1] & 0x02; - results[2] = data->watchdog[2] & 0xd0; - *nrels_mag = 3; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag >= 1) { - data->watchdog[0] = results[0] & 0xff; - printk("fscher: writing value 0x%02x to wdog_preset\n", - data->watchdog[0]); - fscher_write_value(client,FSCHER_REG_WDOG_PRESET,data->watchdog[0]); - } - if (*nrels_mag >= 2) { - data->watchdog[1] = results[1] & 0x02; - printk("fscher: writing value 0x%02x to wdog_state\n", - data->watchdog[1]); - fscher_write_value(client,FSCHER_REG_WDOG_STATE,data->watchdog[1]); - } - if (*nrels_mag >= 3) { - data->watchdog[2] = results[2] & 0xf0; - printk("fscher: writing value 0x%02x to wdog_control\n", - data->watchdog[2]); - fscher_write_value(client,FSCHER_REG_WDOG_CONTROL,data->watchdog[2]); - } - } -} - -static int __init sm_fscher_init(void) -{ - printk("fscher.o version %s (%s)\n", LM_VERSION, LM_DATE); - return i2c_add_driver(&fscher_driver); -} - -static void __exit sm_fscher_exit(void) -{ - i2c_del_driver(&fscher_driver); -} - - - -MODULE_AUTHOR("Reinhard Nissl based on work from Hermann" - " Jung , Frodo Looijaard and" - " Philip Edelbrock "); -MODULE_DESCRIPTION("fujitsu siemens hermes chip driver"); -MODULE_LICENSE("GPL"); - -module_init(sm_fscher_init); -module_exit(sm_fscher_exit); diff --git a/kernel/chips/fscpos.c b/kernel/chips/fscpos.c deleted file mode 100644 index 0bb4858e..00000000 --- a/kernel/chips/fscpos.c +++ /dev/null @@ -1,684 +0,0 @@ -/* - fscpos.c - Part of lm_sensors, Linux kernel modules for hardware - monitoring - Copyright (c) 2001 Hermann Jung - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -/* - fujitsu siemens poseidon chip, - module based on lm80.c - Copyright (c) 1998, 1999 Frodo Looijaard - and Philip Edelbrock -*/ - -#include -#include -#include -#include -#include -#include "version.h" - -/* Addresses to scan */ -static unsigned short normal_i2c[] = { 0x73, SENSORS_I2C_END }; -static unsigned short normal_i2c_range[] = { SENSORS_I2C_END }; -static unsigned int normal_isa[] = { SENSORS_ISA_END }; -static unsigned int normal_isa_range[] = { SENSORS_ISA_END }; - -/* Insmod parameters */ -SENSORS_INSMOD_1(fscpos); - -/* The FSCPOS registers */ - -/* chip identification */ -#define FSCPOS_REG_IDENT_0 0x00 -#define FSCPOS_REG_IDENT_1 0x01 -#define FSCPOS_REG_IDENT_2 0x02 -#define FSCPOS_REG_REVISION 0x03 - -/* global control and status */ -#define FSCPOS_REG_EVENT_STATE 0x04 -#define FSCPOS_REG_CONTROL 0x05 - -/* watchdog */ -#define FSCPOS_REG_WDOG_PRESET 0x28 -#define FSCPOS_REG_WDOG_STATE 0x23 -#define FSCPOS_REG_WDOG_CONTROL 0x21 - -/* fan 0 */ -#define FSCPOS_REG_FAN0_MIN 0x55 -#define FSCPOS_REG_FAN0_ACT 0x0e -#define FSCPOS_REG_FAN0_STATE 0x0d -#define FSCPOS_REG_FAN0_RIPPLE 0x0f - -/* fan 1 */ -#define FSCPOS_REG_FAN1_MIN 0x65 -#define FSCPOS_REG_FAN1_ACT 0x6b -#define FSCPOS_REG_FAN1_STATE 0x62 -#define FSCPOS_REG_FAN1_RIPPLE 0x6f - -/* fan 2 */ -/* min speed fan2 not supported */ -#define FSCPOS_REG_FAN2_ACT 0xab -#define FSCPOS_REG_FAN2_STATE 0xa2 -#define FSCPOS_REG_FAN2_RIPPLE 0x0af - -/* voltage supervision */ -#define FSCPOS_REG_VOLT_12 0x45 -#define FSCPOS_REG_VOLT_5 0x42 -#define FSCPOS_REG_VOLT_BATT 0x48 - -/* temperatures */ -/* sensor 0 */ -#define FSCPOS_REG_TEMP0_ACT 0x64 -#define FSCPOS_REG_TEMP0_STATE 0x71 - -/* sensor 1 */ -#define FSCPOS_REG_TEMP1_ACT 0x32 -#define FSCPOS_REG_TEMP1_STATE 0x81 - -/* sensor 2 */ -#define FSCPOS_REG_TEMP2_ACT 0x35 -#define FSCPOS_REG_TEMP2_STATE 0x91 - - - - -/* Conversions. Rounding and limit checking is only done on the TO_REG - variants. Note that you should be a bit careful with which arguments - these macros are called: arguments may be evaluated more than once. - Fixing this is just not worth it. */ - -#define IN_TO_REG(val,nr) (SENSORS_LIMIT((val),0,255)) -#define IN_FROM_REG(val,nr) (val) - -/* Initial limits */ - -/* For each registered FSCPOS, we need to keep some data in memory. It is - dynamically allocated, at the same time when a new fscpos client is - allocated. */ -struct fscpos_data { - struct i2c_client client; - int sysctl_id; - - struct semaphore update_lock; - char valid; /* !=0 if following fields are valid */ - unsigned long last_updated; /* In jiffies */ - - u8 revision; /* revision of chip */ - u8 global_event; /* global event status */ - u8 global_control; /* global control register */ - u8 watchdog[3]; /* watchdog */ - u8 volt[3]; /* 12, 5, battery current */ - u8 temp_act[3]; /* temperature */ - u8 temp_status[3]; /* status of sensor */ - u8 fan_act[3]; /* fans revolutions per second */ - u8 fan_status[3]; /* fan status */ - u8 fan_min[3]; /* fan min value for rps */ - u8 fan_ripple[3]; /* divider for rps */ -}; - - -static int fscpos_attach_adapter(struct i2c_adapter *adapter); -static int fscpos_detect(struct i2c_adapter *adapter, int address, - unsigned short flags, int kind); -static int fscpos_detach_client(struct i2c_client *client); - -static int fscpos_read_value(struct i2c_client *client, u8 register); -static int fscpos_write_value(struct i2c_client *client, u8 register, - u8 value); -static void fscpos_update_client(struct i2c_client *client); -static void fscpos_init_client(struct i2c_client *client); - - -static void fscpos_in(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results); -static void fscpos_fan(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void fscpos_fan_internal(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results, - int nr, int reg_state, int reg_min, int res_ripple); -static void fscpos_temp(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void fscpos_volt(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void fscpos_wdog(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); - -static struct i2c_driver fscpos_driver = { - .name = "FSCPOS sensor driver", - .id = I2C_DRIVERID_FSCPOS, - .flags = I2C_DF_NOTIFY, - .attach_adapter = fscpos_attach_adapter, - .detach_client = fscpos_detach_client, -}; - -/* -- SENSORS SYSCTL START -- */ -#define FSCPOS_SYSCTL_VOLT0 1000 /* 12 volt supply */ -#define FSCPOS_SYSCTL_VOLT1 1001 /* 5 volt supply */ -#define FSCPOS_SYSCTL_VOLT2 1002 /* batterie voltage*/ -#define FSCPOS_SYSCTL_FAN0 1101 /* state, min, ripple, actual value fan 0 */ -#define FSCPOS_SYSCTL_FAN1 1102 /* state, min, ripple, actual value fan 1 */ -#define FSCPOS_SYSCTL_FAN2 1103 /* state, min, ripple, actual value fan 2 */ -#define FSCPOS_SYSCTL_TEMP0 1201 /* state and value of sensor 0, cpu die */ -#define FSCPOS_SYSCTL_TEMP1 1202 /* state and value of sensor 1, motherboard */ -#define FSCPOS_SYSCTL_TEMP2 1203 /* state and value of sensor 2, chassis */ -#define FSCPOS_SYSCTL_REV 2000 /* Revision */ -#define FSCPOS_SYSCTL_EVENT 2001 /* global event status */ -#define FSCPOS_SYSCTL_CONTROL 2002 /* global control byte */ -#define FSCPOS_SYSCTL_WDOG 2003 /* state, min, ripple, actual value fan 2 */ -/* -- SENSORS SYSCTL END -- */ - -/* These files are created for each detected FSCPOS. This is just a template; - though at first sight, you might think we could use a statically - allocated list, we need some way to get back to the parent - which - is done through one of the 'extra' fields which are initialized - when a new copy is allocated. */ -static ctl_table fscpos_dir_table_template[] = { - {FSCPOS_SYSCTL_REV, "rev", NULL, 0, 0444, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &fscpos_in}, - {FSCPOS_SYSCTL_EVENT, "alarms", NULL, 0, 0444, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &fscpos_in}, - {FSCPOS_SYSCTL_CONTROL, "control", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &fscpos_in}, - {FSCPOS_SYSCTL_TEMP0, "temp1", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &fscpos_temp}, - {FSCPOS_SYSCTL_TEMP1, "temp2", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &fscpos_temp}, - {FSCPOS_SYSCTL_TEMP2, "temp3", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &fscpos_temp}, - {FSCPOS_SYSCTL_VOLT0, "in0", NULL, 0, 0444, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &fscpos_volt}, - {FSCPOS_SYSCTL_VOLT1, "in1", NULL, 0, 0444, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &fscpos_volt}, - {FSCPOS_SYSCTL_VOLT2, "in2", NULL, 0, 0444, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &fscpos_volt}, - {FSCPOS_SYSCTL_FAN0, "fan1", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &fscpos_fan}, - {FSCPOS_SYSCTL_FAN1, "fan2", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &fscpos_fan}, - {FSCPOS_SYSCTL_FAN2, "fan3", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &fscpos_fan}, - {FSCPOS_SYSCTL_WDOG, "wdog", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &fscpos_wdog}, - {0} -}; - -static int fscpos_attach_adapter(struct i2c_adapter *adapter) -{ - return i2c_detect(adapter, &addr_data, fscpos_detect); -} - -static int fscpos_detect(struct i2c_adapter *adapter, int address, - unsigned short flags, int kind) -{ - int i; - struct i2c_client *new_client; - struct fscpos_data *data; - int err = 0; - const char *type_name, *client_name; - - /* Make sure we aren't probing the ISA bus!! This is just a safety check - at this moment; i2c_detect really won't call us. */ -#ifdef DEBUG - if (i2c_is_isa_adapter(adapter)) { - printk - ("fscpos.o: fscpos_detect called for an ISA bus adapter?!?\n"); - return 0; - } -#endif - - if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) - goto ERROR0; - - /* OK. For now, we presume we have a valid client. We now create the - client structure, even though we cannot fill it completely yet. - But it allows us to access fscpos_{read,write}_value. */ - if (!(data = kmalloc(sizeof(struct fscpos_data), GFP_KERNEL))) { - err = -ENOMEM; - goto ERROR0; - } - - new_client = &data->client; - new_client->addr = address; - new_client->data = data; - new_client->adapter = adapter; - new_client->driver = &fscpos_driver; - new_client->flags = 0; - - /* Do the remaining detection unless force or force_fscpos parameter */ - if (kind < 0) { - if (fscpos_read_value(new_client, FSCPOS_REG_IDENT_0) != 0x50) - goto ERROR1; - if (fscpos_read_value(new_client, FSCPOS_REG_IDENT_1) != 0x45) - goto ERROR1; - if (fscpos_read_value(new_client, FSCPOS_REG_IDENT_2) != 0x47) - goto ERROR1; - } - - kind = fscpos; - - type_name = "fscpos"; - client_name = "fsc poseidon chip"; - - /* Fill in the remaining client fields and put it into the global list */ - strcpy(new_client->name, client_name); - data->valid = 0; - init_MUTEX(&data->update_lock); - - /* Tell the I2C layer a new client has arrived */ - if ((err = i2c_attach_client(new_client))) - goto ERROR3; - - /* Register a new directory entry with module sensors */ - if ((i = i2c_register_entry(new_client, type_name, - fscpos_dir_table_template, - THIS_MODULE)) < 0) { - err = i; - goto ERROR4; - } - data->sysctl_id = i; - - fscpos_init_client(new_client); - return 0; - -/* OK, this is not exactly good programming practice, usually. But it is - very code-efficient in this case. */ - ERROR4: - i2c_detach_client(new_client); - ERROR3: - ERROR1: - kfree(data); - ERROR0: - return err; -} - -static int fscpos_detach_client(struct i2c_client *client) -{ - int err; - - i2c_deregister_entry(((struct fscpos_data *) (client->data))-> - sysctl_id); - - if ((err = i2c_detach_client(client))) { - printk - ("fscpos.o: Client deregistration failed, client not detached.\n"); - return err; - } - - kfree(client->data); - - return 0; -} - -static int fscpos_read_value(struct i2c_client *client, u8 reg) -{ -#ifdef DEBUG - printk("fscpos: read reg 0x%02x\n",reg); -#endif - return i2c_smbus_read_byte_data(client, reg); -} - -static int fscpos_write_value(struct i2c_client *client, u8 reg, u8 value) -{ -#ifdef DEBUG - printk("fscpos: write reg 0x%02x, val 0x%02x\n",reg, value); -#endif - return i2c_smbus_write_byte_data(client, reg, value); -} - -/* Called when we have found a new FSCPOS. */ -static void fscpos_init_client(struct i2c_client *client) -{ - struct fscpos_data *data = client->data; - - /* read revision from chip */ - data->revision = fscpos_read_value(client,FSCPOS_REG_REVISION); - /* setup missing fan2_min value */ - data->fan_min[2] = 0xff; -} - -static void fscpos_update_client(struct i2c_client *client) -{ - struct fscpos_data *data = client->data; - - down(&data->update_lock); - - if ((jiffies - data->last_updated > 2 * HZ) || - (jiffies < data->last_updated) || !data->valid) { - -#ifdef DEBUG - printk("Starting fscpos update\n"); -#endif - data->temp_act[0] = fscpos_read_value(client, FSCPOS_REG_TEMP0_ACT); - data->temp_act[1] = fscpos_read_value(client, FSCPOS_REG_TEMP1_ACT); - data->temp_act[2] = fscpos_read_value(client, FSCPOS_REG_TEMP2_ACT); - data->temp_status[0] = fscpos_read_value(client, FSCPOS_REG_TEMP0_STATE); - data->temp_status[1] = fscpos_read_value(client, FSCPOS_REG_TEMP1_STATE); - data->temp_status[2] = fscpos_read_value(client, FSCPOS_REG_TEMP2_STATE); - - data->volt[0] = fscpos_read_value(client, FSCPOS_REG_VOLT_12); - data->volt[1] = fscpos_read_value(client, FSCPOS_REG_VOLT_5); - data->volt[2] = fscpos_read_value(client, FSCPOS_REG_VOLT_BATT); - - data->fan_act[0] = fscpos_read_value(client, FSCPOS_REG_FAN0_ACT); - data->fan_act[1] = fscpos_read_value(client, FSCPOS_REG_FAN1_ACT); - data->fan_act[2] = fscpos_read_value(client, FSCPOS_REG_FAN2_ACT); - data->fan_status[0] = fscpos_read_value(client, FSCPOS_REG_FAN0_STATE); - data->fan_status[1] = fscpos_read_value(client, FSCPOS_REG_FAN1_STATE); - data->fan_status[2] = fscpos_read_value(client, FSCPOS_REG_FAN2_STATE); - data->fan_min[0] = fscpos_read_value(client, FSCPOS_REG_FAN0_MIN); - data->fan_min[1] = fscpos_read_value(client, FSCPOS_REG_FAN1_MIN); - /* fan2_min is not supported */ - data->fan_ripple[0] = fscpos_read_value(client, FSCPOS_REG_FAN0_RIPPLE); - data->fan_ripple[1] = fscpos_read_value(client, FSCPOS_REG_FAN1_RIPPLE); - data->fan_ripple[2] = fscpos_read_value(client, FSCPOS_REG_FAN2_RIPPLE); - - data->watchdog[0] = fscpos_read_value(client, FSCPOS_REG_WDOG_PRESET); - data->watchdog[1] = fscpos_read_value(client, FSCPOS_REG_WDOG_STATE); - data->watchdog[2] = fscpos_read_value(client, FSCPOS_REG_WDOG_CONTROL); - - data->global_event = fscpos_read_value(client, FSCPOS_REG_EVENT_STATE); - - data->last_updated = jiffies; - data->valid = 1; - } - - up(&data->update_lock); -} - - -/* The next few functions are the call-back functions of the /proc/sys and - sysctl files. Which function is used is defined in the ctl_table in - the extra1 field. - Each function must return the magnitude (power of 10 to divide the date - with) if it is called with operation==SENSORS_PROC_REAL_INFO. It must - put a maximum of *nrels elements in results reflecting the data of this - file, and set *nrels to the number it actually put in it, if operation== - SENSORS_PROC_REAL_READ. Finally, it must get upto *nrels elements from - results and write them to the chip, if operations==SENSORS_PROC_REAL_WRITE. - Note that on SENSORS_PROC_REAL_READ, I do not check whether results is - large enough (by checking the incoming value of *nrels). This is not very - good practice, but as long as you put less than about 5 values in results, - you can assume it is large enough. */ -void fscpos_in(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct fscpos_data *data = client->data; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - fscpos_update_client(client); - switch(ctl_name) { - case FSCPOS_SYSCTL_REV: - results[0] = data->revision ; - break; - case FSCPOS_SYSCTL_EVENT: - results[0] = data->global_event & 0x1f; - break; - case FSCPOS_SYSCTL_CONTROL: - results[0] = data->global_control & 0x01; - break; - default: - printk("fscpos: ctl_name %d not supported\n", - ctl_name); - *nrels_mag = 0; - return; - } - *nrels_mag = 1; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if((ctl_name == FSCPOS_SYSCTL_CONTROL) && (*nrels_mag >= 1)) { - data->global_control = (results[0] & 0x01); - printk("fscpos: writing 0x%02x to global_control\n", - data->global_control); - fscpos_write_value(client,FSCPOS_REG_CONTROL, - data->global_control); - } - else - printk("fscpos: writing to chip not supported\n"); - } -} - -#define TEMP_FROM_REG(val) (val-128) - - -void fscpos_temp(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct fscpos_data *data = client->data; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - fscpos_update_client(client); - switch(ctl_name) { - case FSCPOS_SYSCTL_TEMP0: - results[0] = data->temp_status[0] & 0x03; - results[1] = TEMP_FROM_REG(data->temp_act[0]); - break; - case FSCPOS_SYSCTL_TEMP1: - results[0] = data->temp_status[1] & 0x03; - results[1] = TEMP_FROM_REG(data->temp_act[1]); - break; - case FSCPOS_SYSCTL_TEMP2: - results[0] = data->temp_status[2] & 0x03; - results[1] = TEMP_FROM_REG(data->temp_act[2]); - break; - default: - printk("fscpos: ctl_name %d not supported\n", - ctl_name); - *nrels_mag = 0; - return; - } - *nrels_mag = 2; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if(*nrels_mag >= 1) { - switch(ctl_name) { - case FSCPOS_SYSCTL_TEMP0: - data->temp_status[0] = - (data->temp_status[0] & ~0x02) - | (results[0] & 0x02); - printk("fscpos: writing value 0x%02x " - "to temp0_status\n", - data->temp_status[0]); - fscpos_write_value(client, - FSCPOS_REG_TEMP0_STATE, - data->temp_status[0] & 0x02); - break; - case FSCPOS_SYSCTL_TEMP1: - data->temp_status[1] = (data->temp_status[1] & ~0x02) | (results[0] & 0x02); - printk("fscpos: writing value 0x%02x to temp1_status\n", data->temp_status[1]); - fscpos_write_value(client,FSCPOS_REG_TEMP1_STATE, - data->temp_status[1] & 0x02); - break; - case FSCPOS_SYSCTL_TEMP2: - data->temp_status[2] = (data->temp_status[2] & ~0x02) | (results[0] & 0x02); - printk("fscpos: writing value 0x%02x to temp2_status\n", data->temp_status[2]); - fscpos_write_value(client,FSCPOS_REG_TEMP2_STATE, - data->temp_status[2] & 0x02); - break; - default: - printk("fscpos: ctl_name %d not supported\n",ctl_name); - } - } - else - printk("fscpos: writing to chip not supported\n"); - } -} - -#define VOLT_FROM_REG(val,mult) (val*mult/255) - -void fscpos_volt(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct fscpos_data *data = client->data; - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 2; - else if (operation == SENSORS_PROC_REAL_READ) { - fscpos_update_client(client); - switch(ctl_name) { - case FSCPOS_SYSCTL_VOLT0: - results[0] = VOLT_FROM_REG(data->volt[0],1420); - break; - case FSCPOS_SYSCTL_VOLT1: - results[0] = VOLT_FROM_REG(data->volt[1],660); - break; - case FSCPOS_SYSCTL_VOLT2: - results[0] = VOLT_FROM_REG(data->volt[2],330); - break; - default: - printk("fscpos: ctl_name %d not supported\n", - ctl_name); - *nrels_mag = 0; - return; - } - *nrels_mag = 1; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - printk("fscpos: writing to chip not supported\n"); - } -} - -void fscpos_fan(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - - switch(ctl_name) { - case FSCPOS_SYSCTL_FAN0: - fscpos_fan_internal(client,operation,ctl_name,nrels_mag,results, - 0,FSCPOS_REG_FAN0_STATE,FSCPOS_REG_FAN0_MIN, - FSCPOS_REG_FAN0_RIPPLE); - break; - case FSCPOS_SYSCTL_FAN1: - fscpos_fan_internal(client,operation,ctl_name,nrels_mag,results, - 1,FSCPOS_REG_FAN1_STATE,FSCPOS_REG_FAN1_MIN, - FSCPOS_REG_FAN1_RIPPLE); - break; - case FSCPOS_SYSCTL_FAN2: - fscpos_fan_internal(client,operation,ctl_name,nrels_mag,results, - 2,FSCPOS_REG_FAN2_STATE,0xff, - FSCPOS_REG_FAN2_RIPPLE); - break; - default: - printk("fscpos: illegal fan nr %d\n",ctl_name); - } -} - -#define RPM_FROM_REG(val) (val*60) - -void fscpos_fan_internal(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results, int nr, - int reg_state, int reg_min, int reg_ripple ) -{ - struct fscpos_data *data = client->data; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - fscpos_update_client(client); - results[0] = data->fan_status[nr] & 0x04; - results[1] = data->fan_min[nr]; - results[2] = data->fan_ripple[nr] & 0x03; - results[3] = RPM_FROM_REG(data->fan_act[nr]); - *nrels_mag = 4; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if(*nrels_mag >= 1) { - data->fan_status[nr] = results[0] & 0x04; - printk("fscpos: writing value 0x%02x to fan%d_status\n", - data->fan_status[nr],nr); - fscpos_write_value(client,reg_state, - data->fan_status[nr]); - } - if((*nrels_mag >= 2) && (nr < 2)) { - /* minimal speed for fan2 not supported */ - data->fan_min[nr] = results[1]; - printk("fscpos: writing value 0x%02x to fan%d_min\n", - data->fan_min[nr],nr); - fscpos_write_value(client,reg_min, - data->fan_min[nr]); - } - if(*nrels_mag >= 3) { - if((results[2] & 0x03) == 0) { - printk("fscpos: fan%d ripple 0 not allowed\n",nr); - return; - } - data->fan_ripple[nr] = results[2] & 0x03; - printk("fscpos: writing value 0x%02x to fan%d_ripple\n", - data->fan_ripple[nr],nr); - fscpos_write_value(client,reg_ripple, - data->fan_ripple[nr]); - } - } -} - -void fscpos_wdog(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct fscpos_data *data = client->data; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - fscpos_update_client(client); - results[0] = data->watchdog[0] ; - results[1] = data->watchdog[1] & 0x02; - results[2] = data->watchdog[2] & 0xb0; - *nrels_mag = 3; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag >= 1) { - data->watchdog[0] = results[0] & 0xff; - printk("fscpos: writing value 0x%02x to wdog_preset\n", - data->watchdog[0]); - fscpos_write_value(client,FSCPOS_REG_WDOG_PRESET, - data->watchdog[0]); - } - if (*nrels_mag >= 2) { - data->watchdog[1] = results[1] & 0x02; - printk("fscpos: writing value 0x%02x to wdog_state\n", - data->watchdog[1]); - fscpos_write_value(client,FSCPOS_REG_WDOG_STATE, - data->watchdog[1]); - } - if (*nrels_mag >= 3) { - data->watchdog[2] = results[2] & 0xb0; - printk("fscpos: writing value 0x%02x to wdog_control\n", - data->watchdog[2]); - fscpos_write_value(client,FSCPOS_REG_WDOG_CONTROL, - data->watchdog[2]); - } - } -} - -static int __init sm_fscpos_init(void) -{ - printk("fscpos.o version %s (%s)\n", LM_VERSION, LM_DATE); - return i2c_add_driver(&fscpos_driver); -} - -static void __exit sm_fscpos_exit(void) -{ - i2c_del_driver(&fscpos_driver); -} - - - -MODULE_AUTHOR - ("Hermann Jung based on work from Frodo Looijaard and Philip Edelbrock "); -MODULE_DESCRIPTION("fujitsu siemens poseidon chip driver"); -MODULE_LICENSE("GPL"); - -module_init(sm_fscpos_init); -module_exit(sm_fscpos_exit); diff --git a/kernel/chips/fscscy.c b/kernel/chips/fscscy.c deleted file mode 100644 index 559a106b..00000000 --- a/kernel/chips/fscscy.c +++ /dev/null @@ -1,909 +0,0 @@ -/* - fscscy.c - Part of lm_sensors, Linux kernel modules for hardware - monitoring - Copyright (c) 2001 Martin Knoblauch - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -/* - fujitsu siemens scylla chip, - module based on lm80.c, fscpos.c - Copyright (c) 1998, 1999 Frodo Looijaard - and Philip Edelbrock -*/ - -#include -#include -#include -#include -#include -#include "version.h" - -MODULE_LICENSE("GPL"); - -/* Addresses to scan */ -static unsigned short normal_i2c[] = { 0x73, SENSORS_I2C_END }; -static unsigned short normal_i2c_range[] = { SENSORS_I2C_END }; -static unsigned int normal_isa[] = { SENSORS_ISA_END }; -static unsigned int normal_isa_range[] = { SENSORS_ISA_END }; - -/* Insmod parameters */ -SENSORS_INSMOD_1(fscscy); - -/* The FSCSCY registers */ - -/* chip identification */ -#define FSCSCY_REG_IDENT_0 0x00 -#define FSCSCY_REG_IDENT_1 0x01 -#define FSCSCY_REG_IDENT_2 0x02 -#define FSCSCY_REG_REVISION 0x03 - -/* global control and status */ -#define FSCSCY_REG_EVENT_STATE 0x04 -#define FSCSCY_REG_CONTROL 0x05 - -/* watchdog */ -#define FSCSCY_REG_WDOG_PRESET 0x28 -#define FSCSCY_REG_WDOG_STATE 0x23 -#define FSCSCY_REG_WDOG_CONTROL 0x21 - -/* -** Fan definitions -** -** _RPMMIN: Minimum speed. Can be set via interface, but only for three of the fans -** FAN1_RPMMIN is wired to Fan 0 (CPU Fans) -** FAN4_RPMMIN is wired to Fan 2 (PS Fans ??) -** FAN5_RPMMIN is wired to Fan 3 (AUX Fans ??) -** _ACT: Actual Fan Speed -** _STATE: Fan status register -** _RIPPLE: Fan speed multiplier -*/ - -/* fan 0 */ -#define FSCSCY_REG_FAN0_RPMMIN 0x65 -#define FSCSCY_REG_FAN0_ACT 0x6b -#define FSCSCY_REG_FAN0_STATE 0x62 -#define FSCSCY_REG_FAN0_RIPPLE 0x6f - -/* fan 1 */ -#define FSCSCY_REG_FAN1_RPMMIN FSCSCY_REG_FAN0_RPMMIN -#define FSCSCY_REG_FAN1_ACT 0x6c -#define FSCSCY_REG_FAN1_STATE 0x61 -#define FSCSCY_REG_FAN1_RIPPLE 0x6f - -/* fan 2 */ -#define FSCSCY_REG_FAN2_RPMMIN 0x55 -#define FSCSCY_REG_FAN2_ACT 0x0e -#define FSCSCY_REG_FAN2_STATE 0x0d -#define FSCSCY_REG_FAN2_RIPPLE 0x0f - -/* fan 3 */ -#define FSCSCY_REG_FAN3_RPMMIN 0xa5 -#define FSCSCY_REG_FAN3_ACT 0xab -#define FSCSCY_REG_FAN3_STATE 0xa2 -#define FSCSCY_REG_FAN3_RIPPLE 0xaf - -/* fan 4 */ -#define FSCSCY_REG_FAN4_RPMMIN FSCSCY_REG_FAN2_RPMMIN -#define FSCSCY_REG_FAN4_ACT 0x5c -#define FSCSCY_REG_FAN4_STATE 0x52 -#define FSCSCY_REG_FAN4_RIPPLE 0x0f - -/* fan 5 */ -#define FSCSCY_REG_FAN5_RPMMIN FSCSCY_REG_FAN3_RPMMIN -#define FSCSCY_REG_FAN5_ACT 0xbb -#define FSCSCY_REG_FAN5_STATE 0xb2 -#define FSCSCY_REG_FAN5_RIPPLE 0xbf - -/* voltage supervision */ -#define FSCSCY_REG_VOLT_12 0x45 -#define FSCSCY_REG_VOLT_5 0x42 -#define FSCSCY_REG_VOLT_BATT 0x48 - -/* temperatures */ -/* sensor 0 */ -#define FSCSCY_REG_TEMP0_ACT 0x64 -#define FSCSCY_REG_TEMP0_STATE 0x71 -#define FSCSCY_REG_TEMP0_LIM 0x76 - -/* sensor 1 */ -#define FSCSCY_REG_TEMP1_ACT 0xD0 -#define FSCSCY_REG_TEMP1_STATE 0xD1 -#define FSCSCY_REG_TEMP1_LIM 0xD6 - -/* sensor 2 */ -#define FSCSCY_REG_TEMP2_ACT 0x32 -#define FSCSCY_REG_TEMP2_STATE 0x81 -#define FSCSCY_REG_TEMP2_LIM 0x86 - -/* sensor3 */ -#define FSCSCY_REG_TEMP3_ACT 0x35 -#define FSCSCY_REG_TEMP3_STATE 0x91 -#define FSCSCY_REG_TEMP3_LIM 0x96 - -/* PCI Load */ -#define FSCSCY_REG_PCILOAD 0x1a - -/* Intrusion Sensor */ -#define FSCSCY_REG_INTR_STATE 0x13 -#define FSCSCY_REG_INTR_CTRL 0x12 - -/* Conversions. Rounding and limit checking is only done on the TO_REG - variants. Note that you should be a bit careful with which arguments - these macros are called: arguments may be evaluated more than once. - Fixing this is just not worth it. */ - -#define IN_TO_REG(val,nr) (SENSORS_LIMIT((val),0,255)) -#define IN_FROM_REG(val,nr) (val) - -/* Initial limits */ - -/* For each registered FSCSCY, we need to keep some data in memory. It is - dynamically allocated, at the same time when a new fscscy client is - allocated. */ -struct fscscy_data { - struct i2c_client client; - int sysctl_id; - - struct semaphore update_lock; - char valid; /* !=0 if following fields are valid */ - unsigned long last_updated; /* In jiffies */ - - u8 revision; /* revision of chip */ - u8 global_event; /* global event status */ - u8 global_control; /* global control register */ - u8 watchdog[3]; /* watchdog */ - u8 volt[3]; /* 12, 5, battery current */ - u8 volt_min[3]; /* minimum voltages over module "lifetime" */ - u8 volt_max[3]; /* maximum voltages over module "lifetime" */ - u8 temp_act[4]; /* temperature */ - u8 temp_status[4]; /* status of temp. sensor */ - u8 temp_lim[4]; /* limit temperature of temp. sensor */ - u8 temp_min[4]; /* minimum of temp. sensor, this is just calculated by the module */ - u8 temp_max[4]; /* maximum of temp. sensor, this is just calculsted by the module */ - u8 fan_act[6]; /* fans revolutions per second */ - u8 fan_status[6]; /* fan status */ - u8 fan_rpmmin[6]; /* fan min value for rps */ - u8 fan_ripple[6]; /* divider for rps */ - u8 fan_min[6]; /* minimum RPM over module "lifetime" */ - u8 fan_max[6]; /* maximum RPM over module "lifetime" */ - u8 pciload; /* PCILoad value */ - u8 intr_status; /* Intrusion Status */ - u8 intr_control; /* Intrusion Control */ -}; - - -static int fscscy_attach_adapter(struct i2c_adapter *adapter); -static int fscscy_detect(struct i2c_adapter *adapter, int address, - unsigned short flags, int kind); -static int fscscy_detach_client(struct i2c_client *client); - -static int fscscy_read_value(struct i2c_client *client, u8 register); -static int fscscy_write_value(struct i2c_client *client, u8 register, - u8 value); -static void fscscy_update_client(struct i2c_client *client); -static void fscscy_init_client(struct i2c_client *client); - - -static void fscscy_in(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results); -static void fscscy_fan(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void fscscy_fan_internal(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results, - int nr, int reg_state, int reg_min, int res_ripple); -static void fscscy_temp(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void fscscy_volt(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void fscscy_wdog(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void fscscy_pciload(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void fscscy_intrusion(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); - -static struct i2c_driver fscscy_driver = { - .name = "FSCSCY sensor driver", - .id = I2C_DRIVERID_FSCSCY, - .flags = I2C_DF_NOTIFY, - .attach_adapter = fscscy_attach_adapter, - .detach_client = fscscy_detach_client, -}; - -/* The /proc/sys entries */ - -/* -- SENSORS SYSCTL START -- */ -#define FSCSCY_SYSCTL_VOLT0 1000 /* 12 volt supply */ -#define FSCSCY_SYSCTL_VOLT1 1001 /* 5 volt supply */ -#define FSCSCY_SYSCTL_VOLT2 1002 /* batterie voltage*/ -#define FSCSCY_SYSCTL_FAN0 1101 /* state, min, ripple, actual value fan 0 */ -#define FSCSCY_SYSCTL_FAN1 1102 /* state, min, ripple, actual value fan 1 */ -#define FSCSCY_SYSCTL_FAN2 1103 /* state, min, ripple, actual value fan 2 */ -#define FSCSCY_SYSCTL_FAN3 1104 /* state, min, ripple, actual value fan 3 */ -#define FSCSCY_SYSCTL_FAN4 1105 /* state, min, ripple, actual value fan 4 */ -#define FSCSCY_SYSCTL_FAN5 1106 /* state, min, ripple, actual value fan 5 */ -#define FSCSCY_SYSCTL_TEMP0 1201 /* state and value of sensor 0, cpu die */ -#define FSCSCY_SYSCTL_TEMP1 1202 /* state and value of sensor 1, motherboard */ -#define FSCSCY_SYSCTL_TEMP2 1203 /* state and value of sensor 2, chassis */ -#define FSCSCY_SYSCTL_TEMP3 1204 /* state and value of sensor 3, chassis */ -#define FSCSCY_SYSCTL_REV 2000 /* Revision */ -#define FSCSCY_SYSCTL_EVENT 2001 /* global event status */ -#define FSCSCY_SYSCTL_CONTROL 2002 /* global control byte */ -#define FSCSCY_SYSCTL_WDOG 2003 /* state, min, ripple, actual value fan 2 */ -#define FSCSCY_SYSCTL_PCILOAD 2004 /* PCILoad value */ -#define FSCSCY_SYSCTL_INTRUSION 2005 /* state, control for intrusion sensor */ - -/* -- SENSORS SYSCTL END -- */ - -/* These files are created for each detected FSCSCY. This is just a template; - though at first sight, you might think we could use a statically - allocated list, we need some way to get back to the parent - which - is done through one of the 'extra' fields which are initialized - when a new copy is allocated. */ -static ctl_table fscscy_dir_table_template[] = { - {FSCSCY_SYSCTL_REV, "rev", NULL, 0, 0444, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &fscscy_in}, - {FSCSCY_SYSCTL_EVENT, "alarms", NULL, 0, 0444, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &fscscy_in}, - {FSCSCY_SYSCTL_CONTROL, "control", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &fscscy_in}, - {FSCSCY_SYSCTL_TEMP0, "temp1", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &fscscy_temp}, - {FSCSCY_SYSCTL_TEMP1, "temp2", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &fscscy_temp}, - {FSCSCY_SYSCTL_TEMP2, "temp3", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &fscscy_temp}, - {FSCSCY_SYSCTL_TEMP3, "temp4", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &fscscy_temp}, - {FSCSCY_SYSCTL_VOLT0, "in0", NULL, 0, 0444, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &fscscy_volt}, - {FSCSCY_SYSCTL_VOLT1, "in1", NULL, 0, 0444, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &fscscy_volt}, - {FSCSCY_SYSCTL_VOLT2, "in2", NULL, 0, 0444, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &fscscy_volt}, - {FSCSCY_SYSCTL_FAN0, "fan1", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &fscscy_fan}, - {FSCSCY_SYSCTL_FAN1, "fan2", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &fscscy_fan}, - {FSCSCY_SYSCTL_FAN2, "fan3", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &fscscy_fan}, - {FSCSCY_SYSCTL_FAN3, "fan4", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &fscscy_fan}, - {FSCSCY_SYSCTL_FAN4, "fan5", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &fscscy_fan}, - {FSCSCY_SYSCTL_FAN5, "fan6", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &fscscy_fan}, - {FSCSCY_SYSCTL_WDOG, "wdog", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &fscscy_wdog}, - {FSCSCY_SYSCTL_PCILOAD, "pciload", NULL, 0, 0444, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &fscscy_pciload}, - {FSCSCY_SYSCTL_INTRUSION, "intrusion", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &fscscy_intrusion}, - {0} -}; - -static int fscscy_attach_adapter(struct i2c_adapter *adapter) -{ - return i2c_detect(adapter, &addr_data, fscscy_detect); -} - -int fscscy_detect(struct i2c_adapter *adapter, int address, - unsigned short flags, int kind) -{ - int i; - struct i2c_client *new_client; - struct fscscy_data *data; - int err = 0; - const char *type_name, *client_name; - - /* Make sure we aren't probing the ISA bus!! This is just a safety check - at this moment; i2c_detect really won't call us. */ -#ifdef DEBUG - if (i2c_is_isa_adapter(adapter)) { - printk - ("fscscy.o: fscscy_detect called for an ISA bus adapter?!?\n"); - return 0; - } -#endif - - if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) - goto ERROR0; - - /* OK. For now, we presume we have a valid client. We now create the - client structure, even though we cannot fill it completely yet. - But it allows us to access fscscy_{read,write}_value. */ - if (!(data = kmalloc(sizeof(struct fscscy_data), GFP_KERNEL))) { - err = -ENOMEM; - goto ERROR0; - } - - new_client = &data->client; - new_client->addr = address; - new_client->data = data; - new_client->adapter = adapter; - new_client->driver = &fscscy_driver; - new_client->flags = 0; - - /* Do the remaining detection unless force or force_fscscy parameter */ - if (kind < 0) { - if (fscscy_read_value(new_client, FSCSCY_REG_IDENT_0) != 0x53) - goto ERROR1; - if (fscscy_read_value(new_client, FSCSCY_REG_IDENT_1) != 0x43) - goto ERROR1; - if (fscscy_read_value(new_client, FSCSCY_REG_IDENT_2) != 0x59) - goto ERROR1; - } - - kind = fscscy; - - type_name = "fscscy"; - client_name = "fsc scylla chip"; - - /* Fill in the remaining client fields and put it into the global list */ - strcpy(new_client->name, client_name); - data->valid = 0; - init_MUTEX(&data->update_lock); - - /* Tell the I2C layer a new client has arrived */ - if ((err = i2c_attach_client(new_client))) - goto ERROR3; - - /* Register a new directory entry with module sensors */ - if ((i = i2c_register_entry(new_client, type_name, - fscscy_dir_table_template, - THIS_MODULE)) < 0) { - err = i; - goto ERROR4; - } - data->sysctl_id = i; - - fscscy_init_client(new_client); - return 0; - -/* OK, this is not exactly good programming practice, usually. But it is - very code-efficient in this case. */ - ERROR4: - i2c_detach_client(new_client); - ERROR3: - ERROR1: - kfree(data); - ERROR0: - return err; -} - -static int fscscy_detach_client(struct i2c_client *client) -{ - int err; - - i2c_deregister_entry(((struct fscscy_data *) (client->data))-> - sysctl_id); - - if ((err = i2c_detach_client(client))) { - printk - ("fscscy.o: Client deregistration failed, client not detached.\n"); - return err; - } - - kfree(client->data); - - return 0; -} - -static int fscscy_read_value(struct i2c_client *client, u8 reg) -{ -#ifdef DEBUG - printk("fscscy: read reg 0x%02x\n",reg); -#endif - return i2c_smbus_read_byte_data(client, reg); -} - -static int fscscy_write_value(struct i2c_client *client, u8 reg, u8 value) -{ -#ifdef DEBUG - printk("fscscy: write reg 0x%02x, val 0x%02x\n",reg, value); -#endif - return i2c_smbus_write_byte_data(client, reg, value); -} - -/* Called when we have found a new FSCSCY. */ -static void fscscy_init_client(struct i2c_client *client) -{ - struct fscscy_data *data = client->data; - - /* read revision from chip */ - data->revision = fscscy_read_value(client,FSCSCY_REG_REVISION); - - /* Initialize min/max values from chip */ - data->fan_min[0] = data->fan_max[0] = fscscy_read_value(client, FSCSCY_REG_FAN0_ACT); - data->fan_min[1] = data->fan_max[1] = fscscy_read_value(client, FSCSCY_REG_FAN1_ACT); - data->fan_min[2] = data->fan_max[2] = fscscy_read_value(client, FSCSCY_REG_FAN2_ACT); - data->fan_min[3] = data->fan_max[3] = fscscy_read_value(client, FSCSCY_REG_FAN3_ACT); - data->fan_min[4] = data->fan_max[4] = fscscy_read_value(client, FSCSCY_REG_FAN4_ACT); - data->fan_min[4] = data->fan_max[5] = fscscy_read_value(client, FSCSCY_REG_FAN5_ACT); - data->temp_min[0] = data->temp_max[0] = fscscy_read_value(client, FSCSCY_REG_TEMP0_ACT); - data->temp_min[1] = data->temp_max[1] = fscscy_read_value(client, FSCSCY_REG_TEMP1_ACT); - data->temp_min[2] = data->temp_max[2] = fscscy_read_value(client, FSCSCY_REG_TEMP2_ACT); - data->temp_min[3] = data->temp_max[3] = fscscy_read_value(client, FSCSCY_REG_TEMP3_ACT); - data->volt_min[0] = data->volt_max[0] = fscscy_read_value(client, FSCSCY_REG_VOLT_12); - data->volt_min[1] = data->volt_max[1] = fscscy_read_value(client, FSCSCY_REG_VOLT_5); - data->volt_min[2] = data->volt_max[2] = fscscy_read_value(client, FSCSCY_REG_VOLT_BATT); -} - -static void fscscy_update_client(struct i2c_client *client) -{ - struct fscscy_data *data = client->data; - - down(&data->update_lock); - - if ((jiffies - data->last_updated > 2 * HZ) || - (jiffies < data->last_updated) || !data->valid) { - -#ifdef DEBUG - printk("Starting fscscy update\n"); -#endif - data->temp_act[0] = fscscy_read_value(client, FSCSCY_REG_TEMP0_ACT); - if (data->temp_min[0] > data->temp_act[0]) data->temp_min[0] = data->temp_act[0]; - if (data->temp_max[0] < data->temp_act[0]) data->temp_max[0] = data->temp_act[0]; - data->temp_act[1] = fscscy_read_value(client, FSCSCY_REG_TEMP1_ACT); - if (data->temp_min[1] > data->temp_act[1]) data->temp_min[1] = data->temp_act[1]; - if (data->temp_max[1] < data->temp_act[1]) data->temp_max[1] = data->temp_act[1]; - data->temp_act[2] = fscscy_read_value(client, FSCSCY_REG_TEMP2_ACT); - if (data->temp_min[2] > data->temp_act[2]) data->temp_min[2] = data->temp_act[2]; - if (data->temp_max[2] < data->temp_act[2]) data->temp_max[2] = data->temp_act[2]; - data->temp_act[3] = fscscy_read_value(client, FSCSCY_REG_TEMP3_ACT); - if (data->temp_min[3] > data->temp_act[3]) data->temp_min[3] = data->temp_act[3]; - if (data->temp_max[3] < data->temp_act[3]) data->temp_max[3] = data->temp_act[3]; - data->temp_status[0] = fscscy_read_value(client, FSCSCY_REG_TEMP0_STATE); - data->temp_status[1] = fscscy_read_value(client, FSCSCY_REG_TEMP1_STATE); - data->temp_status[2] = fscscy_read_value(client, FSCSCY_REG_TEMP2_STATE); - data->temp_status[3] = fscscy_read_value(client, FSCSCY_REG_TEMP3_STATE); - data->temp_lim[0] = fscscy_read_value(client, FSCSCY_REG_TEMP0_LIM); - data->temp_lim[1] = fscscy_read_value(client, FSCSCY_REG_TEMP1_LIM); - data->temp_lim[2] = fscscy_read_value(client, FSCSCY_REG_TEMP2_LIM); - data->temp_lim[3] = fscscy_read_value(client, FSCSCY_REG_TEMP3_LIM); - - data->volt[0] = fscscy_read_value(client, FSCSCY_REG_VOLT_12); - if (data->volt_min[0] > data->volt[0]) data->volt_min[0] = data->volt[0]; - if (data->volt_max[0] < data->volt[0]) data->volt_max[0] = data->volt[0]; - data->volt[1] = fscscy_read_value(client, FSCSCY_REG_VOLT_5); - if (data->volt_min[1] > data->volt[1]) data->volt_min[1] = data->volt[1]; - if (data->volt_max[1] < data->volt[1]) data->volt_max[1] = data->volt[1]; - data->volt[2] = fscscy_read_value(client, FSCSCY_REG_VOLT_BATT); - if (data->volt_min[2] > data->volt[2]) data->volt_min[2] = data->volt[2]; - if (data->volt_max[2] < data->volt[2]) data->volt_max[2] = data->volt[2]; - - data->fan_act[0] = fscscy_read_value(client, FSCSCY_REG_FAN0_ACT); - if (data->fan_min[0] > data->fan_act[0]) data->fan_min[0] = data->fan_act[0]; - if (data->fan_max[0] < data->fan_act[0]) data->fan_max[0] = data->fan_act[0]; - data->fan_act[1] = fscscy_read_value(client, FSCSCY_REG_FAN1_ACT); - if (data->fan_min[1] > data->fan_act[1]) data->fan_min[1] = data->fan_act[1]; - if (data->fan_max[1] < data->fan_act[1]) data->fan_max[1] = data->fan_act[1]; - data->fan_act[2] = fscscy_read_value(client, FSCSCY_REG_FAN2_ACT); - if (data->fan_min[2] > data->fan_act[2]) data->fan_min[2] = data->fan_act[2]; - if (data->fan_max[2] < data->fan_act[2]) data->fan_max[2] = data->fan_act[2]; - data->fan_act[3] = fscscy_read_value(client, FSCSCY_REG_FAN3_ACT); - if (data->fan_min[3] > data->fan_act[3]) data->fan_min[3] = data->fan_act[3]; - if (data->fan_max[3] < data->fan_act[3]) data->fan_max[3] = data->fan_act[3]; - data->fan_act[4] = fscscy_read_value(client, FSCSCY_REG_FAN4_ACT); - if (data->fan_min[4] > data->fan_act[4]) data->fan_min[4] = data->fan_act[4]; - if (data->fan_max[4] < data->fan_act[4]) data->fan_max[4] = data->fan_act[4]; - data->fan_act[5] = fscscy_read_value(client, FSCSCY_REG_FAN5_ACT); - if (data->fan_min[5] > data->fan_act[5]) data->fan_min[5] = data->fan_act[5]; - if (data->fan_max[5] < data->fan_act[5]) data->fan_max[5] = data->fan_act[5]; - data->fan_status[0] = fscscy_read_value(client, FSCSCY_REG_FAN0_STATE); - data->fan_status[1] = fscscy_read_value(client, FSCSCY_REG_FAN1_STATE); - data->fan_status[2] = fscscy_read_value(client, FSCSCY_REG_FAN2_STATE); - data->fan_status[3] = fscscy_read_value(client, FSCSCY_REG_FAN3_STATE); - data->fan_status[4] = fscscy_read_value(client, FSCSCY_REG_FAN4_STATE); - data->fan_status[5] = fscscy_read_value(client, FSCSCY_REG_FAN5_STATE); - data->fan_rpmmin[0] = fscscy_read_value(client, FSCSCY_REG_FAN0_RPMMIN); - data->fan_rpmmin[1] = fscscy_read_value(client, FSCSCY_REG_FAN1_RPMMIN); - data->fan_rpmmin[2] = fscscy_read_value(client, FSCSCY_REG_FAN2_RPMMIN); - data->fan_rpmmin[3] = fscscy_read_value(client, FSCSCY_REG_FAN3_RPMMIN); - data->fan_rpmmin[4] = fscscy_read_value(client, FSCSCY_REG_FAN4_RPMMIN); - data->fan_rpmmin[5] = fscscy_read_value(client, FSCSCY_REG_FAN5_RPMMIN); - data->fan_ripple[0] = fscscy_read_value(client, FSCSCY_REG_FAN0_RIPPLE); - data->fan_ripple[1] = fscscy_read_value(client, FSCSCY_REG_FAN1_RIPPLE); - data->fan_ripple[2] = fscscy_read_value(client, FSCSCY_REG_FAN2_RIPPLE); - data->fan_ripple[3] = fscscy_read_value(client, FSCSCY_REG_FAN3_RIPPLE); - data->fan_ripple[4] = fscscy_read_value(client, FSCSCY_REG_FAN4_RIPPLE); - data->fan_ripple[5] = fscscy_read_value(client, FSCSCY_REG_FAN5_RIPPLE); - - data->watchdog[0] = fscscy_read_value(client, FSCSCY_REG_WDOG_PRESET); - data->watchdog[1] = fscscy_read_value(client, FSCSCY_REG_WDOG_STATE); - data->watchdog[2] = fscscy_read_value(client, FSCSCY_REG_WDOG_CONTROL); - - data->global_event = fscscy_read_value(client, FSCSCY_REG_EVENT_STATE); - data->global_control = fscscy_read_value(client, FSCSCY_REG_CONTROL); - data->pciload = fscscy_read_value(client, FSCSCY_REG_PCILOAD); - data->intr_status = fscscy_read_value(client, FSCSCY_REG_INTR_STATE); - data->intr_control = fscscy_read_value(client, FSCSCY_REG_INTR_CTRL); - - data->last_updated = jiffies; - data->valid = 1; - } - - up(&data->update_lock); -} - - -/* The next few functions are the call-back functions of the /proc/sys and - sysctl files. Which function is used is defined in the ctl_table in - the extra1 field. - Each function must return the magnitude (power of 10 to divide the date - with) if it is called with operation==SENSORS_PROC_REAL_INFO. It must - put a maximum of *nrels elements in results reflecting the data of this - file, and set *nrels to the number it actually put in it, if operation== - SENSORS_PROC_REAL_READ. Finally, it must get upto *nrels elements from - results and write them to the chip, if operations==SENSORS_PROC_REAL_WRITE. - Note that on SENSORS_PROC_REAL_READ, I do not check whether results is - large enough (by checking the incoming value of *nrels). This is not very - good practice, but as long as you put less than about 5 values in results, - you can assume it is large enough. */ -void fscscy_in(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct fscscy_data *data = client->data; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - fscscy_update_client(client); - switch(ctl_name) { - case FSCSCY_SYSCTL_REV: - results[0] = data->revision ; - break; - case FSCSCY_SYSCTL_EVENT: - results[0] = data->global_event & 0x9f; /* MKN */ - break; - case FSCSCY_SYSCTL_CONTROL: - results[0] = data->global_control & 0x19; /* MKN */ - break; - default: - printk("fscscy: ctl_name %d not supported\n", - ctl_name); - *nrels_mag = 0; - return; - } - *nrels_mag = 1; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if((ctl_name == FSCSCY_SYSCTL_CONTROL) && (*nrels_mag >= 1)) { - data->global_control = (data->global_control & 0x18) | (results[0] & 0x01); /* MKN */ - printk("fscscy: writing 0x%02x to global_control\n", - data->global_control); - fscscy_write_value(client,FSCSCY_REG_CONTROL, - data->global_control); - } - else - printk("fscscy: writing to chip not supported\n"); - } -} - -#define TEMP_FROM_REG(val) (val-128) - - -void fscscy_temp(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct fscscy_data *data = client->data; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - fscscy_update_client(client); - switch(ctl_name) { - case FSCSCY_SYSCTL_TEMP0: - results[0] = data->temp_status[0] & 0x03; - results[1] = TEMP_FROM_REG(data->temp_act[0]); - results[2] = TEMP_FROM_REG(data->temp_lim[0]); - results[3] = TEMP_FROM_REG(data->temp_min[0]); - results[4] = TEMP_FROM_REG(data->temp_max[0]); - break; - case FSCSCY_SYSCTL_TEMP1: - results[0] = data->temp_status[1] & 0x03; - results[1] = TEMP_FROM_REG(data->temp_act[1]); - results[2] = TEMP_FROM_REG(data->temp_lim[1]); - results[3] = TEMP_FROM_REG(data->temp_min[1]); - results[4] = TEMP_FROM_REG(data->temp_max[1]); - break; - case FSCSCY_SYSCTL_TEMP2: - results[0] = data->temp_status[2] & 0x03; - results[1] = TEMP_FROM_REG(data->temp_act[2]); - results[2] = TEMP_FROM_REG(data->temp_lim[2]); - results[3] = TEMP_FROM_REG(data->temp_min[2]); - results[4] = TEMP_FROM_REG(data->temp_max[2]); - break; - case FSCSCY_SYSCTL_TEMP3: - results[0] = data->temp_status[3] & 0x03; - results[1] = TEMP_FROM_REG(data->temp_act[3]); - results[2] = TEMP_FROM_REG(data->temp_lim[3]); - results[3] = TEMP_FROM_REG(data->temp_min[3]); - results[4] = TEMP_FROM_REG(data->temp_max[3]); - break; - default: - printk("fscscy: ctl_name %d not supported\n", - ctl_name); - *nrels_mag = 0; - return; - } - *nrels_mag = 5; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if(*nrels_mag >= 1) { - switch(ctl_name) { - case FSCSCY_SYSCTL_TEMP0: - data->temp_status[0] = - (data->temp_status[0] & ~0x02) - | (results[0] & 0x02); - printk("fscscy: writing value 0x%02x " - "to temp0_status\n", - data->temp_status[0]); - fscscy_write_value(client, - FSCSCY_REG_TEMP0_STATE, - data->temp_status[0] & 0x02); - break; - case FSCSCY_SYSCTL_TEMP1: - data->temp_status[1] = (data->temp_status[1] & ~0x02) | (results[0] & 0x02); - printk("fscscy: writing value 0x%02x to temp1_status\n", data->temp_status[1]); - fscscy_write_value(client,FSCSCY_REG_TEMP1_STATE, - data->temp_status[1] & 0x02); - break; - case FSCSCY_SYSCTL_TEMP2: - data->temp_status[2] = (data->temp_status[2] & ~0x02) | (results[0] & 0x02); - printk("fscscy: writing value 0x%02x to temp2_status\n", data->temp_status[2]); - fscscy_write_value(client,FSCSCY_REG_TEMP2_STATE, - data->temp_status[2] & 0x02); - break; - case FSCSCY_SYSCTL_TEMP3: - data->temp_status[3] = (data->temp_status[3] & ~0x02) | (results[0] & 0x02); - printk("fscscy: writing value 0x%02x to temp3_status\n", data->temp_status[3]); - fscscy_write_value(client,FSCSCY_REG_TEMP3_STATE, - data->temp_status[3] & 0x02); - break; - default: - printk("fscscy: ctl_name %d not supported\n",ctl_name); - } - } - else - printk("fscscy: writing to chip not supported\n"); - } -} - -#define VOLT_FROM_REG(val,mult) (val*mult/255) - -void fscscy_volt(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct fscscy_data *data = client->data; - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 2; - else if (operation == SENSORS_PROC_REAL_READ) { - fscscy_update_client(client); - switch(ctl_name) { - case FSCSCY_SYSCTL_VOLT0: - results[0] = VOLT_FROM_REG(data->volt[0],1420); - results[1] = VOLT_FROM_REG(data->volt_min[0],1420); - results[2] = VOLT_FROM_REG(data->volt_max[0],1420); - break; - case FSCSCY_SYSCTL_VOLT1: - results[0] = VOLT_FROM_REG(data->volt[1],660); - results[1] = VOLT_FROM_REG(data->volt_min[1],660); - results[2] = VOLT_FROM_REG(data->volt_max[1],660); - break; - case FSCSCY_SYSCTL_VOLT2: - results[0] = VOLT_FROM_REG(data->volt[2],330); - results[1] = VOLT_FROM_REG(data->volt_min[2],330); - results[2] = VOLT_FROM_REG(data->volt_max[2],330); - break; - default: - printk("fscscy: ctl_name %d not supported\n", - ctl_name); - *nrels_mag = 0; - return; - } - *nrels_mag = 3; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - printk("fscscy: writing to chip not supported\n"); - } -} - -void fscscy_fan(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - - switch(ctl_name) { - case FSCSCY_SYSCTL_FAN0: - fscscy_fan_internal(client,operation,ctl_name,nrels_mag,results, - 0,FSCSCY_REG_FAN0_STATE,FSCSCY_REG_FAN0_RPMMIN, - FSCSCY_REG_FAN0_RIPPLE); - break; - case FSCSCY_SYSCTL_FAN1: - fscscy_fan_internal(client,operation,ctl_name,nrels_mag,results, - 1,FSCSCY_REG_FAN1_STATE,FSCSCY_REG_FAN1_RPMMIN, - FSCSCY_REG_FAN1_RIPPLE); - break; - case FSCSCY_SYSCTL_FAN2: - fscscy_fan_internal(client,operation,ctl_name,nrels_mag,results, - 2,FSCSCY_REG_FAN2_STATE,FSCSCY_REG_FAN2_RPMMIN, - FSCSCY_REG_FAN2_RIPPLE); - break; - case FSCSCY_SYSCTL_FAN3: - fscscy_fan_internal(client,operation,ctl_name,nrels_mag,results, - 3,FSCSCY_REG_FAN3_STATE,FSCSCY_REG_FAN3_RPMMIN, - FSCSCY_REG_FAN3_RIPPLE); - break; - case FSCSCY_SYSCTL_FAN4: - fscscy_fan_internal(client,operation,ctl_name,nrels_mag,results, - 4,FSCSCY_REG_FAN4_STATE,FSCSCY_REG_FAN4_RPMMIN, - FSCSCY_REG_FAN4_RIPPLE); - break; - case FSCSCY_SYSCTL_FAN5: - fscscy_fan_internal(client,operation,ctl_name,nrels_mag,results, - 5,FSCSCY_REG_FAN5_STATE,FSCSCY_REG_FAN5_RPMMIN, - FSCSCY_REG_FAN5_RIPPLE); - break; - default: - printk("fscscy: illegal fan nr %d\n",ctl_name); - } -} - -#define RPM_FROM_REG(val) (val*60) - -void fscscy_fan_internal(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results, int nr, - int reg_state, int reg_min, int reg_ripple ) -{ - struct fscscy_data *data = client->data; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - fscscy_update_client(client); - results[0] = data->fan_status[nr] & 0x0f; /* MKN */ - results[1] = data->fan_rpmmin[nr]; - results[2] = data->fan_ripple[nr] & 0x03; - results[3] = RPM_FROM_REG(data->fan_act[nr]); - results[4] = RPM_FROM_REG(data->fan_min[nr]); - results[5] = RPM_FROM_REG(data->fan_max[nr]); - *nrels_mag = 6; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if(*nrels_mag >= 1) { - data->fan_status[nr] = (data->fan_status[nr] & 0x0b) | (results[0] & 0x04); /* MKN */ - printk("fscscy: writing value 0x%02x to fan%d_status\n", - data->fan_status[nr],nr); - fscscy_write_value(client,reg_state, - data->fan_status[nr]); - } - if(*nrels_mag >= 2) { - if((results[1] & 0xff) == 0) { - printk("fscscy: fan%d rpmmin 0 not allowed for safety reasons\n",nr); - return; - } - data->fan_rpmmin[nr] = results[1]; - printk("fscscy: writing value 0x%02x to fan%d_min\n", - data->fan_rpmmin[nr],nr); - fscscy_write_value(client,reg_min, - data->fan_rpmmin[nr]); - } - if(*nrels_mag >= 3) { - if((results[2] & 0x03) == 0) { - printk("fscscy: fan%d ripple 0 is nonsense/not allowed\n",nr); - return; - } - data->fan_ripple[nr] = results[2] & 0x03; - printk("fscscy: writing value 0x%02x to fan%d_ripple\n", - data->fan_ripple[nr],nr); - fscscy_write_value(client,reg_ripple, - data->fan_ripple[nr]); - } - } -} - -void fscscy_wdog(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct fscscy_data *data = client->data; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - fscscy_update_client(client); - results[0] = data->watchdog[0] ; - results[1] = data->watchdog[1] & 0x02; - results[2] = data->watchdog[2] & 0xb0; - *nrels_mag = 3; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag >= 1) { - data->watchdog[0] = results[0] & 0xff; - printk("fscscy: writing value 0x%02x to wdog_preset\n", - data->watchdog[0]); - fscscy_write_value(client,FSCSCY_REG_WDOG_PRESET, - data->watchdog[0]); - } - if (*nrels_mag >= 2) { - data->watchdog[1] = results[1] & 0x02; - printk("fscscy: writing value 0x%02x to wdog_state\n", - data->watchdog[1]); - fscscy_write_value(client,FSCSCY_REG_WDOG_STATE, - data->watchdog[1]); - } - if (*nrels_mag >= 3) { - data->watchdog[2] = results[2] & 0xb0; - printk("fscscy: writing value 0x%02x to wdog_control\n", - data->watchdog[2]); - fscscy_write_value(client,FSCSCY_REG_WDOG_CONTROL, - data->watchdog[2]); - } - } -} - -void fscscy_pciload(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct fscscy_data *data = client->data; - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - fscscy_update_client(client); - results[0] = data->pciload; - *nrels_mag = 1; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - printk("fscscy: writing PCILOAD to chip not supported\n"); - } -} - -void fscscy_intrusion(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct fscscy_data *data = client->data; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - fscscy_update_client(client); - results[0] = data->intr_control & 0x80; - results[1] = data->intr_status & 0xc0; - *nrels_mag = 2; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag >= 1) { - data->intr_control = results[0] & 0x80; - printk("fscscy: writing value 0x%02x to intr_control\n", - data->intr_control); - fscscy_write_value(client,FSCSCY_REG_INTR_CTRL, - data->intr_control); - } - } -} - -static int __init sm_fscscy_init(void) -{ - printk("fscscy.o version %s (%s)\n", LM_VERSION, LM_DATE); - return i2c_add_driver(&fscscy_driver); -} - -static void __exit sm_fscscy_exit(void) -{ - i2c_del_driver(&fscscy_driver); -} - - - -MODULE_AUTHOR - ("Martin Knoblauch based on work (fscpos) from Hermann Jung "); -MODULE_DESCRIPTION("fujitsu siemens scylla chip driver"); - -module_init(sm_fscscy_init); -module_exit(sm_fscscy_exit); diff --git a/kernel/chips/gl518sm.c b/kernel/chips/gl518sm.c deleted file mode 100644 index 996c17b6..00000000 --- a/kernel/chips/gl518sm.c +++ /dev/null @@ -1,987 +0,0 @@ -/* - gl518sm.c - Part of lm_sensors, Linux kernel modules for hardware - monitoring - Copyright (c) 1998, 1999 Frodo Looijaard , - Kyösti Mälkki - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - -*/ - -#include -#include -#include -#include -#include -#ifdef __SMP__ -#include -#endif -#include "version.h" - -MODULE_LICENSE("GPL"); - -/* Addresses to scan */ -static unsigned short normal_i2c[] = { 0x2c, 0x2d, SENSORS_I2C_END }; -static unsigned short normal_i2c_range[] = { SENSORS_I2C_END }; -static unsigned int normal_isa[] = { SENSORS_ISA_END }; -static unsigned int normal_isa_range[] = { SENSORS_ISA_END }; - -/* Insmod parameters */ -SENSORS_INSMOD_2(gl518sm_r00, gl518sm_r80); - -/* Defining this will enable debug messages for the voltage iteration - code used with rev 0 ICs */ -#undef DEBUG_VIN - -/* Many GL518 constants specified below */ - -/* The GL518 registers */ -#define GL518_REG_CHIP_ID 0x00 -#define GL518_REG_REVISION 0x01 -#define GL518_REG_VENDOR_ID 0x02 -#define GL518_REG_CONF 0x03 -#define GL518_REG_TEMP 0x04 -#define GL518_REG_TEMP_OVER 0x05 -#define GL518_REG_TEMP_HYST 0x06 -#define GL518_REG_FAN_COUNT 0x07 -#define GL518_REG_FAN_LIMIT 0x08 -#define GL518_REG_VIN1_LIMIT 0x09 -#define GL518_REG_VIN2_LIMIT 0x0a -#define GL518_REG_VIN3_LIMIT 0x0b -#define GL518_REG_VDD_LIMIT 0x0c -#define GL518_REG_VIN3 0x0d -#define GL518_REG_MISC 0x0f -#define GL518_REG_ALARM 0x10 -#define GL518_REG_MASK 0x11 -#define GL518_REG_INT 0x12 -#define GL518_REG_VIN2 0x13 -#define GL518_REG_VIN1 0x14 -#define GL518_REG_VDD 0x15 - - -/* Conversions. Rounding and limit checking is only done on the TO_REG - variants. Note that you should be a bit careful with which arguments - these macros are called: arguments may be evaluated more than once. - Fixing this is just not worth it. */ - -#define TEMP_TO_REG(val) (SENSORS_LIMIT(((((val)<0?(val)-5:(val)+5) / 10)+119),\ - 0,255)) -#define TEMP_FROM_REG(val) (((val) - 119) * 10) - -static inline u8 FAN_TO_REG(long rpm, int div) -{ - if (rpm == 0) - return 255; - rpm = SENSORS_LIMIT(rpm, 1, 1000000); - return SENSORS_LIMIT((480000 + rpm * div / 2) / (rpm * div), 1, - 254); -} - -#define FAN_FROM_REG(val,div) \ - ( (val)==0 ? 0 : (val)==255 ? 0 : (480000/((val)*(div))) ) - -#define IN_TO_REG(val) (SENSORS_LIMIT((((val)*10+8)/19),0,255)) -#define IN_FROM_REG(val) (((val)*19)/10) - -#define VDD_TO_REG(val) (SENSORS_LIMIT((((val)*10+11)/23),0,255)) -#define VDD_FROM_REG(val) (((val)*23)/10) - -#define DIV_TO_REG(val) ((val)==8?3:(val)==4?2:(val)==1?0:1) -#define DIV_FROM_REG(val) (1 << (val)) - -#define ALARMS_FROM_REG(val) val - -#define BEEP_ENABLE_TO_REG(val) ((val)?0:1) -#define BEEP_ENABLE_FROM_REG(val) ((val)?0:1) - -#define BEEPS_TO_REG(val) ((val) & 0x7f) -#define BEEPS_FROM_REG(val) ((val) & 0x7f) - -/* Each client has this additional data */ -struct gl518_data { - struct i2c_client client; - int sysctl_id; - enum chips type; - - struct semaphore update_lock; - - int iterate_lock; - int quit_thread; - struct task_struct *thread; - wait_queue_head_t wq; - char valid; /* !=0 if following fields are valid */ - unsigned long last_updated; /* In jiffies */ - unsigned long last_updated_v00; - /* In jiffies (used only by rev00 chips) */ - - u8 voltage[4]; /* Register values; [0] = VDD */ - u8 voltage_min[4]; /* Register values; [0] = VDD */ - u8 voltage_max[4]; /* Register values; [0] = VDD */ - u8 iter_voltage[4]; /* Register values; [0] = VDD */ - u8 fan[2]; - u8 fan_min[2]; - u8 temp; /* Register values */ - u8 temp_over; /* Register values */ - u8 temp_hyst; /* Register values */ - u8 alarms, beeps; /* Register value */ - u8 alarm_mask; /* Register value */ - u8 fan_div[2]; /* Register encoding, shifted right */ - u8 beep_enable; /* Boolean */ - u8 iterate; /* Voltage iteration mode */ -}; - -static int gl518_attach_adapter(struct i2c_adapter *adapter); -static int gl518_detect(struct i2c_adapter *adapter, int address, - unsigned short flags, int kind); -static void gl518_init_client(struct i2c_client *client); -static int gl518_detach_client(struct i2c_client *client); - -static int gl518_read_value(struct i2c_client *client, u8 reg); -static int gl518_write_value(struct i2c_client *client, u8 reg, u16 value); -static void gl518_update_client(struct i2c_client *client); - -static void gl518_update_client_rev00(struct i2c_client *client); -static void gl518_update_iterate(struct i2c_client *client); - -static void gl518_vin(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void gl518_fan(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void gl518_temp(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void gl518_fan_div(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void gl518_alarms(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void gl518_beep(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void gl518_fan1off(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void gl518_iterate(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); - -/* This is the driver that will be inserted */ -static struct i2c_driver gl518_driver = { - .name = "GL518SM sensor chip driver", - .id = I2C_DRIVERID_GL518, - .flags = I2C_DF_NOTIFY, - .attach_adapter = gl518_attach_adapter, - .detach_client = gl518_detach_client, -}; - -/* -- SENSORS SYSCTL START -- */ - -#define GL518_SYSCTL_VDD 1000 /* Volts * 100 */ -#define GL518_SYSCTL_VIN1 1001 -#define GL518_SYSCTL_VIN2 1002 -#define GL518_SYSCTL_VIN3 1003 -#define GL518_SYSCTL_FAN1 1101 /* RPM */ -#define GL518_SYSCTL_FAN2 1102 -#define GL518_SYSCTL_TEMP 1200 /* Degrees Celsius * 10 */ -#define GL518_SYSCTL_FAN_DIV 2000 /* 1, 2, 4 or 8 */ -#define GL518_SYSCTL_ALARMS 2001 /* bitvector */ -#define GL518_SYSCTL_BEEP 2002 /* bitvector */ -#define GL518_SYSCTL_FAN1OFF 2003 -#define GL518_SYSCTL_ITERATE 2004 - -#define GL518_ALARM_VDD 0x01 -#define GL518_ALARM_VIN1 0x02 -#define GL518_ALARM_VIN2 0x04 -#define GL518_ALARM_VIN3 0x08 -#define GL518_ALARM_TEMP 0x10 -#define GL518_ALARM_FAN1 0x20 -#define GL518_ALARM_FAN2 0x40 - -/* -- SENSORS SYSCTL END -- */ - -/* These files are created for each detected GL518. This is just a template; - though at first sight, you might think we could use a statically - allocated list, we need some way to get back to the parent - which - is done through one of the 'extra' fields which are initialized - when a new copy is allocated. */ -static ctl_table gl518_dir_table_template[] = { - {GL518_SYSCTL_VIN1, "in1", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &gl518_vin}, - {GL518_SYSCTL_VIN2, "in2", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &gl518_vin}, - {GL518_SYSCTL_VIN3, "in3", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &gl518_vin}, - {GL518_SYSCTL_VDD, "in0", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &gl518_vin}, - {GL518_SYSCTL_FAN1, "fan1", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &gl518_fan}, - {GL518_SYSCTL_FAN2, "fan2", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &gl518_fan}, - {GL518_SYSCTL_TEMP, "temp", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &gl518_temp}, - {GL518_SYSCTL_FAN_DIV, "fan_div", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &gl518_fan_div}, - {GL518_SYSCTL_ALARMS, "alarms", NULL, 0, 0444, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &gl518_alarms}, - {GL518_SYSCTL_BEEP, "beep", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &gl518_beep}, - {GL518_SYSCTL_FAN1OFF, "fan1off", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &gl518_fan1off}, - {GL518_SYSCTL_ITERATE, "iterate", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &gl518_iterate}, - {0} -}; - -/* I choose here for semi-static GL518SM allocation. Complete dynamic - allocation could also be used; the code needed for this would probably - take more memory than the datastructure takes now. */ -#define MAX_GL518_NR 4 -static struct i2c_client *gl518_list[MAX_GL518_NR]; - -static int gl518_attach_adapter(struct i2c_adapter *adapter) -{ - return i2c_detect(adapter, &addr_data, gl518_detect); -} - -static int gl518_detect(struct i2c_adapter *adapter, int address, - unsigned short flags, int kind) -{ - int i; - struct i2c_client *new_client; - struct gl518_data *data; - int err = 0; - const char *type_name = ""; - const char *client_name = ""; - - /* Make sure we aren't probing the ISA bus!! This is just a safety check - at this moment; i2c_detect really won't call us. */ -#ifdef DEBUG - if (i2c_is_isa_adapter(adapter)) { - printk - ("gl518sm.o: gl518_detect called for an ISA bus adapter?!?\n"); - return 0; - } -#endif - - if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA | - I2C_FUNC_SMBUS_WORD_DATA)) - goto ERROR0; - - /* OK. For now, we presume we have a valid client. We now create the - client structure, even though we cannot fill it completely yet. - But it allows us to access gl518_{read,write}_value. */ - - if (!(data = kmalloc(sizeof(struct gl518_data), GFP_KERNEL))) { - err = -ENOMEM; - goto ERROR0; - } - - new_client = &data->client; - new_client->addr = address; - new_client->data = data; - new_client->adapter = adapter; - new_client->driver = &gl518_driver; - new_client->flags = 0; - - /* Now, we do the remaining detection. */ - - if (kind < 0) { - if ( - (gl518_read_value(new_client, GL518_REG_CHIP_ID) != - 0x80) - || (gl518_read_value(new_client, GL518_REG_CONF) & - 0x80)) goto ERROR1; - } - - /* Determine the chip type. */ - if (kind <= 0) { - i = gl518_read_value(new_client, GL518_REG_REVISION); - if (i == 0x00) - kind = gl518sm_r00; - else if (i == 0x80) - kind = gl518sm_r80; - else { - if (kind == 0) - printk - ("gl518sm.o: Ignoring 'force' parameter for unknown chip at " - "adapter %d, address 0x%02x\n", - i2c_adapter_id(adapter), address); - goto ERROR1; - } - } - - type_name = "gl518sm"; - if (kind == gl518sm_r00) { - client_name = "GL518SM Revision 0x00 chip"; - } else if (kind == gl518sm_r80) { - client_name = "GL518SM Revision 0x80 chip"; - } else { -#ifdef DEBUG - printk("gl518sm.o: Internal error: unknown kind (%d)\n", - kind); -#endif - goto ERROR1; - } - - /* Fill in the remaining client fields and put it into the global list */ - strcpy(new_client->name, client_name); - data->type = kind; - - for (i = 0; i < MAX_GL518_NR; i++) - if (!gl518_list[i]) - break; - if (i == MAX_GL518_NR) { - printk - ("gl518sm.o: No empty slots left, recompile and heighten " - "MAX_GL518_NR!\n"); - err = -ENOMEM; - goto ERROR2; - } - gl518_list[i] = new_client; - data->valid = 0; - init_MUTEX(&data->update_lock); - - /* Tell the I2C layer a new client has arrived */ - if ((err = i2c_attach_client(new_client))) - goto ERROR3; - - /* Register a new directory entry with module sensors */ - if ((i = i2c_register_entry((struct i2c_client *) new_client, - type_name, - gl518_dir_table_template, - THIS_MODULE)) < 0) { - err = i; - goto ERROR4; - } - data->sysctl_id = i; - - /* Initialize the GL518SM chip */ - if (kind == gl518sm_r00) - data->iterate = 0; - else - data->iterate = 3; - data->iterate_lock = 0; - data->quit_thread = 0; - data->thread = NULL; - data->alarm_mask = 0xff; - data->voltage[0]=data->voltage[1]=data->voltage[2]=0; - gl518_init_client((struct i2c_client *) new_client); - return 0; - -/* OK, this is not exactly good programming practice, usually. But it is - very code-efficient in this case. */ - - ERROR4: - i2c_detach_client(new_client); - ERROR3: - for (i = 0; i < MAX_GL518_NR; i++) - if (new_client == gl518_list[i]) - gl518_list[i] = NULL; - ERROR2: - ERROR1: - kfree(data); - ERROR0: - return err; -} - - -/* Called when we have found a new GL518SM. */ -static void gl518_init_client(struct i2c_client *client) -{ - /* Power-on defaults (bit 7=1) */ - gl518_write_value(client, GL518_REG_CONF, 0x80); - - /* No noisy output (bit 2=1), Comparator mode (bit 3=0), two fans (bit4=0), - standby mode (bit6=0) */ - gl518_write_value(client, GL518_REG_CONF, 0x04); - - /* Never interrupts */ - gl518_write_value(client, GL518_REG_MASK, 0x00); - - /* Clear status register (bit 5=1), start (bit6=1) */ - gl518_write_value(client, GL518_REG_CONF, 0x24); - gl518_write_value(client, GL518_REG_CONF, 0x44); -} - -static int gl518_detach_client(struct i2c_client *client) -{ - int err, i; - struct gl518_data *data = client->data; - - i2c_deregister_entry(((struct gl518_data *) (client->data))-> - sysctl_id); - - if ((err = i2c_detach_client(client))) { - printk - ("gl518sm.o: Client deregistration failed, client not detached.\n"); - return err; - } - - for (i = 0; i < MAX_GL518_NR; i++) - if (client == gl518_list[i]) - break; - if ((i == MAX_GL518_NR)) { - printk("gl518sm.o: Client to detach not found.\n"); - return -ENOENT; - } - gl518_list[i] = NULL; - - if (data->thread) { - data->quit_thread = 1; - wake_up_interruptible(&data->wq); - } - - kfree(client->data); - - return 0; -} - - -/* Registers 0x07 to 0x0c are word-sized, others are byte-sized - GL518 uses a high-byte first convention, which is exactly opposite to - the usual practice. */ -static int gl518_read_value(struct i2c_client *client, u8 reg) -{ - if ((reg >= 0x07) && (reg <= 0x0c)) - return swab16(i2c_smbus_read_word_data(client, reg)); - else - return i2c_smbus_read_byte_data(client, reg); -} - -/* Registers 0x07 to 0x0c are word-sized, others are byte-sized - GL518 uses a high-byte first convention, which is exactly opposite to - the usual practice. */ -static int gl518_write_value(struct i2c_client *client, u8 reg, u16 value) -{ - if ((reg >= 0x07) && (reg <= 0x0c)) - return i2c_smbus_write_word_data(client, reg, swab16(value)); - else - return i2c_smbus_write_byte_data(client, reg, value); -} - -static void gl518_update_client(struct i2c_client *client) -{ - struct gl518_data *data = client->data; - int val; - - down(&data->update_lock); - - if ((jiffies - data->last_updated > HZ + HZ / 2) || - (jiffies < data->last_updated) || !data->valid) { - -#ifdef DEBUG - printk("Starting gl518 update\n"); -#endif - - data->alarms = gl518_read_value(client, GL518_REG_INT); - data->beeps = gl518_read_value(client, GL518_REG_ALARM); - - val = gl518_read_value(client, GL518_REG_VDD_LIMIT); - data->voltage_min[0] = val & 0xff; - data->voltage_max[0] = (val >> 8) & 0xff; - val = gl518_read_value(client, GL518_REG_VIN1_LIMIT); - data->voltage_min[1] = val & 0xff; - data->voltage_max[1] = (val >> 8) & 0xff; - val = gl518_read_value(client, GL518_REG_VIN2_LIMIT); - data->voltage_min[2] = val & 0xff; - data->voltage_max[2] = (val >> 8) & 0xff; - val = gl518_read_value(client, GL518_REG_VIN3_LIMIT); - data->voltage_min[3] = val & 0xff; - data->voltage_max[3] = (val >> 8) & 0xff; - - val = gl518_read_value(client, GL518_REG_FAN_COUNT); - data->fan[0] = (val >> 8) & 0xff; - data->fan[1] = val & 0xff; - - val = gl518_read_value(client, GL518_REG_FAN_LIMIT); - data->fan_min[0] = (val >> 8) & 0xff; - data->fan_min[1] = val & 0xff; - - data->temp = gl518_read_value(client, GL518_REG_TEMP); - data->temp_over = - gl518_read_value(client, GL518_REG_TEMP_OVER); - data->temp_hyst = - gl518_read_value(client, GL518_REG_TEMP_HYST); - - val = gl518_read_value(client, GL518_REG_MISC); - data->fan_div[0] = (val >> 6) & 0x03; - data->fan_div[1] = (val >> 4) & 0x03; - - data->alarms &= data->alarm_mask; - - val = gl518_read_value(client, GL518_REG_CONF); - data->beep_enable = (val >> 2) & 1; - -#ifndef DEBUG_VIN - if (data->type != gl518sm_r00) { - data->voltage[0] = - gl518_read_value(client, GL518_REG_VDD); - data->voltage[1] = - gl518_read_value(client, GL518_REG_VIN1); - data->voltage[2] = - gl518_read_value(client, GL518_REG_VIN2); - data->voltage[3] = - gl518_read_value(client, GL518_REG_VIN3); - } else - gl518_update_client_rev00(client); -#else - gl518_update_client_rev00(client); -#endif - - data->last_updated = jiffies; - data->valid = 1; - } - - up(&data->update_lock); -} - -/* Here we decide how to run the iteration code. - When called, we trigger the iteration and report the last - measured voltage. No delay for user apps */ -static void gl518_update_client_rev00(struct i2c_client *client) -{ - struct gl518_data *data = client->data; - int i; - - if (data->iterate == 1) { /* 10 sec delay */ - /* as that update is slow, we consider the data valid for 30 seconds */ - if ( - ((jiffies - data->last_updated_v00 > 30 * HZ) - || (data->alarms & 7) - || (!data->valid)) && (!data->iterate_lock)) { - data->iterate_lock = 1; - gl518_update_iterate(client); - data->iterate_lock = 0; - } - for (i = 0; i < 4; i++) - data->voltage[i] = data->iter_voltage[i]; - } else if (data->iterate == 2) { /* show results of last iteration */ - for (i = 0; i < 4; i++) - data->voltage[i] = data->iter_voltage[i]; - wake_up_interruptible(&data->wq); - } else { /* no iteration */ - data->voltage[3] = - gl518_read_value(client, GL518_REG_VIN3); - } -} - -static int gl518_update_thread(void *c) -{ - struct i2c_client *client = c; - struct gl518_data *data = client->data; - -#ifdef __SMP__ - lock_kernel(); -#endif - exit_mm(current); - current->session = 1; - current->pgrp = 1; - sigfillset(¤t->blocked); - current->fs->umask = 0; - strcpy(current->comm, "gl518sm"); - - init_waitqueue_head(&(data->wq)); - data->thread = current; - -#ifdef __SMP__ - unlock_kernel(); -#endif - - for (;;) { - if (!data->iterate_lock) { - data->iterate_lock = 1; - gl518_update_iterate(client); - data->iterate_lock = 0; - } - - if ((data->quit_thread) || signal_pending(current)) - break; - interruptible_sleep_on(&data->wq); - } - - data->thread = NULL; - data->quit_thread = 0; - return 0; -} - -/* This updates vdd, vin1, vin2 values by doing slow and multiple - comparisons for the GL518SM rev 00 that lacks support for direct - reading of these values. Values are kept in iter_voltage */ - -static void gl518_update_iterate(struct i2c_client *client) -{ - struct gl518_data *data = client->data; - int i, j, loop_more = 1, min[3], max[3], delta[3]; - int alarm, beeps, irqs; - -#define VIN_REG(c) c==0?GL518_REG_VDD_LIMIT:\ - c==1?GL518_REG_VIN1_LIMIT:\ - GL518_REG_VIN2_LIMIT - - /* disable beeps & irqs for vin0-2 */ - beeps = gl518_read_value(client, GL518_REG_ALARM); - irqs = gl518_read_value(client, GL518_REG_MASK); - gl518_write_value(client, GL518_REG_ALARM, beeps & ~0x7); - gl518_write_value(client, GL518_REG_MASK, irqs & ~0x7); - - alarm = data->alarms; - - for (i = 0; i < 3; i++) { - if (alarm & (1 << i)) { - min[i] = 0; - max[i] = 127; - } else { - min[i] = data->voltage_min[i]; - max[i] = - (data->voltage_max[i] + - data->voltage_min[i]) / 2; - } - delta[i] = (max[i] - min[i]) / 2; - } - - for (j = 0; (j < 10 && loop_more); j++) { - - for (i = 0; i < 3; i++) - gl518_write_value(client, VIN_REG(i), - max[i] << 8 | min[i]); - - if ((data->thread) && - ((data->quit_thread) || signal_pending(current))) - goto finish; - - /* we wait now 1.5 seconds before comparing */ - current->state = TASK_INTERRUPTIBLE; - schedule_timeout(HZ + HZ / 2); - - alarm = gl518_read_value(client, GL518_REG_INT); - -#ifdef DEBUG_VIN - printk("gl518sm: iteration %2d: %4d%c %4d%c %4d%c\n", j, - max[0], (alarm & 1) ? '!' : ' ', - max[1], (alarm & 2) ? '!' : ' ', - max[2], (alarm & 4) ? '!' : ' '); -#endif - - for (loop_more = 0, i = 0; i < 3; i++) { - if (alarm & (1 << i)) - max[i] += delta[i]; - else - max[i] -= delta[i]; - - if (delta[i]) - loop_more++; - delta[i] >>= 1; - } - - } - - for (i = 0; i < 3; i++) - if (alarm & (1 << i)) - max[i]++; - -#ifdef DEBUG_VIN - printk("gl518sm: final :%5d %5d %5d\n", max[0], max[1], - max[2]); - printk("gl518sm: meter :%5d %5d %5d\n", data->voltage[0], - data->voltage[1], data->voltage[2]); -#endif - - /* update values, including vin3 */ - for (i = 0; i < 3; i++) { - data->iter_voltage[i] = max[i]; - } - data->iter_voltage[3] = gl518_read_value(client, GL518_REG_VIN3); - data->last_updated_v00 = jiffies; - - finish: - - /* reset values */ - for (i = 0; i < 3; i++) { - gl518_write_value(client, VIN_REG(i), - data->voltage_max[i] << 8 | data-> - voltage_min[i]); - } - - gl518_write_value(client, GL518_REG_ALARM, beeps); - gl518_write_value(client, GL518_REG_MASK, irqs); - -#undef VIN_REG -} - -void gl518_temp(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct gl518_data *data = client->data; - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 1; - else if (operation == SENSORS_PROC_REAL_READ) { - gl518_update_client(client); - results[0] = TEMP_FROM_REG(data->temp_over); - results[1] = TEMP_FROM_REG(data->temp_hyst); - results[2] = TEMP_FROM_REG(data->temp); - *nrels_mag = 3; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag >= 1) { - data->temp_over = TEMP_TO_REG(results[0]); - gl518_write_value(client, GL518_REG_TEMP_OVER, - data->temp_over); - } - if (*nrels_mag >= 2) { - data->temp_hyst = TEMP_TO_REG(results[1]); - gl518_write_value(client, GL518_REG_TEMP_HYST, - data->temp_hyst); - } - } -} - -void gl518_vin(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct gl518_data *data = client->data; - int nr = ctl_name - GL518_SYSCTL_VDD; - int regnr, old = 0; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 2; - else if (operation == SENSORS_PROC_REAL_READ) { - gl518_update_client(client); - results[0] = nr ? IN_FROM_REG(data->voltage_min[nr]) : - VDD_FROM_REG(data->voltage_min[nr]); - results[1] = nr ? IN_FROM_REG(data->voltage_max[nr]) : - VDD_FROM_REG(data->voltage_max[nr]); - results[2] = nr ? IN_FROM_REG(data->voltage[nr]) : - VDD_FROM_REG(data->voltage[nr]); - *nrels_mag = 3; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - regnr = - nr == 0 ? GL518_REG_VDD_LIMIT : nr == - 1 ? GL518_REG_VIN1_LIMIT : nr == - 2 ? GL518_REG_VIN2_LIMIT : GL518_REG_VIN3_LIMIT; - if (*nrels_mag == 1) - old = gl518_read_value(client, regnr) & 0xff00; - if (*nrels_mag >= 2) { - data->voltage_max[nr] = - nr ? IN_TO_REG(results[1]) : - VDD_TO_REG(results[1]); - old = data->voltage_max[nr] << 8; - } - if (*nrels_mag >= 1) { - data->voltage_min[nr] = - nr ? IN_TO_REG(results[0]) : - VDD_TO_REG(results[0]); - old |= data->voltage_min[nr]; - gl518_write_value(client, regnr, old); - } - } -} - - -void gl518_fan(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct gl518_data *data = client->data; - int nr = ctl_name - GL518_SYSCTL_FAN1; - int old; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - gl518_update_client(client); - results[0] = FAN_FROM_REG(data->fan_min[nr], - DIV_FROM_REG(data->fan_div[nr])); - results[1] = - FAN_FROM_REG(data->fan[nr], - DIV_FROM_REG(data->fan_div[nr])); - *nrels_mag = 2; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag >= 1) { - data->fan_min[nr] = FAN_TO_REG(results[0], - DIV_FROM_REG(data-> - fan_div - [nr])); - old = - gl518_read_value(client, GL518_REG_FAN_LIMIT); - - if (nr == 0) { - old = - (old & 0x00ff) | (data-> - fan_min[0] << 8); - if (results[0] == 0) - data->alarm_mask &= ~0x20; - else - data->alarm_mask |= 0x20; - } else { - old = (old & 0xff00) | data->fan_min[1]; - if (results[0] == 0) - data->alarm_mask &= ~0x40; - else - data->alarm_mask |= 0x40; - } - gl518_write_value(client, GL518_REG_FAN_LIMIT, - old); - } - } -} - - -void gl518_alarms(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct gl518_data *data = client->data; - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - gl518_update_client(client); - results[0] = ALARMS_FROM_REG(data->alarms); - *nrels_mag = 1; - } -} - -void gl518_beep(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct gl518_data *data = client->data; - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - gl518_update_client(client); - results[0] = BEEP_ENABLE_FROM_REG(data->beep_enable); - results[1] = BEEPS_FROM_REG(data->beeps); - *nrels_mag = 2; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag >= 1) { - data->beep_enable = BEEP_ENABLE_TO_REG(results[0]); - gl518_write_value(client, GL518_REG_CONF, - (gl518_read_value(client, - GL518_REG_CONF) - & 0xfb) | (data-> - beep_enable << 2)); - } - if (*nrels_mag >= 2) { - data->beeps = - BEEPS_TO_REG(results[1]) & data->alarm_mask; - gl518_write_value(client, GL518_REG_ALARM, - data->beeps); - } - } -} - - -void gl518_fan_div(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct gl518_data *data = client->data; - int old; - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - gl518_update_client(client); - results[0] = DIV_FROM_REG(data->fan_div[0]); - results[1] = DIV_FROM_REG(data->fan_div[1]); - *nrels_mag = 2; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - old = gl518_read_value(client, GL518_REG_MISC); - if (*nrels_mag >= 2) { - data->fan_div[1] = DIV_TO_REG(results[1]); - old = (old & 0xcf) | (data->fan_div[1] << 4); - } - if (*nrels_mag >= 1) { - data->fan_div[0] = DIV_TO_REG(results[0]); - old = (old & 0x3f) | (data->fan_div[0] << 6); - } - gl518_write_value(client, GL518_REG_MISC, old); - } -} - -void gl518_fan1off(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - int old; - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - results[0] = - ((gl518_read_value(client, GL518_REG_MISC) & 0x08) != - 0); - results[1] = - ((gl518_read_value(client, GL518_REG_CONF) & 0x10) != - 0); - *nrels_mag = 2; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag >= 1) { - old = - gl518_read_value(client, - GL518_REG_MISC) & 0xf7; - if (results[0]) - old |= 0x08; - gl518_write_value(client, GL518_REG_MISC, old); - } - if (*nrels_mag >= 2) { - old = - gl518_read_value(client, - GL518_REG_CONF) & 0xef; - if (results[1]) - old |= 0x10; - gl518_write_value(client, GL518_REG_CONF, old); - } - } -} - -void gl518_iterate(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct gl518_data *data = client->data; - int i; - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - results[0] = data->iterate; - *nrels_mag = 1; - } else if (operation == SENSORS_PROC_REAL_WRITE && - data->type == gl518sm_r00 ) { - if ((*nrels_mag >= 1) && (data->iterate != results[0])) { - data->iterate = results[0]; - for (i = 0; i < 4; i++) { - data->voltage[i] = 0; - data->iter_voltage[i] = 0; - } - data->valid = 0; - - if ((data->iterate != 2) && (data->thread)) { - data->quit_thread = 1; - wake_up_interruptible(&data->wq); - } else if ((data->iterate == 2) && (!data->thread)) { - init_waitqueue_head(&(data->wq)); - kernel_thread(gl518_update_thread, - (void *) client, 0); - } - } - } -} - -static int __init sm_gl518sm_init(void) -{ - printk("gl518sm.o version %s (%s)\n", LM_VERSION, LM_DATE); - return i2c_add_driver(&gl518_driver); -} - -static void __exit sm_gl518sm_exit(void) -{ - i2c_del_driver(&gl518_driver); -} - - - -MODULE_AUTHOR - ("Frodo Looijaard and Kyösti Mälkki "); -MODULE_DESCRIPTION("GL518SM driver"); - -module_init(sm_gl518sm_init); -module_exit(sm_gl518sm_exit); diff --git a/kernel/chips/gl520sm.c b/kernel/chips/gl520sm.c deleted file mode 100644 index 565ef66c..00000000 --- a/kernel/chips/gl520sm.c +++ /dev/null @@ -1,804 +0,0 @@ -/* - gl520sm.c - Part of lm_sensors, Linux kernel modules for hardware - monitoring - Copyright (c) 1998, 1999 Frodo Looijaard , - Kyösti Mälkki - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - -*/ - -#include -#include -#include -#include -#include -#include "version.h" - -MODULE_LICENSE("GPL"); - -/* Addresses to scan */ -static unsigned short normal_i2c[] = { 0x2c, 0x2d, SENSORS_I2C_END }; -static unsigned short normal_i2c_range[] = { SENSORS_I2C_END }; -static unsigned int normal_isa[] = { SENSORS_ISA_END }; -static unsigned int normal_isa_range[] = { SENSORS_ISA_END }; - -/* Insmod parameters */ -SENSORS_INSMOD_1(gl520sm); - -/* Many GL520 constants specified below -One of the inputs can be configured as either temp or voltage. -That's why _TEMP2 and _VIN4 access the same register -*/ - -/* The GL520 registers */ -#define GL520_REG_CHIP_ID 0x00 -#define GL520_REG_REVISION 0x01 -#define GL520_REG_VID 0x02 -#define GL520_REG_CONF 0x03 -#define GL520_REG_TEMP1 0x04 -#define GL520_REG_TEMP1_OVER 0x05 -#define GL520_REG_TEMP1_HYST 0x06 -#define GL520_REG_FAN_COUNT 0x07 -#define GL520_REG_FAN_LIMIT 0x08 -#define GL520_REG_VIN1_LIMIT 0x09 -#define GL520_REG_VIN2_LIMIT 0x0a -#define GL520_REG_VIN3_LIMIT 0x0b -#define GL520_REG_VDD_LIMIT 0x0c -#define GL520_REG_VIN3 0x0d -#define GL520_REG_VIN4 0x0e -#define GL520_REG_TEMP2 0x0e -#define GL520_REG_MISC 0x0f -#define GL520_REG_ALARM 0x10 -#define GL520_REG_MASK 0x11 -#define GL520_REG_INT 0x12 -#define GL520_REG_VIN2 0x13 -#define GL520_REG_VIN1 0x14 -#define GL520_REG_VDD 0x15 -#define GL520_REG_TEMP2_OVER 0x17 -#define GL520_REG_VIN4_MAX 0x17 -#define GL520_REG_TEMP2_HYST 0x18 -#define GL520_REG_VIN4_MIN 0x18 - - -/* Conversions. Rounding and limit checking is only done on the TO_REG - variants. Note that you should be a bit careful with which arguments - these macros are called: arguments may be evaluated more than once. - Fixing this is just not worth it. */ - -#define TEMP_TO_REG(val) (SENSORS_LIMIT(((((val)<0?(val)-5:(val)+5) / 10)+130),\ - 0,255)) -#define TEMP_FROM_REG(val) (((val) - 130) * 10) - -static inline u8 FAN_TO_REG(long rpm, int div) -{ - if (rpm == 0) - return 255; - rpm = SENSORS_LIMIT(rpm, 1, 1000000); - return SENSORS_LIMIT((480000 + rpm * div / 2) / (rpm * div), 1, - 254); -} - -#define FAN_FROM_REG(val,div) \ - ( (val)==0 ? 0 : (val)==255 ? 0 : (480000/((val)*(div))) ) - -#define IN_TO_REG(val) (SENSORS_LIMIT((((val)*10+8)/19),0,255)) -#define IN_FROM_REG(val) (((val)*19)/10) - -#define VDD_TO_REG(val) (SENSORS_LIMIT((((val)*10+11)/23),0,255)) -#define VDD_FROM_REG(val) (((val)*23)/10) - -#define DIV_TO_REG(val) ((val)==8?3:(val)==4?2:(val)==1?0:1) -#define DIV_FROM_REG(val) (1 << (val)) - -#define ALARMS_FROM_REG(val) val - -#define BEEP_ENABLE_TO_REG(val) ((val)?0:1) -#define BEEP_ENABLE_FROM_REG(val) ((val)?0:1) - -#define BEEPS_TO_REG(val) (val) -#define BEEPS_FROM_REG(val) (val) - -#define VID_FROM_REG(val) ((val)==0x1f?0:(val)>=0x10?510-(val)*10:\ - 205-(val)*5) - -/* Each client has this additional data */ -struct gl520_data { - struct i2c_client client; - int sysctl_id; - enum chips type; - - struct semaphore update_lock; - char valid; /* !=0 if following fields are valid */ - unsigned long last_updated; /* In jiffies */ - - u8 voltage[5]; /* Register values; [0] = VDD */ - u8 voltage_min[5]; /* Register values; [0] = VDD */ - u8 voltage_max[5]; /* Register values; [0] = VDD */ - u8 fan[2]; - u8 fan_min[2]; - u8 temp[2]; /* Register values */ - u8 temp_over[2]; /* Register values */ - u8 temp_hyst[2]; /* Register values */ - u8 alarms, beeps, vid; /* Register value */ - u8 alarm_mask; /* Register value */ - u8 fan_div[2]; /* Register encoding, shifted right */ - u8 beep_enable; /* Boolean */ - u8 two_temps; /* Boolean */ -}; - -static int gl520_attach_adapter(struct i2c_adapter *adapter); -static int gl520_detect(struct i2c_adapter *adapter, int address, - unsigned short flags, int kind); -static void gl520_init_client(struct i2c_client *client); -static int gl520_detach_client(struct i2c_client *client); - -static int gl520_read_value(struct i2c_client *client, u8 reg); -static int gl520_write_value(struct i2c_client *client, u8 reg, u16 value); -static void gl520_update_client(struct i2c_client *client); - -static void gl520_vin(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void gl520_vid(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void gl520_fan(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void gl520_temp(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void gl520_fan_div(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void gl520_alarms(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void gl520_beep(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void gl520_fan1off(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void gl520_config(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); - -/* This is the driver that will be inserted */ -static struct i2c_driver gl520_driver = { - .name = "GL520SM sensor chip driver", - .id = I2C_DRIVERID_GL520, - .flags = I2C_DF_NOTIFY, - .attach_adapter = gl520_attach_adapter, - .detach_client = gl520_detach_client, -}; -/* -- SENSORS SYSCTL START -- */ - -#define GL520_SYSCTL_VDD 1000 /* Volts * 100 */ -#define GL520_SYSCTL_VIN1 1001 -#define GL520_SYSCTL_VIN2 1002 -#define GL520_SYSCTL_VIN3 1003 -#define GL520_SYSCTL_VIN4 1004 -#define GL520_SYSCTL_FAN1 1101 /* RPM */ -#define GL520_SYSCTL_FAN2 1102 -#define GL520_SYSCTL_TEMP1 1200 /* Degrees Celsius * 10 */ -#define GL520_SYSCTL_TEMP2 1201 /* Degrees Celsius * 10 */ -#define GL520_SYSCTL_VID 1300 -#define GL520_SYSCTL_FAN_DIV 2000 /* 1, 2, 4 or 8 */ -#define GL520_SYSCTL_ALARMS 2001 /* bitvector */ -#define GL520_SYSCTL_BEEP 2002 /* bitvector */ -#define GL520_SYSCTL_FAN1OFF 2003 -#define GL520_SYSCTL_CONFIG 2004 - -#define GL520_ALARM_VDD 0x01 -#define GL520_ALARM_VIN1 0x02 -#define GL520_ALARM_VIN2 0x04 -#define GL520_ALARM_VIN3 0x08 -#define GL520_ALARM_TEMP1 0x10 -#define GL520_ALARM_FAN1 0x20 -#define GL520_ALARM_FAN2 0x40 -#define GL520_ALARM_TEMP2 0x80 -#define GL520_ALARM_VIN4 0x80 - -/* -- SENSORS SYSCTL END -- */ - -/* These files are created for each detected GL520. This is just a template; - though at first sight, you might think we could use a statically - allocated list, we need some way to get back to the parent - which - is done through one of the 'extra' fields which are initialized - when a new copy is allocated. */ -static ctl_table gl520_dir_table_template[] = { - {GL520_SYSCTL_VIN1, "vin1", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &gl520_vin}, - {GL520_SYSCTL_VIN2, "vin2", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &gl520_vin}, - {GL520_SYSCTL_VIN3, "vin3", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &gl520_vin}, - {GL520_SYSCTL_VIN4, "vin4", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &gl520_vin}, - {GL520_SYSCTL_VDD, "vdd", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &gl520_vin}, - {GL520_SYSCTL_VID, "vid", NULL, 0, 0444, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &gl520_vid}, - {GL520_SYSCTL_FAN1, "fan1", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &gl520_fan}, - {GL520_SYSCTL_FAN2, "fan2", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &gl520_fan}, - {GL520_SYSCTL_TEMP1, "temp1", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &gl520_temp}, - {GL520_SYSCTL_TEMP2, "temp2", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &gl520_temp}, - {GL520_SYSCTL_FAN_DIV, "fan_div", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &gl520_fan_div}, - {GL520_SYSCTL_ALARMS, "alarms", NULL, 0, 0444, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &gl520_alarms}, - {GL520_SYSCTL_BEEP, "beep", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &gl520_beep}, - {GL520_SYSCTL_FAN1OFF, "fan1off", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &gl520_fan1off}, - {GL520_SYSCTL_CONFIG, "config", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &gl520_config}, - {0} -}; - -static int gl520_attach_adapter(struct i2c_adapter *adapter) -{ - return i2c_detect(adapter, &addr_data, gl520_detect); -} - -static int gl520_detect(struct i2c_adapter *adapter, int address, - unsigned short flags, int kind) -{ - int i; - struct i2c_client *new_client; - struct gl520_data *data; - int err = 0; - const char *type_name = ""; - char client_name[32]; - - /* Make sure we aren't probing the ISA bus!! This is just a safety check - at this moment; i2c_detect really won't call us. */ -#ifdef DEBUG - if (i2c_is_isa_adapter(adapter)) { - printk - ("gl520sm.o: gl520_detect called for an ISA bus adapter?!?\n"); - return 0; - } -#endif - - if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA | - I2C_FUNC_SMBUS_WORD_DATA)) - goto ERROR0; - - /* OK. For now, we presume we have a valid client. We now create the - client structure, even though we cannot fill it completely yet. - But it allows us to access gl520_{read,write}_value. */ - - if (!(data = kmalloc(sizeof(struct gl520_data), GFP_KERNEL))) { - err = -ENOMEM; - goto ERROR0; - } - - new_client = &data->client; - new_client->addr = address; - new_client->data = data; - new_client->adapter = adapter; - new_client->driver = &gl520_driver; - new_client->flags = 0; - - /* Determine the chip type. */ - - if (gl520_read_value(new_client, GL520_REG_CHIP_ID) != 0x20) { - printk - ("gl520sm.o: Ignoring 'force' parameter for unknown chip at " - "adapter %d, address 0x%02x\n", - i2c_adapter_id(adapter), address); - goto ERROR1; - } else { - kind = gl520sm; - } - - i = gl520_read_value(new_client, GL520_REG_REVISION); - if (kind == gl520sm) { - type_name = "gl520sm"; - sprintf(client_name, "GL520SM Revision %02x chip", i); - } else { -#ifdef DEBUG - printk("gl520sm.o: Internal error: unknown kind (%d)\n", - kind); -#endif - goto ERROR1; - } - - /* Fill in the remaining client fields and put it into the global list */ - strcpy(new_client->name, client_name); - data->type = kind; - data->valid = 0; - init_MUTEX(&data->update_lock); - - /* Tell the I2C layer a new client has arrived */ - if ((err = i2c_attach_client(new_client))) - goto ERROR3; - - /* Register a new directory entry with module sensors */ - if ((i = i2c_register_entry(new_client, - type_name, - gl520_dir_table_template, - THIS_MODULE)) < 0) { - err = i; - goto ERROR4; - } - data->sysctl_id = i; - - /* Initialize the GL520SM chip */ - data->alarm_mask = 0xff; - gl520_init_client(new_client); - if (data->two_temps) - data->voltage_max[4] = data->voltage_min[4] = - data->voltage[4] = 0; - else - data->temp_hyst[1] = data->temp_over[1] = - data->temp[1] = 0; - - return 0; - -/* OK, this is not exactly good programming practice, usually. But it is - very code-efficient in this case. */ - - ERROR4: - i2c_detach_client(new_client); - ERROR3: - ERROR1: - kfree(data); - ERROR0: - return err; -} - - -/* Called when we have found a new GL520SM. */ -static void gl520_init_client(struct i2c_client *client) -{ - struct gl520_data *data = (struct gl520_data *)(client->data); - u8 oldconf, conf; - - conf = oldconf = gl520_read_value(client, GL520_REG_CONF); - data->two_temps = !(conf & 0x10); - - /* If IRQ# is disabled, we can safely force comparator mode */ - if (!(conf & 0x20)) - conf &= 0xf7; - - /* Enable monitoring if needed */ - conf |= 0x40; - - if (conf != oldconf) - gl520_write_value(client, GL520_REG_CONF, conf); -} - -static int gl520_detach_client(struct i2c_client *client) -{ - int err; - - i2c_deregister_entry(((struct gl520_data *) (client->data))-> - sysctl_id); - - if ((err = i2c_detach_client(client))) { - printk - ("gl520sm.o: Client deregistration failed, client not detached.\n"); - return err; - } - - kfree(client->data); - - return 0; -} - - -/* Registers 0x07 to 0x0c are word-sized, others are byte-sized - GL520 uses a high-byte first convention, which is exactly opposite to - the usual practice. */ -static int gl520_read_value(struct i2c_client *client, u8 reg) -{ - if ((reg >= 0x07) && (reg <= 0x0c)) - return swab16(i2c_smbus_read_word_data(client, reg)); - else - return i2c_smbus_read_byte_data(client, reg); -} - -/* Registers 0x07 to 0x0c are word-sized, others are byte-sized - GL520 uses a high-byte first convention, which is exactly opposite to - the usual practice. */ -static int gl520_write_value(struct i2c_client *client, u8 reg, u16 value) -{ - if ((reg >= 0x07) && (reg <= 0x0c)) - return i2c_smbus_write_word_data(client, reg, swab16(value)); - else - return i2c_smbus_write_byte_data(client, reg, value); -} - -static void gl520_update_client(struct i2c_client *client) -{ - struct gl520_data *data = client->data; - int val; - - down(&data->update_lock); - - if ((jiffies - data->last_updated > HZ + HZ / 2) || - (jiffies < data->last_updated) || !data->valid) { - -#ifdef DEBUG - printk("Starting gl520 update\n"); -#endif - - data->alarms = gl520_read_value(client, GL520_REG_INT); - data->beeps = gl520_read_value(client, GL520_REG_ALARM); - data->vid = gl520_read_value(client, GL520_REG_VID) & 0x1f; - - val = gl520_read_value(client, GL520_REG_VDD_LIMIT); - data->voltage_min[0] = val & 0xff; - data->voltage_max[0] = (val >> 8) & 0xff; - val = gl520_read_value(client, GL520_REG_VIN1_LIMIT); - data->voltage_min[1] = val & 0xff; - data->voltage_max[1] = (val >> 8) & 0xff; - val = gl520_read_value(client, GL520_REG_VIN2_LIMIT); - data->voltage_min[2] = val & 0xff; - data->voltage_max[2] = (val >> 8) & 0xff; - val = gl520_read_value(client, GL520_REG_VIN3_LIMIT); - data->voltage_min[3] = val & 0xff; - data->voltage_max[3] = (val >> 8) & 0xff; - - val = gl520_read_value(client, GL520_REG_FAN_COUNT); - data->fan[0] = (val >> 8) & 0xff; - data->fan[1] = val & 0xff; - - val = gl520_read_value(client, GL520_REG_FAN_LIMIT); - data->fan_min[0] = (val >> 8) & 0xff; - data->fan_min[1] = val & 0xff; - - data->temp[0] = gl520_read_value(client, GL520_REG_TEMP1); - data->temp_over[0] = - gl520_read_value(client, GL520_REG_TEMP1_OVER); - data->temp_hyst[0] = - gl520_read_value(client, GL520_REG_TEMP1_HYST); - - val = gl520_read_value(client, GL520_REG_MISC); - data->fan_div[0] = (val >> 6) & 0x03; - data->fan_div[1] = (val >> 4) & 0x03; - - data->alarms &= data->alarm_mask; - - val = gl520_read_value(client, GL520_REG_CONF); - data->beep_enable = (val >> 2) & 1; - - data->voltage[0] = gl520_read_value(client, GL520_REG_VDD); - data->voltage[1] = - gl520_read_value(client, GL520_REG_VIN1); - data->voltage[2] = - gl520_read_value(client, GL520_REG_VIN2); - data->voltage[3] = - gl520_read_value(client, GL520_REG_VIN3); - - /* Temp1 and Vin4 are the same input */ - if (data->two_temps) { - data->temp[1] = - gl520_read_value(client, GL520_REG_TEMP2); - data->temp_over[1] = - gl520_read_value(client, GL520_REG_TEMP2_OVER); - data->temp_hyst[1] = - gl520_read_value(client, GL520_REG_TEMP2_HYST); - } else { - data->voltage[4] = - gl520_read_value(client, GL520_REG_VIN4); - data->voltage_min[4] = - gl520_read_value(client, GL520_REG_VIN4_MIN); - data->voltage_max[4] = - gl520_read_value(client, GL520_REG_VIN4_MAX); - } - - data->last_updated = jiffies; - data->valid = 1; - } - - up(&data->update_lock); -} - -void gl520_temp(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct gl520_data *data = client->data; - int nr = ctl_name - GL520_SYSCTL_TEMP1; - int regnr; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 1; - else if (operation == SENSORS_PROC_REAL_READ) { - gl520_update_client(client); - results[0] = TEMP_FROM_REG(data->temp_over[nr]); - results[1] = TEMP_FROM_REG(data->temp_hyst[nr]); - results[2] = TEMP_FROM_REG(data->temp[nr]); - *nrels_mag = 3; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if ((nr == 1) && (!data->two_temps)) - return; - regnr = - nr == 0 ? GL520_REG_TEMP1_OVER : GL520_REG_TEMP2_OVER; - if (*nrels_mag >= 1) { - data->temp_over[nr] = TEMP_TO_REG(results[0]); - gl520_write_value(client, regnr, - data->temp_over[nr]); - } - regnr = - nr == 0 ? GL520_REG_TEMP1_HYST : GL520_REG_TEMP2_HYST; - if (*nrels_mag >= 2) { - data->temp_hyst[nr] = TEMP_TO_REG(results[1]); - gl520_write_value(client, regnr, - data->temp_hyst[nr]); - } - } -} - -void gl520_vin(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct gl520_data *data = client->data; - int nr = ctl_name - GL520_SYSCTL_VDD; - int regnr, old = 0; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 2; - else if (operation == SENSORS_PROC_REAL_READ) { - gl520_update_client(client); - results[0] = nr ? IN_FROM_REG(data->voltage_min[nr]) : - VDD_FROM_REG(data->voltage_min[nr]); - results[1] = nr ? IN_FROM_REG(data->voltage_max[nr]) : - VDD_FROM_REG(data->voltage_max[nr]); - results[2] = nr ? IN_FROM_REG(data->voltage[nr]) : - VDD_FROM_REG(data->voltage[nr]); - *nrels_mag = 3; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if (nr != 4) { - regnr = - nr == 0 ? GL520_REG_VDD_LIMIT : nr == - 1 ? GL520_REG_VIN1_LIMIT : nr == - 2 ? GL520_REG_VIN2_LIMIT : - GL520_REG_VIN3_LIMIT; - if (*nrels_mag == 1) - old = - gl520_read_value(client, - regnr) & 0xff00; - if (*nrels_mag >= 2) { - data->voltage_max[nr] = - nr ? IN_TO_REG(results[1]) : - VDD_TO_REG(results[1]); - old = data->voltage_max[nr] << 8; - } - if (*nrels_mag >= 1) { - data->voltage_min[nr] = - nr ? IN_TO_REG(results[0]) : - VDD_TO_REG(results[0]); - old |= data->voltage_min[nr]; - gl520_write_value(client, regnr, old); - } - } else if (!data->two_temps) { - if (*nrels_mag == 1) - gl520_write_value(client, - GL520_REG_VIN4_MIN, - IN_TO_REG(results[0])); - if (*nrels_mag >= 2) - gl520_write_value(client, - GL520_REG_VIN4_MAX, - IN_TO_REG(results[1])); - } - } -} - - -void gl520_fan(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct gl520_data *data = client->data; - int nr = ctl_name - GL520_SYSCTL_FAN1; - int old; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - gl520_update_client(client); - results[0] = FAN_FROM_REG(data->fan_min[nr], - DIV_FROM_REG(data->fan_div[nr])); - results[1] = - FAN_FROM_REG(data->fan[nr], - DIV_FROM_REG(data->fan_div[nr])); - *nrels_mag = 2; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag >= 1) { - data->fan_min[nr] = FAN_TO_REG(results[0], - DIV_FROM_REG(data-> - fan_div - [nr])); - old = - gl520_read_value(client, GL520_REG_FAN_LIMIT); - - if (nr == 0) { - old = - (old & 0x00ff) | (data-> - fan_min[nr] << 8); - if (results[0] == 0) - data->alarm_mask &= ~0x20; - else - data->alarm_mask |= 0x20; - } else { - old = (old & 0xff00) | data->fan_min[nr]; - if (results[0] == 0) - data->alarm_mask &= ~0x40; - else - data->alarm_mask |= 0x40; - } - gl520_write_value(client, GL520_REG_FAN_LIMIT, - old); - } - } -} - - -void gl520_alarms(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct gl520_data *data = client->data; - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - gl520_update_client(client); - results[0] = ALARMS_FROM_REG(data->alarms); - *nrels_mag = 1; - } -} - -void gl520_beep(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct gl520_data *data = client->data; - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - gl520_update_client(client); - results[0] = BEEP_ENABLE_FROM_REG(data->beep_enable); - results[1] = BEEPS_FROM_REG(data->beeps); - *nrels_mag = 2; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag >= 1) { - data->beep_enable = BEEP_ENABLE_TO_REG(results[0]); - gl520_write_value(client, GL520_REG_CONF, - (gl520_read_value(client, - GL520_REG_CONF) - & 0xfb) | (data-> - beep_enable << 2)); - } - if (*nrels_mag >= 2) { - data->beeps = - BEEPS_TO_REG(results[1]) & data->alarm_mask; - gl520_write_value(client, GL520_REG_ALARM, - data->beeps); - } - } -} - - -void gl520_fan_div(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct gl520_data *data = client->data; - int old; - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - gl520_update_client(client); - results[0] = DIV_FROM_REG(data->fan_div[0]); - results[1] = DIV_FROM_REG(data->fan_div[1]); - *nrels_mag = 2; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - old = gl520_read_value(client, GL520_REG_MISC); - if (*nrels_mag >= 2) { - data->fan_div[1] = DIV_TO_REG(results[1]); - old = (old & 0xcf) | (data->fan_div[1] << 4); - } - if (*nrels_mag >= 1) { - data->fan_div[0] = DIV_TO_REG(results[0]); - old = (old & 0x3f) | (data->fan_div[0] << 6); - } - gl520_write_value(client, GL520_REG_MISC, old); - } -} - -void gl520_vid(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct gl520_data *data = client->data; - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 2; - else if (operation == SENSORS_PROC_REAL_READ) { - gl520_update_client(client); - results[0] = VID_FROM_REG(data->vid); - *nrels_mag = 1; - } -} - -void gl520_fan1off(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - int old; - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - results[0] = - ((gl520_read_value(client, GL520_REG_MISC) & 0x04) != - 0); - *nrels_mag = 1; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag >= 1) { - old = - gl520_read_value(client, - GL520_REG_MISC) & 0xfb; - if (results[0]) - old |= 0x04; - gl520_write_value(client, GL520_REG_MISC, old); - } - } -} - -void gl520_config(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct gl520_data *data = client->data; - int old; - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - results[0] = - ((gl520_read_value(client, GL520_REG_CONF) & 0x10) == - 0); - data->two_temps = results[0]; - *nrels_mag = 1; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag >= 1) { - old = - gl520_read_value(client, - GL520_REG_CONF) & 0xef; - if (!results[1]) { - old |= 0x10; - data->two_temps = 0; - data->temp_hyst[1] = data->temp_over[1] = - data->temp[1] = 0; - } else { - data->two_temps = 1; - data->voltage_max[4] = data->voltage_min[4] = - data->voltage[4] = 0; - } - gl520_write_value(client, GL520_REG_CONF, old); - } - } -} - -static int __init sm_gl520sm_init(void) -{ - printk("gl520sm.o version %s (%s)\n", LM_VERSION, LM_DATE); - return i2c_add_driver(&gl520_driver); -} - -static void __exit sm_gl520sm_exit(void) -{ - i2c_del_driver(&gl520_driver); -} - - - -MODULE_AUTHOR - ("Frodo Looijaard and Kyösti Mälkki "); -MODULE_DESCRIPTION("GL520SM driver"); - -module_init(sm_gl520sm_init); -module_exit(sm_gl520sm_exit); diff --git a/kernel/chips/it87.c b/kernel/chips/it87.c deleted file mode 100644 index c3874665..00000000 --- a/kernel/chips/it87.c +++ /dev/null @@ -1,1132 +0,0 @@ -/* - it87.c - Part of lm_sensors, Linux kernel modules for hardware - monitoring. - - Supports: IT8705F Super I/O chip w/LPC interface - IT8712F Super I/O chip w/LPC interface & SMBus - SiS950 A clone of the IT8705F - - Copyright (c) 2001 Chris Gauthron - Largely inspired by lm78.c of the same package - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -/* - djg@pdp8.net David Gesswein 7/18/01 - Modified to fix bug with not all alarms enabled. - Added ability to read battery voltage and select temperature sensor - type at module load time. -*/ - -/* - michael.hufer@gmx.de Michael Hufer 09/07/03 - Modified configure (enable/disable) chip reset at module load time. - Added ability to read and set fan pwm registers and the smart - guardian (sg) features of the chip. -*/ - -#include -#include -#include -#include -#include -#include -#include -#include "version.h" - -MODULE_LICENSE("GPL"); - -/* Addresses to scan */ -static unsigned short normal_i2c[] = { SENSORS_I2C_END }; -static unsigned short normal_i2c_range[] = { 0x28, 0x2f, SENSORS_I2C_END }; -static unsigned int normal_isa[] = { 0x0290, SENSORS_ISA_END }; -static unsigned int normal_isa_range[] = { SENSORS_ISA_END }; - -/* Insmod parameters */ -SENSORS_INSMOD_2(it87, it8712); - - -#define REG 0x2e /* The register to read/write */ -#define DEV 0x07 /* Register: Logical device select */ -#define VAL 0x2f /* The value to read/write */ -#define PME 0x04 /* The device with the fan registers in it */ -#define DEVID 0x20 /* Register: Device ID */ -#define DEVREV 0x22 /* Register: Device Revision */ - -static inline int -superio_inb(int reg) -{ - outb(reg, REG); - return inb(VAL); -} - -static int superio_inw(int reg) -{ - int val; - outb(reg++, REG); - val = inb(VAL) << 8; - outb(reg, REG); - val |= inb(VAL); - return val; -} - -static inline void -superio_select(void) -{ - outb(DEV, REG); - outb(PME, VAL); -} - -static inline void -superio_enter(void) -{ - outb(0x87, REG); - outb(0x01, REG); - outb(0x55, REG); - outb(0x55, REG); -} - -static inline void -superio_exit(void) -{ - outb(0x02, REG); - outb(0x02, VAL); -} - -#define IT87_DEVID_MATCH(id) ((id) == 0x8712 || (id) == 0x8705) - -#define IT87_ACT_REG 0x30 -#define IT87_BASE_REG 0x60 - -/* Update battery voltage after every reading if true */ -static int update_vbat = 0; - -/* Reset the registers on init */ -static int reset = 0; - -/* Many IT87 constants specified below */ - -/* Length of ISA address segment */ -#define IT87_EXTENT 8 - -/* Where are the ISA address/data registers relative to the base address */ -#define IT87_ADDR_REG_OFFSET 5 -#define IT87_DATA_REG_OFFSET 6 - -/*----- The IT87 registers -----*/ - -#define IT87_REG_CONFIG 0x00 - -#define IT87_REG_ALARM1 0x01 -#define IT87_REG_ALARM2 0x02 -#define IT87_REG_ALARM3 0x03 - -#define IT87_REG_VID 0x0a -#define IT87_REG_FAN_DIV 0x0b - -#define IT87_REG_FAN(nr) (0x0c + (nr)) -#define IT87_REG_FAN_MIN(nr) (0x0f + (nr)) -#define IT87_REG_FAN_CTRL 0x13 - -/* pwm and smart guardian registers */ - -#define IT87_REG_FAN_ONOFF 0x14 -#define IT87_REG_PWM(nr) (0x14 + (nr)) -#define IT87_REG_SG_TL_OFF(nr) (0x58 + (nr)*8) -#define IT87_REG_SG_TL_LOW(nr) (0x59 + (nr)*8) -#define IT87_REG_SG_TL_MED(nr) (0x5a + (nr)*8) -#define IT87_REG_SG_TL_HI(nr) (0x5b + (nr)*8) -#define IT87_REG_SG_TL_OVR(nr) (0x5c + (nr)*8) -#define IT87_REG_SG_PWM_LOW(nr) (0x5d + (nr)*8) -#define IT87_REG_SG_PWM_MED(nr) (0x5e + (nr)*8) -#define IT87_REG_SG_PWM_HI(nr) (0x5f + (nr)*8) - -/* Monitors: 9 voltage (0 to 7, battery), 3 temp (1 to 3), 3 fan (1 to 3) */ - -#define IT87_REG_VIN(nr) (0x20 + (nr)) -#define IT87_REG_TEMP(nr) (0x28 + (nr)) - -#define IT87_REG_VIN_MAX(nr) (0x30 + (nr) * 2) -#define IT87_REG_VIN_MIN(nr) (0x31 + (nr) * 2) -#define IT87_REG_TEMP_HIGH(nr) (0x3e + (nr) * 2) -#define IT87_REG_TEMP_LOW(nr) (0x3f + (nr) * 2) - -#define IT87_REG_I2C_ADDR 0x48 - -#define IT87_REG_VIN_ENABLE 0x50 -#define IT87_REG_TEMP_ENABLE 0x51 - -#define IT87_REG_CHIPID 0x58 -#define IT87_REG_CHIPID2 0x5b /* IT8712F only */ - -/* sensor pin types */ -#define UNUSED 0 -#define THERMISTOR 2 -#define PIIDIODE 3 - -/* Conversions. Limit checking is only done on the TO_REG - variants. Note that you should be a bit careful with which arguments - these macros are called: arguments may be evaluated more than once. - Fixing this is just not worth it. */ -#define IN_TO_REG(val) (SENSORS_LIMIT((((val) * 10 + 8)/16),0,255)) -#define IN_FROM_REG(val) (((val) * 16 + 5) / 10) - -static inline u8 FAN_TO_REG(long rpm, int div) -{ - if (rpm == 0) - return 255; - rpm = SENSORS_LIMIT(rpm, 1, 1000000); - return SENSORS_LIMIT((1350000 + rpm * div / 2) / (rpm * div), 1, - 254); -} - -#define FAN_FROM_REG(val,div) ((val)==0?-1:(val)==255?0:1350000/((val)*(div))) - -#define TEMP_TO_REG(val) (SENSORS_LIMIT(((val)<0?(((val)-5)/10):\ - ((val)+5)/10),-127,127)) -#define TEMP_FROM_REG(val) (((val)>0x80?(val)-0x100:(val))*10) - -#define VID_FROM_REG(val) ((val)==0x1f?0:(val)>=0x10?510-(val)*10:\ - 205-(val)*5) -#define ALARMS_FROM_REG(val) (val) - -extern inline u8 DIV_TO_REG(long val) -{ - u8 i; - for( i = 0; i <= 7; i++ ) - { - if( val>>i == 1 ) - return i; - } - return 1; -} -#define DIV_FROM_REG(val) (1 << (val)) - -/* For each registered IT87, we need to keep some data in memory. It is - dynamically allocated, at the same time when a new it87 client is - allocated. */ -struct it87_data { - struct i2c_client client; - struct semaphore lock; - int sysctl_id; - enum chips type; - - struct semaphore update_lock; - char valid; /* !=0 if following fields are valid */ - unsigned long last_updated; /* In jiffies */ - - u8 in[9]; /* Register value */ - u8 in_max[9]; /* Register value */ - u8 in_min[9]; /* Register value */ - u8 fan[3]; /* Register value */ - u8 fan_min[3]; /* Register value */ - u8 temp[3]; /* Register value */ - u8 temp_high[3]; /* Register value */ - u8 temp_low[3]; /* Register value */ - u8 fan_div[3]; /* Register encoding, shifted right */ - u8 vid; /* Register encoding, combined */ - u32 alarms; /* Register encoding, combined */ - u8 pwm[3]; /* Register value */ - u8 fan_ctl[2]; /* Register encoding */ - u8 sg_tl[3][5]; /* Register value */ - u8 sg_pwm[3][3]; /* Register value */ - u8 sens[3]; /* 2 = Thermistor, - 3 = PII/Celeron diode */ -}; - - -static int it87_attach_adapter(struct i2c_adapter *adapter); -static int it87_detect(struct i2c_adapter *adapter, int address, - unsigned short flags, int kind); -static int it87_detach_client(struct i2c_client *client); - -static int it87_read_value(struct i2c_client *client, u8 register); -static int it87_write_value(struct i2c_client *client, u8 register, - u8 value); -static void it87_update_client(struct i2c_client *client); -static void it87_init_client(struct i2c_client *client); - - -static void it87_in(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results); -static void it87_fan(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void it87_temp(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void it87_vid(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void it87_alarms(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void it87_fan_div(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void it87_fan_ctl(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void it87_pwm(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void it87_sgpwm(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void it87_sgtl(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void it87_sens(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); - -static struct i2c_driver it87_driver = { - .name = "IT87xx sensor driver", - .id = I2C_DRIVERID_IT87, - .flags = I2C_DF_NOTIFY, - .attach_adapter = it87_attach_adapter, - .detach_client = it87_detach_client, -}; - -/* The /proc/sys entries */ - -/* -- SENSORS SYSCTL START -- */ -#define IT87_SYSCTL_IN0 1000 /* Volts * 100 */ -#define IT87_SYSCTL_IN1 1001 -#define IT87_SYSCTL_IN2 1002 -#define IT87_SYSCTL_IN3 1003 -#define IT87_SYSCTL_IN4 1004 -#define IT87_SYSCTL_IN5 1005 -#define IT87_SYSCTL_IN6 1006 -#define IT87_SYSCTL_IN7 1007 -#define IT87_SYSCTL_IN8 1008 -#define IT87_SYSCTL_FAN1 1101 /* Rotations/min */ -#define IT87_SYSCTL_FAN2 1102 -#define IT87_SYSCTL_FAN3 1103 -#define IT87_SYSCTL_TEMP1 1200 /* Degrees Celsius * 10 */ -#define IT87_SYSCTL_TEMP2 1201 /* Degrees Celsius * 10 */ -#define IT87_SYSCTL_TEMP3 1202 /* Degrees Celsius * 10 */ -#define IT87_SYSCTL_VID 1300 /* Volts * 100 */ -#define IT87_SYSCTL_FAN_DIV 2000 /* 1, 2, 4 or 8 */ -#define IT87_SYSCTL_ALARMS 2004 /* bitvector */ - -#define IT87_SYSCTL_PWM1 1401 -#define IT87_SYSCTL_PWM2 1402 -#define IT87_SYSCTL_PWM3 1403 -#define IT87_SYSCTL_FAN_CTL 1501 -#define IT87_SYSCTL_FAN_ON_OFF 1502 -#define IT87_SYSCTL_SENS1 1601 /* 1, 2, or Beta (3000-5000) */ -#define IT87_SYSCTL_SENS2 1602 -#define IT87_SYSCTL_SENS3 1603 - -#define IT87_ALARM_IN0 0x000100 -#define IT87_ALARM_IN1 0x000200 -#define IT87_ALARM_IN2 0x000400 -#define IT87_ALARM_IN3 0x000800 -#define IT87_ALARM_IN4 0x001000 -#define IT87_ALARM_IN5 0x002000 -#define IT87_ALARM_IN6 0x004000 -#define IT87_ALARM_IN7 0x008000 -#define IT87_ALARM_FAN1 0x0001 -#define IT87_ALARM_FAN2 0x0002 -#define IT87_ALARM_FAN3 0x0004 -#define IT87_ALARM_FAN4 0x0008 -#define IT87_ALARM_FAN5 0x0040 -#define IT87_ALARM_TEMP1 0x00010000 -#define IT87_ALARM_TEMP2 0x00020000 -#define IT87_ALARM_TEMP3 0x00040000 - -/* -- SENSORS SYSCTL END -- */ - -/* These files are created for each detected IT87. This is just a template; - though at first sight, you might think we could use a statically - allocated list, we need some way to get back to the parent - which - is done through one of the 'extra' fields which are initialized - when a new copy is allocated. */ -static ctl_table it87_dir_table_template[] = { - {IT87_SYSCTL_IN0, "in0", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &it87_in}, - {IT87_SYSCTL_IN1, "in1", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &it87_in}, - {IT87_SYSCTL_IN2, "in2", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &it87_in}, - {IT87_SYSCTL_IN3, "in3", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &it87_in}, - {IT87_SYSCTL_IN4, "in4", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &it87_in}, - {IT87_SYSCTL_IN5, "in5", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &it87_in}, - {IT87_SYSCTL_IN6, "in6", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &it87_in}, - {IT87_SYSCTL_IN7, "in7", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &it87_in}, - {IT87_SYSCTL_IN8, "in8", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &it87_in}, - {IT87_SYSCTL_FAN1, "fan1", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &it87_fan}, - {IT87_SYSCTL_FAN2, "fan2", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &it87_fan}, - {IT87_SYSCTL_FAN3, "fan3", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &it87_fan}, - {IT87_SYSCTL_TEMP1, "temp1", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &it87_temp}, - {IT87_SYSCTL_TEMP2, "temp2", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &it87_temp}, - {IT87_SYSCTL_TEMP3, "temp3", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &it87_temp}, - {IT87_SYSCTL_VID, "vid", NULL, 0, 0444, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &it87_vid}, - {IT87_SYSCTL_FAN_DIV, "fan_div", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &it87_fan_div}, - {IT87_SYSCTL_ALARMS, "alarms", NULL, 0, 0444, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &it87_alarms}, - {IT87_SYSCTL_FAN_CTL, "fan_ctl", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &it87_fan_ctl}, - {IT87_SYSCTL_FAN_ON_OFF, "fan_on_off", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &it87_fan_ctl}, - {IT87_SYSCTL_PWM1, "pwm1", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &it87_pwm}, - {IT87_SYSCTL_PWM2, "pwm2", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &it87_pwm}, - {IT87_SYSCTL_PWM3, "pwm3", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &it87_pwm}, - {IT87_SYSCTL_PWM1, "sg_pwm1", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &it87_sgpwm}, - {IT87_SYSCTL_PWM2, "sg_pwm2", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &it87_sgpwm}, - {IT87_SYSCTL_PWM3, "sg_pwm3", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &it87_sgpwm}, - {IT87_SYSCTL_PWM1, "sg_tl1", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &it87_sgtl}, - {IT87_SYSCTL_PWM2, "sg_tl2", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &it87_sgtl}, - {IT87_SYSCTL_PWM3, "sg_tl3", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &it87_sgtl}, - {IT87_SYSCTL_SENS1, "sensor1", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &it87_sens}, - {IT87_SYSCTL_SENS2, "sensor2", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &it87_sens}, - {IT87_SYSCTL_SENS3, "sensor3", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &it87_sens}, - {0} -}; - - -/* This function is called when: - * it87_driver is inserted (when this module is loaded), for each - available adapter - * when a new adapter is inserted (and it87_driver is still present) */ -static int it87_attach_adapter(struct i2c_adapter *adapter) -{ - return i2c_detect(adapter, &addr_data, it87_detect); -} - -static int __init it87_find(int *address) -{ - int err = -ENODEV; - u16 devid; - - superio_enter(); - devid = superio_inw(DEVID); - if (!IT87_DEVID_MATCH(devid)) - goto exit; - - superio_select(); - if (!(superio_inb(IT87_ACT_REG) & 0x01)) { - printk(KERN_INFO "it87: Device not activated, skipping\n"); - goto exit; - } - - *address = superio_inw(IT87_BASE_REG) & ~(IT87_EXTENT - 1); - if (*address == 0) { - printk(KERN_INFO "it87: Base address not set, skipping\n"); - goto exit; - } - - err = 0; - printk(KERN_INFO "it87: Found IT%04xF chip at 0x%x, revision %d\n", - devid, *address, superio_inb(DEVREV) & 0x0f); - -exit: - superio_exit(); - return err; -} - -/* This function is called by i2c_detect */ -static int it87_detect(struct i2c_adapter *adapter, int address, - unsigned short flags, int kind) -{ - int i; - struct i2c_client *new_client; - struct it87_data *data; - int err = 0; - const char *type_name = ""; - const char *client_name = ""; - int is_isa = i2c_is_isa_adapter(adapter); - - if (!is_isa - && !i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) - return 0; - - if (is_isa - && check_region(address, IT87_EXTENT)) - return 0; - - /* Probe whether there is anything available on this address. Already - done for SMBus clients */ - if (is_isa && kind < 0) { -#define REALLY_SLOW_IO - /* We need the timeouts for at least some IT87-like chips. - But only if we read 'undefined' registers. */ - i = inb_p(address + 1); - if (inb_p(address + 2) != i - || inb_p(address + 3) != i - || inb_p(address + 7) != i) - return 0; -#undef REALLY_SLOW_IO - - /* Let's just hope nothing breaks here */ - i = inb_p(address + 5) & 0x7f; - outb_p(~i & 0x7f, address + 5); - if ((inb_p(address + 5) & 0x7f) != (~i & 0x7f)) { - outb_p(i, address + 5); - return 0; - } - } - - /* OK. For now, we presume we have a valid client. We now create the - client structure, even though we cannot fill it completely yet. - But it allows us to access it87_{read,write}_value. */ - - if (!(data = kmalloc(sizeof(struct it87_data), GFP_KERNEL))) { - err = -ENOMEM; - goto ERROR0; - } - - new_client = &data->client; - if (is_isa) - init_MUTEX(&data->lock); - new_client->addr = address; - new_client->data = data; - new_client->adapter = adapter; - new_client->driver = &it87_driver; - new_client->flags = 0; - - /* Now, we do the remaining detection. */ - - if (kind < 0) { - if ((it87_read_value(new_client, IT87_REG_CONFIG) & 0x80) - || (!is_isa - && it87_read_value(new_client, IT87_REG_I2C_ADDR) != address)) - goto ERROR1; - } - - /* Determine the chip type. */ - if (kind <= 0) { - i = it87_read_value(new_client, IT87_REG_CHIPID); - if (i == 0x90) { - kind = it87; - i = it87_read_value(new_client, IT87_REG_CHIPID2); - if (i == 0x12) - kind = it8712; - } - else { - if (kind == 0) - printk - ("it87.o: Ignoring 'force' parameter for unknown chip at " - "adapter %d, address 0x%02x\n", - i2c_adapter_id(adapter), address); - goto ERROR1; - } - } - - if (kind == it87) { - type_name = "it87"; - client_name = "IT87 chip"; - } else if (kind == it8712) { - type_name = "it8712"; - client_name = "IT8712 chip"; - } else { -#ifdef DEBUG - printk("it87.o: Internal error: unknown kind (%d)\n", - kind); -#endif - goto ERROR1; - } - - /* Reserve the ISA region */ - if (is_isa) - request_region(address, IT87_EXTENT, type_name); - - /* Fill in the remaining client fields and put it into the global list */ - strcpy(new_client->name, client_name); - data->type = kind; - data->valid = 0; - init_MUTEX(&data->update_lock); - - /* The IT8705F doesn't have VID capability */ - data->vid = 0x1f; - - /* Tell the I2C layer a new client has arrived */ - if ((err = i2c_attach_client(new_client))) - goto ERROR3; - - /* Register a new directory entry with module sensors */ - if ((i = i2c_register_entry(new_client, - type_name, - it87_dir_table_template, - THIS_MODULE)) < 0) { - err = i; - goto ERROR4; - } - data->sysctl_id = i; - - /* Initialize the IT87 chip */ - it87_init_client(new_client); - return 0; - -/* OK, this is not exactly good programming practice, usually. But it is - very code-efficient in this case. */ - - ERROR4: - i2c_detach_client(new_client); - ERROR3: - if (is_isa) - release_region(address, IT87_EXTENT); - ERROR1: - kfree(data); - ERROR0: - return err; -} - -static int it87_detach_client(struct i2c_client *client) -{ - int err; - - i2c_deregister_entry(((struct it87_data *) (client->data))-> - sysctl_id); - - if ((err = i2c_detach_client(client))) { - printk - ("it87.o: Client deregistration failed, client not detached.\n"); - return err; - } - - if(i2c_is_isa_client(client)) - release_region(client->addr, IT87_EXTENT); - kfree(client->data); - - return 0; -} - -/* The SMBus locks itself, but ISA access must be locked explicitly! - We don't want to lock the whole ISA bus, so we lock each client - separately. - We ignore the IT87 BUSY flag at this moment - it could lead to deadlocks, - would slow down the IT87 access and should not be necessary. - There are some ugly typecasts here, but the good new is - they should - nowhere else be necessary! */ -static int it87_read_value(struct i2c_client *client, u8 reg) -{ - int res; - if (i2c_is_isa_client(client)) { - down(&(((struct it87_data *) (client->data))->lock)); - outb_p(reg, client->addr + IT87_ADDR_REG_OFFSET); - res = inb_p(client->addr + IT87_DATA_REG_OFFSET); - up(&(((struct it87_data *) (client->data))->lock)); - return res; - } else - return i2c_smbus_read_byte_data(client, reg); -} - -/* The SMBus locks itself, but ISA access muse be locked explicitly! - We don't want to lock the whole ISA bus, so we lock each client - separately. - We ignore the IT87 BUSY flag at this moment - it could lead to deadlocks, - would slow down the IT87 access and should not be necessary. - There are some ugly typecasts here, but the good new is - they should - nowhere else be necessary! */ -static int it87_write_value(struct i2c_client *client, u8 reg, u8 value) -{ - if (i2c_is_isa_client(client)) { - down(&(((struct it87_data *) (client->data))->lock)); - outb_p(reg, client->addr + IT87_ADDR_REG_OFFSET); - outb_p(value, client->addr + IT87_DATA_REG_OFFSET); - up(&(((struct it87_data *) (client->data))->lock)); - return 0; - } else - return i2c_smbus_write_byte_data(client, reg, value); -} - -/* Called when we have found a new IT87. */ -static void it87_init_client(struct i2c_client *client) -{ - int tmp; - - if (reset) { - /* Reset all except Watchdog values and last conversion values - This sets fan-divs to 2, among others */ - it87_write_value(client, IT87_REG_CONFIG, 0x80); - } - - /* Check if temperature channnels are reset manually or by some reason */ - tmp = it87_read_value(client, IT87_REG_TEMP_ENABLE); - if ((tmp & 0x3f) == 0) { - /* Temp1,Temp3=thermistor; Temp2=thermal diode */ - tmp = (tmp & 0xc0) | 0x2a; - it87_write_value(client, IT87_REG_TEMP_ENABLE, tmp); - } - - /* Check if voltage monitors are reset manually or by some reason */ - tmp = it87_read_value(client, IT87_REG_VIN_ENABLE); - if ((tmp & 0xff) == 0) { - /* Enable all voltage monitors */ - it87_write_value(client, IT87_REG_VIN_ENABLE, 0xff); - } - - /* Check if tachometers are reset manually or by some reason */ - tmp = it87_read_value(client, IT87_REG_FAN_CTRL); - if ((tmp & 0x70) == 0) { - /* Enable all fan tachometers */ - tmp = (tmp & 0x8f) | 0x70; - it87_write_value(client, IT87_REG_FAN_CTRL, tmp); - } - - /* Start monitoring */ - it87_write_value(client, IT87_REG_CONFIG, - (it87_read_value(client, IT87_REG_CONFIG) & 0x36) - | (update_vbat ? 0x41 : 0x01)); -} - -static void it87_update_client(struct i2c_client *client) -{ - struct it87_data *data = client->data; - int i, tmp, tmp2; - - down(&data->update_lock); - - if ((jiffies - data->last_updated > HZ + HZ / 2) || - (jiffies < data->last_updated) || !data->valid) { - - if (update_vbat) { - /* Cleared after each update, so reenable. Value - returned by this read will be previous value */ - it87_write_value(client, IT87_REG_CONFIG, - it87_read_value(client, IT87_REG_CONFIG) | 0x40); - } - for (i = 0; i <= 7; i++) { - data->in[i] = - it87_read_value(client, IT87_REG_VIN(i)); - data->in_min[i] = - it87_read_value(client, IT87_REG_VIN_MIN(i)); - data->in_max[i] = - it87_read_value(client, IT87_REG_VIN_MAX(i)); - } - data->in[8] = - it87_read_value(client, IT87_REG_VIN(8)); - /* VBAT sensor doesn't have limit registers, set - to min and max value */ - data->in_min[8] = 0; - data->in_max[8] = 255; - - for (i = 1; i <= 3; i++) { - data->fan[i - 1] = - it87_read_value(client, IT87_REG_FAN(i)); - data->fan_min[i - 1] = - it87_read_value(client, IT87_REG_FAN_MIN(i)); - } - for (i = 1; i <= 3; i++) { - data->temp[i - 1] = - it87_read_value(client, IT87_REG_TEMP(i)); - data->temp_high[i - 1] = - it87_read_value(client, IT87_REG_TEMP_HIGH(i)); - data->temp_low[i - 1] = - it87_read_value(client, IT87_REG_TEMP_LOW(i)); - } - - if (data->type == it8712) { - data->vid = it87_read_value(client, IT87_REG_VID); - data->vid &= 0x1f; - } - - i = it87_read_value(client, IT87_REG_FAN_DIV); - data->fan_div[0] = i & 0x07; - data->fan_div[1] = (i >> 3) & 0x07; - data->fan_div[2] = ( (i&0x40)==0x40 ? 3 : 1 ); - - for( i = 1; i <= 3; i++ ) { - data->pwm[i-1] = it87_read_value(client, IT87_REG_PWM(i)); - data->sg_tl[i-1][0] = it87_read_value(client, IT87_REG_SG_TL_OFF(i)); - data->sg_tl[i-1][1] = it87_read_value(client, IT87_REG_SG_TL_LOW(i)); - data->sg_tl[i-1][2] = it87_read_value(client, IT87_REG_SG_TL_MED(i)); - data->sg_tl[i-1][3] = it87_read_value(client, IT87_REG_SG_TL_HI(i)); - data->sg_tl[i-1][4] = it87_read_value(client, IT87_REG_SG_TL_OVR(i)); - data->sg_pwm[i-1][0] = it87_read_value(client, IT87_REG_SG_PWM_LOW(i)); - data->sg_pwm[i-1][1] = it87_read_value(client, IT87_REG_SG_PWM_MED(i)); - data->sg_pwm[i-1][2] = it87_read_value(client, IT87_REG_SG_PWM_HI(i)); - } - data->alarms = - it87_read_value(client, IT87_REG_ALARM1) | - (it87_read_value(client, IT87_REG_ALARM2) << 8) | - (it87_read_value(client, IT87_REG_ALARM3) << 16); - data->fan_ctl[0] = it87_read_value(client, IT87_REG_FAN_CTRL); - data->fan_ctl[1] = it87_read_value(client, IT87_REG_FAN_ONOFF); - - tmp = it87_read_value(client, IT87_REG_TEMP_ENABLE); - for(i = 0; i < 3; i++) { - tmp2 = (tmp >> i) & 0x09; - if(tmp2 == 0x01) - data->sens[i] = PIIDIODE; - else if(tmp2 == 0x08) - data->sens[i] = THERMISTOR; - else - data->sens[i] = UNUSED; - } - - data->last_updated = jiffies; - data->valid = 1; - } - - up(&data->update_lock); -} - - -/* The next few functions are the call-back functions of the /proc/sys and - sysctl files. Which function is used is defined in the ctl_table in - the extra1 field. - - Each function must return the magnitude (power of 10 to divide the - data with) if it is called with operation==SENSORS_PROC_REAL_INFO. - - It must put a maximum of *nrels elements in results reflecting the - data of this file, and set *nrels to the number it actually put - in it, if operation==SENSORS_PROC_REAL_READ. - - Finally, it must get upto *nrels elements from results and write them - to the chip, if operations==SENSORS_PROC_REAL_WRITE. - Note that on SENSORS_PROC_REAL_READ, I do not check whether results is - large enough (by checking the incoming value of *nrels). This is not very - good practice, but as long as you put less than about 5 values in results, - you can assume it is large enough. */ -void it87_in(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct it87_data *data = client->data; - int nr = ctl_name - IT87_SYSCTL_IN0; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 2; - else if (operation == SENSORS_PROC_REAL_READ) { - it87_update_client(client); - results[0] = IN_FROM_REG(data->in_min[nr]); - results[1] = IN_FROM_REG(data->in_max[nr]); - results[2] = IN_FROM_REG(data->in[nr]); - *nrels_mag = 3; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag >= 1) { - data->in_min[nr] = IN_TO_REG(results[0]); - it87_write_value(client, IT87_REG_VIN_MIN(nr), - data->in_min[nr]); - } - if (*nrels_mag >= 2) { - data->in_max[nr] = IN_TO_REG(results[1]); - it87_write_value(client, IT87_REG_VIN_MAX(nr), - data->in_max[nr]); - } - } -} - -void it87_fan(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct it87_data *data = client->data; - int nr = ctl_name - IT87_SYSCTL_FAN1 + 1; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - it87_update_client(client); - results[0] = FAN_FROM_REG(data->fan_min[nr - 1], - DIV_FROM_REG(data->fan_div[nr - 1])); - results[1] = FAN_FROM_REG(data->fan[nr - 1], - DIV_FROM_REG(data->fan_div[nr - 1])); - *nrels_mag = 2; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag >= 1) { - data->fan_min[nr - 1] = FAN_TO_REG(results[0], - DIV_FROM_REG(data->fan_div[nr - 1])); - it87_write_value(client, IT87_REG_FAN_MIN(nr), - data->fan_min[nr - 1]); - } - } -} - - -void it87_temp(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct it87_data *data = client->data; - int nr = ctl_name - IT87_SYSCTL_TEMP1 + 1; - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 1; - else if (operation == SENSORS_PROC_REAL_READ) { - it87_update_client(client); - results[0] = TEMP_FROM_REG(data->temp_high[nr - 1]); - results[1] = TEMP_FROM_REG(data->temp_low[nr - 1]); - results[2] = TEMP_FROM_REG(data->temp[nr - 1]); - *nrels_mag = 3; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag >= 1) { - data->temp_high[nr - 1] = TEMP_TO_REG(results[0]); - it87_write_value(client, IT87_REG_TEMP_HIGH(nr), - data->temp_high[nr - 1]); - } - if (*nrels_mag >= 2) { - data->temp_low[nr - 1] = TEMP_TO_REG(results[1]); - it87_write_value(client, IT87_REG_TEMP_LOW(nr), - data->temp_low[nr - 1]); - } - } -} - -void it87_pwm(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct it87_data *data = client->data; - int nr = ctl_name - IT87_SYSCTL_PWM1 + 1; - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - it87_update_client(client); - results[0] = data->pwm[nr - 1]; - *nrels_mag = 1; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag >= 1) { - data->pwm[nr - 1] = results[0]; - it87_write_value(client, IT87_REG_PWM(nr), data->pwm[nr - 1]); - } - } -} - -void it87_sgpwm(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct it87_data *data = client->data; - int nr = ctl_name - IT87_SYSCTL_PWM1 + 1; - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - it87_update_client(client); - results[0] = data->sg_pwm[nr - 1][0]; - results[1] = data->sg_pwm[nr - 1][1]; - results[2] = data->sg_pwm[nr - 1][2]; - *nrels_mag = 3; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag >= 1) { - data->sg_pwm[nr - 1][0] = results[0]; - it87_write_value(client, IT87_REG_SG_PWM_LOW(nr), data->sg_pwm[nr - 1][0]); - } - if (*nrels_mag >= 2) { - data->sg_pwm[nr - 1][1] = results[1]; - it87_write_value(client, IT87_REG_SG_PWM_MED(nr), data->sg_pwm[nr - 1][1]); - } - if (*nrels_mag >= 3) { - data->sg_pwm[nr - 1][2] = results[2]; - it87_write_value(client, IT87_REG_SG_PWM_HI(nr), data->sg_pwm[nr - 1][2]); - } - } -} - -void it87_sgtl(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct it87_data *data = client->data; - int nr = ctl_name - IT87_SYSCTL_PWM1 + 1; - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 1; - else if (operation == SENSORS_PROC_REAL_READ) { - it87_update_client(client); - results[0] = TEMP_FROM_REG(data->sg_tl[nr - 1][0]); - results[1] = TEMP_FROM_REG(data->sg_tl[nr - 1][1]); - results[2] = TEMP_FROM_REG(data->sg_tl[nr - 1][2]); - results[3] = TEMP_FROM_REG(data->sg_tl[nr - 1][3]); - results[4] = TEMP_FROM_REG(data->sg_tl[nr - 1][4]); - *nrels_mag = 5; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag >= 1) { - data->sg_tl[nr - 1][0] = TEMP_TO_REG(results[0]); - it87_write_value(client, IT87_REG_SG_TL_OFF(nr), data->sg_tl[nr - 1][0]); - } - if (*nrels_mag >= 2) { - data->sg_tl[nr - 1][1] = TEMP_TO_REG(results[1]); - it87_write_value(client, IT87_REG_SG_TL_LOW(nr), data->sg_tl[nr - 1][1]); - } - if (*nrels_mag >= 3) { - data->sg_tl[nr - 1][2] = TEMP_TO_REG(results[2]); - it87_write_value(client, IT87_REG_SG_TL_MED(nr), data->sg_tl[nr - 1][2]); - } - if (*nrels_mag >= 4) { - data->sg_tl[nr - 1][3] = TEMP_TO_REG(results[3]); - it87_write_value(client, IT87_REG_SG_TL_HI(nr), data->sg_tl[nr - 1][3]); - } - if (*nrels_mag >= 5) { - data->sg_tl[nr - 1][4] = TEMP_TO_REG(results[4]); - it87_write_value(client, IT87_REG_SG_TL_OVR(nr), data->sg_tl[nr - 1][4]); - } - } -} - -void it87_vid(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct it87_data *data = client->data; - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 2; - else if (operation == SENSORS_PROC_REAL_READ) { - it87_update_client(client); - results[0] = VID_FROM_REG(data->vid); - *nrels_mag = 1; - } -} - -void it87_alarms(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results) -{ - struct it87_data *data = client->data; - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - it87_update_client(client); - results[0] = ALARMS_FROM_REG(data->alarms); - *nrels_mag = 1; - } -} - -void it87_fan_div(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct it87_data *data = client->data; - int old; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - it87_update_client(client); - results[0] = DIV_FROM_REG(data->fan_div[0]); - results[1] = DIV_FROM_REG(data->fan_div[1]); - results[2] = DIV_FROM_REG(data->fan_div[2]);; - *nrels_mag = 3; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - old = it87_read_value(client, IT87_REG_FAN_DIV); - if (*nrels_mag >= 3) { - data->fan_div[2] = DIV_TO_REG(results[2]); - if (data->fan_div[2] != 3) { - data->fan_div[2] = 1; - old = (old & 0xbf); - } else { - old = (old | 0x40); - } - } - if (*nrels_mag >= 2) { - data->fan_div[1] = DIV_TO_REG(results[1]); - old = (old & 0xc3) | (data->fan_div[1] << 3); - } - if (*nrels_mag >= 1) { - data->fan_div[0] = DIV_TO_REG(results[0]); - old = (old & 0xf8) | data->fan_div[0]; - it87_write_value(client, IT87_REG_FAN_DIV, old); - } - } -} - -void it87_fan_ctl(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct it87_data *data = client->data; - int index = ctl_name - IT87_SYSCTL_FAN_CTL; - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - it87_update_client(client); - results[0] = data->fan_ctl[index]; - *nrels_mag = 1; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag >= 1) { - data->fan_ctl[index] = results[0]; - if( index == 0 ) - it87_write_value(client, IT87_REG_FAN_CTRL, data->fan_ctl[index] ); - else - it87_write_value(client, IT87_REG_FAN_ONOFF, data->fan_ctl[index] ); - } - } -} - -void it87_sens(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct it87_data *data = client->data; - int nr = 1 + ctl_name - IT87_SYSCTL_SENS1; - u8 tmp, val1, val2; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - results[0] = data->sens[nr - 1]; - *nrels_mag = 1; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag >= 1) { - val1 = 0x01 << (nr - 1); - val2 = 0x08 << (nr - 1); - tmp = it87_read_value(client, IT87_REG_TEMP_ENABLE); - switch (results[0]) { - case PIIDIODE: - tmp &= ~ val2; - tmp |= val1; - break; - case THERMISTOR: - tmp &= ~ val1; - tmp |= val2; - break; - case UNUSED: - tmp &= ~ val1; - tmp &= ~ val2; - break; - default: - printk(KERN_ERR "it87.o: Invalid sensor type %ld; " - "must be 0 (unused), 2 (thermistor) " - "or 3 (diode)\n", results[0]); - return; - } - it87_write_value(client, - IT87_REG_TEMP_ENABLE, tmp); - data->sens[nr - 1] = results[0]; - } - } -} - -static int __init sm_it87_init(void) -{ - int addr; - - printk("it87.o version %s (%s)\n", LM_VERSION, LM_DATE); - if (!it87_find(&addr)) { - normal_isa[0] = addr; - } - return i2c_add_driver(&it87_driver); -} - -static void __exit sm_it87_exit(void) -{ - i2c_del_driver(&it87_driver); -} - - -MODULE_AUTHOR("Chris Gauthron"); -MODULE_DESCRIPTION("IT8705F, IT8712F, Sis950 driver"); -MODULE_PARM(update_vbat, "i"); -MODULE_PARM_DESC(update_vbat, "Update vbat if set else return powerup value"); -MODULE_PARM(reset, "i"); -MODULE_PARM_DESC(reset, "Reset the chip's registers, default no"); - -module_init(sm_it87_init); -module_exit(sm_it87_exit); diff --git a/kernel/chips/lm63.c b/kernel/chips/lm63.c deleted file mode 100644 index 72fd50a5..00000000 --- a/kernel/chips/lm63.c +++ /dev/null @@ -1,645 +0,0 @@ -/* - * lm63.c - driver for the National Semiconductor LM63 temperature sensor - * with integrated fan control - * Copyright (C) 2004 Jean Delvare - * Based on the lm90 driver. - * - * The LM63 is a sensor chip made by National Semiconductor. It measures - * two temperatures (its own and one external one) and the speed of one - * fan, those speed it can additionally control. Complete datasheet can be - * obtained from National's website at: - * http://www.national.com/pf/LM/LM63.html - * - * The LM63 is basically an LM86 with fan speed monitoring and control - * capabilities added. It misses some of the LM86 features though: - * - No low limit for local temperature. - * - No critical limit for local temperature. - * - Critical limit for remote temperature can be changed only once. We - * will consider that the critical limit is read-only. - * - * The datasheet isn't very clear about what the tachometer reading is. - * I had a explanation from National Semiconductor though. The two lower - * bits of the read value have to be masked out. The value is still 16 bit - * in width. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include -#include -#include -#include -#include -#include "version.h" - -/* - * Addresses to scan - * Address is fully defined internally and cannot be changed. - */ - -static unsigned short normal_i2c[] = { 0x4c, SENSORS_I2C_END }; -static unsigned short normal_i2c_range[] = { SENSORS_I2C_END }; -static unsigned int normal_isa[] = { SENSORS_ISA_END }; -static unsigned int normal_isa_range[] = { SENSORS_ISA_END }; -/* - * Insmod parameters - */ - -SENSORS_INSMOD_1(lm63); - -/* - * The LM63 registers - */ - -#define LM63_REG_CONFIG1 0x03 -#define LM63_REG_CONFIG2 0xBF -#define LM63_REG_CONFIG_FAN 0x4A - -#define LM63_REG_TACH_COUNT_MSB 0x47 -#define LM63_REG_TACH_COUNT_LSB 0x46 -#define LM63_REG_TACH_LIMIT_MSB 0x49 -#define LM63_REG_TACH_LIMIT_LSB 0x48 - -#define LM63_REG_PWM_VALUE 0x4C -#define LM63_REG_PWM_FREQ 0x4D - -#define LM63_REG_LOCAL_TEMP 0x00 -#define LM63_REG_LOCAL_HIGH 0x05 - -#define LM63_REG_REMOTE_TEMP_MSB 0x01 -#define LM63_REG_REMOTE_TEMP_LSB 0x10 -#define LM63_REG_REMOTE_OFFSET_MSB 0x11 -#define LM63_REG_REMOTE_OFFSET_LSB 0x12 -#define LM63_REG_REMOTE_HIGH_MSB 0x07 -#define LM63_REG_REMOTE_HIGH_LSB 0x13 -#define LM63_REG_REMOTE_LOW_MSB 0x08 -#define LM63_REG_REMOTE_LOW_LSB 0x14 -#define LM63_REG_REMOTE_TCRIT 0x19 -#define LM63_REG_REMOTE_TCRIT_HYST 0x21 - -#define LM63_REG_ALERT_STATUS 0x02 -#define LM63_REG_ALERT_MASK 0x16 - -#define LM63_REG_MAN_ID 0xFE -#define LM63_REG_CHIP_ID 0xFF - -/* - * Conversions and various macros - * For tachometer counts, the LM63 uses 16-bit values. - * For local temperature and high limit, remote critical limit and hysteresis - * value, it uses signed 8-bit values with LSB = 1 degree Celsius. - * For remote temperature, low and high limits, it uses signed 11-bit values - * with LSB = 0.125 degree Celsius, left-justified in 16-bit registers. - */ - -#define FAN_FROM_REG(reg) ((reg) == 0xFFFC || (reg) == 0 ? 0 : \ - 5400000 / (reg)) -#define FAN_TO_REG(val) ((val) <= 82 ? 0xFFFF : \ - (5400000 / (val)) & 0xFFFC) -#define TEMP8_FROM_REG(reg) (reg) -#define TEMP8_TO_REG(val) ((val) <= -128 ? -128 : \ - (val) >= 127 ? 127 : \ - val) -#define TEMP11_FROM_REG(reg) ((reg) / 32 * 125) -#define TEMP11_TO_REG(val) ((val) <= -128000 ? 0x8000 : \ - (val) >= 127875 ? 0x7FE0 : \ - (val) < 0 ? ((val) - 62) / 125 * 32 : \ - ((val) + 62) / 125 * 32) -#define HYST_TO_REG(val) ((val) <= 0 ? 0 : \ - (val) >= 127 ? 127 : \ - val) - -/* - * Functions declaration - */ - -static int lm63_attach_adapter(struct i2c_adapter *adapter); -static int lm63_detect(struct i2c_adapter *adapter, int address, - unsigned short flags, int kind); -static void lm63_init_client(struct i2c_client *client); -static int lm63_detach_client(struct i2c_client *client); - -static void lm63_local_temp(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void lm63_remote_temp(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void lm63_remote_tcrit(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void lm63_remote_tcrit_hyst(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void lm63_alarms(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void lm63_fan(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void lm63_pwm(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); - -/* - * Driver data (common to all clients) - */ - -static struct i2c_driver lm63_driver = { - .name = "LM63 sensor driver", - .flags = I2C_DF_NOTIFY, - .attach_adapter = lm63_attach_adapter, - .detach_client = lm63_detach_client, -}; - -/* - * Client data (each client gets its own) - */ - -struct lm63_data { - struct i2c_client client; - int sysctl_id; - - struct semaphore update_lock; - char valid; /* zero until following fields are valid */ - unsigned long last_updated; /* in jiffies */ - - /* registers values */ - u8 config, config_fan; - u16 fan1_input; - u16 fan1_low; - u8 pwm1_freq; - u8 pwm1_value; - s8 temp1_input; - s8 temp1_high; - s16 temp2_input; - s16 temp2_high; - s16 temp2_low; - s8 temp2_crit; - u8 temp2_crit_hyst; - u8 alarms; -}; - -/* - * Proc entries - * These files are created for each detected LM63. - */ - -/* -- SENSORS SYSCTL START -- */ - -#define LM63_SYSCTL_TEMP1 1200 -#define LM63_SYSCTL_TEMP2 1201 -#define LM63_SYSCTL_TEMP2_TCRIT 1205 -#define LM63_SYSCTL_TEMP2_TCRIT_HYST 1208 -#define LM63_SYSCTL_ALARMS 1210 -#define LM63_SYSCTL_FAN1 1220 -#define LM63_SYSCTL_PWM1 1230 - -#define LM63_ALARM_LOCAL_HIGH 0x40 -#define LM63_ALARM_REMOTE_HIGH 0x10 -#define LM63_ALARM_REMOTE_LOW 0x08 -#define LM63_ALARM_REMOTE_CRIT 0x02 -#define LM63_ALARM_REMOTE_OPEN 0x04 -#define LM63_ALARM_FAN_LOW 0x01 - -/* -- SENSORS SYSCTL END -- */ - -static ctl_table lm63_dir_table_template[] = -{ - {LM63_SYSCTL_TEMP1, "temp1", NULL, 0, 0644, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &lm63_local_temp}, - {LM63_SYSCTL_TEMP2, "temp2", NULL, 0, 0644, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &lm63_remote_temp}, - {LM63_SYSCTL_TEMP2_TCRIT, "temp2_crit", NULL, 0, 0444, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &lm63_remote_tcrit}, - {LM63_SYSCTL_TEMP2_TCRIT_HYST, "temp2_crit_hyst", NULL, 0, 0644, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &lm63_remote_tcrit_hyst}, - {LM63_SYSCTL_ALARMS, "alarms", NULL, 0, 0444, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &lm63_alarms}, - {LM63_SYSCTL_FAN1, "fan1", NULL, 0, 0644, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &lm63_fan}, - {LM63_SYSCTL_PWM1, "pwm1", NULL, 0, 0644, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &lm63_pwm}, - {0} -}; - -/* - * Real code - */ - -static int lm63_attach_adapter(struct i2c_adapter *adapter) -{ - return i2c_detect(adapter, &addr_data, lm63_detect); -} - -/* - * The following function does more than just detection. If detection - * succeeds, it also registers the new chip. - */ -static int lm63_detect(struct i2c_adapter *adapter, int address, - unsigned short flags, int kind) -{ - struct i2c_client *new_client; - struct lm63_data *data; - int err = 0; - - if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) { -#ifdef DEBUG - printk(KERN_DEBUG "lm63: adapter doesn't support SMBus byte " - "data mode, skipping.\n"); -#endif - return 0; - } - - if (!(data = kmalloc(sizeof(struct lm63_data), GFP_KERNEL))) { - printk(KERN_ERR "lm63: Out of memory in lm63_detect\n"); - return -ENOMEM; - } - - /* - * The common I2C client data is placed right before the - * LM63-specific data. The LM63-specific data is pointed to by the - * data field from the i2c_client structure. - */ - new_client = &data->client; - new_client->addr = address; - new_client->data = data; - new_client->adapter = adapter; - new_client->driver = &lm63_driver; - new_client->flags = 0; - - /* Default to an LM63 if forced */ - if (kind == 0) - kind = lm63; - - if (kind < 0) { /* must identify */ - u8 man_id, chip_id, reg_config1, reg_config2; - u8 reg_alert_status, reg_alert_mask; - - man_id = i2c_smbus_read_byte_data(new_client, - LM63_REG_MAN_ID); - chip_id = i2c_smbus_read_byte_data(new_client, - LM63_REG_CHIP_ID); - reg_config1 = i2c_smbus_read_byte_data(new_client, - LM63_REG_CONFIG1); - reg_config2 = i2c_smbus_read_byte_data(new_client, - LM63_REG_CONFIG2); - reg_alert_status = i2c_smbus_read_byte_data(new_client, - LM63_REG_ALERT_STATUS); - reg_alert_mask = i2c_smbus_read_byte_data(new_client, - LM63_REG_ALERT_MASK); - - if (man_id == 0x01 /* National Semiconductor */ - && chip_id == 0x41 /* LM63 */ - && (reg_config1 & 0x18) == 0x00 - && (reg_config2 & 0xF8) == 0x00 - && (reg_alert_status & 0x20) == 0x00 - && (reg_alert_mask & 0xA4) == 0xA4) { - kind = lm63; - } else { -#ifdef DEBUG - printk(KERN_DEBUG "lm63: Unsupported chip " - "(man_id=0x%02X, chip_id=0x%02X)\n", - man_id, chip_id); -#endif - goto ERROR1; - } - } - - /* Fill in the remaining client fields */ - strcpy(new_client->name, "LM63 chip"); - data->valid = 0; - init_MUTEX(&data->update_lock); - - /* Tell the I2C layer a new client has arrived */ - if ((err = i2c_attach_client(new_client))) { - printk(KERN_ERR "lm63: Failed attaching client\n"); - goto ERROR1; - } - - /* Register a new directory entry */ - if ((err = i2c_register_entry(new_client, "lm63", - lm63_dir_table_template, THIS_MODULE)) < 0) { - printk(KERN_ERR "lm63: Failed registering directory entry\n"); - goto ERROR2; - } - data->sysctl_id = err; - - - /* Initialize the LM63 chip */ - lm63_init_client(new_client); - - return 0; - -ERROR2: - i2c_detach_client(new_client); -ERROR1: - kfree(data); - return err; -} - -/* Idealy we shouldn't have to initialize anything, since the BIOS - should have taken care of everything */ -static void lm63_init_client(struct i2c_client *client) -{ - struct lm63_data *data = client->data; - - data->config = i2c_smbus_read_byte_data(client, LM63_REG_CONFIG1); - data->config_fan = i2c_smbus_read_byte_data(client, - LM63_REG_CONFIG_FAN); - - /* Start converting if needed */ - if (data->config & 0x40) { /* standby */ -#ifdef DEBUG - printk(KERN_DEBUG "lm63: Switching to operational mode\n"); -#endif - data->config &= 0xA7; - i2c_smbus_write_byte_data(client, LM63_REG_CONFIG1, - data->config); - } - - /* We may need pwm1_freq before ever updating the client data */ - data->pwm1_freq = i2c_smbus_read_byte_data(client, LM63_REG_PWM_FREQ); - if (data->pwm1_freq == 0) - data->pwm1_freq = 1; - -#ifdef DEBUG - /* Show some debug info about the LM63 configuration */ - printk(KERN_DEBUG "lm63: Alert/tach pin configured for %s\n", - (data->config & 0x04) ? "tachometer input" : - "alert output"); - printk(KERN_DEBUG "lm63: PWM clock %s kHz, output frequency %u Hz\n", - (data->config_fan & 0x08) ? "1.4" : "360", - ((data->config_fan & 0x08) ? 700 : 180000) / data->pwm1_freq); - printk(KERN_DEBUG "lm63: PWM output active %s, %s mode\n", - (data->config_fan & 0x10) ? "low" : "high", - (data->config_fan & 0x20) ? "manual" : "auto"); -#endif -} - -static int lm63_detach_client(struct i2c_client *client) -{ - struct lm63_data *data = client->data; - int err; - - i2c_deregister_entry(data->sysctl_id); - if ((err = i2c_detach_client(client))) { - printk(KERN_ERR "lm63: Client deregistration failed, client " - "not detached.\n"); - return err; - } - - kfree(data); - return 0; -} - -static void lm63_update_client(struct i2c_client *client) -{ - struct lm63_data *data = client->data; - - down(&data->update_lock); - - if ((jiffies - data->last_updated > HZ) || - (jiffies < data->last_updated) || - !data->valid) { - if (data->config & 0x04) { /* tachometer enabled */ - /* order matters for fan1_input */ - data->fan1_input = i2c_smbus_read_byte_data(client, - LM63_REG_TACH_COUNT_LSB) & 0xFC; - data->fan1_input |= i2c_smbus_read_byte_data(client, - LM63_REG_TACH_COUNT_MSB) << 8; - data->fan1_low = (i2c_smbus_read_byte_data(client, - LM63_REG_TACH_LIMIT_LSB) & 0xFC) - | (i2c_smbus_read_byte_data(client, - LM63_REG_TACH_LIMIT_MSB) << 8); - } - - data->pwm1_freq = i2c_smbus_read_byte_data(client, - LM63_REG_PWM_FREQ); - if (data->pwm1_freq == 0) - data->pwm1_freq = 1; - data->pwm1_value = i2c_smbus_read_byte_data(client, - LM63_REG_PWM_VALUE); - - data->temp1_input = i2c_smbus_read_byte_data(client, - LM63_REG_LOCAL_TEMP); - data->temp1_high = i2c_smbus_read_byte_data(client, - LM63_REG_LOCAL_HIGH); - - /* order matters for temp2_input */ - data->temp2_input = i2c_smbus_read_byte_data(client, - LM63_REG_REMOTE_TEMP_MSB) << 8; - data->temp2_input |= i2c_smbus_read_byte_data(client, - LM63_REG_REMOTE_TEMP_LSB); - data->temp2_high = (i2c_smbus_read_byte_data(client, - LM63_REG_REMOTE_HIGH_MSB) << 8) - | i2c_smbus_read_byte_data(client, - LM63_REG_REMOTE_HIGH_LSB); - data->temp2_low = (i2c_smbus_read_byte_data(client, - LM63_REG_REMOTE_LOW_MSB) << 8) - | i2c_smbus_read_byte_data(client, - LM63_REG_REMOTE_LOW_LSB); - data->temp2_crit = i2c_smbus_read_byte_data(client, - LM63_REG_REMOTE_TCRIT); - data->temp2_crit_hyst = i2c_smbus_read_byte_data(client, - LM63_REG_REMOTE_TCRIT_HYST); - - /* Mask out Busy bit in status register */ - data->alarms = i2c_smbus_read_byte_data(client, - LM63_REG_ALERT_STATUS) & 0x7F; - - data->last_updated = jiffies; - data->valid = 1; - } - - up(&data->update_lock); -} - -static void lm63_local_temp(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results) -{ - struct lm63_data *data = client->data; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; /* magnitude */ - else if (operation == SENSORS_PROC_REAL_READ) { - lm63_update_client(client); - results[0] = TEMP8_FROM_REG(data->temp1_high); - results[1] = TEMP8_FROM_REG(data->temp1_input); - *nrels_mag = 2; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag >= 1) { - data->temp1_high = TEMP8_TO_REG(results[0]); - i2c_smbus_write_byte_data(client, LM63_REG_LOCAL_HIGH, - data->temp1_high); - } - } -} - -static void lm63_remote_temp(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results) -{ - struct lm63_data *data = client->data; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 3; /* magnitude */ - else if (operation == SENSORS_PROC_REAL_READ) { - lm63_update_client(client); - results[0] = TEMP11_FROM_REG(data->temp2_high); - results[1] = TEMP11_FROM_REG(data->temp2_low); - results[2] = TEMP11_FROM_REG(data->temp2_input); - *nrels_mag = 3; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag >= 1) { - data->temp2_high = TEMP11_TO_REG(results[0]); - i2c_smbus_write_byte_data(client, - LM63_REG_REMOTE_HIGH_MSB, - data->temp2_high >> 8); - i2c_smbus_write_byte_data(client, - LM63_REG_REMOTE_HIGH_LSB, - data->temp2_high & 0xFF); - } - if (*nrels_mag >= 2) { - data->temp2_low = TEMP11_TO_REG(results[1]); - i2c_smbus_write_byte_data(client, - LM63_REG_REMOTE_LOW_MSB, - data->temp2_low >> 8); - i2c_smbus_write_byte_data(client, - LM63_REG_REMOTE_LOW_LSB, - data->temp2_low & 0xFF); - } - } -} - -static void lm63_remote_tcrit(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results) -{ - struct lm63_data *data = client->data; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; /* magnitude */ - else if (operation == SENSORS_PROC_REAL_READ) { - lm63_update_client(client); - results[0] = TEMP8_FROM_REG(data->temp2_crit); - *nrels_mag = 1; - } -} - -static void lm63_remote_tcrit_hyst(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results) -{ - struct lm63_data *data = client->data; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; /* magnitude */ - else if (operation == SENSORS_PROC_REAL_READ) { - lm63_update_client(client); - results[0] = TEMP8_FROM_REG(data->temp2_crit) - - TEMP8_FROM_REG(data->temp2_crit_hyst); - *nrels_mag = 1; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag >= 1) { - data->temp2_crit_hyst = HYST_TO_REG(data->temp2_crit - - results[0]); - i2c_smbus_write_byte_data(client, - LM63_REG_REMOTE_TCRIT_HYST, - data->temp2_crit_hyst); - } - } -} - -static void lm63_alarms(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results) -{ - struct lm63_data *data = client->data; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; /* magnitude */ - else if (operation == SENSORS_PROC_REAL_READ) { - lm63_update_client(client); - results[0] = data->alarms; - *nrels_mag = 1; - } -} - -static void lm63_fan(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results) -{ - struct lm63_data *data = client->data; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; /* magnitude */ - else if (operation == SENSORS_PROC_REAL_READ) { - if (!(data->config & 0x04)) { /* tachometer disabled */ - results[0] = 0; - *nrels_mag = 1; - return; - } - - lm63_update_client(client); - results[0] = FAN_FROM_REG(data->fan1_low); - results[1] = FAN_FROM_REG(data->fan1_input); - *nrels_mag = 2; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if (!(data->config & 0x04)) /* tachometer disabled */ - return; - - if (*nrels_mag >= 1) { - data->fan1_low = FAN_TO_REG(results[0]); - i2c_smbus_write_byte_data(client, - LM63_REG_TACH_LIMIT_LSB, - data->fan1_low & 0xFF); - i2c_smbus_write_byte_data(client, - LM63_REG_TACH_LIMIT_MSB, - data->fan1_low >> 8); - } - } -} - -static void lm63_pwm(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results) -{ - struct lm63_data *data = client->data; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; /* magnitude */ - else if (operation == SENSORS_PROC_REAL_READ) { - lm63_update_client(client); - results[0] = data->pwm1_value >= 2 * data->pwm1_freq ? 255 : - (data->pwm1_value * 255 + data->pwm1_freq) / - (2 * data->pwm1_freq); - results[1] = data->config_fan & 0x20 ? 1 : 2; - *nrels_mag = 2; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag >= 1 && (data->config_fan & 0x20)) { - data->pwm1_value = results[0] <= 0 ? 0 : - results[0] >= 255 ? 2 * data->pwm1_freq : - (results[0] * data->pwm1_freq * 2 + 127) / 255; - i2c_smbus_write_byte_data(client, LM63_REG_PWM_VALUE, - data->pwm1_value); - } - } -} - -static int __init lm63_init(void) -{ - printk(KERN_INFO "lm63 version %s (%s)\n", LM_VERSION, LM_DATE); - return i2c_add_driver(&lm63_driver); -} - -static void __exit lm63_exit(void) -{ - i2c_del_driver(&lm63_driver); -} - -MODULE_AUTHOR("Jean Delvare "); -MODULE_DESCRIPTION("LM63 sensor driver"); -MODULE_LICENSE("GPL"); - -module_init(lm63_init); -module_exit(lm63_exit); diff --git a/kernel/chips/lm75.c b/kernel/chips/lm75.c deleted file mode 100644 index ee7f6038..00000000 --- a/kernel/chips/lm75.c +++ /dev/null @@ -1,327 +0,0 @@ -/* - lm75.c - Part of lm_sensors, Linux kernel modules for hardware - monitoring - Copyright (c) 1998, 1999 Frodo Looijaard - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#include -#include -#include -#include -#include -#include "version.h" -#include "lm75.h" - -/* Addresses to scan */ -static unsigned short normal_i2c[] = { SENSORS_I2C_END }; -static unsigned short normal_i2c_range[] = { 0x48, 0x4f, SENSORS_I2C_END }; -static unsigned int normal_isa[] = { SENSORS_ISA_END }; -static unsigned int normal_isa_range[] = { SENSORS_ISA_END }; - -/* Insmod parameters */ -SENSORS_INSMOD_1(lm75); - -/* Many LM75 constants specified below */ - -/* The LM75 registers */ -#define LM75_REG_TEMP 0x00 -#define LM75_REG_CONF 0x01 -#define LM75_REG_TEMP_HYST 0x02 -#define LM75_REG_TEMP_OS 0x03 - -/* Each client has this additional data */ -struct lm75_data { - struct i2c_client client; - int sysctl_id; - - struct semaphore update_lock; - char valid; /* !=0 if following fields are valid */ - unsigned long last_updated; /* In jiffies */ - - u16 temp, temp_os, temp_hyst; /* Register values */ -}; - -static int lm75_attach_adapter(struct i2c_adapter *adapter); -static int lm75_detect(struct i2c_adapter *adapter, int address, - unsigned short flags, int kind); -static void lm75_init_client(struct i2c_client *client); -static int lm75_detach_client(struct i2c_client *client); - -static int lm75_read_value(struct i2c_client *client, u8 reg); -static int lm75_write_value(struct i2c_client *client, u8 reg, u16 value); -static void lm75_temp(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void lm75_update_client(struct i2c_client *client); - - -/* This is the driver that will be inserted */ -static struct i2c_driver lm75_driver = { - .name = "LM75 sensor chip driver", - .id = I2C_DRIVERID_LM75, - .flags = I2C_DF_NOTIFY, - .attach_adapter = lm75_attach_adapter, - .detach_client = lm75_detach_client, -}; - -/* -- SENSORS SYSCTL START -- */ - -#define LM75_SYSCTL_TEMP 1200 /* Degrees Celsius * 10 */ - -/* -- SENSORS SYSCTL END -- */ - -/* These files are created for each detected LM75. This is just a template; - though at first sight, you might think we could use a statically - allocated list, we need some way to get back to the parent - which - is done through one of the 'extra' fields which are initialized - when a new copy is allocated. */ -static ctl_table lm75_dir_table_template[] = { - {LM75_SYSCTL_TEMP, "temp", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &lm75_temp}, - {0} -}; - -static int lm75_attach_adapter(struct i2c_adapter *adapter) -{ - return i2c_detect(adapter, &addr_data, lm75_detect); -} - -/* This function is called by i2c_detect */ -static int lm75_detect(struct i2c_adapter *adapter, int address, - unsigned short flags, int kind) -{ - int i; - struct i2c_client *new_client; - struct lm75_data *data; - int err = 0; - const char *type_name, *client_name; - - /* Make sure we aren't probing the ISA bus!! This is just a safety check - at this moment; i2c_detect really won't call us. */ -#ifdef DEBUG - if (i2c_is_isa_adapter(adapter)) { - printk - ("lm75.o: lm75_detect called for an ISA bus adapter?!?\n"); - return 0; - } -#endif - - if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA | - I2C_FUNC_SMBUS_WORD_DATA)) - goto error0; - - /* OK. For now, we presume we have a valid client. We now create the - client structure, even though we cannot fill it completely yet. - But it allows us to access lm75_{read,write}_value. */ - if (!(data = kmalloc(sizeof(struct lm75_data), GFP_KERNEL))) { - err = -ENOMEM; - goto error0; - } - - new_client = &data->client; - new_client->addr = address; - new_client->data = data; - new_client->adapter = adapter; - new_client->driver = &lm75_driver; - new_client->flags = 0; - - /* Now, we do the remaining detection. There is no identification- - dedicated register so we have to rely on several tricks: - unused bits, registers cycling over 8-address boundaries, - addresses 0x04-0x07 returning the last read value. - The cycling+unused addresses combination is not tested, - since it would significantly slow the detection down and would - hardly add any value. */ - if (kind < 0) { - int cur, conf, hyst, os; - - /* Unused addresses */ - cur = i2c_smbus_read_word_data(new_client, 0); - conf = i2c_smbus_read_byte_data(new_client, 1); - hyst = i2c_smbus_read_word_data(new_client, 2); - if (i2c_smbus_read_word_data(new_client, 4) != hyst - || i2c_smbus_read_word_data(new_client, 5) != hyst - || i2c_smbus_read_word_data(new_client, 6) != hyst - || i2c_smbus_read_word_data(new_client, 7) != hyst) - goto error1; - os = i2c_smbus_read_word_data(new_client, 3); - if (i2c_smbus_read_word_data(new_client, 4) != os - || i2c_smbus_read_word_data(new_client, 5) != os - || i2c_smbus_read_word_data(new_client, 6) != os - || i2c_smbus_read_word_data(new_client, 7) != os) - goto error1; - - /* Unused bits */ - if (conf & 0xe0) - goto error1; - - /* Addresses cycling */ - for (i = 8; i < 0xff; i += 8) - if (i2c_smbus_read_byte_data(new_client, i + 1) != conf - || i2c_smbus_read_word_data(new_client, i + 2) != hyst - || i2c_smbus_read_word_data(new_client, i + 3) != os) - goto error1; - } - - /* Determine the chip type - only one kind supported! */ - if (kind <= 0) - kind = lm75; - - if (kind == lm75) { - type_name = "lm75"; - client_name = "LM75 chip"; - } else { - pr_debug("lm75.o: Internal error: unknown kind (%d)\n", kind); - goto error1; - } - - /* Fill in the remaining client fields and put it into the global list */ - strcpy(new_client->name, client_name); - data->valid = 0; - init_MUTEX(&data->update_lock); - - /* Tell the I2C layer a new client has arrived */ - if ((err = i2c_attach_client(new_client))) - goto error3; - - /* Register a new directory entry with module sensors */ - if ((i = i2c_register_entry(new_client, type_name, - lm75_dir_table_template, - THIS_MODULE)) < 0) { - err = i; - goto error4; - } - data->sysctl_id = i; - - lm75_init_client(new_client); - return 0; - -/* OK, this is not exactly good programming practice, usually. But it is - very code-efficient in this case. */ - - error4: - i2c_detach_client(new_client); - error3: - error1: - kfree(data); - error0: - return err; -} - -static int lm75_detach_client(struct i2c_client *client) -{ - struct lm75_data *data = client->data; - - i2c_deregister_entry(data->sysctl_id); - i2c_detach_client(client); - kfree(client->data); - return 0; -} - -/* All registers are word-sized, except for the configuration register. - LM75 uses a high-byte first convention, which is exactly opposite to - the SMBus standard. */ -static int lm75_read_value(struct i2c_client *client, u8 reg) -{ - if (reg == LM75_REG_CONF) - return i2c_smbus_read_byte_data(client, reg); - else - return swab16(i2c_smbus_read_word_data(client, reg)); -} - -static int lm75_write_value(struct i2c_client *client, u8 reg, u16 value) -{ - if (reg == LM75_REG_CONF) - return i2c_smbus_write_byte_data(client, reg, value); - else - return i2c_smbus_write_word_data(client, reg, swab16(value)); -} - -static void lm75_init_client(struct i2c_client *client) -{ - int i; - - /* Enable if in shutdown mode */ - i = lm75_read_value(client, LM75_REG_CONF); - if (i >= 0 && (i & 0x01)) - lm75_write_value(client, LM75_REG_CONF, i & 0xfe); -} - -static void lm75_update_client(struct i2c_client *client) -{ - struct lm75_data *data = client->data; - - down(&data->update_lock); - - if ((jiffies - data->last_updated > HZ + HZ / 2) || - (jiffies < data->last_updated) || !data->valid) { - pr_debug("Starting lm75 update\n"); - - data->temp = lm75_read_value(client, LM75_REG_TEMP); - data->temp_os = lm75_read_value(client, LM75_REG_TEMP_OS); - data->temp_hyst = - lm75_read_value(client, LM75_REG_TEMP_HYST); - data->last_updated = jiffies; - data->valid = 1; - } - - up(&data->update_lock); -} - - -void lm75_temp(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct lm75_data *data = client->data; - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 1; - else if (operation == SENSORS_PROC_REAL_READ) { - lm75_update_client(client); - results[0] = LM75_TEMP_FROM_REG(data->temp_os); - results[1] = LM75_TEMP_FROM_REG(data->temp_hyst); - results[2] = LM75_TEMP_FROM_REG(data->temp); - *nrels_mag = 3; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag >= 1) { - data->temp_os = LM75_TEMP_TO_REG(results[0]); - lm75_write_value(client, LM75_REG_TEMP_OS, - data->temp_os); - } - if (*nrels_mag >= 2) { - data->temp_hyst = LM75_TEMP_TO_REG(results[1]); - lm75_write_value(client, LM75_REG_TEMP_HYST, - data->temp_hyst); - } - } -} - -static int __init sm_lm75_init(void) -{ - printk(KERN_INFO "lm75.o version %s (%s)\n", LM_VERSION, LM_DATE); - return i2c_add_driver(&lm75_driver); -} - -static void __exit sm_lm75_exit(void) -{ - i2c_del_driver(&lm75_driver); -} - -MODULE_AUTHOR("Frodo Looijaard "); -MODULE_DESCRIPTION("LM75 driver"); -MODULE_LICENSE("GPL"); - -module_init(sm_lm75_init); -module_exit(sm_lm75_exit); diff --git a/kernel/chips/lm75.h b/kernel/chips/lm75.h deleted file mode 100644 index 2180f976..00000000 --- a/kernel/chips/lm75.h +++ /dev/null @@ -1,49 +0,0 @@ -/* - lm75.h - Part of lm_sensors, Linux kernel modules for hardware - monitoring - Copyright (c) 2003 Mark M. Hoffman - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -/* - This file contains common code for encoding/decoding LM75 type - temperature readings, which are emulated by many of the chips - we support. As the user is unlikely to load more than one driver - which contains this code, we don't worry about the wasted space. -*/ - -#include - -/* straight from the datasheet */ -#define LM75_TEMP_MIN (-550) -#define LM75_TEMP_MAX 1250 - -/* TEMP: 0.1C/bit (-55C to +125C) - REG: (0.5C/bit, two's complement) << 7 */ -static inline u16 LM75_TEMP_TO_REG(int temp) -{ - int ntemp = SENSORS_LIMIT(temp, LM75_TEMP_MIN, LM75_TEMP_MAX); - ntemp += (ntemp<0 ? -2 : 2); - return (u16)((ntemp / 5) << 7); -} - -static inline int LM75_TEMP_FROM_REG(u16 reg) -{ - /* use integer division instead of equivalent right shift to - guarantee arithmetic shift and preserve the sign */ - return ((s16)reg / 128) * 5; -} - diff --git a/kernel/chips/lm78.c b/kernel/chips/lm78.c deleted file mode 100644 index 055dde49..00000000 --- a/kernel/chips/lm78.c +++ /dev/null @@ -1,725 +0,0 @@ -/* - lm78.c - Part of lm_sensors, Linux kernel modules for hardware - monitoring - Copyright (c) 1998, 1999 Frodo Looijaard - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#include -#include -#include -#include -#include -#include -#include -#include "version.h" - -MODULE_LICENSE("GPL"); - -/* Addresses to scan */ -static unsigned short normal_i2c[] = { SENSORS_I2C_END }; -static unsigned short normal_i2c_range[] = { 0x20, 0x2f, SENSORS_I2C_END }; -static unsigned int normal_isa[] = { 0x0290, SENSORS_ISA_END }; -static unsigned int normal_isa_range[] = { SENSORS_ISA_END }; - -/* Insmod parameters */ -SENSORS_INSMOD_3(lm78, lm78j, lm79); - -/* Many LM78 constants specified below */ - -/* Length of ISA address segment */ -#define LM78_EXTENT 8 - -/* Where are the ISA address/data registers relative to the base address */ -#define LM78_ADDR_REG_OFFSET 5 -#define LM78_DATA_REG_OFFSET 6 - -/* The LM78 registers */ -#define LM78_REG_IN_MAX(nr) (0x2b + (nr) * 2) -#define LM78_REG_IN_MIN(nr) (0x2c + (nr) * 2) -#define LM78_REG_IN(nr) (0x20 + (nr)) - -#define LM78_REG_FAN_MIN(nr) (0x3a + (nr)) -#define LM78_REG_FAN(nr) (0x27 + (nr)) - -#define LM78_REG_TEMP 0x27 -#define LM78_REG_TEMP_OVER 0x39 -#define LM78_REG_TEMP_HYST 0x3a - -#define LM78_REG_ALARM1 0x41 -#define LM78_REG_ALARM2 0x42 - -#define LM78_REG_VID_FANDIV 0x47 - -#define LM78_REG_CONFIG 0x40 -#define LM78_REG_CHIPID 0x49 -#define LM78_REG_I2C_ADDR 0x48 - - -/* Conversions. Limit checking is only done on the TO_REG - variants. Note that you should be a bit careful with which arguments - these macros are called: arguments may be evaluated more than once. - Fixing this is just not worth it. */ -#define IN_TO_REG(val) (SENSORS_LIMIT((((val) * 10 + 8)/16),0,255)) -#define IN_FROM_REG(val) (((val) * 16 + 5) / 10) - -static inline u8 FAN_TO_REG(long rpm, int div) -{ - if (rpm <= 0) - return 255; - return SENSORS_LIMIT((1350000 + rpm * div / 2) / (rpm * div), 1, - 254); -} - -#define FAN_FROM_REG(val,div) ((val)==0?-1:(val)==255?0:1350000/((val)*(div))) - -#define TEMP_TO_REG(val) (SENSORS_LIMIT(((val)<0?(((val)-5)/10):\ - ((val)+5)/10), -128, 127)) -#define TEMP_FROM_REG(val) ((val)*10) - -#define VID_FROM_REG(val) ((val)==0x1f?0:(val)>=0x10?510-(val)*10:\ - 205-(val)*5) - -#define DIV_TO_REG(val) ((val)==8?3:(val)==4?2:(val)==1?0:1) -#define DIV_FROM_REG(val) (1 << (val)) - -/* There are some complications in a module like this. First off, LM78 chips - may be both present on the SMBus and the ISA bus, and we have to handle - those cases separately at some places. Second, there might be several - LM78 chips available (well, actually, that is probably never done; but - it is a clean illustration of how to handle a case like that). Finally, - a specific chip may be attached to *both* ISA and SMBus, and we would - not like to detect it double. Fortunately, in the case of the LM78 at - least, a register tells us what SMBus address we are on, so that helps - a bit - except if there could be more than one SMBus. Groan. No solution - for this yet. */ - -/* This module may seem overly long and complicated. In fact, it is not so - bad. Quite a lot of bookkeeping is done. A real driver can often cut - some corners. */ - -/* For each registered LM78, we need to keep some data in memory. It is - dynamically allocated, at the same time when a new lm78 client is - allocated. */ -struct lm78_data { - struct i2c_client client; - struct semaphore lock; - int sysctl_id; - enum chips type; - - struct semaphore update_lock; - char valid; /* !=0 if following fields are valid */ - unsigned long last_updated; /* In jiffies */ - - u8 in[7]; /* Register value */ - u8 in_max[7]; /* Register value */ - u8 in_min[7]; /* Register value */ - u8 fan[3]; /* Register value */ - u8 fan_min[3]; /* Register value */ - s8 temp; /* Register value */ - s8 temp_over; /* Register value */ - s8 temp_hyst; /* Register value */ - u8 fan_div[3]; /* Register encoding, shifted right */ - u8 vid; /* Register encoding, combined */ - u16 alarms; /* Register encoding, combined */ -}; - - -static int lm78_attach_adapter(struct i2c_adapter *adapter); -static int lm78_detect(struct i2c_adapter *adapter, int address, - unsigned short flags, int kind); -static int lm78_detach_client(struct i2c_client *client); - -static int lm78_read_value(struct i2c_client *client, u8 register); -static int lm78_write_value(struct i2c_client *client, u8 register, - u8 value); -static void lm78_update_client(struct i2c_client *client); -static void lm78_init_client(struct i2c_client *client); - - -static void lm78_in(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results); -static void lm78_fan(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void lm78_temp(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void lm78_vid(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void lm78_alarms(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void lm78_fan_div(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); - -static struct i2c_driver lm78_driver = { - .name = "LM78(-J) and LM79 sensor driver", - .id = I2C_DRIVERID_LM78, - .flags = I2C_DF_NOTIFY, - .attach_adapter = lm78_attach_adapter, - .detach_client = lm78_detach_client, -}; - -/* The /proc/sys entries */ - -/* -- SENSORS SYSCTL START -- */ -#define LM78_SYSCTL_IN0 1000 /* Volts * 100 */ -#define LM78_SYSCTL_IN1 1001 -#define LM78_SYSCTL_IN2 1002 -#define LM78_SYSCTL_IN3 1003 -#define LM78_SYSCTL_IN4 1004 -#define LM78_SYSCTL_IN5 1005 -#define LM78_SYSCTL_IN6 1006 -#define LM78_SYSCTL_FAN1 1101 /* Rotations/min */ -#define LM78_SYSCTL_FAN2 1102 -#define LM78_SYSCTL_FAN3 1103 -#define LM78_SYSCTL_TEMP 1200 /* Degrees Celsius * 10 */ -#define LM78_SYSCTL_VID 1300 /* Volts * 100 */ -#define LM78_SYSCTL_FAN_DIV 2000 /* 1, 2, 4 or 8 */ -#define LM78_SYSCTL_ALARMS 2001 /* bitvector */ - -#define LM78_ALARM_IN0 0x0001 -#define LM78_ALARM_IN1 0x0002 -#define LM78_ALARM_IN2 0x0004 -#define LM78_ALARM_IN3 0x0008 -#define LM78_ALARM_IN4 0x0100 -#define LM78_ALARM_IN5 0x0200 -#define LM78_ALARM_IN6 0x0400 -#define LM78_ALARM_FAN1 0x0040 -#define LM78_ALARM_FAN2 0x0080 -#define LM78_ALARM_FAN3 0x0800 -#define LM78_ALARM_TEMP 0x0010 -#define LM78_ALARM_BTI 0x0020 -#define LM78_ALARM_CHAS 0x1000 -#define LM78_ALARM_FIFO 0x2000 -#define LM78_ALARM_SMI_IN 0x4000 - -/* -- SENSORS SYSCTL END -- */ - -/* These files are created for each detected LM78. This is just a template; - though at first sight, you might think we could use a statically - allocated list, we need some way to get back to the parent - which - is done through one of the 'extra' fields which are initialized - when a new copy is allocated. */ -static ctl_table lm78_dir_table_template[] = { - {LM78_SYSCTL_IN0, "in0", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &lm78_in}, - {LM78_SYSCTL_IN1, "in1", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &lm78_in}, - {LM78_SYSCTL_IN2, "in2", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &lm78_in}, - {LM78_SYSCTL_IN3, "in3", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &lm78_in}, - {LM78_SYSCTL_IN4, "in4", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &lm78_in}, - {LM78_SYSCTL_IN5, "in5", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &lm78_in}, - {LM78_SYSCTL_IN6, "in6", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &lm78_in}, - {LM78_SYSCTL_FAN1, "fan1", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &lm78_fan}, - {LM78_SYSCTL_FAN2, "fan2", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &lm78_fan}, - {LM78_SYSCTL_FAN3, "fan3", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &lm78_fan}, - {LM78_SYSCTL_TEMP, "temp", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &lm78_temp}, - {LM78_SYSCTL_VID, "vid", NULL, 0, 0444, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &lm78_vid}, - {LM78_SYSCTL_FAN_DIV, "fan_div", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &lm78_fan_div}, - {LM78_SYSCTL_ALARMS, "alarms", NULL, 0, 0444, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &lm78_alarms}, - {0} -}; - - -/* This function is called when: - * lm78_driver is inserted (when this module is loaded), for each - available adapter - * when a new adapter is inserted (and lm78_driver is still present) */ -static int lm78_attach_adapter(struct i2c_adapter *adapter) -{ - return i2c_detect(adapter, &addr_data, lm78_detect); -} - -/* This function is called by i2c_detect */ -static int lm78_detect(struct i2c_adapter *adapter, int address, - unsigned short flags, int kind) -{ - int i; - struct i2c_client *new_client; - struct lm78_data *data; - int err = 0; - const char *type_name = ""; - const char *client_name = ""; - int is_isa = i2c_is_isa_adapter(adapter); - - if (!is_isa - && !i2c_check_functionality(adapter, - I2C_FUNC_SMBUS_BYTE_DATA)) goto - ERROR0; - - if (is_isa) { - if (check_region(address, LM78_EXTENT)) - goto ERROR0; - } - - /* Probe whether there is anything available on this address. Already - done for SMBus clients */ - if (kind < 0) { - if (is_isa) { - -#define REALLY_SLOW_IO - /* We need the timeouts for at least some LM78-like chips. But only - if we read 'undefined' registers. */ - i = inb_p(address + 1); - if (inb_p(address + 2) != i) - goto ERROR0; - if (inb_p(address + 3) != i) - goto ERROR0; - if (inb_p(address + 7) != i) - goto ERROR0; -#undef REALLY_SLOW_IO - - /* Let's just hope nothing breaks here */ - i = inb_p(address + 5) & 0x7f; - outb_p(~i & 0x7f, address + 5); - if ((inb_p(address + 5) & 0x7f) != (~i & 0x7f)) { - outb_p(i, address + 5); - return 0; - } - } - } - - /* OK. For now, we presume we have a valid client. We now create the - client structure, even though we cannot fill it completely yet. - But it allows us to access lm78_{read,write}_value. */ - - if (!(data = kmalloc(sizeof(struct lm78_data), GFP_KERNEL))) { - err = -ENOMEM; - goto ERROR0; - } - - new_client = &data->client; - if (is_isa) - init_MUTEX(&data->lock); - new_client->addr = address; - new_client->data = data; - new_client->adapter = adapter; - new_client->driver = &lm78_driver; - new_client->flags = 0; - - /* Now, we do the remaining detection. */ - - if (kind < 0) { - if (lm78_read_value(new_client, LM78_REG_CONFIG) & 0x80) - goto ERROR1; - if (!is_isa - && (lm78_read_value(new_client, LM78_REG_I2C_ADDR) != - address)) goto ERROR1; - /* Explicitly prevent the misdetection of Winbond chips */ - i = lm78_read_value(new_client, 0x4f); - if (i == 0xa3 || i == 0x5c) - goto ERROR1; - } - - /* Determine the chip type. */ - if (kind <= 0) { - i = lm78_read_value(new_client, LM78_REG_CHIPID); - if (i == 0x00 || i == 0x20) - kind = lm78; - else if (i == 0x40) - kind = lm78j; - else if ((i & 0xfe) == 0xc0) - kind = lm79; - else { - if (kind == 0) - printk - ("lm78.o: Ignoring 'force' parameter for unknown chip at " - "adapter %d, address 0x%02x\n", - i2c_adapter_id(adapter), address); - goto ERROR1; - } - } - - if (kind == lm78) { - type_name = "lm78"; - client_name = "LM78 chip"; - } else if (kind == lm78j) { - type_name = "lm78-j"; - client_name = "LM78-J chip"; - } else if (kind == lm79) { - type_name = "lm79"; - client_name = "LM79 chip"; - } else { -#ifdef DEBUG - printk("lm78.o: Internal error: unknown kind (%d)\n", - kind); -#endif - goto ERROR1; - } - - /* Reserve the ISA region */ - if (is_isa) - request_region(address, LM78_EXTENT, type_name); - - /* Fill in the remaining client fields and put it into the global list */ - strcpy(new_client->name, client_name); - data->type = kind; - data->valid = 0; - init_MUTEX(&data->update_lock); - - /* Tell the I2C layer a new client has arrived */ - if ((err = i2c_attach_client(new_client))) - goto ERROR3; - - /* Register a new directory entry with module sensors */ - if ((i = i2c_register_entry(new_client, - type_name, - lm78_dir_table_template, - THIS_MODULE)) < 0) { - err = i; - goto ERROR4; - } - data->sysctl_id = i; - - /* Initialize the LM78 chip */ - lm78_init_client(new_client); - return 0; - -/* OK, this is not exactly good programming practice, usually. But it is - very code-efficient in this case. */ - - ERROR4: - i2c_detach_client(new_client); - ERROR3: - if (is_isa) - release_region(address, LM78_EXTENT); - ERROR1: - kfree(data); - ERROR0: - return err; -} - -static int lm78_detach_client(struct i2c_client *client) -{ - int err; - - i2c_deregister_entry(((struct lm78_data *) (client->data))-> - sysctl_id); - - if ((err = i2c_detach_client(client))) { - printk - ("lm78.o: Client deregistration failed, client not detached.\n"); - return err; - } - - if(i2c_is_isa_client(client)) - release_region(client->addr, LM78_EXTENT); - kfree(client->data); - - return 0; -} - -/* The SMBus locks itself, but ISA access must be locked explicitly! - We don't want to lock the whole ISA bus, so we lock each client - separately. - We ignore the LM78 BUSY flag at this moment - it could lead to deadlocks, - would slow down the LM78 access and should not be necessary. - There are some ugly typecasts here, but the good new is - they should - nowhere else be necessary! */ -static int lm78_read_value(struct i2c_client *client, u8 reg) -{ - int res; - if (i2c_is_isa_client(client)) { - down(&(((struct lm78_data *) (client->data))->lock)); - outb_p(reg, client->addr + LM78_ADDR_REG_OFFSET); - res = inb_p(client->addr + LM78_DATA_REG_OFFSET); - up(&(((struct lm78_data *) (client->data))->lock)); - return res; - } else - return i2c_smbus_read_byte_data(client, reg); -} - -/* The SMBus locks itself, but ISA access muse be locked explicitly! - We don't want to lock the whole ISA bus, so we lock each client - separately. - We ignore the LM78 BUSY flag at this moment - it could lead to deadlocks, - would slow down the LM78 access and should not be necessary. - There are some ugly typecasts here, but the good new is - they should - nowhere else be necessary! */ -static int lm78_write_value(struct i2c_client *client, u8 reg, u8 value) -{ - if (i2c_is_isa_client(client)) { - down(&(((struct lm78_data *) (client->data))->lock)); - outb_p(reg, client->addr + LM78_ADDR_REG_OFFSET); - outb_p(value, client->addr + LM78_DATA_REG_OFFSET); - up(&(((struct lm78_data *) (client->data))->lock)); - return 0; - } else - return i2c_smbus_write_byte_data(client, reg, value); -} - -/* Called when we have found a new LM78. */ -static void lm78_init_client(struct i2c_client *client) -{ - u8 config = lm78_read_value(client, LM78_REG_CONFIG); - - /* Start monitoring */ - if (!(config & 0x01)) - lm78_write_value(client, LM78_REG_CONFIG, - (config & 0xf7) | 0x01); -} - -static void lm78_update_client(struct i2c_client *client) -{ - struct lm78_data *data = client->data; - int i; - - down(&data->update_lock); - - if ((jiffies - data->last_updated > HZ + HZ / 2) || - (jiffies < data->last_updated) || !data->valid) { - -#ifdef DEBUG - printk("Starting lm78 update\n"); -#endif - for (i = 0; i <= 6; i++) { - data->in[i] = - lm78_read_value(client, LM78_REG_IN(i)); - data->in_min[i] = - lm78_read_value(client, LM78_REG_IN_MIN(i)); - data->in_max[i] = - lm78_read_value(client, LM78_REG_IN_MAX(i)); - } - for (i = 1; i <= 3; i++) { - data->fan[i - 1] = - lm78_read_value(client, LM78_REG_FAN(i)); - data->fan_min[i - 1] = - lm78_read_value(client, LM78_REG_FAN_MIN(i)); - } - data->temp = lm78_read_value(client, LM78_REG_TEMP); - data->temp_over = - lm78_read_value(client, LM78_REG_TEMP_OVER); - data->temp_hyst = - lm78_read_value(client, LM78_REG_TEMP_HYST); - i = lm78_read_value(client, LM78_REG_VID_FANDIV); - data->vid = i & 0x0f; - if (data->type == lm79) - data->vid |= - (lm78_read_value(client, LM78_REG_CHIPID) & - 0x01) << 4; - else - data->vid |= 0x10; - data->fan_div[0] = (i >> 4) & 0x03; - data->fan_div[1] = i >> 6; - data->alarms = lm78_read_value(client, LM78_REG_ALARM1) + - (lm78_read_value(client, LM78_REG_ALARM2) << 8); - data->last_updated = jiffies; - data->valid = 1; - - data->fan_div[2] = 1; - } - - up(&data->update_lock); -} - - -/* The next few functions are the call-back functions of the /proc/sys and - sysctl files. Which function is used is defined in the ctl_table in - the extra1 field. - Each function must return the magnitude (power of 10 to divide the date - with) if it is called with operation==SENSORS_PROC_REAL_INFO. It must - put a maximum of *nrels elements in results reflecting the data of this - file, and set *nrels to the number it actually put in it, if operation== - SENSORS_PROC_REAL_READ. Finally, it must get upto *nrels elements from - results and write them to the chip, if operations==SENSORS_PROC_REAL_WRITE. - Note that on SENSORS_PROC_REAL_READ, I do not check whether results is - large enough (by checking the incoming value of *nrels). This is not very - good practice, but as long as you put less than about 5 values in results, - you can assume it is large enough. */ -void lm78_in(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct lm78_data *data = client->data; - int nr = ctl_name - LM78_SYSCTL_IN0; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 2; - else if (operation == SENSORS_PROC_REAL_READ) { - lm78_update_client(client); - results[0] = IN_FROM_REG(data->in_min[nr]); - results[1] = IN_FROM_REG(data->in_max[nr]); - results[2] = IN_FROM_REG(data->in[nr]); - *nrels_mag = 3; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag >= 1) { - data->in_min[nr] = IN_TO_REG(results[0]); - lm78_write_value(client, LM78_REG_IN_MIN(nr), - data->in_min[nr]); - } - if (*nrels_mag >= 2) { - data->in_max[nr] = IN_TO_REG(results[1]); - lm78_write_value(client, LM78_REG_IN_MAX(nr), - data->in_max[nr]); - } - } -} - -void lm78_fan(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct lm78_data *data = client->data; - int nr = ctl_name - LM78_SYSCTL_FAN1 + 1; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - lm78_update_client(client); - results[0] = FAN_FROM_REG(data->fan_min[nr - 1], - DIV_FROM_REG(data-> - fan_div[nr - 1])); - results[1] = - FAN_FROM_REG(data->fan[nr - 1], - DIV_FROM_REG(data->fan_div[nr - 1])); - *nrels_mag = 2; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag >= 1) { - data->fan_min[nr - 1] = FAN_TO_REG(results[0], - DIV_FROM_REG - (data-> - fan_div[nr - - 1])); - lm78_write_value(client, LM78_REG_FAN_MIN(nr), - data->fan_min[nr - 1]); - } - } -} - - -void lm78_temp(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct lm78_data *data = client->data; - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 1; - else if (operation == SENSORS_PROC_REAL_READ) { - lm78_update_client(client); - results[0] = TEMP_FROM_REG(data->temp_over); - results[1] = TEMP_FROM_REG(data->temp_hyst); - results[2] = TEMP_FROM_REG(data->temp); - *nrels_mag = 3; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag >= 1) { - data->temp_over = TEMP_TO_REG(results[0]); - lm78_write_value(client, LM78_REG_TEMP_OVER, - data->temp_over); - } - if (*nrels_mag >= 2) { - data->temp_hyst = TEMP_TO_REG(results[1]); - lm78_write_value(client, LM78_REG_TEMP_HYST, - data->temp_hyst); - } - } -} - -void lm78_vid(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct lm78_data *data = client->data; - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 2; - else if (operation == SENSORS_PROC_REAL_READ) { - lm78_update_client(client); - results[0] = VID_FROM_REG(data->vid); - *nrels_mag = 1; - } -} - -void lm78_alarms(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct lm78_data *data = client->data; - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - lm78_update_client(client); - results[0] = data->alarms; - *nrels_mag = 1; - } -} - -/* Note: we save and restore the fan minimum here, because its value is - determined in part by the fan divisor. This follows the principle of - least surprise: the user doesn't expect the fan minimum to change just - because the divisor changed. */ -void lm78_fan_div(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct lm78_data *data = client->data; - int old, min; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - lm78_update_client(client); - results[0] = DIV_FROM_REG(data->fan_div[0]); - results[1] = DIV_FROM_REG(data->fan_div[1]); - results[2] = 2; - *nrels_mag = 3; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - old = lm78_read_value(client, LM78_REG_VID_FANDIV); - if (*nrels_mag >= 2) { - min = FAN_FROM_REG(data->fan_min[1], - DIV_FROM_REG(data->fan_div[1])); - data->fan_div[1] = DIV_TO_REG(results[1]); - old = (old & 0x3f) | (data->fan_div[1] << 6); - data->fan_min[1] = FAN_TO_REG(min, - DIV_FROM_REG(data->fan_div[1])); - lm78_write_value(client, LM78_REG_FAN_MIN(2), - data->fan_min[1]); - } - if (*nrels_mag >= 1) { - min = FAN_FROM_REG(data->fan_min[0], - DIV_FROM_REG(data->fan_div[0])); - data->fan_div[0] = DIV_TO_REG(results[0]); - old = (old & 0xcf) | (data->fan_div[0] << 4); - data->fan_min[0] = FAN_TO_REG(min, - DIV_FROM_REG(data->fan_div[0])); - lm78_write_value(client, LM78_REG_FAN_MIN(1), - data->fan_min[0]); - lm78_write_value(client, LM78_REG_VID_FANDIV, old); - } - } -} - -static int __init sm_lm78_init(void) -{ - printk("lm78.o version %s (%s)\n", LM_VERSION, LM_DATE); - return i2c_add_driver(&lm78_driver); -} - -static void __exit sm_lm78_exit(void) -{ - i2c_del_driver(&lm78_driver); -} - - - -MODULE_AUTHOR("Frodo Looijaard "); -MODULE_DESCRIPTION("LM78, LM78-J and LM79 driver"); - -module_init(sm_lm78_init); -module_exit(sm_lm78_exit); diff --git a/kernel/chips/lm80.c b/kernel/chips/lm80.c deleted file mode 100644 index c3c91bdd..00000000 --- a/kernel/chips/lm80.c +++ /dev/null @@ -1,599 +0,0 @@ -/* - lm80.c - Part of lm_sensors, Linux kernel modules for hardware - monitoring - Copyright (c) 1998, 1999 Frodo Looijaard - and Philip Edelbrock - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#include -#include -#include -#include -#include -#include "version.h" - -MODULE_LICENSE("GPL"); - -/* Addresses to scan */ -static unsigned short normal_i2c[] = { SENSORS_I2C_END }; -static unsigned short normal_i2c_range[] = { 0x20, 0x2f, SENSORS_I2C_END }; -static unsigned int normal_isa[] = { SENSORS_ISA_END }; -static unsigned int normal_isa_range[] = { SENSORS_ISA_END }; - -/* Insmod parameters */ -SENSORS_INSMOD_1(lm80); - -/* Many LM80 constants specified below */ - -/* The LM80 registers */ -#define LM80_REG_IN_MAX(nr) (0x2a + (nr) * 2) -#define LM80_REG_IN_MIN(nr) (0x2b + (nr) * 2) -#define LM80_REG_IN(nr) (0x20 + (nr)) - -#define LM80_REG_FAN1_MIN 0x3c -#define LM80_REG_FAN2_MIN 0x3d -#define LM80_REG_FAN1 0x28 -#define LM80_REG_FAN2 0x29 - -#define LM80_REG_TEMP 0x27 -#define LM80_REG_TEMP_HOT_MAX 0x38 -#define LM80_REG_TEMP_HOT_HYST 0x39 -#define LM80_REG_TEMP_OS_MAX 0x3a -#define LM80_REG_TEMP_OS_HYST 0x3b - -#define LM80_REG_CONFIG 0x00 -#define LM80_REG_ALARM1 0x01 -#define LM80_REG_ALARM2 0x02 -#define LM80_REG_MASK1 0x03 -#define LM80_REG_MASK2 0x04 -#define LM80_REG_FANDIV 0x05 -#define LM80_REG_RES 0x06 - - -/* Conversions. Rounding and limit checking is only done on the TO_REG - variants. Note that you should be a bit careful with which arguments - these macros are called: arguments may be evaluated more than once. - Fixing this is just not worth it. */ - -#define IN_TO_REG(val) (SENSORS_LIMIT((val),0,255)) -#define IN_FROM_REG(val) (val) - -static inline unsigned char FAN_TO_REG(unsigned rpm, unsigned div) -{ - if (rpm == 0) - return 255; - rpm = SENSORS_LIMIT(rpm, 1, 1000000); - return SENSORS_LIMIT((1350000 + rpm * div / 2) / (rpm * div), 1, - 254); -} - -#define FAN_FROM_REG(val,div) ((val)==0?-1:\ - (val)==255?0:1350000/((div)*(val))) - -static inline long TEMP_FROM_REG(u16 temp) -{ - long res; - - temp >>= 4; - if (temp < 0x0800) - res = 625 * (long) temp; - else - res = ((long) temp - 0x01000) * 625; - - return res / 100; -} - -#define TEMP_LIMIT_FROM_REG(val) (((val)>0x80?(val)-0x100:(val))*100) - -#define TEMP_LIMIT_TO_REG(val) SENSORS_LIMIT(((val)<0?(((val)-50)/100):\ - ((val)+50)/100), \ - 0,255) - -#define DIV_FROM_REG(val) (1 << (val)) -#define DIV_TO_REG(val) ((val)==8?3:(val)==4?2:(val)==1?0:1) - -struct lm80_data { - struct i2c_client client; - int sysctl_id; - - struct semaphore update_lock; - char valid; /* !=0 if following fields are valid */ - unsigned long last_updated; /* In jiffies */ - - u8 in[7]; /* Register value */ - u8 in_max[7]; /* Register value */ - u8 in_min[7]; /* Register value */ - u8 fan[2]; /* Register value */ - u8 fan_min[2]; /* Register value */ - u8 fan_div[2]; /* Register encoding, shifted right */ - u16 temp; /* Register values, shifted right */ - u8 temp_hot_max; /* Register value */ - u8 temp_hot_hyst; /* Register value */ - u8 temp_os_max; /* Register value */ - u8 temp_os_hyst; /* Register value */ - u16 alarms; /* Register encoding, combined */ -}; - - - -static int lm80_attach_adapter(struct i2c_adapter *adapter); -static int lm80_detect(struct i2c_adapter *adapter, int address, - unsigned short flags, int kind); -static int lm80_detach_client(struct i2c_client *client); - -static int lm80_read_value(struct i2c_client *client, u8 reg); -static int lm80_write_value(struct i2c_client *client, u8 reg, u8 value); -static void lm80_update_client(struct i2c_client *client); -static void lm80_init_client(struct i2c_client *client); - - -static void lm80_in(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results); -static void lm80_fan(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void lm80_temp(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void lm80_alarms(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void lm80_fan_div(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); - -static struct i2c_driver lm80_driver = { - .name = "LM80 sensor driver", - .id = I2C_DRIVERID_LM80, - .flags = I2C_DF_NOTIFY, - .attach_adapter = lm80_attach_adapter, - .detach_client = lm80_detach_client, -}; - -/* The /proc/sys entries */ - -/* -- SENSORS SYSCTL START -- */ - -#define LM80_SYSCTL_IN0 1000 /* Volts * 100 */ -#define LM80_SYSCTL_IN1 1001 -#define LM80_SYSCTL_IN2 1002 -#define LM80_SYSCTL_IN3 1003 -#define LM80_SYSCTL_IN4 1004 -#define LM80_SYSCTL_IN5 1005 -#define LM80_SYSCTL_IN6 1006 -#define LM80_SYSCTL_FAN1 1101 /* Rotations/min */ -#define LM80_SYSCTL_FAN2 1102 -#define LM80_SYSCTL_TEMP 1250 /* Degrees Celsius * 100 */ -#define LM80_SYSCTL_FAN_DIV 2000 /* 1, 2, 4 or 8 */ -#define LM80_SYSCTL_ALARMS 2001 /* bitvector */ - -#define LM80_ALARM_IN0 0x0001 -#define LM80_ALARM_IN1 0x0002 -#define LM80_ALARM_IN2 0x0004 -#define LM80_ALARM_IN3 0x0008 -#define LM80_ALARM_IN4 0x0010 -#define LM80_ALARM_IN5 0x0020 -#define LM80_ALARM_IN6 0x0040 -#define LM80_ALARM_FAN1 0x0400 -#define LM80_ALARM_FAN2 0x0800 -#define LM80_ALARM_TEMP_HOT 0x0100 -#define LM80_ALARM_TEMP_OS 0x2000 -#define LM80_ALARM_CHAS 0x1000 -#define LM80_ALARM_BTI 0x0200 -#define LM80_ALARM_INT_IN 0x0080 - -/* -- SENSORS SYSCTL END -- */ - -/* These files are created for each detected LM80. This is just a template; - though at first sight, you might think we could use a statically - allocated list, we need some way to get back to the parent - which - is done through one of the 'extra' fields which are initialized - when a new copy is allocated. */ -static ctl_table lm80_dir_table_template[] = { - {LM80_SYSCTL_IN0, "in0", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &lm80_in}, - {LM80_SYSCTL_IN1, "in1", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &lm80_in}, - {LM80_SYSCTL_IN2, "in2", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &lm80_in}, - {LM80_SYSCTL_IN3, "in3", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &lm80_in}, - {LM80_SYSCTL_IN4, "in4", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &lm80_in}, - {LM80_SYSCTL_IN5, "in5", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &lm80_in}, - {LM80_SYSCTL_IN6, "in6", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &lm80_in}, - {LM80_SYSCTL_FAN1, "fan1", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &lm80_fan}, - {LM80_SYSCTL_FAN2, "fan2", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &lm80_fan}, - {LM80_SYSCTL_TEMP, "temp", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &lm80_temp}, - {LM80_SYSCTL_FAN_DIV, "fan_div", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &lm80_fan_div}, - {LM80_SYSCTL_ALARMS, "alarms", NULL, 0, 0444, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &lm80_alarms}, - {0} -}; - -static int lm80_attach_adapter(struct i2c_adapter *adapter) -{ - return i2c_detect(adapter, &addr_data, lm80_detect); -} - -static int lm80_detect(struct i2c_adapter *adapter, int address, - unsigned short flags, int kind) -{ - int i, cur; - struct i2c_client *new_client; - struct lm80_data *data; - int err = 0; - const char *type_name, *client_name; - - /* Make sure we aren't probing the ISA bus!! This is just a safety check - at this moment; i2c_detect really won't call us. */ -#ifdef DEBUG - if (i2c_is_isa_adapter(adapter)) { - printk - ("lm80.o: lm80_detect called for an ISA bus adapter?!?\n"); - return 0; - } -#endif - - if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) - goto ERROR0; - - /* OK. For now, we presume we have a valid client. We now create the - client structure, even though we cannot fill it completely yet. - But it allows us to access lm80_{read,write}_value. */ - if (!(data = kmalloc(sizeof(struct lm80_data), GFP_KERNEL))) { - err = -ENOMEM; - goto ERROR0; - } - - new_client = &data->client; - new_client->addr = address; - new_client->data = data; - new_client->adapter = adapter; - new_client->driver = &lm80_driver; - new_client->flags = 0; - - /* Now, we do the remaining detection. It is lousy. */ - if (lm80_read_value(new_client, LM80_REG_ALARM2) & 0xc0) - goto ERROR1; - for (i = 0x2a; i <= 0x3d; i++) { - cur = i2c_smbus_read_byte_data(new_client, i); - if ((i2c_smbus_read_byte_data(new_client, i + 0x40) != cur) - || (i2c_smbus_read_byte_data(new_client, i + 0x80) != - cur) - || (i2c_smbus_read_byte_data(new_client, i + 0xc0) != - cur)) goto ERROR1; - } - - /* Determine the chip type - only one kind supported! */ - if (kind <= 0) - kind = lm80; - - if (kind == lm80) { - type_name = "lm80"; - client_name = "LM80 chip"; - } else { -#ifdef DEBUG - printk("lm80.o: Internal error: unknown kind (%d)\n", - kind); -#endif - goto ERROR1; - } - - /* Fill in the remaining client fields and put it into the global list */ - strcpy(new_client->name, client_name); - data->valid = 0; - init_MUTEX(&data->update_lock); - - /* Tell the I2C layer a new client has arrived */ - if ((err = i2c_attach_client(new_client))) - goto ERROR3; - - /* Register a new directory entry with module sensors */ - if ((i = i2c_register_entry(new_client, type_name, - lm80_dir_table_template, - THIS_MODULE)) < 0) { - err = i; - goto ERROR4; - } - data->sysctl_id = i; - - lm80_init_client(new_client); - return 0; - -/* OK, this is not exactly good programming practice, usually. But it is - very code-efficient in this case. */ - ERROR4: - i2c_detach_client(new_client); - ERROR3: - ERROR1: - kfree(data); - ERROR0: - return err; -} - -static int lm80_detach_client(struct i2c_client *client) -{ - int err; - - i2c_deregister_entry(((struct lm80_data *) (client->data))-> - sysctl_id); - - if ((err = i2c_detach_client(client))) { - printk - ("lm80.o: Client deregistration failed, client not detached.\n"); - return err; - } - - kfree(client->data); - - return 0; -} - -static int lm80_read_value(struct i2c_client *client, u8 reg) -{ - return i2c_smbus_read_byte_data(client, reg); -} - -static int lm80_write_value(struct i2c_client *client, u8 reg, u8 value) -{ - return i2c_smbus_write_byte_data(client, reg, value); -} - -/* Called when we have found a new LM80. */ -static void lm80_init_client(struct i2c_client *client) -{ - /* Reset all except Watchdog values and last conversion values - This sets fan-divs to 2, among others. This makes most other - initializations unnecessary */ - lm80_write_value(client, LM80_REG_CONFIG, 0x80); - /* Set 11-bit temperature resolution */ - lm80_write_value(client, LM80_REG_RES, 0x08); - - /* Start monitoring */ - lm80_write_value(client, LM80_REG_CONFIG, 0x01); -} - -static void lm80_update_client(struct i2c_client *client) -{ - struct lm80_data *data = client->data; - int i; - - down(&data->update_lock); - - if ((jiffies - data->last_updated > 2 * HZ) || - (jiffies < data->last_updated) || !data->valid) { - -#ifdef DEBUG - printk("Starting lm80 update\n"); -#endif - for (i = 0; i <= 6; i++) { - data->in[i] = - lm80_read_value(client, LM80_REG_IN(i)); - data->in_min[i] = - lm80_read_value(client, LM80_REG_IN_MIN(i)); - data->in_max[i] = - lm80_read_value(client, LM80_REG_IN_MAX(i)); - } - data->fan[0] = lm80_read_value(client, LM80_REG_FAN1); - data->fan_min[0] = - lm80_read_value(client, LM80_REG_FAN1_MIN); - data->fan[1] = lm80_read_value(client, LM80_REG_FAN2); - data->fan_min[1] = - lm80_read_value(client, LM80_REG_FAN2_MIN); - - data->temp = - (lm80_read_value(client, LM80_REG_TEMP) << 8) | - (lm80_read_value(client, LM80_REG_RES) & 0xf0); - data->temp_os_max = - lm80_read_value(client, LM80_REG_TEMP_OS_MAX); - data->temp_os_hyst = - lm80_read_value(client, LM80_REG_TEMP_OS_HYST); - data->temp_hot_max = - lm80_read_value(client, LM80_REG_TEMP_HOT_MAX); - data->temp_hot_hyst = - lm80_read_value(client, LM80_REG_TEMP_HOT_HYST); - - i = lm80_read_value(client, LM80_REG_FANDIV); - data->fan_div[0] = (i >> 2) & 0x03; - data->fan_div[1] = (i >> 4) & 0x03; - data->alarms = lm80_read_value(client, LM80_REG_ALARM1) + - (lm80_read_value(client, LM80_REG_ALARM2) << 8); - data->last_updated = jiffies; - data->valid = 1; - } - - up(&data->update_lock); -} - - -/* The next few functions are the call-back functions of the /proc/sys and - sysctl files. Which function is used is defined in the ctl_table in - the extra1 field. - Each function must return the magnitude (power of 10 to divide the date - with) if it is called with operation==SENSORS_PROC_REAL_INFO. It must - put a maximum of *nrels elements in results reflecting the data of this - file, and set *nrels to the number it actually put in it, if operation== - SENSORS_PROC_REAL_READ. Finally, it must get upto *nrels elements from - results and write them to the chip, if operations==SENSORS_PROC_REAL_WRITE. - Note that on SENSORS_PROC_REAL_READ, I do not check whether results is - large enough (by checking the incoming value of *nrels). This is not very - good practice, but as long as you put less than about 5 values in results, - you can assume it is large enough. */ -void lm80_in(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct lm80_data *data = client->data; - int nr = ctl_name - LM80_SYSCTL_IN0; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 2; - else if (operation == SENSORS_PROC_REAL_READ) { - lm80_update_client(client); - results[0] = IN_FROM_REG(data->in_min[nr]); - results[1] = IN_FROM_REG(data->in_max[nr]); - results[2] = IN_FROM_REG(data->in[nr]); - *nrels_mag = 3; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag >= 1) { - data->in_min[nr] = IN_TO_REG(results[0]); - lm80_write_value(client, LM80_REG_IN_MIN(nr), - data->in_min[nr]); - } - if (*nrels_mag >= 2) { - data->in_max[nr] = IN_TO_REG(results[1]); - lm80_write_value(client, LM80_REG_IN_MAX(nr), - data->in_max[nr]); - } - } -} - -void lm80_fan(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct lm80_data *data = client->data; - int nr = ctl_name - LM80_SYSCTL_FAN1 + 1; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - lm80_update_client(client); - results[0] = FAN_FROM_REG(data->fan_min[nr - 1], - DIV_FROM_REG(data-> - fan_div[nr - 1])); - results[1] = - FAN_FROM_REG(data->fan[nr - 1], - DIV_FROM_REG(data->fan_div[nr - 1])); - *nrels_mag = 2; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag >= 1) { - data->fan_min[nr - 1] = FAN_TO_REG(results[0], - DIV_FROM_REG - (data-> - fan_div[nr - - 1])); - lm80_write_value(client, - nr == - 1 ? LM80_REG_FAN1_MIN : - LM80_REG_FAN2_MIN, - data->fan_min[nr - 1]); - } - } -} - - -void lm80_temp(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct lm80_data *data = client->data; - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 2; - else if (operation == SENSORS_PROC_REAL_READ) { - lm80_update_client(client); - results[0] = TEMP_LIMIT_FROM_REG(data->temp_hot_max); - results[1] = TEMP_LIMIT_FROM_REG(data->temp_hot_hyst); - results[2] = TEMP_LIMIT_FROM_REG(data->temp_os_max); - results[3] = TEMP_LIMIT_FROM_REG(data->temp_os_hyst); - results[4] = TEMP_FROM_REG(data->temp); - *nrels_mag = 5; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag >= 1) { - data->temp_hot_max = TEMP_LIMIT_TO_REG(results[0]); - lm80_write_value(client, LM80_REG_TEMP_HOT_MAX, - data->temp_hot_max); - } - if (*nrels_mag >= 2) { - data->temp_hot_hyst = - TEMP_LIMIT_TO_REG(results[1]); - lm80_write_value(client, LM80_REG_TEMP_HOT_HYST, - data->temp_hot_hyst); - } - if (*nrels_mag >= 3) { - data->temp_os_max = TEMP_LIMIT_TO_REG(results[2]); - lm80_write_value(client, LM80_REG_TEMP_OS_MAX, - data->temp_os_max); - } - if (*nrels_mag >= 4) { - data->temp_os_hyst = TEMP_LIMIT_TO_REG(results[3]); - lm80_write_value(client, LM80_REG_TEMP_OS_HYST, - data->temp_os_hyst); - } - } -} - -void lm80_alarms(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct lm80_data *data = client->data; - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - lm80_update_client(client); - results[0] = data->alarms; - *nrels_mag = 1; - } -} - -void lm80_fan_div(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct lm80_data *data = client->data; - int old; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - lm80_update_client(client); - results[0] = DIV_FROM_REG(data->fan_div[0]); - results[1] = DIV_FROM_REG(data->fan_div[1]); - results[2] = 2; - *nrels_mag = 3; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - old = lm80_read_value(client, LM80_REG_FANDIV); - if (*nrels_mag >= 2) { - data->fan_div[1] = DIV_TO_REG(results[1]); - old = (old & 0xcf) | (data->fan_div[1] << 4); - } - if (*nrels_mag >= 1) { - data->fan_div[0] = DIV_TO_REG(results[0]); - old = (old & 0xf3) | (data->fan_div[0] << 2); - lm80_write_value(client, LM80_REG_FANDIV, old); - } - } -} - -static int __init sm_lm80_init(void) -{ - printk("lm80.o version %s (%s)\n", LM_VERSION, LM_DATE); - return i2c_add_driver(&lm80_driver); -} - -static void __exit sm_lm80_exit(void) -{ - i2c_del_driver(&lm80_driver); -} - - - -MODULE_AUTHOR - ("Frodo Looijaard and Philip Edelbrock "); -MODULE_DESCRIPTION("LM80 driver"); - -module_init(sm_lm80_init); -module_exit(sm_lm80_exit); diff --git a/kernel/chips/lm83.c b/kernel/chips/lm83.c deleted file mode 100644 index d58d5c9d..00000000 --- a/kernel/chips/lm83.c +++ /dev/null @@ -1,528 +0,0 @@ -/* - * lm83.c - Part of lm_sensors, Linux kernel modules for hardware - * monitoring - * Copyright (C) 2003 Jean Delvare - * - * Heavily inspired from the lm78, lm75 and adm1021 drivers. The LM83 is - * a sensor chip made by National Semiconductor. It reports up to four - * temperatures (its own plus up to three external ones) with a 1 deg - * resolution and a 3-4 deg accuracy. Complete datasheet can be obtained - * from National's website at: - * http://www.national.com/pf/LM/LM83.html - * Since the datasheet omits to give the chip stepping code, I give it - * here: 0x03 (at register 0xff). - * - * Also supports the LM82 temp sensor, which is basically a stripped down - * model of the LM83. Datasheet is here: - * http://www.national.com/pf/LM/LM82.html - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include -#include -#include -#include -#include -#include "version.h" - -/* - * Addresses to scan - * Address is selected using 2 three-level pins, resulting in 9 possible - * addresses. - */ - -static unsigned short normal_i2c[] = { SENSORS_I2C_END }; -static unsigned short normal_i2c_range[] = { 0x18, 0x1a, 0x29, 0x2b, - 0x4c, 0x4e, SENSORS_I2C_END }; -static unsigned int normal_isa[] = { SENSORS_ISA_END }; -static unsigned int normal_isa_range[] = { SENSORS_ISA_END }; - -/* - * Insmod parameters - */ - -SENSORS_INSMOD_2(lm83, lm82); - -/* - * The LM83 registers - * Manufacturer ID is 0x01 for National Semiconductor. - */ - -#define LM83_REG_R_MAN_ID 0xFE -#define LM83_REG_R_CHIP_ID 0xFF -#define LM83_REG_R_CONFIG 0x03 -#define LM83_REG_W_CONFIG 0x09 -#define LM83_REG_R_STATUS1 0x02 -#define LM83_REG_R_STATUS2 0x35 -#define LM83_REG_R_LOCAL_TEMP 0x00 -#define LM83_REG_R_LOCAL_HIGH 0x05 -#define LM83_REG_W_LOCAL_HIGH 0x0B -#define LM83_REG_R_REMOTE1_TEMP 0x30 -#define LM83_REG_R_REMOTE1_HIGH 0x38 -#define LM83_REG_W_REMOTE1_HIGH 0x50 -#define LM83_REG_R_REMOTE2_TEMP 0x01 -#define LM83_REG_R_REMOTE2_HIGH 0x07 -#define LM83_REG_W_REMOTE2_HIGH 0x0D -#define LM83_REG_R_REMOTE3_TEMP 0x31 -#define LM83_REG_R_REMOTE3_HIGH 0x3A -#define LM83_REG_W_REMOTE3_HIGH 0x52 -#define LM83_REG_R_TCRIT 0x42 -#define LM83_REG_W_TCRIT 0x5A - -/* - * Conversions and various macros - * The LM83 uses signed 8-bit values with LSB = 1 degree Celsius. - */ - -#define TEMP_FROM_REG(val) (val) -#define TEMP_TO_REG(val) ((val) <= -50 ? -50 : \ - (val) >= 127 ? 127 : (val)) - -static const u8 LM83_REG_R_TEMP[] = { - LM83_REG_R_LOCAL_TEMP, - LM83_REG_R_REMOTE1_TEMP, - LM83_REG_R_REMOTE2_TEMP, - LM83_REG_R_REMOTE3_TEMP -}; - -static const u8 LM83_REG_R_HIGH[] = { - LM83_REG_R_LOCAL_HIGH, - LM83_REG_R_REMOTE1_HIGH, - LM83_REG_R_REMOTE2_HIGH, - LM83_REG_R_REMOTE3_HIGH -}; - -static const u8 LM83_REG_W_HIGH[] = { - LM83_REG_W_LOCAL_HIGH, - LM83_REG_W_REMOTE1_HIGH, - LM83_REG_W_REMOTE2_HIGH, - LM83_REG_W_REMOTE3_HIGH -}; - -/* - * Functions declaration - */ - -static int lm83_attach_adapter(struct i2c_adapter *adapter); -static int lm83_detect(struct i2c_adapter *adapter, int address, unsigned - short flags, int kind); -static int lm83_detach_client(struct i2c_client *client); -static void lm83_update_client(struct i2c_client *client); -static void lm83_temp(struct i2c_client *client, int operation, int - ctl_name, int *nrels_mag, long *results); -static void lm83_tcrit(struct i2c_client *client, int operation, int - ctl_name, int *nrels_mag, long *results); -static void lm83_alarms(struct i2c_client *client, int operation, int - ctl_name, int *nrels_mag, long *results); - -/* - * Driver data (common to all clients) - */ - -static struct i2c_driver lm83_driver = { - .name = "LM83 sensor driver", - .id = I2C_DRIVERID_LM83, - .flags = I2C_DF_NOTIFY, - .attach_adapter = lm83_attach_adapter, - .detach_client = lm83_detach_client, -}; - -/* - * Client data (each client gets its own) - */ - -struct lm83_data -{ - struct i2c_client client; - int sysctl_id; - - struct semaphore update_lock; - char valid; /* zero until following fields are valid */ - unsigned long last_updated; /* in jiffies */ - - /* registers values */ - s8 temp[4], temp_high[4], tcrit; - u16 alarms; /* bitvector, combined */ -}; - -/* - * Proc entries - * These files are created for each detected LM83. - */ - -/* -- SENSORS SYSCTL START -- */ - -#define LM83_SYSCTL_LOCAL_TEMP 1200 -#define LM83_SYSCTL_REMOTE1_TEMP 1201 -#define LM83_SYSCTL_REMOTE2_TEMP 1202 -#define LM83_SYSCTL_REMOTE3_TEMP 1203 -#define LM83_SYSCTL_TCRIT 1208 -#define LM83_SYSCTL_ALARMS 1210 - -#define LM83_ALARM_LOCAL_HIGH 0x0040 -#define LM83_ALARM_LOCAL_CRIT 0x0001 -#define LM83_ALARM_REMOTE1_HIGH 0x8000 -#define LM83_ALARM_REMOTE1_CRIT 0x0100 -#define LM83_ALARM_REMOTE1_OPEN 0x2000 -#define LM83_ALARM_REMOTE2_HIGH 0x0010 -#define LM83_ALARM_REMOTE2_CRIT 0x0002 -#define LM83_ALARM_REMOTE2_OPEN 0x0004 -#define LM83_ALARM_REMOTE3_HIGH 0x1000 -#define LM83_ALARM_REMOTE3_CRIT 0x0200 -#define LM83_ALARM_REMOTE3_OPEN 0x0400 - -/* -- SENSORS SYSCTL END -- */ - - -static ctl_table lm83_dir_table_template[] = -{ - {LM83_SYSCTL_LOCAL_TEMP, "temp1", NULL, 0, 0644, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &lm83_temp}, - {LM83_SYSCTL_REMOTE1_TEMP, "temp2", NULL, 0, 0644, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &lm83_temp}, - {LM83_SYSCTL_REMOTE2_TEMP, "temp3", NULL, 0, 0644, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &lm83_temp}, - {LM83_SYSCTL_REMOTE3_TEMP, "temp4", NULL, 0, 0644, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &lm83_temp}, - {LM83_SYSCTL_TCRIT, "tcrit", NULL, 0, 0644, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &lm83_tcrit}, - {LM83_SYSCTL_ALARMS, "alarms", NULL, 0, 0444, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &lm83_alarms}, - {0} -}; - -static ctl_table lm82_dir_table_template[] = -{ - {LM83_SYSCTL_LOCAL_TEMP, "temp1", NULL, 0, 0644, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &lm83_temp}, - {LM83_SYSCTL_REMOTE2_TEMP, "temp3", NULL, 0, 0644, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &lm83_temp}, - {LM83_SYSCTL_TCRIT, "tcrit", NULL, 0, 0644, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &lm83_tcrit}, - {LM83_SYSCTL_ALARMS, "alarms", NULL, 0, 0444, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &lm83_alarms}, - {0} -}; - -/* - * Real code - */ - -static int lm83_attach_adapter(struct i2c_adapter *adapter) -{ - return i2c_detect(adapter, &addr_data, lm83_detect); -} - -/* - * The following function does more than just detection. If detection - * succeeds, it also registers the new chip. - */ -static int lm83_detect(struct i2c_adapter *adapter, int address, unsigned - short flags, int kind) -{ - struct i2c_client *new_client; - struct lm83_data *data; - int err = 0; - const char *type_name = ""; - const char *client_name = ""; - -#ifdef DEBUG - if (i2c_is_isa_adapter(adapter)) - { - printk("lm83.o: Called for an ISA bus adapter, aborting.\n"); - return 0; - } -#endif - - if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) - { -#ifdef DEBUG - printk("lm83.o: I2C bus doesn't support byte read mode, " - "skipping.\n"); -#endif - return 0; - } - - if (!(data = kmalloc(sizeof(struct lm83_data), GFP_KERNEL))) - { - printk("lm83.o: Out of memory in lm83_detect (new_client).\n"); - return -ENOMEM; - } - - /* - * The common I2C client data is placed right before the - * LM83-specific data. The LM83-specific data is pointed to by the - * data field from the I2C client data. - */ - - new_client = &data->client; - new_client->addr = address; - new_client->data = data; - new_client->adapter = adapter; - new_client->driver = &lm83_driver; - new_client->flags = 0; - - /* - * Now we do the remaining detection. A negative kind means that - * the driver was loaded with no force parameter (default), so we - * must both detect and identify the chip (actually there is only - * one possible kind of chip for now, LM83). A zero kind means that - * the driver was loaded with the force parameter, the detection - * step shall be skipped. A positive kind means that the driver - * was loaded with the force parameter and a given kind of chip is - * requested, so both the detection and the identification steps - * are skipped. - */ - - /* Default to an LM83 if forced */ - if (kind == 0) - kind = lm83; - - if (kind < 0) /* detection */ - { - if (((i2c_smbus_read_byte_data(new_client, LM83_REG_R_STATUS1) - & 0xA8) != 0x00) - || ((i2c_smbus_read_byte_data(new_client, LM83_REG_R_STATUS2) - & 0x48) != 0x00) - || ((i2c_smbus_read_byte_data(new_client, LM83_REG_R_CONFIG) - & 0x41) != 0x00)) - { -#ifdef DEBUG - printk(KERN_DEBUG "lm83.o: Detection failed at 0x%02x.\n", - address); -#endif - goto ERROR1; - } - } - - if (kind <= 0) /* identification */ - { - u8 man_id, chip_id; - - man_id = i2c_smbus_read_byte_data(new_client, LM83_REG_R_MAN_ID); - chip_id = i2c_smbus_read_byte_data(new_client, LM83_REG_R_CHIP_ID); - if (man_id == 0x01) /* National Semiconductor */ - { - if (chip_id == 0x03) - kind = lm83; - else if (chip_id == 0x01) - kind = lm82; - } - } - - if (kind <= 0) /* identification failed */ - { - printk("lm83.o: Unsupported chip.\n"); - goto ERROR1; - } - - if (kind == lm83) - { - type_name = "lm83"; - client_name = "LM83 chip"; - } - else if (kind == lm82) - { - type_name = "lm82"; - client_name = "LM82 chip"; - } - else - { - printk("lm83.o: Unknown kind %d.\n", kind); - goto ERROR1; - } - - /* - * OK, we got a valid chip so we can fill in the remaining client - * fields. - */ - - strcpy(new_client->name, client_name); - data->valid = 0; - init_MUTEX(&data->update_lock); - - /* - * Tell the I2C layer a new client has arrived. - */ - - if ((err = i2c_attach_client(new_client))) - { -#ifdef DEBUG - printk("lm83.o: Failed attaching client.\n"); -#endif - goto ERROR1; - } - - /* - * Register a new directory entry. - */ - - if ((kind == lm83 && (err = i2c_register_entry(new_client, type_name, - lm83_dir_table_template, THIS_MODULE)) < 0) || - (kind == lm82 && (err = i2c_register_entry(new_client, type_name, - lm82_dir_table_template, THIS_MODULE)) < 0)) - { -#ifdef DEBUG - printk("lm83.o: Failed registering directory entry.\n"); -#endif - goto ERROR2; - } - data->sysctl_id = err; - - /* - * Initialize the LM83 chip - * (Nothing to do for this one.) - */ - - return 0; - - ERROR2: - i2c_detach_client(new_client); - ERROR1: - kfree(data); - return err; -} - -static int lm83_detach_client(struct i2c_client *client) -{ - int err; - - i2c_deregister_entry(((struct lm83_data *) (client->data))->sysctl_id); - if ((err = i2c_detach_client(client))) - { - printk("lm83.o: Client deregistration failed, client not " - "detached.\n"); - return err; - } - - kfree(client->data); - return 0; -} - -static void lm83_update_client(struct i2c_client *client) -{ - struct lm83_data *data = client->data; - - down(&data->update_lock); - - if ((jiffies - data->last_updated > HZ * 2) || - (jiffies < data->last_updated) || !data->valid) - { - int nr; -#ifdef DEBUG - printk("lm83.o: Updating LM83 data.\n"); -#endif - for (nr = 0; nr < 4 ; nr++) - { - data->temp[nr] = - i2c_smbus_read_byte_data(client, LM83_REG_R_TEMP[nr]); - data->temp_high[nr] = - i2c_smbus_read_byte_data(client, LM83_REG_R_HIGH[nr]); - } - data->tcrit = i2c_smbus_read_byte_data(client, LM83_REG_R_TCRIT); - data->alarms = - i2c_smbus_read_byte_data(client, LM83_REG_R_STATUS1) + - (i2c_smbus_read_byte_data(client, LM83_REG_R_STATUS2) << 8); - - data->last_updated = jiffies; - data->valid = 1; - } - - up(&data->update_lock); -} - -static void lm83_temp(struct i2c_client *client, int operation, int - ctl_name, int *nrels_mag, long *results) -{ - struct lm83_data *data = client->data; - int nr = ctl_name - LM83_SYSCTL_LOCAL_TEMP; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; /* magnitude */ - else if (operation == SENSORS_PROC_REAL_READ) - { - lm83_update_client(client); - results[0] = TEMP_FROM_REG(data->temp_high[nr]); - results[1] = TEMP_FROM_REG(data->temp[nr]); - *nrels_mag = 2; - } - else if (operation == SENSORS_PROC_REAL_WRITE) - { - if (*nrels_mag >= 1) - { - data->temp_high[nr] = TEMP_TO_REG(results[0]); - i2c_smbus_write_byte_data(client, LM83_REG_W_HIGH[nr], - data->temp_high[nr]); - } - } -} - -static void lm83_tcrit(struct i2c_client *client, int operation, int - ctl_name, int *nrels_mag, long *results) -{ - struct lm83_data *data = client->data; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; /* magnitude */ - else if (operation == SENSORS_PROC_REAL_READ) - { - lm83_update_client(client); - results[0] = TEMP_FROM_REG(data->tcrit); - *nrels_mag = 1; - } - else if (operation == SENSORS_PROC_REAL_WRITE) - { - if (*nrels_mag >= 1) - { - data->tcrit = TEMP_TO_REG(results[0]); - i2c_smbus_write_byte_data(client, LM83_REG_W_TCRIT, - data->tcrit); - } - } -} - -static void lm83_alarms(struct i2c_client *client, int operation, int - ctl_name, int *nrels_mag, long *results) -{ - struct lm83_data *data = client->data; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; /* magnitude */ - else if (operation == SENSORS_PROC_REAL_READ) - { - lm83_update_client(client); - results[0] = data->alarms; - *nrels_mag = 1; - } -} - -static int __init sm_lm83_init(void) -{ - printk(KERN_INFO "lm83.o version %s (%s)\n", LM_VERSION, LM_DATE); - return i2c_add_driver(&lm83_driver); -} - -static void __exit sm_lm83_exit(void) -{ - i2c_del_driver(&lm83_driver); -} - -MODULE_AUTHOR("Jean Delvare "); -MODULE_DESCRIPTION("LM83 sensor driver"); -MODULE_LICENSE("GPL"); - -module_init(sm_lm83_init); -module_exit(sm_lm83_exit); diff --git a/kernel/chips/lm85.c b/kernel/chips/lm85.c deleted file mode 100644 index cc388bb2..00000000 --- a/kernel/chips/lm85.c +++ /dev/null @@ -1,2061 +0,0 @@ -/* - lm85.c - Part of lm_sensors, Linux kernel modules for hardware - monitoring - Copyright (c) 1998, 1999 Frodo Looijaard - Copyright (c) 2002, 2003 Philip Pokorny - Copyright (c) 2003 Margit Schubert-While - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - - CHANGELOG - - 2002-11-13 First patch for LM85 functionality - 2002-11-18 LM85 functionality mostly done - 2002-12-02 Adding ADM1027 functionality - 2002-12-06 Adding ADT7463 functionality - 2003-01-09 Code cleanup. - Save reserved bits in case they are implemented - in a future chip. (Solve problem with lockups - on ADM1027 due to chip initialization) - Added chip initialization bypass option - 2003-02-12 Add THERM asserted counts for ADT7463 - Added #ifdef so we can compile against 2.6.5 - without updating i2c-ids.h - 2003-02-17 Prepare for switch to 2.7.0 development - Implement tmin_control for ADT7463 - Expose THERM asserted counts to /proc - Code cleanup - 2003-02-19 Working with Margit and LM_SENSORS developers - 2003-02-23 Removed chip initialization entirely - Scale voltages in driver at Margit's request - Change PWM from 0-100% to 0-255 per LM sensors standard - 2003-02-27 Documentation and code cleanups - Added this CHANGELOG - Print additional precision for temperatures and voltages - Many thanks to Margit Schubert-While and Brandt xxxxxx - for help testing this version - 2003-02-28 More diagnostic messages regarding BIOS setup - 2003-03-01 Added Interrupt mask register support. - 2003-03-08 Fixed problem with pseudo 16-bit registers - Cleaned up some compiler warnings. - Fixed problem with Operating Point and THERM counting - 2003-03-21 Initial support for EMC6D100 and EMC6D101 chips - 2003-06-30 Add support for EMC6D100 extra voltage inputs. -*/ - -#include -#include -#include -#include -#include -#include "version.h" -#include "sensors_vid.h" - -#ifndef I2C_DRIVERID_LM85 -#define I2C_DRIVERID_LM85 1039 -#endif - -/* Addresses to scan */ -static unsigned short normal_i2c[] = { 0x2c, 0x2d, 0x2e, SENSORS_I2C_END }; -static unsigned short normal_i2c_range[] = { SENSORS_I2C_END }; -static unsigned int normal_isa[] = { SENSORS_ISA_END }; -static unsigned int normal_isa_range[] = { SENSORS_ISA_END }; - -/* Insmod parameters */ -SENSORS_INSMOD_6(lm85b, lm85c, adm1027, adt7463, emc6d100, emc6d102); - -/* Many LM85 constants specified below */ - -/* The LM85 registers */ -#define LM85_REG_IN(nr) (0x20 + (nr)) -#define LM85_REG_IN_MIN(nr) (0x44 + (nr) * 2) -#define LM85_REG_IN_MAX(nr) (0x45 + (nr) * 2) - -#define LM85_REG_TEMP(nr) (0x25 + (nr)) -#define LM85_REG_TEMP_MIN(nr) (0x4e + (nr) * 2) -#define LM85_REG_TEMP_MAX(nr) (0x4f + (nr) * 2) - -/* Fan speeds are LSB, MSB (2 bytes) */ -#define LM85_REG_FAN(nr) (0x28 + (nr) *2) -#define LM85_REG_FAN_MIN(nr) (0x54 + (nr) *2) - -#define LM85_REG_PWM(nr) (0x30 + (nr)) - -#define ADT7463_REG_OPPOINT(nr) (0x33 + (nr)) - -#define ADT7463_REG_TMIN_CTL1 0x36 -#define ADT7463_REG_TMIN_CTL2 0x37 -#define ADT7463_REG_TMIN_CTL 0x0136 - -#define LM85_REG_DEVICE 0x3d -#define LM85_REG_COMPANY 0x3e -#define LM85_REG_VERSTEP 0x3f -/* These are the recognized values for the above regs */ -#define LM85_DEVICE_ADX 0x27 -#define LM85_COMPANY_NATIONAL 0x01 -#define LM85_COMPANY_ANALOG_DEV 0x41 -#define LM85_COMPANY_SMSC 0x5c -#define LM85_VERSTEP_VMASK 0xf0 -#define LM85_VERSTEP_SMASK 0x0f -#define LM85_VERSTEP_GENERIC 0x60 -#define LM85_VERSTEP_LM85C 0x60 -#define LM85_VERSTEP_LM85B 0x62 -#define LM85_VERSTEP_ADM1027 0x60 -#define LM85_VERSTEP_ADT7463 0x62 -#define LM85_VERSTEP_ADT7463C 0x6A -#define LM85_VERSTEP_EMC6D100_A0 0x60 -#define LM85_VERSTEP_EMC6D100_A1 0x61 -#define LM85_VERSTEP_EMC6D102 0x65 - -#define LM85_REG_CONFIG 0x40 - -#define LM85_REG_ALARM1 0x41 -#define LM85_REG_ALARM2 0x42 -#define LM85_REG_ALARM 0x0141 - -#define LM85_REG_VID 0x43 - -/* Automated FAN control */ -#define LM85_REG_AFAN_CONFIG(nr) (0x5c + (nr)) -#define LM85_REG_AFAN_RANGE(nr) (0x5f + (nr)) -#define LM85_REG_AFAN_SPIKE1 0x62 -#define LM85_REG_AFAN_SPIKE2 0x63 -#define LM85_REG_AFAN_MINPWM(nr) (0x64 + (nr)) -#define LM85_REG_AFAN_LIMIT(nr) (0x67 + (nr)) -#define LM85_REG_AFAN_CRITICAL(nr) (0x6a + (nr)) -#define LM85_REG_AFAN_HYST1 0x6d -#define LM85_REG_AFAN_HYST2 0x6e - -#define LM85_REG_TACH_MODE 0x74 -#define LM85_REG_SPINUP_CTL 0x75 - -#define ADM1027_REG_TEMP_OFFSET(nr) (0x70 + (nr)) -#define ADM1027_REG_CONFIG2 0x73 -#define ADM1027_REG_INTMASK1 0x74 -#define ADM1027_REG_INTMASK2 0x75 -#define ADM1027_REG_INTMASK 0x0174 -#define ADM1027_REG_EXTEND_ADC1 0x76 -#define ADM1027_REG_EXTEND_ADC2 0x77 -#define ADM1027_REG_EXTEND_ADC 0x0176 -#define ADM1027_REG_CONFIG3 0x78 -#define ADM1027_REG_FAN_PPR 0x7b - -#define ADT7463_REG_THERM 0x79 -#define ADT7463_REG_THERM_LIMIT 0x7A -#define ADT7463_REG_CONFIG4 0x7D - -#define EMC6D100_REG_SFR 0x7c -#define EMC6D100_REG_ALARM3 0x7d -#define EMC6D100_REG_CONF 0x7f -#define EMC6D100_REG_INT_EN 0x80 -/* IN5, IN6 and IN7 */ -#define EMC6D100_REG_IN(nr) (0x70 + ((nr)-5)) -#define EMC6D100_REG_IN_MIN(nr) (0x73 + ((nr)-5) * 2) -#define EMC6D100_REG_IN_MAX(nr) (0x74 + ((nr)-5) * 2) - -#define EMC6D102_REG_EXTEND_ADC1 0x85 -#define EMC6D102_REG_EXTEND_ADC2 0x86 -#define EMC6D102_REG_EXTEND_ADC3 0x87 -#define EMC6D102_REG_EXTEND_ADC4 0x88 - -/* Conversions. Rounding and limit checking is only done on the TO_REG - variants. Note that you should be a bit careful with which arguments - these macros are called: arguments may be evaluated more than once. - */ - -/* IN are scaled 1.000 == 0xc0, mag = 3 */ -#define IN_TO_REG(val) (SENSORS_LIMIT((((val)*0xc0+500)/1000),0,255)) -#define INEXT_FROM_REG(val,ext) (((val)*1000 + (ext)*250 + 96)/0xc0) -#define IN_FROM_REG(val) (INEXT_FROM_REG(val,0)) - -/* IN are scaled acording to built-in resistors */ -static int lm85_scaling[] = { /* .001 Volts */ - 2500, 2250, 3300, 5000, 12000, - 3300, 1500, 1800, /* EMC6D100 */ - }; -#define SCALE(val,from,to) (((val)*(to) + ((from)/2))/(from)) -#define INS_TO_REG(n,val) (SENSORS_LIMIT(SCALE(val,lm85_scaling[n],192),0,255)) -#define INSEXT_FROM_REG(n,val,ext) (SCALE((val)*4 + (ext),192*4,lm85_scaling[n])) -#define INS_FROM_REG(n,val) (INSEXT_FROM_REG(n,val,0)) - -/* FAN speed is measured using 90kHz clock */ -#define FAN_TO_REG(val) ((val)<=0?0xffff:SENSORS_LIMIT(5400000/(val),1,65534)) -#define FAN_FROM_REG(val) ((val)==0?-1:(val)==0xffff?0:5400000/(val)) - -/* Temperature is reported in .01 degC increments */ -#define TEMP_TO_REG(val) (SENSORS_LIMIT(((val)+50)/100,-127,127)) -#define TEMPEXT_FROM_REG(val,ext) ((val)*100 + (ext)*25) -#define TEMP_FROM_REG(val) (TEMPEXT_FROM_REG(val,0)) -#define EXTTEMP_TO_REG(val) (SENSORS_LIMIT((val)/25,-127,127)) -#define OPPOINT_TO_REG(val) (SENSORS_LIMIT(val,-127,127)) -#define OPPOINT_FROM_REG(val) (val) - -#define PWM_TO_REG(val) (SENSORS_LIMIT(val,0,255)) -#define PWM_FROM_REG(val) (val) - -#define EXT_FROM_REG(val,sensor) (((val)>>(sensor * 2))&0x03) - -/* ZONEs have the following parameters: - * Limit (low) temp, 1. degC - * Hysteresis (below limit), 1. degC (0-15) - * Range of speed control, .1 degC (2-80) - * Critical (high) temp, 1. degC - * - * FAN PWMs have the following parameters: - * Reference Zone, 1, 2, 3, etc. - * Spinup time, .05 sec - * PWM value at limit/low temp, 1 count - * PWM Frequency, 1. Hz - * PWM is Min or OFF below limit, flag - * Invert PWM output, flag - * - * Some chips filter the temp, others the fan. - * Filter constant (or disabled) .1 seconds - */ - -/* These are the zone temperature range encodings */ -static int lm85_range_map[] = { /* .1 degC */ - 20, 25, 33, 40, 50, 66, - 80, 100, 133, 160, 200, 266, - 320, 400, 533, 800 - }; -static int RANGE_TO_REG( int range ) -{ - int i; - - if( range >= lm85_range_map[15] ) { return 15 ; } - for( i = 0 ; i < 15 ; ++i ) - if( range <= lm85_range_map[i] ) - break ; - return( i & 0x0f ); -} -#define RANGE_FROM_REG(val) (lm85_range_map[(val)&0x0f]) - -/* These are the Acoustic Enhancement, or Temperature smoothing encodings - * NOTE: The enable/disable bit is INCLUDED in these encodings as the - * MSB (bit 3, value 8). If the enable bit is 0, the encoded value - * is ignored, or set to 0. - */ -static int lm85_smooth_map[] = { /* .1 sec */ - 350, 176, 118, 70, 44, 30, 16, 8 -/* 35.4 * 1/1, 1/2, 1/3, 1/5, 1/8, 1/12, 1/24, 1/48 */ - }; -static int SMOOTH_TO_REG( int smooth ) -{ - int i; - - if( smooth <= 0 ) { return 0 ; } /* Disabled */ - for( i = 0 ; i < 7 ; ++i ) - if( smooth >= lm85_smooth_map[i] ) - break ; - return( (i & 0x07) | 0x08 ); -} -#define SMOOTH_FROM_REG(val) ((val)&0x08?lm85_smooth_map[(val)&0x07]:0) - -/* These are the fan spinup delay time encodings */ -static int lm85_spinup_map[] = { /* .1 sec */ - 0, 1, 2, 4, 7, 10, 20, 40 - }; -static int SPINUP_TO_REG( int spinup ) -{ - int i; - - if( spinup >= lm85_spinup_map[7] ) { return 7 ; } - for( i = 0 ; i < 7 ; ++i ) - if( spinup <= lm85_spinup_map[i] ) - break ; - return( i & 0x07 ); -} -#define SPINUP_FROM_REG(val) (lm85_spinup_map[(val)&0x07]) - -/* These are the PWM frequency encodings */ -static int lm85_freq_map[] = { /* .1 Hz */ - 100, 150, 230, 300, 380, 470, 620, 980 - }; -static int FREQ_TO_REG( int freq ) -{ - int i; - - if( freq >= lm85_freq_map[7] ) { return 7 ; } - for( i = 0 ; i < 7 ; ++i ) - if( freq <= lm85_freq_map[i] ) - break ; - return( i & 0x07 ); -} -#define FREQ_FROM_REG(val) (lm85_freq_map[(val)&0x07]) - -/* Since we can't use strings, I'm abusing these numbers - * to stand in for the following meanings: - * 1 -- PWM responds to Zone 1 - * 2 -- PWM responds to Zone 2 - * 3 -- PWM responds to Zone 3 - * 23 -- PWM responds to the higher temp of Zone 2 or 3 - * 123 -- PWM responds to highest of Zone 1, 2, or 3 - * 0 -- PWM is always at 0% (ie, off) - * -1 -- PWM is always at 100% - * -2 -- PWM responds to manual control - */ -static int lm85_zone_map[] = { 1, 2, 3, -1, 0, 23, 123, -2 }; -static int ZONE_TO_REG( int zone ) -{ - int i; - - for( i = 0 ; i <= 7 ; ++i ) - if( zone == lm85_zone_map[i] ) - break ; - if( i > 7 ) /* Not found. */ - i = 3; /* Always 100% */ - return( (i & 0x07)<<5 ); -} -#define ZONE_FROM_REG(val) (lm85_zone_map[((val)>>5)&0x07]) - -#define HYST_TO_REG(val) (SENSORS_LIMIT((-(val)+5)/10,0,15)) -#define HYST_FROM_REG(val) (-(val)*10) - -#define OFFSET_TO_REG(val) (SENSORS_LIMIT((val)/25,-127,127)) -#define OFFSET_FROM_REG(val) ((val)*25) - -#define PPR_MASK(fan) (0x03<<(fan *2)) -#define PPR_TO_REG(val,fan) (SENSORS_LIMIT((val)-1,0,3)<<(fan *2)) -#define PPR_FROM_REG(val,fan) ((((val)>>(fan * 2))&0x03)+1) - -/* When converting to REG, we need to fixup the carry-over bit */ -#define INTMASK_FROM_REG(val) (val) -#define INTMASK_TO_REG(val) (SENSORS_LIMIT((val)|((val)&0xff00?0x80:0),0,65535)) - -/* Typically used with Pentium 4 systems v9.1 VRM spec */ -#define LM85_INIT_VRM 91 - -/* Chip sampling rates - * - * Some sensors are not updated more frequently than once per second - * so it doesn't make sense to read them more often than that. - * We cache the results and return the saved data if the driver - * is called again before a second has elapsed. - * - * Also, there is significant configuration data for this chip - * given the automatic PWM fan control that is possible. There - * are about 47 bytes of config data to only 22 bytes of actual - * readings. So, we keep the config data up to date in the cache - * when it is written and only sample it once every 5 *minutes* - */ -#define LM85_DATA_INTERVAL (1 * HZ) -#define LM85_CONFIG_INTERVAL (5 * 60 * HZ) - -/* For each registered LM85, we need to keep some data in memory. That - data is pointed to by client->data. The structure itself is - dynamically allocated, when a new lm85 client is allocated. */ - -/* LM85 can automatically adjust fan speeds based on temperature - * This structure encapsulates an entire Zone config. There are - * three zones (one for each temperature input) on the lm85 - */ -struct lm85_zone { - s8 limit; /* Low temp limit */ - u8 hyst; /* Low limit hysteresis. (0-15) */ - u8 range; /* Temp range, encoded */ - s8 critical; /* "All fans ON" temp limit */ -}; - -struct lm85_autofan { - u8 config; /* Register value */ - u8 freq; /* PWM frequency, encoded */ - u8 min_pwm; /* Minimum PWM value, encoded */ - u8 min_off; /* Min PWM or OFF below "limit", flag */ -}; - -struct lm85_data { - struct i2c_client client; - int sysctl_id; - enum chips type; - - struct semaphore update_lock; - int valid; /* !=0 if following fields are valid */ - unsigned long last_reading; /* In jiffies */ - unsigned long last_config; /* In jiffies */ - - u8 in[8]; /* Register value */ - u8 in_max[8]; /* Register value */ - u8 in_min[8]; /* Register value */ - s8 temp[3]; /* Register value */ - s8 temp_min[3]; /* Register value */ - s8 temp_max[3]; /* Register value */ - s8 temp_offset[3]; /* Register value */ - u16 fan[4]; /* Register value */ - u16 fan_min[4]; /* Register value */ - u8 pwm[3]; /* Register value */ - u8 spinup_ctl; /* Register encoding, combined */ - u8 tach_mode; /* Register encoding, combined */ - u16 extend_adc; /* Register value */ - u8 fan_ppr; /* Register value */ - u8 smooth[3]; /* Register encoding */ - u8 vid; /* Register value */ - u8 vrm; /* VRM version */ - u8 syncpwm3; /* Saved PWM3 for TACH 2,3,4 config */ - s8 oppoint[3]; /* Register value */ - u16 tmin_ctl; /* Register value */ - long therm_total; /* Cummulative therm count */ - long therm_ovfl; /* Count of therm overflows */ - u8 therm_limit; /* Register value */ - u32 alarms; /* Register encoding, combined */ - u32 alarm_mask; /* Register encoding, combined */ - struct lm85_autofan autofan[3]; - struct lm85_zone zone[3]; -}; - -static int lm85_attach_adapter(struct i2c_adapter *adapter); -static int lm85_detect(struct i2c_adapter *adapter, int address, - unsigned short flags, int kind); -static int lm85_detach_client(struct i2c_client *client); -static int lm85_read_value(struct i2c_client *client, u16 register); -static int lm85_write_value(struct i2c_client *client, u16 register, int value); -static void lm85_update_client(struct i2c_client *client); -static void lm85_init_client(struct i2c_client *client); - - -static void lm85_in(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results); -static void lm85_fan(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void lm85_temp(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void lm85_vid(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void lm85_vrm(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void lm85_alarms(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void lm85_pwm(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void lm85_zone(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void lm85_pwm_config(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void lm85_pwm_zone(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void lm85_smooth(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); - -static void lm85_spinup_ctl(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void lm85_tach_mode(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); - -static void adm1027_tach_mode(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void adm1027_temp_offset(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void adm1027_fan_ppr(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void adm1027_alarm_mask(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); - -static void adt7463_tmin_ctl(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void adt7463_therm_signal(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); - -static void emc6d100_in(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); - -static struct i2c_driver lm85_driver = { - .name = "LM85 compatible sensor driver", - .id = I2C_DRIVERID_LM85, - .flags = I2C_DF_NOTIFY, - .attach_adapter = &lm85_attach_adapter, - .detach_client = &lm85_detach_client, -}; - -/* Unique ID assigned to each LM85 detected */ -static int lm85_id = 0; - -/* -- SENSORS SYSCTL START -- */ -/* Common parameters */ -#define LM85_SYSCTL_IN0 1000 -#define LM85_SYSCTL_IN1 1001 -#define LM85_SYSCTL_IN2 1002 -#define LM85_SYSCTL_IN3 1003 -#define LM85_SYSCTL_IN4 1004 -#define LM85_SYSCTL_FAN1 1005 -#define LM85_SYSCTL_FAN2 1006 -#define LM85_SYSCTL_FAN3 1007 -#define LM85_SYSCTL_FAN4 1008 -#define LM85_SYSCTL_TEMP1 1009 -#define LM85_SYSCTL_TEMP2 1010 -#define LM85_SYSCTL_TEMP3 1011 -#define LM85_SYSCTL_VID 1012 -#define LM85_SYSCTL_ALARMS 1013 -#define LM85_SYSCTL_PWM1 1014 -#define LM85_SYSCTL_PWM2 1015 -#define LM85_SYSCTL_PWM3 1016 -#define LM85_SYSCTL_VRM 1017 -#define LM85_SYSCTL_PWM_CFG1 1019 -#define LM85_SYSCTL_PWM_CFG2 1020 -#define LM85_SYSCTL_PWM_CFG3 1021 -#define LM85_SYSCTL_PWM_ZONE1 1022 -#define LM85_SYSCTL_PWM_ZONE2 1023 -#define LM85_SYSCTL_PWM_ZONE3 1024 -#define LM85_SYSCTL_ZONE1 1025 -#define LM85_SYSCTL_ZONE2 1026 -#define LM85_SYSCTL_ZONE3 1027 -#define LM85_SYSCTL_SMOOTH1 1028 -#define LM85_SYSCTL_SMOOTH2 1029 -#define LM85_SYSCTL_SMOOTH3 1030 - -/* Vendor specific values */ -#define LM85_SYSCTL_SPINUP_CTL 1100 -#define LM85_SYSCTL_TACH_MODE 1101 - -/* Analog Devices variant of the LM85 */ -#define ADM1027_SYSCTL_TACH_MODE 1200 -#define ADM1027_SYSCTL_TEMP_OFFSET1 1201 -#define ADM1027_SYSCTL_TEMP_OFFSET2 1202 -#define ADM1027_SYSCTL_TEMP_OFFSET3 1203 -#define ADM1027_SYSCTL_FAN_PPR 1204 -#define ADM1027_SYSCTL_ALARM_MASK 1205 - -/* Analog Devices variant of the LM85/ADM1027 */ -#define ADT7463_SYSCTL_TMIN_CTL1 1300 -#define ADT7463_SYSCTL_TMIN_CTL2 1301 -#define ADT7463_SYSCTL_TMIN_CTL3 1302 -#define ADT7463_SYSCTL_THERM_SIGNAL 1303 - -/* SMSC variant of the LM85 */ -#define EMC6D100_SYSCTL_IN5 1400 -#define EMC6D100_SYSCTL_IN6 1401 -#define EMC6D100_SYSCTL_IN7 1402 - -#define LM85_ALARM_IN0 0x0001 -#define LM85_ALARM_IN1 0x0002 -#define LM85_ALARM_IN2 0x0004 -#define LM85_ALARM_IN3 0x0008 -#define LM85_ALARM_TEMP1 0x0010 -#define LM85_ALARM_TEMP2 0x0020 -#define LM85_ALARM_TEMP3 0x0040 -#define LM85_ALARM_ALARM2 0x0080 -#define LM85_ALARM_IN4 0x0100 -#define LM85_ALARM_RESERVED 0x0200 -#define LM85_ALARM_FAN1 0x0400 -#define LM85_ALARM_FAN2 0x0800 -#define LM85_ALARM_FAN3 0x1000 -#define LM85_ALARM_FAN4 0x2000 -#define LM85_ALARM_TEMP1_FAULT 0x4000 -#define LM85_ALARM_TEMP3_FAULT 0x08000 -#define LM85_ALARM_IN6 0x10000 -#define LM85_ALARM_IN7 0x20000 -#define LM85_ALARM_IN5 0x40000 -/* -- SENSORS SYSCTL END -- */ - -/* The /proc/sys entries */ -/* These files are created for each detected LM85. This is just a template; - * The actual list is built from this and additional per-chip - * custom lists below. Note the XXX_LEN macros. These must be - * compile time constants because they will be used to allocate - * space for the final template passed to i2c_register_entry. - * We depend on the ability of GCC to evaluate expressions at - * compile time to turn these expressions into compile time - * constants, but this can generate a warning. - */ -static ctl_table lm85_common[] = { - {LM85_SYSCTL_IN0, "in0", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &lm85_in}, - {LM85_SYSCTL_IN1, "in1", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &lm85_in}, - {LM85_SYSCTL_IN2, "in2", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &lm85_in}, - {LM85_SYSCTL_IN3, "in3", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &lm85_in}, - {LM85_SYSCTL_IN4, "in4", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &lm85_in}, - {LM85_SYSCTL_FAN1, "fan1", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &lm85_fan}, - {LM85_SYSCTL_FAN2, "fan2", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &lm85_fan}, - {LM85_SYSCTL_FAN3, "fan3", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &lm85_fan}, - {LM85_SYSCTL_FAN4, "fan4", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &lm85_fan}, - {LM85_SYSCTL_TEMP1, "temp1", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &lm85_temp}, - {LM85_SYSCTL_TEMP2, "temp2", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &lm85_temp}, - {LM85_SYSCTL_TEMP3, "temp3", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &lm85_temp}, - {LM85_SYSCTL_VID, "vid", NULL, 0, 0444, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &lm85_vid}, - {LM85_SYSCTL_VRM, "vrm", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &lm85_vrm}, - {LM85_SYSCTL_ALARMS, "alarms", NULL, 0, 0444, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &lm85_alarms}, - {LM85_SYSCTL_PWM1, "pwm1", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &lm85_pwm}, - {LM85_SYSCTL_PWM2, "pwm2", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &lm85_pwm}, - {LM85_SYSCTL_PWM3, "pwm3", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &lm85_pwm}, - {LM85_SYSCTL_PWM_CFG1, "pwm1_cfg", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &lm85_pwm_config}, - {LM85_SYSCTL_PWM_CFG2, "pwm2_cfg", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &lm85_pwm_config}, - {LM85_SYSCTL_PWM_CFG3, "pwm3_cfg", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &lm85_pwm_config}, - {LM85_SYSCTL_PWM_ZONE1, "pwm1_zone", NULL, 0, 0644, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &lm85_pwm_zone}, - {LM85_SYSCTL_PWM_ZONE2, "pwm2_zone", NULL, 0, 0644, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &lm85_pwm_zone}, - {LM85_SYSCTL_PWM_ZONE3, "pwm3_zone", NULL, 0, 0644, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &lm85_pwm_zone}, - {LM85_SYSCTL_ZONE1, "zone1", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &lm85_zone}, - {LM85_SYSCTL_ZONE2, "zone2", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &lm85_zone}, - {LM85_SYSCTL_ZONE3, "zone3", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &lm85_zone}, - {LM85_SYSCTL_SMOOTH1, "smooth1", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &lm85_smooth}, - {LM85_SYSCTL_SMOOTH2, "smooth2", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &lm85_smooth}, - {LM85_SYSCTL_SMOOTH3, "smooth3", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &lm85_smooth}, - {0} -}; -#define CTLTBL_COMMON (sizeof(lm85_common)/sizeof(lm85_common[0])) - -/* NOTE: tach_mode is a shared name, but implemented with - * different functions - */ -static ctl_table lm85_specific[] = { - {LM85_SYSCTL_SPINUP_CTL, "spinup_ctl", NULL, 0, 0644, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &lm85_spinup_ctl}, - {LM85_SYSCTL_TACH_MODE, "tach_mode", NULL, 0, 0644, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &lm85_tach_mode}, -/* {0} The doc generator needs this. */ -}; -#define CTLTBL_LM85 (sizeof(lm85_specific)/sizeof(lm85_specific[0])) - -static ctl_table adm1027_specific[] = { - {ADM1027_SYSCTL_TACH_MODE, "tach_mode", NULL, 0, 0644, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &adm1027_tach_mode}, - {ADM1027_SYSCTL_TEMP_OFFSET1, "temp1_offset", NULL, 0, 0644, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &adm1027_temp_offset}, - {ADM1027_SYSCTL_TEMP_OFFSET2, "temp2_offset", NULL, 0, 0644, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &adm1027_temp_offset}, - {ADM1027_SYSCTL_TEMP_OFFSET3, "temp3_offset", NULL, 0, 0644, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &adm1027_temp_offset}, - {ADM1027_SYSCTL_FAN_PPR, "fan_ppr", NULL, 0, 0644, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &adm1027_fan_ppr}, - {ADM1027_SYSCTL_ALARM_MASK, "alarm_mask", NULL, 0, 0644, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &adm1027_alarm_mask}, -/* {0} The doc generator needs this. */ -}; -#define CTLTBL_ADM1027 (sizeof(adm1027_specific)/sizeof(adm1027_specific[0])) - -static ctl_table adt7463_specific[] = { - {ADT7463_SYSCTL_TMIN_CTL1, "tmin_ctl1", NULL, 0, 0644, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &adt7463_tmin_ctl}, - {ADT7463_SYSCTL_TMIN_CTL2, "tmin_ctl2", NULL, 0, 0644, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &adt7463_tmin_ctl}, - {ADT7463_SYSCTL_TMIN_CTL3, "tmin_ctl3", NULL, 0, 0644, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &adt7463_tmin_ctl}, - {ADT7463_SYSCTL_THERM_SIGNAL, "therm_signal", NULL, 0, 0644, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &adt7463_therm_signal}, -/* {0} The doc generator needs this. */ -}; -#define CTLTBL_ADT7463 (sizeof(adt7463_specific)/sizeof(adt7463_specific[0])) - -static ctl_table emc6d100_specific[] = { - {EMC6D100_SYSCTL_IN5, "in5", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &emc6d100_in}, - {EMC6D100_SYSCTL_IN6, "in6", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &emc6d100_in}, - {EMC6D100_SYSCTL_IN7, "in7", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &emc6d100_in}, -/* {0} The doc generator needs this. */ -}; -#define CTLTBL_EMC6D100 (sizeof(emc6d100_specific)/sizeof(emc6d100_specific[0])) - - -#define MAX2(a,b) ((a)>(b)?(a):(b)) -#define MAX3(a,b,c) ((a)>(b)?MAX2((a),(c)):MAX2((b),(c))) -#define MAX4(a,b,c,d) ((a)>(b)?MAX3((a),(c),(d)):MAX3((b),(c),(d))) - -#define CTLTBL_MAX (CTLTBL_COMMON + MAX3(CTLTBL_LM85, CTLTBL_ADM1027+CTLTBL_ADT7463, CTLTBL_EMC6D100)) - -/* This function is called when: - * lm85_driver is inserted (when this module is loaded), for each - available adapter - * when a new adapter is inserted (and lm85_driver is still present) */ -static int lm85_attach_adapter(struct i2c_adapter *adapter) -{ - return i2c_detect(adapter, &addr_data, lm85_detect); -} - -/* This function is called by i2c_detect */ -static int lm85_detect(struct i2c_adapter *adapter, int address, - unsigned short flags, int kind) -{ - int i; - int company, verstep ; - struct i2c_client *new_client; - struct lm85_data *data; - int err = 0; - const char *type_name = ""; - struct ctl_table template[CTLTBL_MAX] ; - int template_used ; - - if (i2c_is_isa_adapter(adapter)) { - /* This chip has no ISA interface */ - goto ERROR0 ; - }; - - if (!i2c_check_functionality(adapter, - I2C_FUNC_SMBUS_BYTE_DATA)) { - /* We need to be able to do byte I/O */ - goto ERROR0 ; - }; - - /* OK. For now, we presume we have a valid client. We now create the - client structure, even though we cannot fill it completely yet. - But it allows us to access lm85_{read,write}_value. */ - - if (!(data = kmalloc(sizeof(struct lm85_data), GFP_KERNEL))) { - err = -ENOMEM; - goto ERROR0; - } - - new_client = &data->client; - new_client->addr = address; - new_client->data = data; - new_client->adapter = adapter; - new_client->driver = &lm85_driver; - new_client->flags = 0; - - /* Now, we do the remaining detection. */ - - company = lm85_read_value(new_client, LM85_REG_COMPANY); - verstep = lm85_read_value(new_client, LM85_REG_VERSTEP); - -#ifdef DEBUG - printk("lm85: Detecting device at %d,0x%02x with" - " COMPANY: 0x%02x and VERSTEP: 0x%02x\n", - i2c_adapter_id(new_client->adapter), new_client->addr, - company, verstep - ); -#endif - - /* If auto-detecting, Determine the chip type. */ - if (kind <= 0) { -#ifdef DEBUG - printk("lm85: Autodetecting device at %d,0x%02x ...\n", - i2c_adapter_id(adapter), address ); -#endif - if( company == LM85_COMPANY_NATIONAL - && verstep == LM85_VERSTEP_LM85C ) { - kind = lm85c ; - } else if( company == LM85_COMPANY_NATIONAL - && verstep == LM85_VERSTEP_LM85B ) { - kind = lm85b ; - } else if( company == LM85_COMPANY_NATIONAL - && (verstep & LM85_VERSTEP_VMASK) == LM85_VERSTEP_GENERIC) { - printk("lm85: Detected National Semiconductor chip\n"); - printk("lm85: Unrecognized version/stepping 0x%02x" - " Defaulting to Generic LM85.\n", verstep ); - kind = any_chip ; - } else if( company == LM85_COMPANY_ANALOG_DEV - && verstep == LM85_VERSTEP_ADM1027 ) { - kind = adm1027 ; - } else if( company == LM85_COMPANY_ANALOG_DEV - && (verstep == LM85_VERSTEP_ADT7463 - || verstep == LM85_VERSTEP_ADT7463C) ) { - kind = adt7463 ; - } else if( company == LM85_COMPANY_ANALOG_DEV - && (verstep & LM85_VERSTEP_VMASK) == LM85_VERSTEP_GENERIC) { - printk("lm85: Detected Analog Devices chip\n"); - printk("lm85: Unrecognized version/stepping 0x%02x" - " Defaulting to Generic LM85.\n", verstep ); - kind = any_chip ; - } else if( company == LM85_COMPANY_SMSC - && verstep == LM85_VERSTEP_EMC6D102) { - kind = emc6d102; - } else if( company == LM85_COMPANY_SMSC - && (verstep == LM85_VERSTEP_EMC6D100_A0 - || verstep == LM85_VERSTEP_EMC6D100_A1) ) { - /* Unfortunately, we can't tell a '100 from a '101 - * from the registers. Since a '101 is a '100 - * in a package with fewer pins and therefore no - * 3.3V, 1.5V or 1.8V inputs, perhaps if those - * inputs read 0, then it's a '101. - */ - kind = emc6d100 ; - } else if( company == LM85_COMPANY_SMSC - && (verstep & LM85_VERSTEP_VMASK) == LM85_VERSTEP_GENERIC) { - printk("lm85: Detected SMSC chip\n"); - printk("lm85: Unrecognized version/stepping 0x%02x" - " Defaulting to Generic LM85.\n", verstep ); - kind = any_chip ; - } else if( kind == any_chip - && (verstep & LM85_VERSTEP_VMASK) == LM85_VERSTEP_GENERIC) { - printk("lm85: Generic LM85 Version 6 detected\n"); - /* Leave kind as "any_chip" */ - } else { -#ifdef DEBUG - printk("lm85: Autodetection failed\n"); -#endif - /* Not an LM85 ... */ - if( kind == any_chip ) { /* User used force=x,y */ - printk("lm85: Generic LM85 Version 6 not" - " found at %d,0x%02x. Try force_lm85c.\n", - i2c_adapter_id(adapter), address ); - } - goto ERROR1; - } - } - - /* Fill in the chip specific driver values */ - switch (kind) { - case any_chip : - type_name = "lm85"; - strcpy(new_client->name, "Generic LM85"); - template_used = 0 ; - break ; - case lm85b : - type_name = "lm85b"; - strcpy(new_client->name, "National LM85-B"); - memcpy( template, lm85_specific, sizeof(lm85_specific) ); - template_used = CTLTBL_LM85 ; - break ; - case lm85c : - type_name = "lm85c"; - strcpy(new_client->name, "National LM85-C"); - memcpy( template, lm85_specific, sizeof(lm85_specific) ); - template_used = CTLTBL_LM85 ; - break ; - case adm1027 : - type_name = "adm1027"; - strcpy(new_client->name, "Analog Devices ADM1027"); - memcpy( template, adm1027_specific, sizeof(adm1027_specific) ); - template_used = CTLTBL_ADM1027 ; - break ; - case adt7463 : - type_name = "adt7463"; - strcpy(new_client->name, "Analog Devices ADT7463"); - memcpy( template, adt7463_specific, sizeof(adt7463_specific) ); - template_used = CTLTBL_ADT7463 ; - memcpy( template+template_used, adm1027_specific, sizeof(adm1027_specific) ); - template_used += CTLTBL_ADM1027 ; - break ; - case emc6d100 : - type_name = "emc6d100"; - strcpy(new_client->name, "SMSC EMC6D100"); - memcpy(template, emc6d100_specific, sizeof(emc6d100_specific)); - template_used = CTLTBL_EMC6D100 ; - break ; - case emc6d102 : - type_name = "emc6d102"; - strcpy(new_client->name, "SMSC EMC6D102"); - template_used = 0; - break; - default : - printk("lm85: Internal error, invalid kind (%d)!\n", kind); - err = -EFAULT ; - goto ERROR1; - } - - /* Fill in the remaining client fields */ - new_client->id = lm85_id++; - printk("lm85: Assigning ID %d to %s at %d,0x%02x\n", - new_client->id, new_client->name, - i2c_adapter_id(new_client->adapter), - new_client->addr - ); - - /* Housekeeping values */ - data->type = kind; - data->valid = 0; - - /* Set the VRM version */ - data->vrm = LM85_INIT_VRM ; - - /* Zero the accumulators */ - data->therm_total = 0; - data->therm_ovfl = 0; - - init_MUTEX(&data->update_lock); - data->extend_adc = 0; - - /* Initialize the LM85 chip */ - lm85_init_client(new_client); - - /* Tell the I2C layer a new client has arrived */ - if ((err = i2c_attach_client(new_client))) - goto ERROR1; - - /* Finish out the template */ - memcpy( template + template_used, lm85_common, sizeof(lm85_common) ); - - /* Register a new directory entry with module sensors */ - if ((i = i2c_register_entry(new_client, - type_name, - template, - THIS_MODULE)) < 0) { - err = i; - goto ERROR2; - } - data->sysctl_id = i; - - return 0; - - /* Error out and cleanup code */ - ERROR2: - i2c_detach_client(new_client); - ERROR1: - kfree(data); - ERROR0: - return err; -} - -static int lm85_detach_client(struct i2c_client *client) -{ - int err; - int id ; - - id = client->id; - i2c_deregister_entry(((struct lm85_data *)(client->data))->sysctl_id); - - if ((err = i2c_detach_client(client))) { - printk("lm85(%d): Client deregistration failed," - " client not detached.\n", id ); - return err; - } - - kfree(client->data); - - return 0; -} - -static int lm85_read_value(struct i2c_client *client, u16 reg) -{ - int res; - - /* What size location is it? */ - switch( reg ) { - case LM85_REG_FAN(0) : /* Read WORD data */ - case LM85_REG_FAN(1) : - case LM85_REG_FAN(2) : - case LM85_REG_FAN(3) : - case LM85_REG_FAN_MIN(0) : - case LM85_REG_FAN_MIN(1) : - case LM85_REG_FAN_MIN(2) : - case LM85_REG_FAN_MIN(3) : - case LM85_REG_ALARM : /* Read ALARM1 and ALARM2 */ - case ADM1027_REG_INTMASK : /* Read MASK1 and MASK2 */ - case ADM1027_REG_EXTEND_ADC : /* Read ADC1 and ADC2 */ - reg &= 0xff ; /* Pseudo words have address + 0x0100 */ - res = i2c_smbus_read_byte_data(client, reg) & 0xff ; - res |= (i2c_smbus_read_byte_data(client, reg+1) & 0xff) << 8 ; - break ; - case ADT7463_REG_TMIN_CTL : /* Read WORD MSB, LSB */ - reg &= 0xff ; /* Pseudo words have address + 0x0100 */ - res = (i2c_smbus_read_byte_data(client, reg) & 0xff) << 8 ; - res |= i2c_smbus_read_byte_data(client, reg+1) & 0xff ; - break ; - default: /* Read BYTE data */ - res = i2c_smbus_read_byte_data(client, reg & 0xff) & 0xff ; - break ; - } - - return res ; -} - -static int lm85_write_value(struct i2c_client *client, u16 reg, int value) -{ - int res ; - - switch( reg ) { - case LM85_REG_FAN(0) : /* Write WORD data */ - case LM85_REG_FAN(1) : - case LM85_REG_FAN(2) : - case LM85_REG_FAN(3) : - case LM85_REG_FAN_MIN(0) : - case LM85_REG_FAN_MIN(1) : - case LM85_REG_FAN_MIN(2) : - case LM85_REG_FAN_MIN(3) : - case ADM1027_REG_INTMASK : - /* NOTE: ALARM and ADC are read only, so not included here */ - reg &= 0xff ; /* Pseudo words have address + 0x0100 */ - res = i2c_smbus_write_byte_data(client, reg, value & 0xff) ; - res |= i2c_smbus_write_byte_data(client, reg+1, (value>>8) & 0xff) ; - break ; - case ADT7463_REG_TMIN_CTL : /* Write WORD MSB, LSB */ - reg &= 0xff ; /* Pseudo words have address + 0x0100 */ - res = i2c_smbus_write_byte_data(client, reg, (value>>8) & 0xff); - res |= i2c_smbus_write_byte_data(client, reg+1, value & 0xff) ; - break ; - default: /* Write BYTE data */ - res = i2c_smbus_write_byte_data(client, reg & 0xff, value); - break ; - } - - return res ; -} - -/* Called when we have found a new LM85. */ -static void lm85_init_client(struct i2c_client *client) -{ - int value; - struct lm85_data *data = client->data; - -#ifdef DEBUG - printk("lm85(%d): Initializing device\n", client->id); -#endif - - /* Warn if part was not "READY" */ - value = lm85_read_value(client, LM85_REG_CONFIG); -#ifdef DEBUG - printk("lm85(%d): LM85_REG_CONFIG is: 0x%02x\n", client->id, value ); -#endif - if( value & 0x02 ) { - printk("lm85(%d): Client (%d,0x%02x) config is locked.\n", - client->id, - i2c_adapter_id(client->adapter), client->addr ); - }; - if( ! (value & 0x04) ) { - printk("lm85(%d): Client (%d,0x%02x) is not ready.\n", - client->id, - i2c_adapter_id(client->adapter), client->addr ); - }; - if( (data->type == adm1027 || data->type == adt7463) - && (value & 0x10) - ) { - printk("lm85(%d): Client (%d,0x%02x) VxI mode is set. " - "Please report this to the lm85 maintainer.\n", - client->id, - i2c_adapter_id(client->adapter), client->addr ); - }; - - /* See if SYNC to PWM3 is set */ - if( data->type == adt7463 - && (lm85_read_value(client, LM85_REG_AFAN_SPIKE1) & 0x10) - ) { - printk("lm85(%d): Sync to PWM3 is set. Expect PWM3 " - "to control fans 2, 3, and 4\n", - client->id ); - }; - - /* See if PWM2 is #SMBALERT */ - if( (data->type == adm1027 || data->type == adt7463) - && (lm85_read_value(client, ADM1027_REG_CONFIG3) & 0x01) - ) { - printk("lm85(%d): PWM2 is SMBALERT. PWM2 not available.\n", - client->id ); - }; - - /* Check if 2.5V and 5V inputs are reconfigured */ - if( data->type == adt7463 ) { - value = lm85_read_value(client, ADT7463_REG_CONFIG4); - if( value & 0x01 ) { - printk("lm85(%d): 2.5V input (in0) is SMBALERT. " - "in0 not available.\n", client->id ); - }; - if( value & 0x02 ) { - printk("lm85(%d): 5V input (in3) is THERM. " - "in3 not available.\n", client->id ); - } - }; - - /* FIXME? Display EMC6D100 config info? */ - - /* WE INTENTIONALLY make no changes to the limits, - * offsets, pwms, fans and zones. If they were - * configured, we don't want to mess with them. - * If they weren't, the default is 100% PWM, no - * control and will suffice until 'sensors -s' - * can be run by the user. - */ - - /* Start monitoring */ - value = lm85_read_value(client, LM85_REG_CONFIG); - /* Try to clear LOCK, Set START, save everything else */ - value = ((value & ~ 0x02) | 0x01) & 0xff ; -#ifdef DEBUG - printk("lm85(%d): Setting CONFIG to: 0x%02x\n", client->id, value ); -#endif - lm85_write_value(client, LM85_REG_CONFIG, value); - -} - -static void lm85_update_client(struct i2c_client *client) -{ - struct lm85_data *data = client->data; - int i; - - down(&data->update_lock); - - if (!data->valid - || (jiffies - data->last_reading > LM85_DATA_INTERVAL )) { - /* Things that change quickly */ - -#ifdef DEBUG - printk("lm85(%d): Reading sensor values\n", client->id); -#endif - /* Have to read extended bits first to "freeze" the - * more significant bits that are read later. - */ - switch( data->type ) { - case adm1027 : - case adt7463 : - data->extend_adc = - lm85_read_value(client, ADM1027_REG_EXTEND_ADC); - break ; - default : - break ; - } - - for (i = 0; i <= 4; ++i) { - data->in[i] = - lm85_read_value(client, LM85_REG_IN(i)); - } - - for (i = 0; i <= 3; ++i) { - data->fan[i] = - lm85_read_value(client, LM85_REG_FAN(i)); - } - - for (i = 0; i <= 2; ++i) { - data->temp[i] = - lm85_read_value(client, LM85_REG_TEMP(i)); - } - - for (i = 0; i <= 2; ++i) { - data->pwm[i] = - lm85_read_value(client, LM85_REG_PWM(i)); - } - - data->alarms = lm85_read_value(client, LM85_REG_ALARM); - - switch( data->type ) { - case adt7463 : - /* REG_THERM code duplicated in therm_signal() */ - i = lm85_read_value(client, ADT7463_REG_THERM); - if( data->therm_total < LONG_MAX - 256 ) { - data->therm_total += i ; - } - if( i >= 255 ) { - ++data->therm_ovfl ; - } - break ; - case emc6d100 : - /* Three more voltage sensors */ - for (i = 5; i <= 7; ++i) { - data->in[i] = - lm85_read_value(client, EMC6D100_REG_IN(i)); - } - /* More alarm bits */ - data->alarms |= - lm85_read_value(client, EMC6D100_REG_ALARM3) << 16; - - break ; - case emc6d102 : - /* Have to read LSB bits after the MSB ones because - the reading of the MSB bits has frozen the - LSBs (backward from the ADM1027). - We use only two extra bits per channel, and encode - them in the same format the ADM1027 uses, to keep the - rest of the code unchanged. - */ - i = lm85_read_value(client, EMC6D102_REG_EXTEND_ADC1); - data->extend_adc = (i & 0xcc) << 8; /* temp3, temp1 */ - i = lm85_read_value(client, EMC6D102_REG_EXTEND_ADC2); - data->extend_adc |= (i & 0x0c) << 10; /* temp2 */ - data->extend_adc |= (i & 0xc0) << 2; /* in4 */ - i = lm85_read_value(client, EMC6D102_REG_EXTEND_ADC3); - data->extend_adc |= (i & 0x0c) >> 2; /* in0 */ - data->extend_adc |= i & 0xc0; /* in3 */ - i = lm85_read_value(client, EMC6D102_REG_EXTEND_ADC4); - data->extend_adc |= i & 0x0c; /* in1 */ - data->extend_adc |= (i & 0xc0) >> 2; /* in2 */ - break; - default : break ; /* no warnings */ - } - - data->last_reading = jiffies ; - }; /* last_reading */ - - if (!data->valid - || (jiffies - data->last_config > LM85_CONFIG_INTERVAL) ) { - /* Things that don't change often */ - -#ifdef DEBUG - printk("lm85(%d): Reading config values\n", client->id); -#endif - for (i = 0; i <= 4; ++i) { - data->in_min[i] = - lm85_read_value(client, LM85_REG_IN_MIN(i)); - data->in_max[i] = - lm85_read_value(client, LM85_REG_IN_MAX(i)); - } - - for (i = 0; i <= 3; ++i) { - data->fan_min[i] = - lm85_read_value(client, LM85_REG_FAN_MIN(i)); - } - - for (i = 0; i <= 2; ++i) { - data->temp_min[i] = - lm85_read_value(client, LM85_REG_TEMP_MIN(i)); - data->temp_max[i] = - lm85_read_value(client, LM85_REG_TEMP_MAX(i)); - } - - data->vid = lm85_read_value(client, LM85_REG_VID); - - for (i = 0; i <= 2; ++i) { - int val ; - data->autofan[i].config = - lm85_read_value(client, LM85_REG_AFAN_CONFIG(i)); - val = lm85_read_value(client, LM85_REG_AFAN_RANGE(i)); - data->autofan[i].freq = val & 0x07 ; - data->zone[i].range = (val >> 4) & 0x0f ; - data->autofan[i].min_pwm = - lm85_read_value(client, LM85_REG_AFAN_MINPWM(i)); - data->zone[i].limit = - lm85_read_value(client, LM85_REG_AFAN_LIMIT(i)); - data->zone[i].critical = - lm85_read_value(client, LM85_REG_AFAN_CRITICAL(i)); - } - - i = lm85_read_value(client, LM85_REG_AFAN_SPIKE1); - data->smooth[0] = i & 0x0f ; - data->syncpwm3 = i & 0x10 ; /* Save PWM3 config */ - data->autofan[0].min_off = i & 0x20 ; - data->autofan[1].min_off = i & 0x40 ; - data->autofan[2].min_off = i & 0x80 ; - i = lm85_read_value(client, LM85_REG_AFAN_SPIKE2); - data->smooth[1] = (i>>4) & 0x0f ; - data->smooth[2] = i & 0x0f ; - - i = lm85_read_value(client, LM85_REG_AFAN_HYST1); - data->zone[0].hyst = (i>>4) & 0x0f ; - data->zone[1].hyst = i & 0x0f ; - - i = lm85_read_value(client, LM85_REG_AFAN_HYST2); - data->zone[2].hyst = (i>>4) & 0x0f ; - - switch( data->type ) { - case lm85b : - case lm85c : - data->tach_mode = lm85_read_value(client, - LM85_REG_TACH_MODE ); - data->spinup_ctl = lm85_read_value(client, - LM85_REG_SPINUP_CTL ); - break ; - case adt7463 : - for (i = 0; i <= 2; ++i) { - data->oppoint[i] = lm85_read_value(client, - ADT7463_REG_OPPOINT(i) ); - } - data->tmin_ctl = lm85_read_value(client, - ADT7463_REG_TMIN_CTL ); - data->therm_limit = lm85_read_value(client, - ADT7463_REG_THERM_LIMIT ); - /* FALL THROUGH */ - case adm1027 : - for (i = 0; i <= 2; ++i) { - data->temp_offset[i] = lm85_read_value(client, - ADM1027_REG_TEMP_OFFSET(i) ); - } - data->tach_mode = lm85_read_value(client, - ADM1027_REG_CONFIG3 ); - data->fan_ppr = lm85_read_value(client, - ADM1027_REG_FAN_PPR ); - data->alarm_mask = lm85_read_value(client, - ADM1027_REG_INTMASK ); - break ; - case emc6d100 : - for (i = 5; i <= 7; ++i) { - data->in_min[i] = - lm85_read_value(client, EMC6D100_REG_IN_MIN(i)); - data->in_max[i] = - lm85_read_value(client, EMC6D100_REG_IN_MAX(i)); - } - break ; - default : break ; /* no warnings */ - } - - data->last_config = jiffies; - }; /* last_config */ - - data->valid = 1; - - up(&data->update_lock); -} - - -/* The next functions are the call-back functions of the /proc/sys and - sysctl files. Which function is used is defined in the ctl_table in - the extra1 field. - Each function must return the magnitude (power of 10 to divide the data - with) if it is called with operation==SENSORS_PROC_REAL_INFO. It must - put a maximum of *nrels elements in results reflecting the data of this - file, and set *nrels to the number it actually put in it, if operation== - SENSORS_PROC_REAL_READ. Finally, it must get upto *nrels elements from - results and write them to the chip, if operations==SENSORS_PROC_REAL_WRITE. - */ -void lm85_in(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct lm85_data *data = client->data; - int nr = ctl_name - LM85_SYSCTL_IN0; - - if (nr < 0 || nr > 4) - return ; /* ERROR */ - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 3; /* 1.000 */ - else if (operation == SENSORS_PROC_REAL_READ) { - int ext; - lm85_update_client(client); - ext = EXT_FROM_REG(data->extend_adc, nr); - results[0] = INS_FROM_REG(nr,data->in_min[nr]); - results[1] = INS_FROM_REG(nr,data->in_max[nr]); - results[2] = INSEXT_FROM_REG(nr,data->in[nr],ext); - *nrels_mag = 3; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - down(&data->update_lock); - if (*nrels_mag > 1) { - data->in_max[nr] = INS_TO_REG(nr,results[1]); - lm85_write_value(client, LM85_REG_IN_MAX(nr), - data->in_max[nr]); - } - if (*nrels_mag > 0) { - data->in_min[nr] = INS_TO_REG(nr,results[0]); - lm85_write_value(client, LM85_REG_IN_MIN(nr), - data->in_min[nr]); - } - up(&data->update_lock); - } -} - -void lm85_fan(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct lm85_data *data = client->data; - int nr = ctl_name - LM85_SYSCTL_FAN1 ; - - if (nr < 0 || nr > 3) - return ; /* ERROR */ - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - lm85_update_client(client); - results[0] = FAN_FROM_REG(data->fan_min[nr]); - results[1] = FAN_FROM_REG(data->fan[nr]); - *nrels_mag = 2; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - down(&data->update_lock); - if (*nrels_mag > 0) { - data->fan_min[nr] = FAN_TO_REG(results[0]); - lm85_write_value(client, LM85_REG_FAN_MIN(nr), - data->fan_min[nr]); - } - up(&data->update_lock); - } -} - - -void lm85_temp(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct lm85_data *data = client->data; - int nr = ctl_name - LM85_SYSCTL_TEMP1 ; - - if (nr < 0 || nr > 2) - return ; /* ERROR */ - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 2; - else if (operation == SENSORS_PROC_REAL_READ) { - int ext; - lm85_update_client(client); - - /* +5 for offset of temp data in ext reg */ - ext = EXT_FROM_REG(data->extend_adc, nr+5); - - results[0] = TEMP_FROM_REG(data->temp_min[nr]); - results[1] = TEMP_FROM_REG(data->temp_max[nr]); - results[2] = TEMPEXT_FROM_REG(data->temp[nr],ext); - *nrels_mag = 3; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - down(&data->update_lock); - if (*nrels_mag > 1) { - data->temp_max[nr] = TEMP_TO_REG(results[1]); - lm85_write_value(client, LM85_REG_TEMP_MAX(nr), - data->temp_max[nr]); - } - if (*nrels_mag > 0) { - data->temp_min[nr] = TEMP_TO_REG(results[0]); - lm85_write_value(client, LM85_REG_TEMP_MIN(nr), - data->temp_min[nr]); - } - up(&data->update_lock); - } -} - -void lm85_pwm(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct lm85_data *data = client->data; - int nr = ctl_name - LM85_SYSCTL_PWM1 ; - int pwm_zone ; - - if (nr < 0 || nr > 2) - return ; /* ERROR */ - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - lm85_update_client(client); - results[0] = PWM_FROM_REG(data->pwm[nr]); - pwm_zone = ZONE_FROM_REG(data->autofan[nr].config); - /* PWM "enabled" if not off (0) nor on (-1) */ - results[1] = pwm_zone != 0 && pwm_zone != -1 ; - *nrels_mag = 2; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - down(&data->update_lock); - /* PWM enable is read-only */ - if (*nrels_mag > 0) { - data->pwm[nr] = PWM_TO_REG(results[0]); - lm85_write_value(client, LM85_REG_PWM(nr), - data->pwm[nr]); - } - up(&data->update_lock); - } -} - -void lm85_vid(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct lm85_data *data = client->data; - - if( ctl_name != LM85_SYSCTL_VID ) - return ; /* ERROR */ - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 3; - else if (operation == SENSORS_PROC_REAL_READ) { - lm85_update_client(client); - results[0] = vid_from_reg((data->vid)&0x3f, data->vrm); - *nrels_mag = 1; - } -} - -void lm85_vrm(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct lm85_data *data = client->data; - - if( ctl_name != LM85_SYSCTL_VRM ) - return ; /* ERROR */ - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 1; - else if (operation == SENSORS_PROC_REAL_READ) { - results[0] = data->vrm ; - *nrels_mag = 1; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - down(&data->update_lock); - if (*nrels_mag > 0) { - data->vrm = results[0] ; - } - up(&data->update_lock); - } -} - -void lm85_alarms(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct lm85_data *data = client->data; - - if( ctl_name != LM85_SYSCTL_ALARMS ) - return ; /* ERROR */ - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - lm85_update_client(client); - results[0] = data->alarms; - *nrels_mag = 1; - } -} - -void lm85_spinup_ctl(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct lm85_data *data = client->data; - int old; - - if( ctl_name != LM85_SYSCTL_SPINUP_CTL ) - return ; /* ERROR */ - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - lm85_update_client(client); - results[0] = (data->spinup_ctl & 1) != 0 ; - results[1] = (data->spinup_ctl & 2) != 0 ; - results[2] = (data->spinup_ctl & 4) != 0 ; - *nrels_mag = 3; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - down(&data->update_lock); - old = data->spinup_ctl ; - if (*nrels_mag > 2) { - old = (old & (~4)) | (results[2]?4:0) ; - } - if (*nrels_mag > 1) { - old = (old & (~2)) | (results[1]?2:0) ; - } - if (*nrels_mag > 0) { - old = (old & (~1)) | (results[0]?1:0) ; - lm85_write_value(client, LM85_REG_SPINUP_CTL, old); - data->spinup_ctl = old ; - } - up(&data->update_lock); - } -} - -void lm85_tach_mode(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct lm85_data *data = client->data; - int old; - - /* Tach Mode 1, Tach Mode 2, Tach Mode 3 & 4 */ - - if( ctl_name != LM85_SYSCTL_TACH_MODE ) - return ; /* ERROR */ - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - lm85_update_client(client); - results[0] = (data->tach_mode & 0x03) ; - results[1] = (data->tach_mode & 0x0c) >> 2 ; - results[2] = (data->tach_mode & 0x30) >> 4 ; - *nrels_mag = 3; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - down(&data->update_lock); - old = data->tach_mode ; - if (*nrels_mag > 2) { - old = (old & (~0x30)) | ((results[2]&3) << 4) ; - } - if (*nrels_mag > 1) { - old = (old & (~0x0c)) | ((results[1]&3) << 2) ; - } - if (*nrels_mag > 0) { - old = (old & (~0x03)) | (results[0]&3) ; - lm85_write_value(client, LM85_REG_TACH_MODE, old); - data->tach_mode = old ; - } - up(&data->update_lock); - } -} - -void adm1027_tach_mode(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct lm85_data *data = client->data; - int old; - - /* Tach/DC 1, Tach/DC 2, Tach/DC 3, Tach/DC 4 */ - - if( ctl_name != ADM1027_SYSCTL_TACH_MODE ) - return ; /* ERROR */ - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - lm85_update_client(client); - results[0] = (data->tach_mode & 0x10) != 0 ; - results[1] = (data->tach_mode & 0x20) != 0 ; - results[2] = (data->tach_mode & 0x40) != 0 ; - results[3] = (data->tach_mode & 0x80) != 0 ; - *nrels_mag = 4; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - down(&data->update_lock); - old = data->tach_mode ; - if (*nrels_mag > 3) { - old = (old & (~0x80)) | (results[3] ? 0x80 : 0) ; - } - if (*nrels_mag > 2) { - old = (old & (~0x40)) | (results[2] ? 0x40 : 0) ; - } - if (*nrels_mag > 1) { - old = (old & (~0x20)) | (results[1] ? 0x20 : 0) ; - } - if (*nrels_mag > 0) { - old = (old & (~0x10)) | (results[0] ? 0x10 : 0) ; - - /* Enable fast measurements if any TACH's are DC */ - old = (old & (~0x08)) | ((old&0xf0) ? 0x08 : 0) ; - - lm85_write_value(client, ADM1027_REG_CONFIG3, old); - data->tach_mode = old ; - } - up(&data->update_lock); - } -} - -void lm85_pwm_config(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct lm85_data *data = client->data; - int nr = ctl_name - LM85_SYSCTL_PWM_CFG1 ; - - /* Spinup, min PWM, PWM Frequency, min below limit, Invert */ - - if (nr < 0 || nr > 2) - return ; /* ERROR */ - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 1; - else if (operation == SENSORS_PROC_REAL_READ) { - lm85_update_client(client); - - results[0] = SPINUP_FROM_REG(data->autofan[nr].config); - results[1] = PWM_FROM_REG(data->autofan[nr].min_pwm)*10; - results[2] = FREQ_FROM_REG(data->autofan[nr].freq); - results[3] = data->autofan[nr].min_off ? 10 : 0 ; - results[4] = (data->autofan[nr].config & 0x10) ? 10 : 0 ; - *nrels_mag = 5; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - int old_config ; - - down(&data->update_lock); - old_config = data->autofan[nr].config ; - if (*nrels_mag > 4) { - old_config = (old_config & (~0x10)) | (results[4]?0x10:0) ; - } - if (*nrels_mag > 3) { - data->autofan[nr].min_off = results[3] != 0 ; - lm85_write_value(client, LM85_REG_AFAN_SPIKE1, - data->smooth[0] - | data->syncpwm3 - | (data->autofan[0].min_off ? 0x20 : 0) - | (data->autofan[1].min_off ? 0x40 : 0) - | (data->autofan[2].min_off ? 0x80 : 0) - ); - } - if (*nrels_mag > 2) { - data->autofan[nr].freq = FREQ_TO_REG(results[2]) ; - lm85_write_value(client, LM85_REG_AFAN_RANGE(nr), - (data->zone[nr].range << 4) - | data->autofan[nr].freq - ); - } - if (*nrels_mag > 1) { - data->autofan[nr].min_pwm = PWM_TO_REG((results[1]+5)/10); - lm85_write_value(client, LM85_REG_AFAN_MINPWM(nr), - data->autofan[nr].min_pwm - ); - } - if (*nrels_mag > 0) { - old_config = (old_config & (~0x07)) | SPINUP_TO_REG(results[0]) ; - lm85_write_value(client, LM85_REG_AFAN_CONFIG(nr), old_config); - data->autofan[nr].config = old_config ; - } - up(&data->update_lock); - } -} - -void lm85_smooth(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct lm85_data *data = client->data; - int nr = ctl_name - LM85_SYSCTL_SMOOTH1 ; - - if (nr < 0 || nr > 2) - return ; /* ERROR */ - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 1; - else if (operation == SENSORS_PROC_REAL_READ) { - lm85_update_client(client); - results[0] = SMOOTH_FROM_REG(data->smooth[nr]); - *nrels_mag = 1; - - } else if (operation == SENSORS_PROC_REAL_WRITE) { - down(&data->update_lock); - if( *nrels_mag > 0 ) { - data->smooth[nr] = SMOOTH_TO_REG(results[0]); - } - if( nr == 0 ) { - lm85_write_value(client, LM85_REG_AFAN_SPIKE1, - data->smooth[0] - | data->syncpwm3 - | (data->autofan[0].min_off ? 0x20 : 0) - | (data->autofan[1].min_off ? 0x40 : 0) - | (data->autofan[2].min_off ? 0x80 : 0) - ); - } else { - lm85_write_value(client, LM85_REG_AFAN_SPIKE2, - (data->smooth[1] << 4) | data->smooth[2]); - } - up(&data->update_lock); - } -} - -void lm85_zone(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct lm85_data *data = client->data; - int nr = ctl_name - LM85_SYSCTL_ZONE1 ; - - /* Limit, Hysteresis (neg), Range, Critical */ - - if (nr < 0 || nr > 2) - return ; /* ERROR */ - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 1; - else if (operation == SENSORS_PROC_REAL_READ) { - lm85_update_client(client); - - results[0] = TEMP_FROM_REG(data->zone[nr].limit) / 10; - results[1] = HYST_FROM_REG(data->zone[nr].hyst); - results[2] = RANGE_FROM_REG(data->zone[nr].range); - results[3] = TEMP_FROM_REG(data->zone[nr].critical) / 10; - *nrels_mag = 4; - - } else if (operation == SENSORS_PROC_REAL_WRITE) { - down(&data->update_lock); - if (*nrels_mag > 3) { - data->zone[nr].critical = TEMP_TO_REG(results[3]*10); - lm85_write_value(client, LM85_REG_AFAN_CRITICAL(nr), - data->zone[nr].critical ); - } - if (*nrels_mag > 2) { - data->zone[nr].range = RANGE_TO_REG(results[2]); - lm85_write_value(client, LM85_REG_AFAN_RANGE(nr), - (data->zone[nr].range << 4) - | data->autofan[nr].freq - ); - } - if (*nrels_mag > 1) { - data->zone[nr].hyst = HYST_TO_REG(results[1]); - if( nr == 0 || nr == 1 ) { - lm85_write_value(client, LM85_REG_AFAN_HYST1, - (data->zone[0].hyst << 4) - | data->zone[1].hyst - ); - } else { - lm85_write_value(client, LM85_REG_AFAN_HYST2, - (data->zone[2].hyst << 4) - ); - } - } - if (*nrels_mag > 0) { - data->zone[nr].limit = TEMP_TO_REG(results[0]*10); - lm85_write_value(client, LM85_REG_AFAN_LIMIT(nr), - data->zone[nr].limit - ); - } - up(&data->update_lock); - } -} - -void lm85_pwm_zone(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct lm85_data *data = client->data; - int nr = ctl_name - LM85_SYSCTL_PWM_ZONE1 ; - - if (nr < 0 || nr > 2) - return ; /* ERROR */ - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - lm85_update_client(client); - results[0] = ZONE_FROM_REG(data->autofan[nr].config); - *nrels_mag = 1; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - down(&data->update_lock); - if (*nrels_mag > 0) { - data->autofan[nr].config = - (data->autofan[nr].config & (~0xe0)) - | ZONE_TO_REG(results[0]) ; - lm85_write_value(client, LM85_REG_AFAN_CONFIG(nr), - data->autofan[nr].config); - } - up(&data->update_lock); - } -} - -void adm1027_temp_offset(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct lm85_data *data = client->data; - int nr = ctl_name - ADM1027_SYSCTL_TEMP_OFFSET1 ; - - if (nr < 0 || nr > 2) - return ; /* ERROR */ - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 2; - else if (operation == SENSORS_PROC_REAL_READ) { - lm85_update_client(client); - switch( data->type ) { - case adm1027 : - default : - results[0] = TEMP_FROM_REG(data->temp_offset[nr]); - break ; - case adt7463 : - results[0] = TEMPEXT_FROM_REG(0,data->temp_offset[nr]); - break ; - } - *nrels_mag = 1; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - down(&data->update_lock); - if (*nrels_mag > 0) { - switch( data->type ) { - case adm1027 : - default : - data->temp_offset[nr] = TEMP_TO_REG(results[0]); - break ; - case adt7463 : - data->temp_offset[nr] = EXTTEMP_TO_REG(results[0]); - break ; - }; - lm85_write_value(client, ADM1027_REG_TEMP_OFFSET(nr), - data->temp_offset[nr]); - } - up(&data->update_lock); - } -} - -void adm1027_fan_ppr(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct lm85_data *data = client->data; - int old ; - - if (ctl_name != ADM1027_SYSCTL_FAN_PPR) - return ; /* ERROR */ - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - lm85_update_client(client); - results[0] = PPR_FROM_REG(data->fan_ppr,0); - results[1] = PPR_FROM_REG(data->fan_ppr,1); - results[2] = PPR_FROM_REG(data->fan_ppr,2); - results[3] = PPR_FROM_REG(data->fan_ppr,3); - *nrels_mag = 4; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - down(&data->update_lock); - old = data->fan_ppr ; - if (*nrels_mag > 3) { - old = (old & ~PPR_MASK(3)) | PPR_TO_REG(results[3],3); - }; - if (*nrels_mag > 2) { - old = (old & ~PPR_MASK(2)) | PPR_TO_REG(results[2],2); - }; - if (*nrels_mag > 1) { - old = (old & ~PPR_MASK(1)) | PPR_TO_REG(results[1],1); - }; - if (*nrels_mag > 0) { - old = (old & ~PPR_MASK(0)) | PPR_TO_REG(results[0],0); - lm85_write_value(client, ADM1027_REG_FAN_PPR, old); - data->fan_ppr = old ; - } - up(&data->update_lock); - } -} - -void adm1027_alarm_mask(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results) -{ - struct lm85_data *data = client->data; - - if( ctl_name != ADM1027_SYSCTL_ALARM_MASK ) - return ; /* ERROR */ - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - lm85_update_client(client); - results[0] = INTMASK_FROM_REG(data->alarm_mask); - *nrels_mag = 1; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - down(&data->update_lock); - if (*nrels_mag > 0) { - data->alarm_mask = INTMASK_TO_REG(results[0]); - lm85_write_value(client, ADM1027_REG_INTMASK, - data->alarm_mask); - } - up(&data->update_lock); - } -} - -void adt7463_tmin_ctl(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct lm85_data *data = client->data; - int nr = ctl_name - ADT7463_SYSCTL_TMIN_CTL1 ; - u16 old ; - - if (nr < 0 || nr > 2) - return ; /* ERROR */ - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - old = data->tmin_ctl ; - results[0] = (old & ( 0x2000 << nr )) != 0 ; - results[1] = (old >> (nr*3)) & 0x07 ; - results[2] = (old & ( 0x0400 << nr )) != 0 ; - results[3] = OPPOINT_FROM_REG(data->oppoint[nr]); - *nrels_mag = 4; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - down(&data->update_lock); - old = data->tmin_ctl ; - if (*nrels_mag > 3) { - data->oppoint[nr] = OPPOINT_TO_REG(results[3]); - lm85_write_value(client, ADT7463_REG_OPPOINT(nr), - data->oppoint[nr]); - }; - if (*nrels_mag > 2) { - if( results[2] ) { - old |= (0x0400 << nr) ; - } else { - old &= ~(0x0400 << nr) ; - } - }; - if (*nrels_mag > 1) { - old &= ~(0x07 << (nr*3)) ; - old |= (results[1] & 0x07) << (nr*3) ; - }; - if (*nrels_mag > 0) { - if( results[0] ) { - old |= 0x2000 << nr ; - } else { - old &= ~(0x2000 << nr) ; - } - lm85_write_value(client, ADT7463_REG_TMIN_CTL, old); - data->tmin_ctl = old ; - } - up(&data->update_lock); - } -} - -void adt7463_therm_signal(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results) -{ - struct lm85_data *data = client->data; - int counts ; - - if (ctl_name != ADT7463_SYSCTL_THERM_SIGNAL) - return ; /* ERROR */ - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - /* Don't call update_client here because - * ADT7463_REG_THERM has to be read every - * 5 seconds to prevent lost counts - */ - down(&data->update_lock); - counts = lm85_read_value(client, ADT7463_REG_THERM) & 0xff; - if( data->therm_total < LONG_MAX - 256 ) { - data->therm_total += counts ; - } - if( counts >= 255 ) { - ++data->therm_ovfl ; - } - up(&data->update_lock); - - results[0] = data->therm_limit ; - results[1] = data->therm_total ; - results[2] = data->therm_ovfl ; - *nrels_mag = 3; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - down(&data->update_lock); - /* therm_total and therm_ovfl are read only */ - if (*nrels_mag > 0) { - data->therm_limit = SENSORS_LIMIT(results[0],0,255); - lm85_write_value(client, ADT7463_REG_THERM_LIMIT, - data->therm_limit); - }; - up(&data->update_lock); - } -} - - -void emc6d100_in(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct lm85_data *data = client->data; - int nr = ctl_name - EMC6D100_SYSCTL_IN5 +5; - - if (nr < 5 || nr > 7) - return ; /* ERROR */ - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 3; /* 1.000 */ - else if (operation == SENSORS_PROC_REAL_READ) { - lm85_update_client(client); - results[0] = INS_FROM_REG(nr,data->in_min[nr]); - results[1] = INS_FROM_REG(nr,data->in_max[nr]); - results[2] = INS_FROM_REG(nr,data->in[nr]); - *nrels_mag = 3; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - down(&data->update_lock); - if (*nrels_mag > 1) { - data->in_max[nr] = INS_TO_REG(nr,results[1]); - lm85_write_value(client, EMC6D100_REG_IN_MAX(nr), - data->in_max[nr]); - } - if (*nrels_mag > 0) { - data->in_min[nr] = INS_TO_REG(nr,results[0]); - lm85_write_value(client, EMC6D100_REG_IN_MIN(nr), - data->in_min[nr]); - } - up(&data->update_lock); - } -} - - -static int __init sm_lm85_init(void) -{ - printk("lm85: Version %s (%s)\n", LM_VERSION, LM_DATE); - return i2c_add_driver(&lm85_driver); -} - -static void __exit sm_lm85_exit(void) -{ - i2c_del_driver(&lm85_driver); -} - -/* Thanks to Richard Barrington for adding the LM85 to sensors-detect. - * Thanks to Margit Schubert-While for help with - * post 2.7.0 CVS changes - */ -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Philip Pokorny - Philip Edelbrock - Stephen Rousset - Dan Eaton - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - - -#include -#include -#include -#include -#include -#include -#include "version.h" -#include "sensors_vid.h" - -/* Chip configuration settings. These should be set to reflect the -HARDWARE configuration of your chip. By default (read: when all of -these are left commented out), this driver assumes that the -configuration is the same as National's defaults for the Channel Mode -register. - -Set to '1' the appropriate defines, as nessesary: - - - External temp sensors 2 (possible second CPU temp) - This will disable the 2.5V and Vccp2 readings. - Ironically, National decided that you can read the - temperature of a second CPU or it's core voltage, - but not both! Comment out if FAULT is reported. */ - -/* #define LM87_EXT2 1 */ - -/* Aux analog input. When enabled, the Fan 1 reading - will be disabled */ - -/* #define LM87_AIN1 1 */ - -/* Aux analog input 2. When enabled, the Fan 2 reading - will be disabled */ - -/* #define LM87_AIN2 1 */ - -/* Internal Vcc is 5V instead of 3.3V */ - -/* #define LM87_5V_VCC 1 */ - -/* That's the end of the hardware config defines. I would have made - them insmod params, but it would be too much work. ;') */ - - - -/* Addresses to scan */ -static unsigned short normal_i2c[] = { SENSORS_I2C_END }; -static unsigned short normal_i2c_range[] = { 0x2c, 0x2e, SENSORS_I2C_END }; -static unsigned int normal_isa[] = { SENSORS_ISA_END }; -static unsigned int normal_isa_range[] = { SENSORS_ISA_END }; - -/* Insmod parameters */ -SENSORS_INSMOD_1(lm87); - -/* The following is the calculation for the register offset - * for the monitored items minimum and maximum locations. - */ -#define LM87_REG_IN_MAX(nr) (0x2b + ((nr) * 2)) -#define LM87_REG_IN_MIN(nr) (0x2c + ((nr) * 2)) -#define LM87_REG_IN(nr) (0x20 + (nr)) - -/* Initial limits */ - -/* - * LM87 register definition - * - */ - - /* The LM87 registers */ -#define LM87_INT_TEMP_HI_LIMIT_LOCKABLE 0x13 -#define LM87_EXT_TEMP_HI_LIMIT_LOCKABLE 0x14 -#define LM87_REG_TEST 0x15 -#define LM87_REG_CHANNEL_MODE 0x16 -#define LM87_REG_INT_TEMP_HI_LIMIT 0x17 -#define LM87_REG_EXT_TEMP_HI_LIMIT 0x18 -#define LM87_REG_ANALOG_OUT 0x19 - - /* These are all read-only */ -#define LM87_REG_2_5V_EXT_TEMP_2 0x20 -#define LM87_REG_VCCP1 0x21 -#define LM87_REG_3_3V 0x22 -#define LM87_REG_5V 0x23 -#define LM87_REG_12V 0x24 -#define LM87_REG_VCCP2 0x25 -#define LM87_REG_EXT_TEMP_1 0x26 -#define LM87_REG_INT_TEMP 0x27 /* LM87 temp. */ -#define LM87_REG_FAN1_AIN1 0x28 -#define LM87_REG_FAN2_AIN2 0x29 - -/* These are read/write */ -#define LM87_REG_AIN1_LOW 0x1A -#define LM87_REG_AIN2_LOW 0x1B -#define LM87_REG_2_5V_EXT_TEMP_2_HIGH 0x2B -#define LM87_REG_2_5V_EXT_TEMP_2_LOW 0x2C -#define LM87_REG_VCCP1_HIGH 0x2D -#define LM87_REG_VCCP1_LOW 0x2E -#define LM87_REG_3_3V_HIGH 0x2F -#define LM87_REG_3_3V_LOW 0x30 -#define LM87_REG_5V_HIGH 0x31 -#define LM87_REG_5V_LOW 0x32 -#define LM87_REG_12V_HIGH 0x33 -#define LM87_REG_12V_LOW 0x34 -#define LM87_REG_VCCP2_HIGH 0x35 -#define LM87_REG_VCCP2_LOW 0x36 -#define LM87_REG_EXT_TEMP_1_HIGH 0x37 -#define LM87_REG_EXT_TEMP_1_LOW 0x38 -#define LM87_REG_INT_TEMP_HIGH 0x39 -#define LM87_REG_INT_TEMP_LOW 0x3A -#define LM87_REG_FAN1_AIN1_LIMIT 0x3B -#define LM87_REG_FAN2_AIN2_LIMIT 0x3C -#define LM87_REG_COMPANY_ID 0x3E -#define LM87_REG_DIE_REV 0x3F - -#define LM87_REG_CONFIG 0x40 -#define LM87_REG_INT1_STAT 0x41 -#define LM87_REG_INT2_STAT 0x42 -#define LM87_REG_INT1_MASK 0x43 -#define LM87_REG_INT2_MASK 0x44 -#define LM87_REG_CHASSIS_CLEAR 0x46 -#define LM87_REG_VID_FAN_DIV 0x47 -#define LM87_REG_VID4 0x49 -#define LM87_REG_CONFIG_2 0x4A -#define LM87_REG_INTRPT_STATUS_1_MIRROR 0x4C -#define LM87_REG_INTRPT_STATUS_2_MIRROR 0x4D -#define LM87_REG_SMBALERT_NUM_ENABLE 0x80 - - - -/* Conversions. Rounding and limit checking is only done on the TO_REG - variants. Note that you should be a bit careful with which arguments - these macros are called: arguments may be evaluated more than once. - Fixing this is just not worth it. */ - -static inline u8 FAN_TO_REG(long rpm, int div) -{ - if (rpm == 0) - return 255; - rpm = SENSORS_LIMIT(rpm, 1, 1000000); - return SENSORS_LIMIT((1350000 + rpm * div / 2) / (rpm * div), 1, - 254); -} - -#define FAN_FROM_REG(val,div) ((val)==0?-1:\ - (val)==255?0:1350000/((div)*(val))) - -#define TEMP_FROM_REG(val) ((val)*10) - -#define TEMP_LIMIT_TO_REG(val) SENSORS_LIMIT(((val)<0?(val)-5:\ - (val)+5)/10,-128,127) - -#define DIV_FROM_REG(val) (1 << (val)) -#define DIV_TO_REG(val) ((val)==1?0:((val)==8?3:((val)==4?2:1))) - -/* For each registered LM87, we need to keep some data in memory. The - structure is dynamically allocated whenever a new LM87 client is - found. */ -struct lm87_data { - struct i2c_client client; - int sysctl_id; - enum chips type; - - struct semaphore update_lock; - char valid; /* !=0 if following fields are valid */ - unsigned long last_updated; /* In jiffies */ - - u8 in[6]; /* Scaled Register value */ - u8 in_max[6]; /* Scaled Register value */ - u8 in_min[6]; /* Scaled Register value */ - u8 ain1; /* Register value */ - u8 ain1_min; /* Register value */ - u8 ain1_max; /* Register value */ - u8 ain2; /* Register value */ - u8 ain2_min; /* Register value */ - u8 ain2_max; /* Register value */ - u8 fan; /* Register value */ - u8 fan_min; /* Register value */ - u8 fan_div; /* Register encoding, shifted right */ - u8 fan2; /* Register value */ - u8 fan2_min; /* Register value */ - u8 fan2_div; /* Register encoding, shifted right */ - s8 ext2_temp; /* Register value */ - s8 ext_temp; /* Register value */ - s8 int_temp; /* Register value */ - u8 ext_temp_max; /* Register value */ - u8 ext_temp_min; /* Register value */ - u8 ext2_temp_max; /* Register value */ - u8 ext2_temp_min; /* Register value */ - u8 int_temp_max; /* Register value */ - u8 int_temp_min; /* Register value */ - u16 alarms; /* Register encoding, combined */ - u8 analog_out; /* Register value */ - u8 vid; /* Register value combined */ - u8 vrm; /* VRM version * 10 */ -}; - -static int lm87_attach_adapter(struct i2c_adapter *adapter); -static int lm87_detect(struct i2c_adapter *adapter, int address, - unsigned short flags, int kind); -static int lm87_detach_client(struct i2c_client *client); - -static int lm87_read_value(struct i2c_client *client, u8 register); -static int lm87_write_value(struct i2c_client *client, u8 register, - u8 value); -static void lm87_update_client(struct i2c_client *client); -static void lm87_init_client(struct i2c_client *client); - - -static void lm87_in(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -#if defined (LM87_AIN1) || defined (LM87_AIN2) -static void lm87_ain(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -#endif -static void lm87_fan(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void lm87_temp(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void lm87_alarms(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void lm87_fan_div(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void lm87_analog_out(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, - long *results); -static void lm87_vid(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void lm87_vrm(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); - -static struct i2c_driver LM87_driver = { - .name = "LM87 sensor driver", - .id = I2C_DRIVERID_LM87, - .flags = I2C_DF_NOTIFY, - .attach_adapter = lm87_attach_adapter, - .detach_client = lm87_detach_client, -}; - -/* -- SENSORS SYSCTL START -- */ -#define LM87_SYSCTL_IN0 1000 /* Volts * 100 */ -#define LM87_SYSCTL_IN1 1001 -#define LM87_SYSCTL_IN2 1002 -#define LM87_SYSCTL_IN3 1003 -#define LM87_SYSCTL_IN4 1004 -#define LM87_SYSCTL_IN5 1005 -#define LM87_SYSCTL_AIN1 1006 -#define LM87_SYSCTL_AIN2 1007 -#define LM87_SYSCTL_FAN1 1102 -#define LM87_SYSCTL_FAN2 1103 -#define LM87_SYSCTL_TEMP1 1250 /* Degrees Celsius * 10 */ -#define LM87_SYSCTL_TEMP2 1251 /* Degrees Celsius * 10 */ -#define LM87_SYSCTL_TEMP3 1252 /* Degrees Celsius * 10 */ -#define LM87_SYSCTL_FAN_DIV 2000 /* 1, 2, 4 or 8 */ -#define LM87_SYSCTL_ALARMS 2001 /* bitvector */ -#define LM87_SYSCTL_ANALOG_OUT 2002 -#define LM87_SYSCTL_VID 2003 -#define LM87_SYSCTL_VRM 2004 - -#define LM87_ALARM_IN0 0x0001 -#define LM87_ALARM_IN1 0x0002 -#define LM87_ALARM_IN2 0x0004 -#define LM87_ALARM_IN3 0x0008 -#define LM87_ALARM_TEMP1 0x0010 -#define LM87_ALARM_TEMP2 0x0020 -#define LM87_ALARM_TEMP3 0x0020 /* same?? */ -#define LM87_ALARM_FAN1 0x0040 -#define LM87_ALARM_FAN2 0x0080 -#define LM87_ALARM_IN4 0x0100 -#define LM87_ALARM_IN5 0x0200 -#define LM87_ALARM_CHAS 0x1000 -#define LM87_ALARM_THERM_SIG 0x2000 -#define LM87_ALARM_TEMP2_FAULT 0x4000 -#define LM87_ALARM_TEMP3_FAULT 0x8000 - -/* -- SENSORS SYSCTL END -- */ - -/* The /proc/sys entries */ -/* These files are created for each detected LM87. This is just a template; - though at first sight, you might think we could use a statically - allocated list, we need some way to get back to the parent - which - is done through one of the 'extra' fields which are initialized - when a new copy is allocated. */ - -static ctl_table LM87_dir_table_template[] = { -#ifdef LM87_AIN1 - {LM87_SYSCTL_AIN1, "in6", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &lm87_ain}, -#endif -#ifdef LM87_AIN2 - {LM87_SYSCTL_AIN2, "in7", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &lm87_ain}, -#endif -#ifndef LM87_EXT2 - {LM87_SYSCTL_IN0, "in0", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &lm87_in}, - {LM87_SYSCTL_IN5, "in5", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &lm87_in}, -#endif - {LM87_SYSCTL_IN1, "in1", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &lm87_in}, - {LM87_SYSCTL_IN2, "in2", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &lm87_in}, - {LM87_SYSCTL_IN3, "in3", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &lm87_in}, - {LM87_SYSCTL_IN4, "in4", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &lm87_in}, -#ifndef LM87_AIN1 - {LM87_SYSCTL_FAN1, "fan1", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &lm87_fan}, - {LM87_SYSCTL_FAN_DIV, "fan_div", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &lm87_fan_div}, -#define LM87_FANDIV_FLAG -#endif -#ifndef LM87_AIN2 - {LM87_SYSCTL_FAN2, "fan2", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &lm87_fan}, -#ifndef LM87_FANDIV_FLAG - {LM87_SYSCTL_FAN_DIV, "fan_div", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &lm87_fan_div}, -#endif /* LM87_FANDIV_FLAG */ -#endif /* LM87_AIN2 */ -#ifdef LM87_EXT2 - {LM87_SYSCTL_TEMP3, "temp3", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &lm87_temp}, -#endif - {LM87_SYSCTL_TEMP2, "temp2", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &lm87_temp}, - {LM87_SYSCTL_TEMP1, "temp1", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &lm87_temp}, - {LM87_SYSCTL_ALARMS, "alarms", NULL, 0, 0444, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &lm87_alarms}, - {LM87_SYSCTL_ANALOG_OUT, "analog_out", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &lm87_analog_out}, - {LM87_SYSCTL_VID, "vid", NULL, 0, 0444, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &lm87_vid}, - {LM87_SYSCTL_VRM, "vrm", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &lm87_vrm}, - {0} -}; - -static int lm87_attach_adapter(struct i2c_adapter *adapter) -{ - int error; - struct i2c_client_address_data lm87_client_data; - - lm87_client_data.normal_i2c = addr_data.normal_i2c; - lm87_client_data.normal_i2c_range = addr_data.normal_i2c_range; - lm87_client_data.probe = addr_data.probe; - lm87_client_data.probe_range = addr_data.probe_range; - lm87_client_data.ignore = addr_data.ignore; - lm87_client_data.ignore_range = addr_data.ignore_range; - lm87_client_data.force = addr_data.forces->force; - - error = i2c_probe(adapter, &lm87_client_data, lm87_detect); - i2c_detect(adapter, &addr_data, lm87_detect); - - return error; -} - -static int lm87_detect(struct i2c_adapter *adapter, int address, - unsigned short flags, int kind) -{ - int i; - struct i2c_client *new_client; - struct lm87_data *data; - int err = 0; - const char *type_name = ""; - const char *client_name = ""; - - if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) - goto ERROR0; - - /* OK. For now, we presume we have a valid client. We now create the - client structure, even though we cannot fill it completely yet. - But it allows us to access LM87_{read,write}_value. */ - - if (!(data = kmalloc(sizeof(struct lm87_data), GFP_KERNEL))) { - err = -ENOMEM; - goto ERROR0; - } - - new_client = &data->client; - new_client->addr = address; - new_client->data = data; - new_client->adapter = adapter; - new_client->driver = &LM87_driver; - new_client->flags = 0; - - /* Now, we do the remaining detection. */ - - if (kind < 0) { - if (((lm87_read_value(new_client, LM87_REG_CONFIG) & 0x80) - != 0x00) || - (lm87_read_value(new_client, LM87_REG_COMPANY_ID) != 0x02)) - goto ERROR1; - } - - /* Fill in the remaining client fields and put into the global list */ - type_name = "lm87"; - client_name = "LM87 chip"; - strcpy(new_client->name, client_name); - data->type = kind; - data->valid = 0; - init_MUTEX(&data->update_lock); - - /* Tell the I2C layer a new client has arrived */ - if ((err = i2c_attach_client(new_client))) - goto ERROR3; - - /* Register a new directory entry with module sensors */ - if ((i = i2c_register_entry(new_client, - type_name, - LM87_dir_table_template, - THIS_MODULE)) < 0) { - err = i; - goto ERROR4; - } - data->sysctl_id = i; - - /* Initialize the LM87 chip */ - lm87_init_client(new_client); - return 0; - -/* OK, this is not exactly good programming practice, usually. But it is - very code-efficient in this case. */ - - ERROR4: - i2c_detach_client(new_client); - ERROR3: - ERROR1: - kfree(data); - ERROR0: - return err; -} - -static int lm87_detach_client(struct i2c_client *client) -{ - int err; - - i2c_deregister_entry(((struct lm87_data *) (client->data))-> - sysctl_id); - - if ((err = i2c_detach_client(client))) { - printk(KERN_ERR "lm87.o: Client deregistration failed, " - "client not detached\n"); - return err; - } - - kfree(client->data); - - return 0; -} - -#define MAX_RETRIES 5 - -static int lm87_read_value(struct i2c_client *client, u8 reg) -{ - int value, i; - - /* Retry in case of read errors */ - for (i = 1; i <= MAX_RETRIES; i++) { - if ((value = i2c_smbus_read_byte_data(client, reg)) >= 0) - return value; - - printk(KERN_WARNING "lm87.o: Read byte data failed, " - "address 0x%02x\n", reg); - mdelay(i + 3); - } - - /* what to return in case of error? */ - printk(KERN_ERR "lm87.o: All read byte retries failed!!\n"); - return 0; -} - -static int lm87_write_value(struct i2c_client *client, u8 reg, u8 value) -{ - return i2c_smbus_write_byte_data(client, reg, value); -} - -/* Called when we have found a new LM87. */ -static void lm87_init_client(struct i2c_client *client) -{ - struct lm87_data *data = client->data; - u8 reg; - - /* Setup Channel Mode register for configuration of monitoring - * Default is 00000000b - * bit 0 - Configures Fan 1/AIN 1 input (1 = AIN) - * bit 1 - Configures Fan 2/AIN 2 input (1 = AIN) - * bit 2 - Configures 2.5V&Vccp2/D2 input (1 = 2nd Therm.) - * bit 3 - Configures Vcc for 5V/3.3V reading (0 = 3.3V) - * bit 4 - Configures IRQ0 Enable if = 1 - * bit 5 - Configures IRQ1 Enable if = 1 - * bit 6 - Configures IRQ2 Enable if = 1 - * bit 7 - Configures VID/IRQ input as interrupts if = 1 - */ - - /* Preserve 4 MSB */ - reg = lm87_read_value(client, LM87_REG_CHANNEL_MODE); -/* I know, not clean, but it works. :'p */ - lm87_write_value(client, LM87_REG_CHANNEL_MODE, (reg & 0xf0) | -#ifdef LM87_AIN1 - 0x01 -#else -0 -#endif - | -#ifdef LM87_AIN2 - 0x02 -#else -0 -#endif - | -#ifdef LM87_EXT2 - 0x04 -#else -0 -#endif - | -#ifdef LM87_5V_VCC -0x08 -#else -0 -#endif - ); - - data->vrm = 82; - - /* Start monitoring */ - reg = lm87_read_value(client, LM87_REG_CONFIG); - if (!(reg & 0x01)) { - printk(KERN_INFO "lm87.o: Monitoring starts\n"); - lm87_write_value(client, LM87_REG_CONFIG, - (reg & 0x7e) | 0x01); - } -} - -static void lm87_update_client(struct i2c_client *client) -{ - struct lm87_data *data = client->data; - int i; - - down(&data->update_lock); - - if ((jiffies - data->last_updated > HZ) || /* 1 sec cache */ - (jiffies < data->last_updated) || - !data->valid) { - for (i = 0; i <= 5; i++) { - data->in[i] = - lm87_read_value(client,LM87_REG_IN(i)); - data->in_min[i] = - lm87_read_value(client,LM87_REG_IN_MIN(i)); - data->in_max[i] = - lm87_read_value(client,LM87_REG_IN_MAX(i)); - } - data->ain1 = - lm87_read_value(client,LM87_REG_FAN1_AIN1); - data->ain1_min = - lm87_read_value(client,LM87_REG_AIN1_LOW); - data->ain1_max = - lm87_read_value(client,LM87_REG_FAN1_AIN1_LIMIT); - data->ain2 = - lm87_read_value(client,LM87_REG_FAN2_AIN2); - data->ain2_min = - lm87_read_value(client,LM87_REG_AIN2_LOW); - data->ain2_max = - lm87_read_value(client,LM87_REG_FAN2_AIN2_LIMIT); - - data->fan = - lm87_read_value(client, LM87_REG_FAN1_AIN1); - data->fan_min = - lm87_read_value(client, LM87_REG_FAN1_AIN1_LIMIT); - data->fan2 = - lm87_read_value(client, LM87_REG_FAN2_AIN2); - data->fan2_min = - lm87_read_value(client, LM87_REG_FAN2_AIN2_LIMIT); - - data->ext2_temp = - lm87_read_value(client, LM87_REG_2_5V_EXT_TEMP_2); - data->ext_temp = - lm87_read_value(client, LM87_REG_EXT_TEMP_1); - data->int_temp = - lm87_read_value(client, LM87_REG_INT_TEMP); - - data->ext2_temp_max = - lm87_read_value(client, LM87_REG_2_5V_EXT_TEMP_2_HIGH); - data->ext2_temp_min = - lm87_read_value(client, LM87_REG_2_5V_EXT_TEMP_2_LOW); - - data->ext_temp_max = - lm87_read_value(client, LM87_REG_EXT_TEMP_1_HIGH); - data->ext_temp_min = - lm87_read_value(client, LM87_REG_EXT_TEMP_1_LOW); - - data->int_temp_max = - lm87_read_value(client, LM87_REG_INT_TEMP_HIGH); - data->int_temp_min = - lm87_read_value(client, LM87_REG_INT_TEMP_LOW); - - i = lm87_read_value(client, LM87_REG_VID_FAN_DIV); - data->fan_div = (i >> 4) & 0x03; - data->fan2_div = (i >> 6) & 0x03; - data->vid = i & 0x0f; - data->vid |= - (lm87_read_value(client, LM87_REG_VID4) & 0x01) - << 4; - data->alarms = - lm87_read_value(client, LM87_REG_INT1_STAT) + - (lm87_read_value(client, LM87_REG_INT2_STAT) << 8); - data->analog_out = - lm87_read_value(client, LM87_REG_ANALOG_OUT); - data->last_updated = jiffies; - data->valid = 1; - } - up(&data->update_lock); -} - - -/* The next few functions are the call-back functions of the /proc/sys and - sysctl files. Which function is used is defined in the ctl_table in - the extra1 field. - Each function must return the magnitude (power of 10 to divide the date - with) if it is called with operation==SENSORS_PROC_REAL_INFO. It must - put a maximum of *nrels elements in results reflecting the data of this - file, and set *nrels to the number it actually put in it, if operation== - SENSORS_PROC_REAL_READ. Finally, it must get upto *nrels elements from - results and write them to the chip, if operations==SENSORS_PROC_REAL_WRITE. - Note that on SENSORS_PROC_REAL_READ, I do not check whether results is - large enough (by checking the incoming value of *nrels). This is not very - good practice, but as long as you put less than about 5 values in results, - you can assume it is large enough. */ -void lm87_in(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - long scales[6] = { 250, 270, -#ifdef LM87_5V_VCC -500, -#else -330, -#endif - 500, 1200, 270 }; - - struct lm87_data *data = client->data; - int nr = ctl_name - LM87_SYSCTL_IN0; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 2; - else if (operation == SENSORS_PROC_REAL_READ) { - lm87_update_client(client); - results[0] = (data->in_min[nr] * scales[nr] + 96) / 192; - results[1] = (data->in_max[nr] * scales[nr] + 96) / 192; - results[2] = (data->in[nr] * scales[nr] + 96) / 192; - *nrels_mag = 3; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag >= 1) { - data->in_min[nr] = (results[0] * 192 + scales[nr] / 2) - / scales[nr]; - lm87_write_value(client, LM87_REG_IN_MIN(nr), - data->in_min[nr]); - } - if (*nrels_mag >= 2) { - data->in_max[nr] = (results[1] * 192 + scales[nr] / 2) - / scales[nr]; - lm87_write_value(client, LM87_REG_IN_MAX(nr), - data->in_max[nr]); - } - } -} - -#if defined (LM87_AIN1) || defined (LM87_AIN2) -void lm87_ain(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct lm87_data *data = client->data; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - lm87_update_client(client); - if (ctl_name == LM87_SYSCTL_AIN1) { - results[0] = data->ain1_min; - results[1] = data->ain1_max; - results[2] = data->ain1; - } else { - results[0] = data->ain2_min; - results[1] = data->ain2_max; - results[2] = data->ain2; - } - *nrels_mag = 3; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag >= 1) { - if (ctl_name == LM87_SYSCTL_AIN1) { - data->ain1_min = results[0]; - lm87_write_value(client, LM87_REG_AIN1_LOW, - data->ain1_min); - } else { - data->ain2_min = results[0]; - lm87_write_value(client, LM87_REG_AIN2_LOW, - data->ain2_min); - } - } - if (*nrels_mag >= 2) { - if (ctl_name == LM87_SYSCTL_AIN1) { - data->ain1_max = results[1]; - lm87_write_value(client, LM87_REG_FAN1_AIN1_LIMIT, - data->ain1_max); - } else { - data->ain2_max = results[1]; - lm87_write_value(client, LM87_REG_FAN2_AIN2_LIMIT, - data->ain2_max); - } - } - } -} -#endif - -void lm87_fan(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct lm87_data *data = client->data; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - lm87_update_client(client); - if (ctl_name == LM87_SYSCTL_FAN1) { - results[0] = FAN_FROM_REG(data->fan_min, - DIV_FROM_REG(data->fan_div)); - results[1] = FAN_FROM_REG(data->fan, - DIV_FROM_REG(data->fan_div)); - } else { - results[0] = FAN_FROM_REG(data->fan2_min, - DIV_FROM_REG(data->fan2_div)); - results[1] = FAN_FROM_REG(data->fan2, - DIV_FROM_REG(data->fan2_div)); - } - *nrels_mag = 2; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag >= 0) { - if (ctl_name == LM87_SYSCTL_FAN1) { - data->fan_min = FAN_TO_REG(results[0], - DIV_FROM_REG - (data->fan_div)); - lm87_write_value(client, LM87_REG_FAN1_AIN1_LIMIT, - data->fan_min); - } else { - data->fan2_min = FAN_TO_REG(results[0], - DIV_FROM_REG - (data->fan2_div)); - lm87_write_value(client, LM87_REG_FAN2_AIN2_LIMIT, - data->fan2_min); - } - } - } -} - - -void lm87_temp(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct lm87_data *data = client->data; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 1; - else if (operation == SENSORS_PROC_REAL_READ) - { - lm87_update_client(client); - - /* find out which temp. is being requested */ - if (ctl_name == LM87_SYSCTL_TEMP3) - { - results[0] = TEMP_FROM_REG(data->ext2_temp_max); - results[1] = TEMP_FROM_REG(data->ext2_temp_min); - results[2] = TEMP_FROM_REG(data->ext2_temp); - } - else if(ctl_name == LM87_SYSCTL_TEMP2) - { - results[0] = TEMP_FROM_REG(data->ext_temp_max); - results[1] = TEMP_FROM_REG(data->ext_temp_min); - results[2] = TEMP_FROM_REG(data->ext_temp); - } - else if(ctl_name == LM87_SYSCTL_TEMP1) - { - results[0] = TEMP_FROM_REG(data->int_temp_max); - results[1] = TEMP_FROM_REG(data->int_temp_min); - results[2] = TEMP_FROM_REG(data->int_temp); - } - *nrels_mag = 3; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag >= 1) { - if (ctl_name == LM87_SYSCTL_TEMP3) { - data->ext2_temp_max = TEMP_LIMIT_TO_REG(results[0]); - lm87_write_value(client, LM87_REG_2_5V_EXT_TEMP_2_HIGH, - data->ext2_temp_max); - } - if (ctl_name == LM87_SYSCTL_TEMP2) { - data->ext_temp_max = TEMP_LIMIT_TO_REG(results[0]); - lm87_write_value(client, LM87_REG_EXT_TEMP_1_HIGH, - data->ext_temp_max); - } - if (ctl_name == LM87_SYSCTL_TEMP1) { - data->int_temp_max = TEMP_LIMIT_TO_REG(results[0]); - lm87_write_value(client, LM87_REG_INT_TEMP_HIGH, - data->int_temp_max); - } - } - if (*nrels_mag >= 2) { - if (ctl_name == LM87_SYSCTL_TEMP3) { - data->ext2_temp_min = TEMP_LIMIT_TO_REG(results[1]); - lm87_write_value(client, LM87_REG_2_5V_EXT_TEMP_2_LOW, - data->ext2_temp_min); - } - if (ctl_name == LM87_SYSCTL_TEMP2) { - data->ext_temp_min = TEMP_LIMIT_TO_REG(results[1]); - lm87_write_value(client, LM87_REG_EXT_TEMP_1_LOW, - data->ext_temp_min); - } - if (ctl_name == LM87_SYSCTL_TEMP1) { - data->int_temp_min = TEMP_LIMIT_TO_REG(results[1]); - lm87_write_value(client, LM87_REG_INT_TEMP_LOW, - data->int_temp_min); - } - } - } -} - -void lm87_alarms(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct lm87_data *data = client->data; - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - lm87_update_client(client); - results[0] = data->alarms; - *nrels_mag = 1; - } -} - -void lm87_fan_div(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results) -{ -/* This gets a little hairy depending on the hardware config */ - - struct lm87_data *data = client->data; - int old; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - lm87_update_client(client); -#ifndef LM87_AIN1 - results[0] = DIV_FROM_REG(data->fan_div); -# ifndef LM87_AIN2 - results[1] = DIV_FROM_REG(data->fan2_div); - *nrels_mag = 2; -# else - *nrels_mag = 1; -# endif -#else /* Must be referring to fan 2 */ - results[0] = DIV_FROM_REG(data->fan2_div); - *nrels_mag = 1; -#endif - } else if (operation == SENSORS_PROC_REAL_WRITE) { - old = lm87_read_value(client, LM87_REG_VID_FAN_DIV); -/* Note: it's OK to change fan2 div even if fan2 isn't enabled */ -#ifndef LM87_AIN1 - if (*nrels_mag >= 2) { - data->fan2_div = DIV_TO_REG(results[1]); - old = (old & 0x3f) | (data->fan2_div << 6); - } - if (*nrels_mag >= 1) { - data->fan_div = DIV_TO_REG(results[0]); - old = (old & 0xcf) | (data->fan_div << 4); - lm87_write_value(client, LM87_REG_VID_FAN_DIV, old); - } -#else /* Must be referring to fan 2 */ - if (*nrels_mag >= 1) { - data->fan2_div = DIV_TO_REG(results[0]); - old = (old & 0xcf) | (data->fan2_div << 6); - lm87_write_value(client, LM87_REG_VID_FAN_DIV, old); - } -#endif - } -} - -void lm87_analog_out(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results) -{ - struct lm87_data *data = client->data; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - lm87_update_client(client); - results[0] = data->analog_out; - *nrels_mag = 1; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag >= 1) { - data->analog_out = results[0]; - lm87_write_value(client, LM87_REG_ANALOG_OUT, - data->analog_out); - } - } -} - -void lm87_vid(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct lm87_data *data = client->data; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 3; - else if (operation == SENSORS_PROC_REAL_READ) { - lm87_update_client(client); - results[0] = vid_from_reg(data->vid, data->vrm); - *nrels_mag = 1; - } -} - -void lm87_vrm(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct lm87_data *data = client->data; - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 1; - else if (operation == SENSORS_PROC_REAL_READ) { - results[0] = data->vrm; - *nrels_mag = 1; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag >= 1) - data->vrm = results[0]; - } -} - -static int __init sm_lm87_init(void) -{ - printk(KERN_INFO "lm87.o version %s (%s)\n", LM_VERSION, LM_DATE); - return i2c_add_driver(&LM87_driver); -} - -static void __exit sm_lm87_exit(void) -{ - i2c_del_driver(&LM87_driver); -} - - - -MODULE_LICENSE("GPL"); - -MODULE_AUTHOR - ("Frodo Looijaard , Philip Edelbrock , " - "Mark Studebaker , and Stephen Rousset "); - -MODULE_DESCRIPTION("LM87 driver"); - -module_init(sm_lm87_init); -module_exit(sm_lm87_exit); diff --git a/kernel/chips/lm90.c b/kernel/chips/lm90.c deleted file mode 100644 index b1b369e5..00000000 --- a/kernel/chips/lm90.c +++ /dev/null @@ -1,844 +0,0 @@ -/* - * lm90.c - Part of lm_sensors, Linux kernel modules for hardware - * monitoring - * Copyright (C) 2003-2005 Jean Delvare - * - * Based on the lm83 driver. The LM90 is a sensor chip made by National - * Semiconductor. It reports up to two temperatures (its own plus up to - * one external one) with a 0.125 deg resolution (1 deg for local - * temperature) and a 3-4 deg accuracy. - * - * This driver also supports the LM89 and LM99, two other sensor chips - * made by National Semiconductor. Both have an increased remote - * temperature measurement accuracy (1 degree), and the LM99 - * additionally shifts remote temperatures (measured and limits) by 16 - * degrees, which allows for higher temperatures measurement. The - * driver doesn't handle it since it can be done easily in user-space. - * Note that there is no way to differentiate between both chips. - * - * This driver also supports the LM86, another sensor chip made by - * National Semiconductor. It is exactly similar to the LM90 except it - * has a higher accuracy. - * - * This driver also supports the ADM1032, a sensor chip made by Analog - * Devices. That chip is similar to the LM90, with a few differences - * that are not handled by this driver. Among others, it has a higher - * accuracy than the LM90, much like the LM86 does. - * - * This driver also supports the MAX6657, MAX6658 and MAX6659 sensor - * chips made by Maxim. These chips are similar to the LM86. - * Note that there is no easy way to differentiate between the three - * variants. The extra address and features of the MAX6659 are not - * supported by this driver. - * - * This driver also supports the ADT7461 chip from Analog Devices but - * only in its "compatability mode". If an ADT7461 chip is found but - * is configured in non-compatible mode (where its temperature - * register values are decoded differently) it is ignored by this - * driver. - * - * Since the LM90 was the first chipset supported by this driver, most - * comments will refer to this chipset, but are actually general and - * concern all supported chipsets, unless mentioned otherwise. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include -#include -#include -#include -#include -#include "version.h" - -#ifndef I2C_DRIVERID_LM90 -#define I2C_DRIVERID_LM90 1042 -#endif - -/* - * Addresses to scan - * Address is fully defined internally and cannot be changed except for - * MAX6659. - * LM86, LM89, LM90, LM99, ADM1032, ADM1032-1, ADT7461, MAX6657 and MAX6658 - * have address 0x4c. - * ADM1032-2, ADT7461-2, LM89-1, and LM99-1 have address 0x4d. - * MAX6659 can have address 0x4c, 0x4d or 0x4e (unsupported). - */ - -static unsigned short normal_i2c[] = { 0x4c, 0x4d, SENSORS_I2C_END }; -static unsigned short normal_i2c_range[] = { SENSORS_I2C_END }; -static unsigned int normal_isa[] = { SENSORS_ISA_END }; -static unsigned int normal_isa_range[] = { SENSORS_ISA_END }; - -/* - * Insmod parameters - */ - -SENSORS_INSMOD_6(lm90, adm1032, lm99, lm86, max6657, adt7461); - -/* - * The LM90 registers - */ - -#define LM90_REG_R_MAN_ID 0xFE -#define LM90_REG_R_CHIP_ID 0xFF -#define LM90_REG_R_CONFIG1 0x03 -#define LM90_REG_W_CONFIG1 0x09 -#define LM90_REG_R_CONFIG2 0xBF -#define LM90_REG_W_CONFIG2 0xBF -#define LM90_REG_R_CONVRATE 0x04 -#define LM90_REG_W_CONVRATE 0x0A -#define LM90_REG_R_STATUS 0x02 -#define LM90_REG_R_LOCAL_TEMP 0x00 -#define LM90_REG_R_LOCAL_HIGH 0x05 -#define LM90_REG_W_LOCAL_HIGH 0x0B -#define LM90_REG_R_LOCAL_LOW 0x06 -#define LM90_REG_W_LOCAL_LOW 0x0C -#define LM90_REG_R_LOCAL_CRIT 0x20 -#define LM90_REG_W_LOCAL_CRIT 0x20 -#define LM90_REG_R_REMOTE_TEMPH 0x01 -#define LM90_REG_R_REMOTE_TEMPL 0x10 -#define LM90_REG_R_REMOTE_OFFSH 0x11 -#define LM90_REG_W_REMOTE_OFFSH 0x11 -#define LM90_REG_R_REMOTE_OFFSL 0x12 -#define LM90_REG_W_REMOTE_OFFSL 0x12 -#define LM90_REG_R_REMOTE_HIGHH 0x07 -#define LM90_REG_W_REMOTE_HIGHH 0x0D -#define LM90_REG_R_REMOTE_HIGHL 0x13 -#define LM90_REG_W_REMOTE_HIGHL 0x13 -#define LM90_REG_R_REMOTE_LOWH 0x08 -#define LM90_REG_W_REMOTE_LOWH 0x0E -#define LM90_REG_R_REMOTE_LOWL 0x14 -#define LM90_REG_W_REMOTE_LOWL 0x14 -#define LM90_REG_R_REMOTE_CRIT 0x19 -#define LM90_REG_W_REMOTE_CRIT 0x19 -#define LM90_REG_R_TCRIT_HYST 0x21 -#define LM90_REG_W_TCRIT_HYST 0x21 - -/* - * Conversions and various macros - * For local temperatures and limits, critical limits and the hysteresis - * value, the LM90 uses signed 8-bit values with LSB = 1 degree Celsius. - * For remote temperatures and limits, it uses signed 11-bit values with - * LSB = 0.125 degree Celsius, left-justified in 16-bit registers. - */ - -#define TEMP1_FROM_REG(val) (val) -#define TEMP1_TO_REG(val) ((val) <= -128 ? -128 : \ - (val) >= 127 ? 127 : (val)) -#define TEMP2_FROM_REG(val) ((val) / 32 * 125 / 100) -#define TEMP2_TO_REG(val) ((val) <= -1280 ? 0x8000 : \ - (val) >= 1270 ? 0x7FE0 : \ - ((val) * 100 / 125 * 32)) -#define HYST_TO_REG(val) ((val) <= 0 ? 0 : \ - (val) >= 31 ? 31 : (val)) - -/* - * ADT7461 is almost identical to LM90 except that attempts to write - * values that are outside the range 0 < temp < 127 are treated as - * the boundary value. - */ - -#define TEMP1_TO_REG_ADT7461(val) ((val) <= 0 ? 0 : \ - (val) >= 127 ? 127 : (val)) -#define TEMP2_TO_REG_ADT7461(val) ((val) <= 0 ? 0 : \ - (val) >= 1277 ? 0x7FC0 : \ - ((val) * 100 / 250 * 64)) - -/* - * Functions declaration - */ - -static int lm90_attach_adapter(struct i2c_adapter *adapter); -static int lm90_detect(struct i2c_adapter *adapter, int address, - unsigned short flags, int kind); -static void lm90_init_client(struct i2c_client *client); -static int lm90_detach_client(struct i2c_client *client); -static void lm90_local_temp(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void lm90_remote_temp(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void lm90_local_tcrit(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void lm90_remote_tcrit(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void lm90_local_hyst(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void lm90_remote_hyst(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void lm90_alarms(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void adm1032_pec(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); - -/* - * Driver data (common to all clients) - */ - -static struct i2c_driver lm90_driver = { - .name = "LM90/ADM1032 sensor driver", - .id = I2C_DRIVERID_LM90, - .flags = I2C_DF_NOTIFY, - .attach_adapter = lm90_attach_adapter, - .detach_client = lm90_detach_client -}; - -/* - * Client data (each client gets its own) - */ - -struct lm90_data { - struct i2c_client client; - int sysctl_id; - - struct semaphore update_lock; - char valid; /* zero until following fields are valid */ - unsigned long last_updated; /* in jiffies */ - int kind; - - /* registers values */ - s8 local_temp, local_high, local_low; - s16 remote_temp, remote_high, remote_low; /* combined */ - s8 local_crit, remote_crit; - u8 hyst; /* linked to two sysctl files (hyst1 RW, hyst2 RO) */ - u8 alarms; /* bitvector */ -}; - -/* - * Proc entries - * These files are created for each detected LM90. - */ - -/* -- SENSORS SYSCTL START -- */ - -#define LM90_SYSCTL_LOCAL_TEMP 1200 -#define LM90_SYSCTL_REMOTE_TEMP 1201 -#define LM90_SYSCTL_LOCAL_TCRIT 1204 -#define LM90_SYSCTL_REMOTE_TCRIT 1205 -#define LM90_SYSCTL_LOCAL_HYST 1207 -#define LM90_SYSCTL_REMOTE_HYST 1208 -#define LM90_SYSCTL_ALARMS 1210 -#define LM90_SYSCTL_PEC 1214 - -#define LM90_ALARM_LOCAL_HIGH 0x40 -#define LM90_ALARM_LOCAL_LOW 0x20 -#define LM90_ALARM_LOCAL_CRIT 0x01 -#define LM90_ALARM_REMOTE_HIGH 0x10 -#define LM90_ALARM_REMOTE_LOW 0x08 -#define LM90_ALARM_REMOTE_CRIT 0x02 -#define LM90_ALARM_REMOTE_OPEN 0x04 - -/* -- SENSORS SYSCTL END -- */ - - -static ctl_table lm90_dir_table_template[] = -{ - {LM90_SYSCTL_LOCAL_TEMP, "temp1", NULL, 0, 0644, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &lm90_local_temp}, - {LM90_SYSCTL_REMOTE_TEMP, "temp2", NULL, 0, 0644, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &lm90_remote_temp}, - {LM90_SYSCTL_LOCAL_TCRIT, "tcrit1", NULL, 0, 0644, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &lm90_local_tcrit}, - {LM90_SYSCTL_REMOTE_TCRIT, "tcrit2", NULL, 0, 0644, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &lm90_remote_tcrit}, - {LM90_SYSCTL_LOCAL_HYST, "hyst1", NULL, 0, 0644, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &lm90_local_hyst}, - {LM90_SYSCTL_REMOTE_HYST, "hyst2", NULL, 0, 0444, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &lm90_remote_hyst}, - {LM90_SYSCTL_ALARMS, "alarms", NULL, 0, 0444, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &lm90_alarms}, - {0} -}; - -static ctl_table adm1032_dir_table_template[] = -{ - {LM90_SYSCTL_LOCAL_TEMP, "temp1", NULL, 0, 0644, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &lm90_local_temp}, - {LM90_SYSCTL_REMOTE_TEMP, "temp2", NULL, 0, 0644, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &lm90_remote_temp}, - {LM90_SYSCTL_LOCAL_TCRIT, "tcrit1", NULL, 0, 0644, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &lm90_local_tcrit}, - {LM90_SYSCTL_REMOTE_TCRIT, "tcrit2", NULL, 0, 0644, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &lm90_remote_tcrit}, - {LM90_SYSCTL_LOCAL_HYST, "hyst1", NULL, 0, 0644, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &lm90_local_hyst}, - {LM90_SYSCTL_REMOTE_HYST, "hyst2", NULL, 0, 0444, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &lm90_remote_hyst}, - {LM90_SYSCTL_ALARMS, "alarms", NULL, 0, 0444, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &lm90_alarms}, - {LM90_SYSCTL_PEC, "pec", NULL, 0, 0644, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &adm1032_pec}, - {0} -}; - -/* - * Real code - */ - -/* The ADM1032 supports PEC but not on write byte transactions, so we need - to explicitly ask for a transaction without PEC. */ -static inline s32 adm1032_write_byte(struct i2c_client *client, u8 value) -{ - return i2c_smbus_xfer(client->adapter, client->addr, - client->flags & ~I2C_CLIENT_PEC, - I2C_SMBUS_WRITE, value, I2C_SMBUS_BYTE, NULL); -} - -/* It is assumed that client->update_lock is held (unless we are in - detection or initialization steps). This matters when PEC is enabled, - because we don't want the address pointer to change between the write - byte and the read byte transactions. */ -static int lm90_read_reg(struct i2c_client* client, u8 reg, u8 *value) -{ - int err; - - if (client->flags & I2C_CLIENT_PEC) { - err = adm1032_write_byte(client, reg); - if (err >= 0) - err = i2c_smbus_read_byte(client); - } else - err = i2c_smbus_read_byte_data(client, reg); - - if (err < 0) { - printk(KERN_WARNING "lm90: Register 0x%02x read failed (%d)\n", - reg, err); - return err; - } - *value = err; - - return 0; -} - -static int lm90_attach_adapter(struct i2c_adapter *adapter) -{ - return i2c_detect(adapter, &addr_data, lm90_detect); -} - -/* - * The following function does more than just detection. If detection - * succeeds, it also registers the new chip. - */ -static int lm90_detect(struct i2c_adapter *adapter, int address, - unsigned short flags, int kind) -{ - struct i2c_client *new_client; - struct lm90_data *data; - int err = 0; - const char *type_name = ""; - const char *client_name = ""; - - if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) { -#ifdef DEBUG - printk(KERN_DEBUG "lm90: adapter doesn't support byte mode, " - "skipping\n"); -#endif - return 0; - } - - if (!(data = kmalloc(sizeof(struct lm90_data), GFP_KERNEL))) { - printk(KERN_ERR "lm90: Out of memory in lm90_detect\n"); - return -ENOMEM; - } - - /* - * The common I2C client data is placed right before the - * LM90-specific data. The LM90-specific data is pointed to by the - * data field from the I2C client data. - */ - - new_client = &data->client; - new_client->addr = address; - new_client->data = data; - new_client->adapter = adapter; - new_client->driver = &lm90_driver; - new_client->flags = 0; - - /* - * Now we do the remaining detection. A negative kind means that - * the driver was loaded with no force parameter (default), so we - * must both detect and identify the chip. A zero kind means that - * the driver was loaded with the force parameter, the detection - * step shall be skipped. A positive kind means that the driver - * was loaded with the force parameter and a given kind of chip is - * requested, so both the detection and the identification steps - * are skipped. - */ - - /* Default to an LM90 if forced */ - if (kind == 0) - kind = lm90; - - if (kind < 0) { /* detection and identification */ - int man_id, chip_id, reg_config1, reg_convrate; - - if ((man_id = i2c_smbus_read_byte_data(new_client, - LM90_REG_R_MAN_ID)) < 0 - || (chip_id = i2c_smbus_read_byte_data(new_client, - LM90_REG_R_CHIP_ID)) < 0 - || (reg_config1 = i2c_smbus_read_byte_data(new_client, - LM90_REG_R_CONFIG1)) < 0 - || (reg_convrate = i2c_smbus_read_byte_data(new_client, - LM90_REG_R_CONVRATE)) < 0) - goto exit_free; - - if (man_id == 0x01) { /* National Semiconductor */ - int reg_config2; - - if ((reg_config2 = i2c_smbus_read_byte_data(new_client, - LM90_REG_R_CONFIG2)) < 0) - goto exit_free; - - if ((reg_config1 & 0x2A) == 0x00 - && (reg_config2 & 0xF8) == 0x00 - && reg_convrate <= 0x09) { - if (address == 0x4C - && (chip_id & 0xF0) == 0x20) /* LM90 */ - kind = lm90; - else if ((chip_id & 0xF0) == 0x30) /* LM89/LM99 */ - kind = lm99; - else if (address == 0x4C - && (chip_id & 0xF0) == 0x10) /* LM86 */ - kind = lm86; - } - } else - if (man_id == 0x41) { /* Analog Devices */ - if ((chip_id & 0xF0) == 0x40 /* ADM1032 */ - && (reg_config1 & 0x3F) == 0x00 - && reg_convrate <= 0x0A) - kind = adm1032; - else - if (chip_id == 0x51 /* ADT7461 */ - && (reg_config1 & 0x1F) == 0x00 /* check compat mode */ - && reg_convrate <= 0x0A) - kind = adt7461; - } else - if (man_id == 0x4D) { /* Maxim */ - /* - * The Maxim variants do NOT have a chip_id register. - * Reading from that address will return the last read - * value, which in our case is those of the man_id - * register. Likewise, the config1 register seems to - * lack a low nibble, so the value will be those of the - * previous read, so in our case those of the man_id - * register. - */ - if (chip_id == man_id - && (reg_config1 & 0x1F) == (man_id & 0x0F) - && reg_convrate <= 0x09) - kind = max6657; - } - } - - if (kind <= 0) { /* identification failed */ - printk(KERN_DEBUG "lm90: Unsupported chip\n"); - goto exit_free; - } - - if (kind == lm90) { - type_name = "lm90"; - client_name = "LM90 chip"; - } else if (kind == adm1032) { - type_name = "adm1032"; - client_name = "ADM1032 chip"; - /* The ADM1032 supports PEC, but only if combined - transactions are not used. */ - if (i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE)) { - new_client->flags |= I2C_CLIENT_PEC; - printk(KERN_DEBUG "lm90: Enabling PEC for ADM1032\n"); - } - } else if (kind == lm99) { - type_name = "lm99"; - client_name = "LM99 chip"; - } else if (kind == lm86) { - type_name = "lm86"; - client_name = "LM86 chip"; - } else if (kind == max6657) { - type_name = "max6657"; - client_name = "MAX6657 chip"; - } else if (kind == adt7461) { - type_name = "adt7461"; - client_name = "ADT7561 chip"; - } else { - printk(KERN_ERR "lm90: Unknown kind %d\n", kind); - goto exit_free; - } - - /* - * OK, we got a valid chip so we can fill in the remaining client - * fields. - */ - - strcpy(new_client->name, client_name); - data->valid = 0; - data->kind = kind; - init_MUTEX(&data->update_lock); - - /* - * Tell the I2C layer a new client has arrived. - */ - - if ((err = i2c_attach_client(new_client))) { - printk(KERN_ERR "lm90: Failed to attach client (%d)\n", err); - goto exit_free; - } - - /* - * Register a new directory entry. - */ - - if ((err = i2c_register_entry(new_client, type_name, - (new_client->flags & I2C_CLIENT_PEC) ? - adm1032_dir_table_template : - lm90_dir_table_template, THIS_MODULE)) < 0) { - printk(KERN_ERR "lm90: Failed to register directory entry " - "(%d)\n", err); - goto exit_detach; - } - data->sysctl_id = err; - - /* - * Initialize the LM90 chip. - */ - - lm90_init_client(new_client); - return 0; - -exit_detach: - i2c_detach_client(new_client); -exit_free: - kfree(data); - return err; -} - -static void lm90_init_client(struct i2c_client *client) -{ - u8 config; - - /* - * Start the conversions. - */ - - i2c_smbus_write_byte_data(client, LM90_REG_W_CONVRATE, - 5); /* 2 Hz */ - if (lm90_read_reg(client, LM90_REG_R_CONFIG1, &config) < 0) { - printk(KERN_ERR "lm90: Initialization failed!\n"); - return; - } - if (config & 0x40) - i2c_smbus_write_byte_data(client, LM90_REG_W_CONFIG1, - config & 0xBF); /* run */ -} - - -static int lm90_detach_client(struct i2c_client *client) -{ - int err; - - i2c_deregister_entry(((struct lm90_data *) (client->data))->sysctl_id); - if ((err = i2c_detach_client(client))) { - printk(KERN_ERR "lm90: Client deregistration failed, client " - "not detached (%d)\n", err); - return err; - } - - kfree(client->data); - return 0; -} - -static void lm90_update_client(struct i2c_client *client) -{ - struct lm90_data *data = client->data; - - down(&data->update_lock); - - if ((jiffies - data->last_updated > HZ * 2) || - (jiffies < data->last_updated) || !data->valid) { - u8 oldh, newh, l; -#ifdef DEBUG - printk(KERN_DEBUG "lm90: Updating register values\n"); -#endif - - lm90_read_reg(client, LM90_REG_R_LOCAL_TEMP, - &data->local_temp); - lm90_read_reg(client, LM90_REG_R_LOCAL_HIGH, - &data->local_high); - lm90_read_reg(client, LM90_REG_R_LOCAL_LOW, - &data->local_low); - lm90_read_reg(client, LM90_REG_R_LOCAL_CRIT, - &data->local_crit); - lm90_read_reg(client, LM90_REG_R_REMOTE_CRIT, - &data->remote_crit); - lm90_read_reg(client, LM90_REG_R_TCRIT_HYST, - &data->hyst); - - /* - * There is a trick here. We have to read two registers to - * have the remote sensor temperature, but we have to beware - * a conversion could occur inbetween the readings. The - * datasheet says we should either use the one-shot - * conversion register, which we don't want to do (disables - * hardware monitoring) or monitor the busy bit, which is - * impossible (we can't read the values and monitor that bit - * at the exact same time). So the solution used here is to - * read the high byte once, then the low byte, then the high - * byte again. If the new high byte matches the old one, - * then we have a valid reading. Else we have to read the low - * byte again, and now we believe we have a correct reading. - */ - - if (lm90_read_reg(client, LM90_REG_R_REMOTE_TEMPH, &oldh) == 0 - && lm90_read_reg(client, LM90_REG_R_REMOTE_TEMPL, &l) == 0 - && lm90_read_reg(client, LM90_REG_R_REMOTE_TEMPH, &newh) == 0 - && (newh == oldh - || lm90_read_reg(client, LM90_REG_R_REMOTE_TEMPL, &l) == 0)) - data->remote_temp = (newh << 8) | l; - - if (lm90_read_reg(client, LM90_REG_R_REMOTE_LOWH, &newh) == 0 - && lm90_read_reg(client, LM90_REG_R_REMOTE_LOWL, &l) == 0) - data->remote_low = (newh << 8) | l; - if (lm90_read_reg(client, LM90_REG_R_REMOTE_HIGHH, &newh) == 0 - && lm90_read_reg(client, LM90_REG_R_REMOTE_HIGHL, &l) == 0) - data->remote_high = (newh << 8) | l; - lm90_read_reg(client, LM90_REG_R_STATUS, &data->alarms); - - data->last_updated = jiffies; - data->valid = 1; - } - - up(&data->update_lock); -} - -static void lm90_local_temp(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results) -{ - struct lm90_data *data = client->data; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; /* magnitude */ - else if (operation == SENSORS_PROC_REAL_READ) { - lm90_update_client(client); - results[0] = TEMP1_FROM_REG(data->local_high); - results[1] = TEMP1_FROM_REG(data->local_low); - results[2] = TEMP1_FROM_REG(data->local_temp); - *nrels_mag = 3; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag >= 1) { - if (data->kind == adt7461) - data->local_high = TEMP1_TO_REG_ADT7461(results[0]); - else - data->local_high = TEMP1_TO_REG(results[0]); - i2c_smbus_write_byte_data(client, LM90_REG_W_LOCAL_HIGH, - data->local_high); - } - if (*nrels_mag >= 2) { - if (data->kind == adt7461) - data->local_low = TEMP1_TO_REG_ADT7461(results[1]); - else - data->local_low = TEMP1_TO_REG(results[1]); - i2c_smbus_write_byte_data(client, LM90_REG_W_LOCAL_LOW, - data->local_low); - } - } -} - -static void lm90_remote_temp(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results) -{ - struct lm90_data *data = client->data; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 1; /* magnitude */ - else if (operation == SENSORS_PROC_REAL_READ) { - lm90_update_client(client); - results[0] = TEMP2_FROM_REG(data->remote_high); - results[1] = TEMP2_FROM_REG(data->remote_low); - results[2] = TEMP2_FROM_REG(data->remote_temp); - *nrels_mag = 3; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag >= 1) { - if (data->kind == adt7461) - data->remote_high = TEMP2_TO_REG_ADT7461(results[0]); - else - data->remote_high = TEMP2_TO_REG(results[0]); - i2c_smbus_write_byte_data(client, LM90_REG_W_REMOTE_HIGHH, - data->remote_high >> 8); - i2c_smbus_write_byte_data(client, LM90_REG_W_REMOTE_HIGHL, - data->remote_high & 0xFF); - } - if (*nrels_mag >= 2) { - if (data->kind == adt7461) - data->remote_low = TEMP2_TO_REG_ADT7461(results[1]); - else - data->remote_low = TEMP2_TO_REG(results[1]); - i2c_smbus_write_byte_data(client, LM90_REG_W_REMOTE_LOWH, - data->remote_low >> 8); - i2c_smbus_write_byte_data(client, LM90_REG_W_REMOTE_LOWL, - data->remote_low & 0xFF); - } - } -} - -static void lm90_local_tcrit(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results) -{ - struct lm90_data *data = client->data; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; /* magnitude */ - else if (operation == SENSORS_PROC_REAL_READ) { - lm90_update_client(client); - results[0] = TEMP1_FROM_REG(data->local_crit); - *nrels_mag = 1; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag >= 1) { - if (data->kind == adt7461) - data->local_crit = TEMP1_TO_REG_ADT7461(results[0]); - else - data->local_crit = TEMP1_TO_REG(results[0]); - i2c_smbus_write_byte_data(client, LM90_REG_W_LOCAL_CRIT, - data->local_crit); - } - } -} - -static void lm90_remote_tcrit(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results) -{ - struct lm90_data *data = client->data; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; /* magnitude */ - else if (operation == SENSORS_PROC_REAL_READ) { - lm90_update_client(client); - results[0] = TEMP1_FROM_REG(data->remote_crit); - *nrels_mag = 1; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag >= 1) { - if (data->kind == adt7461) - data->remote_crit = TEMP1_TO_REG_ADT7461(results[0]); - else - data->remote_crit = TEMP1_TO_REG(results[0]); - i2c_smbus_write_byte_data(client, LM90_REG_W_REMOTE_CRIT, - data->remote_crit); - } - } -} - -/* - * One quick note about hysteresis. Internally, the hysteresis value - * is held in a single register by the LM90, as a relative value. - * This relative value applies to both the local critical temperature - * and the remote critical temperature. Since all temperatures exported - * through procfs have to be absolute, we have to do some conversions. - * The solution retained here is to export two absolute values, one for - * each critical temperature. In order not to confuse the users too - * much, only one file is writable. Would we fail to do so, users - * would probably attempt to write to both files, as if they were - * independant, and since they aren't, they wouldn't understand why - * setting one affects the other one (and would probably claim there's - * a bug in the driver). - */ - -static void lm90_local_hyst(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results) -{ - struct lm90_data *data = client->data; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; /* magnitude */ - else if (operation == SENSORS_PROC_REAL_READ) { - lm90_update_client(client); - results[0] = TEMP1_FROM_REG(data->local_crit) - - TEMP1_FROM_REG(data->hyst); - *nrels_mag = 1; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag >= 1) { - data->hyst = HYST_TO_REG(data->local_crit - results[0]); - i2c_smbus_write_byte_data(client, LM90_REG_W_TCRIT_HYST, - data->hyst); - } - } -} - -static void lm90_remote_hyst(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results) -{ - struct lm90_data *data = client->data; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; /* magnitude */ - else if (operation == SENSORS_PROC_REAL_READ) { - lm90_update_client(client); - results[0] = TEMP1_FROM_REG(data->remote_crit) - - TEMP1_FROM_REG(data->hyst); - *nrels_mag = 1; - } -} - -static void lm90_alarms(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results) -{ - struct lm90_data *data = client->data; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; /* magnitude */ - else if (operation == SENSORS_PROC_REAL_READ) { - lm90_update_client(client); - results[0] = data->alarms; - *nrels_mag = 1; - } -} - -/* pec used for ADM1032 only */ -static void adm1032_pec(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results) -{ - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; /* magnitude */ - else if (operation == SENSORS_PROC_REAL_READ) { - results[0] = !!(client->flags & I2C_CLIENT_PEC); - *nrels_mag = 1; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag >= 1) { - switch (results[0]) { - case 0: - client->flags &= ~I2C_CLIENT_PEC; - break; - case 1: - client->flags |= I2C_CLIENT_PEC; - break; - } - } - } -} - -static int __init sm_lm90_init(void) -{ - printk(KERN_INFO "lm90 driver version %s (%s)\n", LM_VERSION, - LM_DATE); - return i2c_add_driver(&lm90_driver); -} - -static void __exit sm_lm90_exit(void) -{ - i2c_del_driver(&lm90_driver); -} - -MODULE_AUTHOR("Jean Delvare "); -MODULE_DESCRIPTION("LM90/ADM1032 sensor driver"); -MODULE_LICENSE("GPL"); - -module_init(sm_lm90_init); -module_exit(sm_lm90_exit); diff --git a/kernel/chips/lm92.c b/kernel/chips/lm92.c deleted file mode 100644 index 73154fcb..00000000 --- a/kernel/chips/lm92.c +++ /dev/null @@ -1,416 +0,0 @@ - -/* - * LM92 - Part of lm_sensors, Linux kernel modules for hardware - * monitoring - * - * Author: Abraham van der Merwe - * - * Linux support for the National Semiconductor LM92 Temperature - * Sensor. - * - * Based on code from the lm-sensors project which is available - * at http://www.lm-sensors.org/. lm87.c have been particularly - * helpful (: - * - * This source code is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * version 2 as published by the Free Software Foundation. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "version.h" - -/* if defined, 4 faults must occur consecutively to set alarm flags */ -/* #define ENABLE_FAULT_QUEUE */ - -#define LM92_REG_TEMPERATURE 0x00 /* ro, 16-bit */ -#define LM92_REG_CONFIGURATION 0x01 /* rw, 8-bit */ -#define LM92_REG_TRIP_HYSTERESIS 0x02 /* rw, 16-bit */ -#define LM92_REG_TRIP_CRITICAL 0x03 /* rw, 16-bit */ -#define LM92_REG_TRIP_LOW 0x04 /* rw, 16-bit */ -#define LM92_REG_TRIP_HIGH 0x05 /* rw, 16-bit */ -#define LM92_REG_MANUFACTURER 0x07 /* ro, 16-bit */ - -#define LM92_MANUFACTURER_ID 0x8001 - -#define TEMP_MIN (-4096) -#define TEMP_MAX 4095 - -#define LIMIT(x) do { \ - if ((x) < TEMP_MIN) (x) = TEMP_MIN; \ - if ((x) > TEMP_MAX) (x) = TEMP_MAX; \ - } while (0) - -#define PROC_TO_NATIVE(x) ((x) / 625) -#define NATIVE_TO_PROC(x) ((x) * 625) -#define CELSIUS(x) ((x) * 16) - -static void lm92_temp (struct i2c_client *client,int operation,int ctl_name,int *nrels_mag,long *results); -static void lm92_alarms (struct i2c_client *client,int operation,int ctl_name,int *nrels_mag,long *results); - -/* -- SENSORS SYSCTL START -- */ -#define LM92_SYSCTL_ALARMS 2001 /* high, low, critical */ -#define LM92_SYSCTL_TEMP 1200 /* high, low, critical, hysteresis, input */ - -#define LM92_ALARM_TEMP_HIGH 0x01 -#define LM92_ALARM_TEMP_LOW 0x02 -#define LM92_ALARM_TEMP_CRIT 0x04 -#define LM92_TEMP_HIGH 0x08 -#define LM92_TEMP_LOW 0x10 -#define LM92_TEMP_CRIT 0x20 -#define LM92_TEMP_HYST 0x40 -#define LM92_TEMP_INPUT 0x80 - -/* -- SENSORS SYSCTL END -- */ - -static ctl_table lm92_dir_table[] = { - {LM92_SYSCTL_TEMP, "temp", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &lm92_temp, NULL}, - {LM92_SYSCTL_ALARMS, "alarms", NULL, 0, 0444, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &lm92_alarms, NULL}, - {0} -}; - -/* NOTE: all temperatures are degrees centigrade * 16 */ -typedef struct { - struct i2c_client client; - int sysctl_id; - unsigned long timestamp; - struct { - long high; - long low; - long crit; - long hyst; - long input; - } temp; - struct { - long low; - long high; - long crit; - } alarms; -} lm92_t; - -/* this is needed for each client driver method */ -static struct i2c_driver lm92_driver; - -/* ensure exclusive access to chip and static variables */ -static DECLARE_MUTEX (mutex); - -/* addresses to scan */ -static unsigned short normal_i2c[] = { SENSORS_I2C_END }; -static unsigned short normal_i2c_range[] = { 0x48, 0x4f, SENSORS_I2C_END }; -static unsigned int normal_isa[] = { SENSORS_ISA_END }; -static unsigned int normal_isa_range[] = { SENSORS_ISA_END }; - -/* insmod parameters */ -SENSORS_INSMOD_1 (lm92); - -static inline int lm92_write8 (struct i2c_client *client,u8 reg,u8 value) -{ - return (i2c_smbus_write_byte_data (client,reg,value) < 0 ? -EIO : 0); -} - -static inline int lm92_read16 (struct i2c_client *client,u8 reg,u16 *value) -{ - s32 tmp = i2c_smbus_read_word_data (client,reg); - - if (tmp < 0) return (-EIO); - - /* convert the data to little endian format */ - *value = swab16((u16) tmp); - - return (0); -} - -static inline int lm92_write16 (struct i2c_client *client,u8 reg,u16 value) -{ - /* convert the data to big endian format */ - if (i2c_smbus_write_word_data(client, reg, swab16(value)) < 0) - return -EIO; - - return 0; -} - -static int lm92_read (struct i2c_client *client) -{ - lm92_t *data = (lm92_t *) client->data; - u16 value[5]; - - if ((jiffies - data->timestamp) > HZ) { - if (lm92_read16 (client,LM92_REG_TEMPERATURE,value) < 0 || - lm92_read16 (client,LM92_REG_TRIP_HYSTERESIS,value + 1) < 0 || - lm92_read16 (client,LM92_REG_TRIP_CRITICAL,value + 2) < 0 || - lm92_read16 (client,LM92_REG_TRIP_LOW,value + 3) < 0 || - lm92_read16 (client,LM92_REG_TRIP_HIGH,value + 4) < 0) - return (-EIO); - - data->temp.input = (s16) value[0] >> 3; - data->temp.hyst = (s16) value[1] >> 3; - data->temp.crit = (s16) value[2] >> 3; - data->temp.low = (s16) value[3] >> 3; - data->temp.high = (s16) value[4] >> 3; - - data->alarms.low = value[0] & 1; - data->alarms.high = (value[0] & 2) >> 1; - data->alarms.crit = (value[0] & 4) >> 2; - - data->timestamp = jiffies; - } - - return (0); -} - -static int lm92_write (struct i2c_client *client) -{ - lm92_t *data = (lm92_t *) client->data; - - LIMIT (data->temp.hyst); - LIMIT (data->temp.crit); - LIMIT (data->temp.low); - LIMIT (data->temp.high); - - if (lm92_write16 (client,LM92_REG_TRIP_HYSTERESIS,((s16) data->temp.hyst << 3)) < 0 || - lm92_write16 (client,LM92_REG_TRIP_CRITICAL,((s16) data->temp.crit << 3)) < 0 || - lm92_write16 (client,LM92_REG_TRIP_LOW,((s16) data->temp.low << 3)) < 0 || - lm92_write16 (client,LM92_REG_TRIP_HIGH,((s16) data->temp.high << 3)) < 0) - return (-EIO); - - return (0); -} - -static void lm92_temp (struct i2c_client *client,int operation,int ctl_name,int *nrels_mag,long *results) -{ - if (!down_interruptible (&mutex)) { - lm92_t *data = (lm92_t *) client->data; - - if (operation == SENSORS_PROC_REAL_READ) { - lm92_read (client); - results[0] = NATIVE_TO_PROC (data->temp.input); - results[1] = NATIVE_TO_PROC (data->temp.high); - results[2] = NATIVE_TO_PROC (data->temp.low); - results[3] = NATIVE_TO_PROC (data->temp.crit); - results[4] = NATIVE_TO_PROC (data->temp.hyst); - *nrels_mag = 5; - } else if (operation == SENSORS_PROC_REAL_WRITE && *nrels_mag == 4) { - data->temp.high = PROC_TO_NATIVE (results[0]); - data->temp.low = PROC_TO_NATIVE (results[1]); - data->temp.crit = PROC_TO_NATIVE (results[2]); - data->temp.hyst = PROC_TO_NATIVE (results[3]); - lm92_write (client); - } else if (operation == SENSORS_PROC_REAL_INFO) { - *nrels_mag = 4; - } - - up (&mutex); - } -} - -static void lm92_alarms (struct i2c_client *client,int operation,int ctl_name,int *nrels_mag,long *results) -{ - if (!down_interruptible (&mutex)) { - lm92_t *data = (lm92_t *) client->data; - - if (operation == SENSORS_PROC_REAL_READ) { - lm92_read (client); - results[0] = data->alarms.high || (data->alarms.low << 1) || (data->alarms.crit << 2); - *nrels_mag = 1; - } else if (operation == SENSORS_PROC_REAL_INFO) { - *nrels_mag = 0; - } - - up (&mutex); - } -} - -static int max6635_check(struct i2c_client *client) -{ - int i; - u16 temp_low, temp_high, temp_hyst, temp_crit; - u8 conf; - - temp_low = i2c_smbus_read_word_data(client, LM92_REG_TRIP_LOW); - temp_high = i2c_smbus_read_word_data(client, LM92_REG_TRIP_HIGH); - temp_hyst = i2c_smbus_read_word_data(client, LM92_REG_TRIP_HYSTERESIS); - temp_crit = i2c_smbus_read_word_data(client, LM92_REG_TRIP_CRITICAL); - - if ((temp_low & 0x7f00) || (temp_high & 0x7f00) - || (temp_hyst & 0x7f00) || (temp_crit & 0x7f00)) - return 0; - - conf = i2c_smbus_read_byte_data(client, LM92_REG_CONFIGURATION); - - for (i=0; i<128; i+=16) { - if (temp_low != i2c_smbus_read_word_data(client, LM92_REG_TRIP_LOW + i) - || temp_high != i2c_smbus_read_word_data(client, LM92_REG_TRIP_HIGH + i) - || temp_hyst != i2c_smbus_read_word_data(client, LM92_REG_TRIP_HYSTERESIS + i) - || temp_crit != i2c_smbus_read_word_data(client, LM92_REG_TRIP_CRITICAL + i) - || conf != i2c_smbus_read_byte_data(client, LM92_REG_CONFIGURATION + i)) - return 0; - } - - return 1; -} - -static int lm92_init_client (struct i2c_client *client) -{ - lm92_t *data = (lm92_t *) client->data; - u8 value = 0; - int result; - - /* force reads to query the chip */ - data->timestamp = 0; - - /* setup the configuration register */ - -#ifdef ENABLE_FAULT_QUEUE - value |= 0x10; -#endif /* #ifdef ENABLE_FAULT_QUEUE */ - - if (lm92_write8 (client,LM92_REG_CONFIGURATION,value) < 0) - return (-ENODEV); - - /* set default alarm trigger values */ - - data->temp.high = CELSIUS (64); - data->temp.low = CELSIUS (10); - data->temp.crit = CELSIUS (80); - data->temp.hyst = CELSIUS (2); - - if ((result = lm92_write (client)) < 0) - return (result); - - /* read everything once so that our cached data is updated */ - - if ((result = lm92_read (client)) < 0) - return (result); - - return (0); -} - -static int lm92_detect (struct i2c_adapter *adapter,int address,unsigned short flags,int kind) -{ - struct i2c_client *client; - lm92_t *data; - int result = 0; - u16 manufacturer; - - if (!i2c_check_functionality (adapter,I2C_FUNC_SMBUS_BYTE_DATA)) - return 0; - - if (!(data = kmalloc(sizeof(lm92_t), GFP_KERNEL))) - return (-ENOMEM); - - client = &data->client; - client->addr = address; - client->data = data; - client->adapter = adapter; - client->driver = &lm92_driver; - client->flags = 0; - strcpy (client->name,lm92_driver.name); - - if (down_interruptible (&mutex)) { - result = -ERESTARTSYS; - goto ERROR1; - } - - if (kind < 0) { - /* Is it an lm92? */ - if (address < 0x4c - && (lm92_read16(client,LM92_REG_MANUFACTURER,&manufacturer) < 0 - || manufacturer != LM92_MANUFACTURER_ID)) { - /* Is it a MAX6635/MAX6635/MAX6635? */ - if (!max6635_check(client)) { - goto ERROR2; - } - } - } - - if ((result = i2c_attach_client (client))) { - goto ERROR2; - } - - if ((result = i2c_register_entry(client, client->name, lm92_dir_table, - THIS_MODULE)) < 0) { - goto ERROR3; - } - data->sysctl_id = result; - - if ((result = lm92_init_client (client)) < 0) { - goto ERROR4; - } - - up (&mutex); - - return (0); - -ERROR4: - i2c_deregister_entry(data->sysctl_id); -ERROR3: - i2c_detach_client(client); -ERROR2: - up(&mutex); -ERROR1: - kfree(data); - return result; -} - -static int lm92_attach_adapter (struct i2c_adapter *adapter) -{ - return i2c_detect (adapter,&addr_data,lm92_detect); -} - -static int lm92_detach_client (struct i2c_client *client) -{ - int result; - - i2c_deregister_entry (((lm92_t *) (client->data))->sysctl_id); - - if ((result = i2c_detach_client (client))) - return (result); - - kfree(client->data); - - return (0); -} - - -static struct i2c_driver lm92_driver = { - .name = "lm92", - .id = I2C_DRIVERID_LM92, - .flags = I2C_DF_NOTIFY, - .attach_adapter = lm92_attach_adapter, - .detach_client = lm92_detach_client, -}; - -static int __init sm_lm92_init(void) -{ - printk ("lm92.o version %s (%s)\n",LM_VERSION,LM_DATE); - return i2c_add_driver(&lm92_driver); -} - - -static void __exit sm_lm92_exit(void) -{ - i2c_del_driver(&lm92_driver); -} - - - -MODULE_AUTHOR ("Abraham van der Merwe "); -MODULE_DESCRIPTION ("Linux support for LM92 Temperature Sensor"); - -MODULE_LICENSE ("GPL"); - -module_init(sm_lm92_init); -module_exit(sm_lm92_exit); - diff --git a/kernel/chips/lm93.c b/kernel/chips/lm93.c deleted file mode 100644 index 29b8df5e..00000000 --- a/kernel/chips/lm93.c +++ /dev/null @@ -1,2343 +0,0 @@ -/* - lm93.c - Part of lm_sensors, Linux kernel modules for hardware monitoring - - Author/Maintainer: Mark M. Hoffman - Copyright (c) 2004 Utilitek Systems, Inc. - - derived in part from lm78.c: - Copyright (c) 1998, 1999 Frodo Looijaard - - derived in part from lm85.c: - Copyright (c) 2002, 2003 Philip Pokorny - Copyright (c) 2003 Margit Schubert-While - - derived in part from w83l785ts.c: - Copyright (c) 2003-2004 Jean Delvare - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#define DEBUG 1 - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "version.h" -#include "sensors_vid.h" -#include "lm93.h" - -#ifndef I2C_DRIVERID_LM93 -#define I2C_DRIVERID_LM93 1049 -#endif - -/* I2C addresses to scan */ -static unsigned short normal_i2c[] = { SENSORS_I2C_END }; -static unsigned short normal_i2c_range[] = { 0x2c, 0x2e, SENSORS_I2C_END }; - -/* ISA addresses to scan (none) */ -static unsigned int normal_isa[] = { SENSORS_ISA_END }; -static unsigned int normal_isa_range[] = { SENSORS_ISA_END }; - -/* module parameters */ -SENSORS_INSMOD_1(lm93); - -static int disable_block /* = 0 */ ; -MODULE_PARM(disable_block, "i"); -MODULE_PARM_DESC(disable_block, - "Set to non-zero to disable SMBus block data transactions."); - -static int init = 1; -MODULE_PARM(init, "i"); -MODULE_PARM_DESC(init, "Set to zero to bypass most chip initialization"); - -static int vccp_limit_type[2] /* = {0,0} */ ; -MODULE_PARM(vccp_limit_type, "2-2i"); -MODULE_PARM_DESC(vccp_limit_type, "Configures in7 and in8 limit modes"); - -static int vid_agtl = 0; -MODULE_PARM(vid_agtl, "i"); -MODULE_PARM_DESC(vid_agtl, "Configures VID pin input thresholds"); - -/* -- SENSORS SYSCTL START -- */ -/* volts * 100 */ -#define LM93_SYSCTL_IN1 1001 -#define LM93_SYSCTL_IN2 1002 -#define LM93_SYSCTL_IN3 1003 -#define LM93_SYSCTL_IN4 1004 -#define LM93_SYSCTL_IN5 1005 -#define LM93_SYSCTL_IN6 1006 -#define LM93_SYSCTL_IN7 1007 -#define LM93_SYSCTL_IN8 1008 -#define LM93_SYSCTL_IN9 1009 -#define LM93_SYSCTL_IN10 1010 -#define LM93_SYSCTL_IN11 1011 -#define LM93_SYSCTL_IN12 1012 -#define LM93_SYSCTL_IN13 1013 -#define LM93_SYSCTL_IN14 1014 -#define LM93_SYSCTL_IN15 1015 -#define LM93_SYSCTL_IN16 1016 - -/* degrees Celsius * 10 */ -#define LM93_SYSCTL_TEMP1 1101 -#define LM93_SYSCTL_TEMP2 1102 -#define LM93_SYSCTL_TEMP3 1103 - -#define LM93_SYSCTL_TEMP1_AUTO_BASE 1111 -#define LM93_SYSCTL_TEMP2_AUTO_BASE 1112 -#define LM93_SYSCTL_TEMP3_AUTO_BASE 1113 - -#define LM93_SYSCTL_TEMP1_AUTO_OFFSETS 1121 -#define LM93_SYSCTL_TEMP2_AUTO_OFFSETS 1122 -#define LM93_SYSCTL_TEMP3_AUTO_OFFSETS 1123 - -#define LM93_SYSCTL_TEMP1_AUTO_BOOST 1131 -#define LM93_SYSCTL_TEMP2_AUTO_BOOST 1132 -#define LM93_SYSCTL_TEMP3_AUTO_BOOST 1133 - -#define LM93_SYSCTL_TEMP1_AUTO_BOOST_HYST 1141 -#define LM93_SYSCTL_TEMP2_AUTO_BOOST_HYST 1142 -#define LM93_SYSCTL_TEMP3_AUTO_BOOST_HYST 1143 - -/* 0 => off, 255 => 100% */ -#define LM93_SYSCTL_TEMP1_AUTO_PWM_MIN 1151 -#define LM93_SYSCTL_TEMP2_AUTO_PWM_MIN 1152 -#define LM93_SYSCTL_TEMP3_AUTO_PWM_MIN 1153 - -/* degrees Celsius * 10 */ -#define LM93_SYSCTL_TEMP1_AUTO_OFFSET_HYST 1161 -#define LM93_SYSCTL_TEMP2_AUTO_OFFSET_HYST 1162 -#define LM93_SYSCTL_TEMP3_AUTO_OFFSET_HYST 1163 - -/* rotations/minute */ -#define LM93_SYSCTL_FAN1 1201 -#define LM93_SYSCTL_FAN2 1202 -#define LM93_SYSCTL_FAN3 1203 -#define LM93_SYSCTL_FAN4 1204 - -/* 1-2 => enable smart tach mode associated with this pwm #, or disable */ -#define LM93_SYSCTL_FAN1_SMART_TACH 1205 -#define LM93_SYSCTL_FAN2_SMART_TACH 1206 -#define LM93_SYSCTL_FAN3_SMART_TACH 1207 -#define LM93_SYSCTL_FAN4_SMART_TACH 1208 - -/* volts * 1000 */ -#define LM93_SYSCTL_VID1 1301 -#define LM93_SYSCTL_VID2 1302 - -/* 0 => off, 255 => 100% */ -#define LM93_SYSCTL_PWM1 1401 -#define LM93_SYSCTL_PWM2 1402 - -/* Hz */ -#define LM93_SYSCTL_PWM1_FREQ 1411 -#define LM93_SYSCTL_PWM2_FREQ 1412 - -/* bitvector */ -#define LM93_SYSCTL_PWM1_AUTO_CHANNELS 1421 -#define LM93_SYSCTL_PWM2_AUTO_CHANNELS 1422 - -/* Hz */ -#define LM93_SYSCTL_PWM1_AUTO_SPINUP_MIN 1431 -#define LM93_SYSCTL_PWM2_AUTO_SPINUP_MIN 1432 - -/* seconds */ -#define LM93_SYSCTL_PWM1_AUTO_SPINUP_TIME 1441 -#define LM93_SYSCTL_PWM2_AUTO_SPINUP_TIME 1442 - -/* seconds */ -#define LM93_SYSCTL_PWM_AUTO_PROCHOT_RAMP 1451 -#define LM93_SYSCTL_PWM_AUTO_VRDHOT_RAMP 1452 - -/* 0 => 0%, 255 => > 99.6% */ -#define LM93_SYSCTL_PROCHOT1 1501 -#define LM93_SYSCTL_PROCHOT2 1502 - -/* !0 => enable #PROCHOT logical short */ -#define LM93_SYSCTL_PROCHOT_SHORT 1503 - -/* 2 boolean enable/disable, 3rd value indicates duty cycle */ -#define LM93_SYSCTL_PROCHOT_OVERRIDE 1504 - -/* 2 values, 0-9 */ -#define LM93_SYSCTL_PROCHOT_INTERVAL 1505 - -/* GPIO input (bitmask) */ -#define LM93_SYSCTL_GPIO 1601 - -/* #VRDHOT input (boolean) */ -#define LM93_SYSCTL_VRDHOT1 1701 -#define LM93_SYSCTL_VRDHOT2 1702 - -/* alarms (bitmask) */ -#define LM93_SYSCTL_ALARMS 2001 - -/* alarm bitmask definitions - The LM93 has nearly 64 bits of error status... I've pared that down to - what I think is a useful subset in order to fit it into 32 bits. - - Especially note that the #VRD_HOT alarms are missing because we provide - that information as values in another /proc file. - - If libsensors is extended to support 64 bit values, this could be revisited. -*/ -#define LM93_ALARM_IN1 0x00000001 -#define LM93_ALARM_IN2 0x00000002 -#define LM93_ALARM_IN3 0x00000004 -#define LM93_ALARM_IN4 0x00000008 -#define LM93_ALARM_IN5 0x00000010 -#define LM93_ALARM_IN6 0x00000020 -#define LM93_ALARM_IN7 0x00000040 -#define LM93_ALARM_IN8 0x00000080 -#define LM93_ALARM_IN9 0x00000100 -#define LM93_ALARM_IN10 0x00000200 -#define LM93_ALARM_IN11 0x00000400 -#define LM93_ALARM_IN12 0x00000800 -#define LM93_ALARM_IN13 0x00001000 -#define LM93_ALARM_IN14 0x00002000 -#define LM93_ALARM_IN15 0x00004000 -#define LM93_ALARM_IN16 0x00008000 -#define LM93_ALARM_FAN1 0x00010000 -#define LM93_ALARM_FAN2 0x00020000 -#define LM93_ALARM_FAN3 0x00040000 -#define LM93_ALARM_FAN4 0x00080000 -#define LM93_ALARM_PH1_ERR 0x00100000 -#define LM93_ALARM_PH2_ERR 0x00200000 -#define LM93_ALARM_SCSI1_ERR 0x00400000 -#define LM93_ALARM_SCSI2_ERR 0x00800000 -#define LM93_ALARM_DVDDP1_ERR 0x01000000 -#define LM93_ALARM_DVDDP2_ERR 0x02000000 -#define LM93_ALARM_D1_ERR 0x04000000 -#define LM93_ALARM_D2_ERR 0x08000000 -#define LM93_ALARM_TEMP1 0x10000000 -#define LM93_ALARM_TEMP2 0x20000000 -#define LM93_ALARM_TEMP3 0x40000000 - -/* -- SENSORS SYSCTL END -- */ - -/* SMBus capabilities */ -#define LM93_SMBUS_FUNC_FULL (I2C_FUNC_SMBUS_BYTE_DATA | \ - I2C_FUNC_SMBUS_WORD_DATA | I2C_FUNC_SMBUS_BLOCK_DATA) -#define LM93_SMBUS_FUNC_MIN (I2C_FUNC_SMBUS_BYTE_DATA | \ - I2C_FUNC_SMBUS_WORD_DATA) - -/* LM93 BLOCK READ COMMANDS */ -static const struct { u8 cmd; u8 len; } lm93_block_read_cmds[12] = { - { 0xf2, 8 }, - { 0xf3, 8 }, - { 0xf4, 6 }, - { 0xf5, 16 }, - { 0xf6, 4 }, - { 0xf7, 8 }, - { 0xf8, 12 }, - { 0xf9, 32 }, - { 0xfa, 8 }, - { 0xfb, 8 }, - { 0xfc, 16 }, - { 0xfd, 9 }, -}; - -/* ALARMS: SYSCTL format described further below - REG: 64 bits in 8 registers, as immediately below */ -struct block1_t { - u8 host_status_1; - u8 host_status_2; - u8 host_status_3; - u8 host_status_4; - u8 p1_prochot_status; - u8 p2_prochot_status; - u8 gpi_status; - u8 fan_status; -}; - -/* unique ID for each LM93 detected */ -static int lm93_id = 0; - -/* For each registered client, we need to keep some data in memory. That - data is pointed to by client->data. The structure itself is dynamically - allocated, at the same time the client itself is allocated. */ - -struct lm93_data { - struct i2c_client client; - int sysctl_id; - - struct semaphore update_lock; - unsigned long last_updated; /* In jiffies */ - - /* client update function */ - void (*update)(struct lm93_data *, struct i2c_client *); - - char valid; /* !=0 if following fields are valid */ - - /* register values, arranged by block read groups */ - struct block1_t block1; - - /* temp1 - temp4: unfiltered readings - temp1 - temp2: filtered readings */ - u8 block2[6]; - - /* vin1 - vin16: readings */ - u8 block3[16]; - - /* prochot1 - prochot2: readings */ - struct { u8 cur; u8 avg; } block4[2]; - - /* fan counts 1-4 => 14-bits, LE, *left* justified */ - u16 block5[4]; - - /* block6 has a lot of data we don't need */ - struct { u8 min; u8 max; } temp_lim[4]; - - /* vin1 - vin16: low and high limits */ - struct { u8 min; u8 max; } block7[16]; - - /* fan count limits 1-4 => same format as block5 */ - u16 block8[4]; - - /* pwm control registers (2 pwms, 4 regs) */ - u8 block9[2][4]; - - /* auto/pwm base temp and offset temp registers */ - struct { u8 base[4]; u8 offset[12]; } block10; - - /* master config register */ - u8 config; - - /* VID1 & VID2 => register format, 6-bits, right justified */ - u8 vid[2]; - - /* prochot1 - prochot2: limits */ - u8 prochot_max[2]; - - /* vccp1 & vccp2 (in7 & in8): VID relative limits (register format) */ - u8 vccp_limits[2]; - - /* GPIO input state (register format, i.e. inverted) */ - u8 gpi; - - /* #PROCHOT override (register format) */ - u8 prochot_override; - - /* #PROCHOT intervals (register format) */ - u8 prochot_interval; - - /* Fan Boost Temperatures (register format) */ - u8 boost[4]; - - /* Fan Boost Hysteresis (register format) */ - u8 boost_hyst[2]; - - /* Temperature Zone Min. PWM & Hysteresis (register format) */ - u8 auto_pwm_min_hyst[2]; - - /* #PROCHOT & #VRDHOT PWM Ramp Control */ - u8 pwm_ramp_ctl; - - /* miscellaneous setup regs */ - u8 sfc1; - u8 sfc2; - u8 sf_tach_to_pwm; - - /* The two PWM CTL2 registers can read something other than what was - last written for the OVR_DC field (duty cycle override). So, we - save the user-commanded value here. */ - u8 pwm_override[2]; -}; - -#define MAX_RETRIES 5 - -static u8 lm93_read_byte(struct i2c_client *client, u8 reg) -{ - int value, i; - - /* retry in case of read errors */ - for (i=1; i<=MAX_RETRIES; i++) { - if ((value = i2c_smbus_read_byte_data(client, reg)) >= 0) { - return value; - } else { - printk(KERN_WARNING "lm93.o: read byte data failed, " - "address 0x%02x.\n", reg); - mdelay(i + 3); - } - - } - - /* what to return in case of error? */ - printk(KERN_ERR "lm93.o: All read byte retries failed!!\n"); - return 0; -} - -static int lm93_write_byte(struct i2c_client *client, u8 reg, u8 value) -{ - int result; - - /* how to handle write errors? */ - result = i2c_smbus_write_byte_data(client, reg, value); - - if (result < 0) - printk(KERN_WARNING "lm93.o: write byte data failed, " - "0x%02x at address 0x%02x.\n", value, reg); - - return result; -} - -static u16 lm93_read_word(struct i2c_client *client, u8 reg) -{ - int value, i; - - /* retry in case of read errors */ - for (i=1; i<=MAX_RETRIES; i++) { - if ((value = i2c_smbus_read_word_data(client, reg)) >= 0) { - return value; - } else { - printk(KERN_WARNING "lm93.o: read word data failed, " - "address 0x%02x.\n", reg); - mdelay(i + 3); - } - - } - - /* what to return in case of error? */ - printk(KERN_ERR "lm93.o: All read word retries failed!!\n"); - return 0; -} - -static int lm93_write_word(struct i2c_client *client, u8 reg, u16 value) -{ - int result; - - /* how to handle write errors? */ - result = i2c_smbus_write_word_data(client, reg, value); - - if (result < 0) - printk(KERN_WARNING "lm93.o: write word data failed, " - "0x%04x at address 0x%02x.\n", value, reg); - - return result; -} - -static u8 lm93_block_buffer[I2C_SMBUS_BLOCK_MAX]; - -/* - read block data into values, retry if not expected length - fbn => index to lm93_block_read_cmds table - (Fixed Block Number - section 14.5.2 of LM93 datasheet) -*/ -static void lm93_read_block(struct i2c_client *client, u8 fbn, u8 *values) -{ - int i, result=0; - - for (i = 1; i <= MAX_RETRIES; i++) { - result = i2c_smbus_read_block_data(client, - lm93_block_read_cmds[fbn].cmd, lm93_block_buffer); - - if (result == lm93_block_read_cmds[fbn].len) { - break; - } else { - printk(KERN_WARNING "lm93.o: block read data failed, " - "command 0x%02x.\n", - lm93_block_read_cmds[fbn].cmd); - mdelay(i + 3); - } - } - - if (result == lm93_block_read_cmds[fbn].len) { - memcpy(values,lm93_block_buffer,lm93_block_read_cmds[fbn].len); - } else { - /* what to do in case of error? */ - } -} - -static void lm93_update_client(struct i2c_client *client) -{ - struct lm93_data *data = client->data; - - down(&data->update_lock); - - if (time_after(jiffies - data->last_updated, HZ + HZ / 2) || - time_before(jiffies, data->last_updated) || !data->valid) { - - data->update(data, client); - data->last_updated = jiffies; - data->valid = 1; - } - - up(&data->update_lock); -} - -/* update routine for data that has no corresponding SMBus block data command */ -static void lm93_update_client_common(struct lm93_data *data, - struct i2c_client *client) -{ - int i; - u8 *ptr; - - /* temp1 - temp4: limits */ - for (i = 0; i < 4; i++) { - data->temp_lim[i].min = - lm93_read_byte(client, LM93_REG_TEMP_MIN(i)); - data->temp_lim[i].max = - lm93_read_byte(client, LM93_REG_TEMP_MAX(i)); - } - - /* config register */ - data->config = lm93_read_byte(client, LM93_REG_CONFIG); - - /* vid1 - vid2: values */ - for (i = 0; i < 2; i++) - data->vid[i] = lm93_read_byte(client, LM93_REG_VID(i)); - - /* prochot1 - prochot2: limits */ - for (i = 0; i < 2; i++) - data->prochot_max[i] = lm93_read_byte(client, - LM93_REG_PROCHOT_MAX(i)); - - /* vccp1 - vccp2: VID relative limits */ - for (i = 0; i < 2; i++) - data->vccp_limits[i] = lm93_read_byte(client, - LM93_REG_VCCP_LIMIT_OFF(i)); - - /* GPIO input state */ - data->gpi = lm93_read_byte(client, LM93_REG_GPI); - - /* #PROCHOT override state */ - data->prochot_override = lm93_read_byte(client, - LM93_REG_PROCHOT_OVERRIDE); - - /* #PROCHOT intervals */ - data->prochot_interval = lm93_read_byte(client, - LM93_REG_PROCHOT_INTERVAL); - - /* Fan Boost Termperature registers */ - for (i = 0; i < 4; i++) - data->boost[i] = lm93_read_byte(client, LM93_REG_BOOST(i)); - - /* Fan Boost Temperature Hyst. registers */ - data->boost_hyst[0] = lm93_read_byte(client, LM93_REG_BOOST_HYST_12); - data->boost_hyst[1] = lm93_read_byte(client, LM93_REG_BOOST_HYST_34); - - /* Temperature Zone Min. PWM & Hysteresis registers */ - data->auto_pwm_min_hyst[0] = - lm93_read_byte(client, LM93_REG_PWM_MIN_HYST_12); - data->auto_pwm_min_hyst[1] = - lm93_read_byte(client, LM93_REG_PWM_MIN_HYST_34); - - /* #PROCHOT & #VRDHOT PWM Ramp Control register */ - data->pwm_ramp_ctl = lm93_read_byte(client, LM93_REG_PWM_RAMP_CTL); - - /* misc setup registers */ - data->sfc1 = lm93_read_byte(client, LM93_REG_SFC1); - data->sfc2 = lm93_read_byte(client, LM93_REG_SFC2); - data->sf_tach_to_pwm = lm93_read_byte(client, - LM93_REG_SF_TACH_TO_PWM); - - /* write back alarm values to clear */ - for (i = 0, ptr = (u8 *)(&data->block1); i < 8; i++) - lm93_write_byte(client, LM93_REG_HOST_ERROR_1 + i, *(ptr + i)); -} - -/* update routine which uses SMBus block data commands */ -static void lm93_update_client_full(struct lm93_data *data, - struct i2c_client *client) -{ - pr_debug("lm93.o: starting device update (block data enabled)\n"); - - /* in1 - in16: values & limits */ - lm93_read_block(client, 3, (u8 *)(data->block3)); - lm93_read_block(client, 7, (u8 *)(data->block7)); - - /* temp1 - temp4: values */ - lm93_read_block(client, 2, (u8 *)(data->block2)); - - /* prochot1 - prochot2: values */ - lm93_read_block(client, 4, (u8 *)(data->block4)); - - /* fan1 - fan4: values & limits */ - lm93_read_block(client, 5, (u8 *)(data->block5)); - lm93_read_block(client, 8, (u8 *)(data->block8)); - - /* pmw control registers */ - lm93_read_block(client, 9, (u8 *)(data->block9)); - - /* alarm values */ - lm93_read_block(client, 1, (u8 *)(&data->block1)); - - /* auto/pwm registers */ - lm93_read_block(client, 10, (u8 *)(&data->block10)); - - lm93_update_client_common(data, client); -} - -/* update routine which uses SMBus byte/word data commands only */ -static void lm93_update_client_min(struct lm93_data *data, - struct i2c_client *client) -{ - int i,j; - u8 *ptr; - - pr_debug("lm93.o: starting device update (block data disabled)\n"); - - /* in1 - in16: values & limits */ - for (i = 0; i < 16; i++) { - data->block3[i] = - lm93_read_byte(client, LM93_REG_IN(i)); - data->block7[i].min = - lm93_read_byte(client, LM93_REG_IN_MIN(i)); - data->block7[i].max = - lm93_read_byte(client, LM93_REG_IN_MAX(i)); - } - - /* temp1 - temp4: values */ - for (i = 0; i < 4; i++) { - data->block2[i] = - lm93_read_byte(client, LM93_REG_TEMP(i)); - } - - /* prochot1 - prochot2: values */ - for (i = 0; i < 2; i++) { - data->block4[i].cur = - lm93_read_byte(client, LM93_REG_PROCHOT_CUR(i)); - data->block4[i].avg = - lm93_read_byte(client, LM93_REG_PROCHOT_AVG(i)); - } - - /* fan1 - fan4: values & limits */ - for (i = 0; i < 4; i++) { - data->block5[i] = - lm93_read_word(client, LM93_REG_FAN(i)); - data->block8[i] = - lm93_read_word(client, LM93_REG_FAN_MIN(i)); - } - - /* pwm control registers */ - for (i = 0; i < 2; i++) { - for (j = 0; j < 4; j++) { - data->block9[i][j] = - lm93_read_byte(client, LM93_REG_PWM_CTL(i,j)); - } - } - - /* alarm values */ - for (i = 0, ptr = (u8 *)(&data->block1); i < 8; i++) { - *(ptr + i) = - lm93_read_byte(client, LM93_REG_HOST_ERROR_1 + i); - } - - /* auto/pwm (base temp) registers */ - for (i = 0; i < 4; i++) { - data->block10.base[i] = - lm93_read_byte(client, LM93_REG_TEMP_BASE(i)); - } - - /* auto/pwm (offset temp) registers */ - for (i = 0; i < 12; i++) { - data->block10.offset[i] = - lm93_read_byte(client, LM93_REG_TEMP_OFFSET(i)); - } - - lm93_update_client_common(data, client); -} - -/* VID: mV - REG: 6-bits, right justified, *always* using Intel VRM/VRD 10 */ -static int LM93_VID_FROM_REG(u8 reg) -{ - return vid_from_reg((reg & 0x3f), 100); -} - -static void lm93_vid(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct lm93_data *data = client->data; - int nr = ctl_name - LM93_SYSCTL_VID1; - - if (0 > nr || nr > 1) - return; /* ERROR */ - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 3; - else if (operation == SENSORS_PROC_REAL_READ) { - lm93_update_client(client); - results[0] = LM93_VID_FROM_REG(data->vid[nr]); - *nrels_mag = 1; - } -} - -/* min, max, and nominal voltage readings, per channel (mV)*/ -static const unsigned long lm93_vin_val_min[16] = { - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 3000, -}; -static const unsigned long lm93_vin_val_max[16] = { - 1236, 1236, 1236, 1600, 2000, 2000, 1600, 1600, - 4400, 6500, 3333, 2625, 1312, 1312, 1236, 3600, -}; -/* -static const unsigned long lm93_vin_val_nom[16] = { - 927, 927, 927, 1200, 1500, 1500, 1200, 1200, - 3300, 5000, 2500, 1969, 984, 984, 309, 3300, -}; -*/ - -/* min, max, and nominal register values, per channel (u8) */ -static const u8 lm93_vin_reg_min[16] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xae, -}; -static const u8 lm93_vin_reg_max[16] = { - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xfa, 0xff, 0xff, 0xff, 0xff, 0xff, 0xd1, -}; -/* -static const u8 lm93_vin_reg_nom[16] = { - 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, - 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0x40, 0xc0, -}; -*/ - -/* IN: 1/100 V, limits determined by channel nr - REG: scaling determined by channel nr */ -static u8 LM93_IN_TO_REG(int nr, unsigned val) -{ - /* range limit */ - const long mV = SENSORS_LIMIT(val * 10, - lm93_vin_val_min[nr], lm93_vin_val_max[nr]); - - /* try not to lose too much precision here */ - const long uV = mV * 1000; - const long uV_max = lm93_vin_val_max[nr] * 1000; - const long uV_min = lm93_vin_val_min[nr] * 1000; - - /* convert */ - const long slope = (uV_max - uV_min) / - (lm93_vin_reg_max[nr] - lm93_vin_reg_min[nr]); - const long intercept = uV_min - slope * lm93_vin_reg_min[nr]; - - u8 result = ((uV - intercept + (slope/2)) / slope); - result = SENSORS_LIMIT(result, - lm93_vin_reg_min[nr], lm93_vin_reg_max[nr]); - return result; -} - -static unsigned LM93_IN_FROM_REG(int nr, u8 reg) -{ - const long uV_max = lm93_vin_val_max[nr] * 1000; - const long uV_min = lm93_vin_val_min[nr] * 1000; - - const long slope = (uV_max - uV_min) / - (lm93_vin_reg_max[nr] - lm93_vin_reg_min[nr]); - const long intercept = uV_min - slope * lm93_vin_reg_min[nr]; - - return (slope * reg + intercept + 5000) / 10000; -} - -/* vid in mV , upper == 0 indicates low limit, otherwise upper limit - upper also determines which nibble of the register is returned - (the other nibble will be 0x0) */ -static u8 LM93_IN_REL_TO_REG(unsigned val, int upper, int vid) -{ - long uV_offset = vid * 1000 - val * 10000; - if (upper) { - uV_offset = SENSORS_LIMIT(uV_offset, 12500, 200000); - return (u8)((uV_offset / 12500 - 1) << 4); - } else { - uV_offset = SENSORS_LIMIT(uV_offset, -400000, -25000); - return (u8)((uV_offset / -25000 - 1) << 0); - } -} - -/* vid in mV, upper == 0 indicates low limit, otherwise upper limit */ -static unsigned LM93_IN_REL_FROM_REG(u8 reg, int upper, int vid) -{ - const long uV_offset = upper ? (((reg >> 4 & 0x0f) + 1) * 12500) : - (((reg >> 0 & 0x0f) + 1) * -25000); - const long uV_vid = vid * 1000; - return (uV_vid + uV_offset + 5000) / 10000; -} - -static void lm93_in(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct lm93_data *data = client->data; - int nr = ctl_name - LM93_SYSCTL_IN1; /* 0 <= nr <= 15 */ - int vccp = ctl_name - LM93_SYSCTL_IN7; /* 0 <= vccp <= 1 if relevant */ - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 2; - else if (operation == SENSORS_PROC_REAL_READ) { - - lm93_update_client(client); - - /* for limits, check in7 and in8 for VID relative mode */ - if ((ctl_name==LM93_SYSCTL_IN7 || ctl_name==LM93_SYSCTL_IN8) && - (vccp_limit_type[vccp])) { - long vid = LM93_VID_FROM_REG(data->vid[vccp]); - results[0] = LM93_IN_REL_FROM_REG( - data->vccp_limits[vccp], 0, vid); - results[1] = LM93_IN_REL_FROM_REG( - data->vccp_limits[vccp], 1, vid); - - /* otherwise, use absolute limits */ - } else { - results[0] = LM93_IN_FROM_REG(nr, - data->block7[nr].min); - results[1] = LM93_IN_FROM_REG(nr, - data->block7[nr].max); - } - - results[2] = LM93_IN_FROM_REG(nr, data->block3[nr]); - *nrels_mag = 3; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - down(&data->update_lock); - - /* for limits, check in7 and in8 for VID relative mode */ - if ((ctl_name==LM93_SYSCTL_IN7 || ctl_name==LM93_SYSCTL_IN8) && - (vccp_limit_type[vccp])) { - - long vid = LM93_VID_FROM_REG(data->vid[vccp]); - if (*nrels_mag >= 2) { - data->vccp_limits[vccp] = - (data->vccp_limits[vccp] & 0x0f) | - LM93_IN_REL_TO_REG(results[1], 1, vid); - } - if (*nrels_mag >= 1) { - data->vccp_limits[vccp] = - (data->vccp_limits[vccp] & 0xf0) | - LM93_IN_REL_TO_REG(results[0], 0, vid); - lm93_write_byte(client, - LM93_REG_VCCP_LIMIT_OFF(vccp), - data->vccp_limits[vccp]); - } - - /* otherwise, use absolute limits */ - } else { - if (*nrels_mag >= 1) { - data->block7[nr].min = LM93_IN_TO_REG(nr, - results[0]); - lm93_write_byte(client, LM93_REG_IN_MIN(nr), - data->block7[nr].min); - } - if (*nrels_mag >= 2) { - data->block7[nr].max = LM93_IN_TO_REG(nr, - results[1]); - lm93_write_byte(client, LM93_REG_IN_MAX(nr), - data->block7[nr].max); - } - } - up(&data->update_lock); - } -} - -static unsigned LM93_ALARMS_FROM_REG(struct block1_t b1) -{ - unsigned result; - result = b1.host_status_2 & 0x3f; - - if (vccp_limit_type[0]) - result |= (b1.host_status_4 & 0x10) << 2; - else - result |= b1.host_status_2 & 0x40; - - if (vccp_limit_type[1]) - result |= (b1.host_status_4 & 0x20) << 2; - else - result |= b1.host_status_2 & 0x80; - - result |= b1.host_status_3 << 8; - result |= (b1.fan_status & 0x0f) << 16; - result |= (b1.p1_prochot_status & 0x80) << 13; - result |= (b1.p2_prochot_status & 0x80) << 14; - result |= (b1.host_status_4 & 0xfc) << 20; - result |= (b1.host_status_1 & 0x07) << 28; - return result; -} - -static void lm93_alarms(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results) -{ - struct lm93_data *data = client->data; - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - lm93_update_client(client); - results[0] = LM93_ALARMS_FROM_REG(data->block1); - *nrels_mag = 1; - } -} - -#define LM93_TEMP_MIN (-1280) -#define LM93_TEMP_MAX ( 1270) - -/* TEMP: 1/10 degrees C (-128C to +127C) - REG: 1C/bit, two's complement */ -static u8 LM93_TEMP_TO_REG(int temp) -{ - int ntemp = SENSORS_LIMIT(temp, LM93_TEMP_MIN, LM93_TEMP_MAX); - ntemp += (ntemp<0 ? -5 : 5); - return (u8)(ntemp / 10); -} - -static int LM93_TEMP_FROM_REG(u8 reg) -{ - return (s8)reg * 10; -} - -static void lm93_temp(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct lm93_data *data = client->data; - int nr = ctl_name - LM93_SYSCTL_TEMP1; - - if (0 > nr || nr > 2) - return; /* ERROR */ - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 1; - else if (operation == SENSORS_PROC_REAL_READ) { - lm93_update_client(client); - results[0] = LM93_TEMP_FROM_REG(data->temp_lim[nr].max); - results[1] = LM93_TEMP_FROM_REG(data->temp_lim[nr].min); - results[2] = LM93_TEMP_FROM_REG(data->block2[nr]); - *nrels_mag = 3; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - down(&data->update_lock); - if (*nrels_mag >= 1) { - data->temp_lim[nr].max = LM93_TEMP_TO_REG(results[0]); - lm93_write_byte(client, LM93_REG_TEMP_MAX(nr), - data->temp_lim[nr].max); - } - if (*nrels_mag >= 2) { - data->temp_lim[nr].min = LM93_TEMP_TO_REG(results[1]); - lm93_write_byte(client, LM93_REG_TEMP_MIN(nr), - data->temp_lim[nr].min); - } - up(&data->update_lock); - } -} - -/* Determine 4-bit temperature offset resolution */ -static int LM93_TEMP_OFFSET_MODE_FROM_REG(u8 sfc2, int nr) -{ - /* mode: 0 => 1C/bit, nonzero => 0.5C/bit */ - return sfc2 & (nr < 2 ? 0x10 : 0x20); -} - -#define LM93_TEMP_OFFSET_MIN ( 0) -#define LM93_TEMP_OFFSET_MAX0 (150) -#define LM93_TEMP_OFFSET_MAX1 ( 75) - -/* This function is common to all 4-bit temperature offsets - returns 4 bits right justified - mode 0 => 1C/bit, mode !0 => 0.5C/bit */ -static u8 LM93_TEMP_OFFSET_TO_REG(int off, int mode) -{ - int factor = mode ? 5 : 10; - - off = SENSORS_LIMIT(off, LM93_TEMP_OFFSET_MIN, - mode ? LM93_TEMP_OFFSET_MAX1 : LM93_TEMP_OFFSET_MAX0); - return (u8)((off + factor/2) / factor); -} - -/* This function is common to all 4-bit temperature offsets - reg is 4 bits right justified - mode 0 => 1C/bit, mode !0 => 0.5C/bit */ -static int LM93_TEMP_OFFSET_FROM_REG(u8 reg, int mode) -{ - return (reg & 0x0f) * (mode ? 5 : 10); -} - -/* TEMP: 1/10 degrees C (0C to +15C (mode 0) or +7.5C (mode non-zero)) - REG: 1.0C/bit (mode 0) or 0.5C/bit (mode non-zero) - 0 <= nr <= 3 */ -static u8 LM93_TEMP_AUTO_OFFSET_TO_REG(u8 old, int off, int nr, int mode) -{ - u8 new = LM93_TEMP_OFFSET_TO_REG(off, mode); - - /* temp1-temp2 (nr=0,1) use lower nibble */ - if (nr < 2) - return (old & 0xf0) | (new & 0x0f); - - /* temp3-temp4 (nr=2,3) use upper nibble */ - else - return (new << 4 & 0xf0) | (old & 0x0f); -} - -/* 0 <= nr <= 3 */ -static int LM93_TEMP_AUTO_OFFSET_FROM_REG(u8 reg, int nr, int mode) -{ - /* temp1-temp2 (nr=0,1) use lower nibble */ - if (nr < 2) - return LM93_TEMP_OFFSET_FROM_REG(reg & 0x0f, mode); - - /* temp3-temp4 (nr=2,3) use upper nibble */ - else - return LM93_TEMP_OFFSET_FROM_REG(reg >> 4 & 0x0f, mode); -} - -static void lm93_temp_auto_offsets(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results) -{ - struct lm93_data *data = client->data; - int nr = ctl_name - LM93_SYSCTL_TEMP1_AUTO_OFFSETS; - int ii; - - if (0 > nr || nr > 2) - return; /* ERROR */ - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 1; - else if (operation == SENSORS_PROC_REAL_READ) { - int mode; - lm93_update_client(client); - - /* mode: 0 => 1C/bit, nonzero => 0.5C/bit */ - mode = LM93_TEMP_OFFSET_MODE_FROM_REG(data->sfc2, nr); - - for (ii = 0; ii < 12; ii++) { - results[ii] = LM93_TEMP_AUTO_OFFSET_FROM_REG( - data->block10.offset[ii], nr, mode); - } - *nrels_mag = 12; - } - else if (operation == SENSORS_PROC_REAL_WRITE) { - /* we only care about the first 12 values */ - int nrels = *nrels_mag > 12 ? 12 : *nrels_mag; - - down(&data->update_lock); - - /* force 0.5C/bit mode */ - data->sfc2 = lm93_read_byte(client, LM93_REG_SFC2); - data->sfc2 |= ((nr < 2) ? 0x10 : 0x20); - lm93_write_byte(client, LM93_REG_SFC2, data->sfc2); - - for (ii = 0; ii < nrels; ii++) { - data->block10.offset[ii] = LM93_TEMP_AUTO_OFFSET_TO_REG( - data->block10.offset[ii], results[ii], nr, 1); - lm93_write_byte(client, LM93_REG_TEMP_OFFSET(ii), - data->block10.offset[ii]); - } - up(&data->update_lock); - } -} - -/* RPM: (82.5 to 1350000) - REG: 14-bits, LE, *left* justified */ -static u16 LM93_FAN_TO_REG(long rpm) -{ - u16 count, regs; - - if (rpm == 0) { - count = 0x3fff; - } else { - rpm = SENSORS_LIMIT(rpm, 1, 1000000); - count = SENSORS_LIMIT((1350000 + rpm) / rpm, 1, 0x3ffe); - } - - regs = count << 2; - return cpu_to_le16(regs); -} - -static int LM93_FAN_FROM_REG(u16 regs) -{ - const u16 count = le16_to_cpu(regs) >> 2; - return count==0 ? -1 : count==0x3fff ? 0: 1350000 / count; -} - -static void lm93_fan(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct lm93_data *data = client->data; - int nr = ctl_name - LM93_SYSCTL_FAN1; - - if (0 > nr || nr > 3) - return; /* ERROR */ - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - lm93_update_client(client); - results[0] = LM93_FAN_FROM_REG(data->block8[nr]); /* min */ - results[1] = LM93_FAN_FROM_REG(data->block5[nr]); /* val */ - *nrels_mag = 2; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag >= 1) { - down(&data->update_lock); - data->block8[nr] = LM93_FAN_TO_REG(results[0]); - lm93_write_word(client, LM93_REG_FAN_MIN(nr), - data->block8[nr]); - up(&data->update_lock); - } - } -} - -/* PROCHOT: 0-255, 0 => 0%, 255 => > 96.6% - * REG: (same) */ -static u8 LM93_PROCHOT_TO_REG(long prochot) -{ - prochot = SENSORS_LIMIT(prochot, 0, 255); - return (u8)prochot; -} - -static void lm93_prochot(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results) -{ - struct lm93_data *data = client->data; - int nr = ctl_name - LM93_SYSCTL_PROCHOT1; - - if (0 > nr || nr > 1) - return; /* ERROR */ - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - lm93_update_client(client); - results[0] = data->prochot_max[nr]; - results[1] = data->block4[nr].cur; - results[2] = data->block4[nr].avg; - *nrels_mag = 3; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - down(&data->update_lock); - if (*nrels_mag >= 1) { - data->prochot_max[nr] = LM93_PROCHOT_TO_REG(results[0]); - lm93_write_byte(client, LM93_REG_PROCHOT_MAX(nr), - data->prochot_max[nr]); - } - up(&data->update_lock); - } -} - -/* PROCHOT-OVERRIDE; 0-15, 0 is 6.25%, 15 is 99.88% - * REG: (same) */ -static u8 LM93_PROCHOT_OVERRIDE_TO_REG(int force1, int force2, long prochot) -{ - u8 result = 0; - - result |= force1 ? 0x80 : 0x00; - result |= force2 ? 0x40 : 0x00; - prochot = SENSORS_LIMIT(prochot, 0, 15); - result |= prochot; - return result; -} - -static void lm93_prochot_override(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results) -{ - struct lm93_data *data = client->data; - - if (ctl_name != LM93_SYSCTL_PROCHOT_OVERRIDE) - return; /* ERROR */ - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - lm93_update_client(client); - results[0] = (data->prochot_override & 0x80) ? 1 : 0; - results[1] = (data->prochot_override & 0x40) ? 1 : 0; - results[2] = data->prochot_override & 0x0f; - *nrels_mag = 3; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - - /* grab old values */ - int force2 = (data->prochot_override & 0x40) ? 1 : 0; - int prochot = data->prochot_override & 0x0f; - - down(&data->update_lock); - if (*nrels_mag >= 3) { - data->prochot_override = LM93_PROCHOT_OVERRIDE_TO_REG( - results[0], results[1], results[2]); - } - if (*nrels_mag == 2) { - data->prochot_override = LM93_PROCHOT_OVERRIDE_TO_REG( - results[0], results[1], prochot); - } - if (*nrels_mag == 1) { - data->prochot_override = LM93_PROCHOT_OVERRIDE_TO_REG( - results[0], force2, prochot); - } - if (*nrels_mag >= 1) { - lm93_write_byte(client, LM93_REG_PROCHOT_OVERRIDE, - data->prochot_override); - } - up(&data->update_lock); - } -} - -/* PROCHOT-INTERVAL: 73 - 37200 (1/100 seconds) - * REG: 0-9 as mapped below */ -static int lm93_interval_map[10] = { - 73, 146, 290, 580, 1170, 2330, 4660, 9320, 18600, 37200, -}; - -static int LM93_INTERVAL_FROM_REG(u8 reg) -{ - return lm93_interval_map[reg & 0x0f]; -} - -/* round up to nearest match */ -static u8 LM93_INTERVAL_TO_REG(long interval) -{ - int i; - for (i = 0; i < 9; i++) - if (interval <= lm93_interval_map[i]) - break; - - /* can fall through with i==9 */ - return (u8)i; -} - -static void lm93_prochot_interval(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results) -{ - struct lm93_data *data = client->data; - - if (ctl_name != LM93_SYSCTL_PROCHOT_INTERVAL) - return; /* ERROR */ - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 2; - else if (operation == SENSORS_PROC_REAL_READ) { - lm93_update_client(client); - results[0] = LM93_INTERVAL_FROM_REG( - data->prochot_interval & 0x0f); - results[1] = LM93_INTERVAL_FROM_REG( - (data->prochot_interval & 0xf0) >> 4); - *nrels_mag = 2; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - down(&data->update_lock); - data->prochot_interval = lm93_read_byte(client, - LM93_REG_PROCHOT_INTERVAL); - if (*nrels_mag >= 2) { - data->prochot_interval = - (LM93_INTERVAL_TO_REG(results[1]) << 4) | - (data->prochot_interval & 0x0f); - } - if (*nrels_mag >= 1) { - data->prochot_interval = - (data->prochot_interval & 0xf0) | - LM93_INTERVAL_TO_REG(results[0]); - lm93_write_byte(client, LM93_REG_PROCHOT_INTERVAL, - data->prochot_interval); - } - up(&data->update_lock); - } -} - -/* PWM: 0-255 per sensors documentation - REG: 0-13 as mapped below... right justified */ -typedef enum { LM93_PWM_MAP_HI_FREQ, LM93_PWM_MAP_LO_FREQ } pwm_freq_t; -static int lm93_pwm_map[2][14] = { - { - 0x00, /* 0.00% */ 0x40, /* 25.00% */ - 0x50, /* 31.25% */ 0x60, /* 37.50% */ - 0x70, /* 43.75% */ 0x80, /* 50.00% */ - 0x90, /* 56.25% */ 0xa0, /* 62.50% */ - 0xb0, /* 68.75% */ 0xc0, /* 75.00% */ - 0xd0, /* 81.25% */ 0xe0, /* 87.50% */ - 0xf0, /* 93.75% */ 0xff, /* 100.00% */ - }, - { - 0x00, /* 0.00% */ 0x40, /* 25.00% */ - 0x49, /* 28.57% */ 0x52, /* 32.14% */ - 0x5b, /* 35.71% */ 0x64, /* 39.29% */ - 0x6d, /* 42.86% */ 0x76, /* 46.43% */ - 0x80, /* 50.00% */ 0x89, /* 53.57% */ - 0x92, /* 57.14% */ 0xb6, /* 71.43% */ - 0xdb, /* 85.71% */ 0xff, /* 100.00% */ - }, -}; - -static int LM93_PWM_FROM_REG(u8 reg, pwm_freq_t freq) -{ - return lm93_pwm_map[freq][reg & 0x0f]; -} - -/* round up to nearest match */ -static u8 LM93_PWM_TO_REG(int pwm, pwm_freq_t freq) -{ - int i; - for (i = 0; i < 13; i++) - if (pwm <= lm93_pwm_map[freq][i]) - break; - - /* can fall through with i==13 */ - return (u8)i; -} - -static void lm93_pwm(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct lm93_data *data = client->data; - int nr = ctl_name - LM93_SYSCTL_PWM1; - u8 ctl2, ctl4; - - if (0 > nr || nr > 1) - return; /* ERROR */ - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - lm93_update_client(client); - ctl2 = data->block9[nr][LM93_PWM_CTL2]; - ctl4 = data->block9[nr][LM93_PWM_CTL4]; - results[1] = (ctl2 & 0x01) ? 1 : 0; - ctl2 = ctl2 >> 4 & 0x0f; - if (results[1]) /* show user commanded value if enabled */ - results[0] = data->pwm_override[nr]; - else /* show present h/w value if manual pwm disabled */ - results[0] = LM93_PWM_FROM_REG(ctl2, (ctl4 & 0x07) ? - LM93_PWM_MAP_LO_FREQ : LM93_PWM_MAP_HI_FREQ); - *nrels_mag = 2; - } - else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag >= 1) { - down(&data->update_lock); - ctl2 = lm93_read_byte( - client, LM93_REG_PWM_CTL(nr,LM93_PWM_CTL2)); - ctl4 = lm93_read_byte( - client, LM93_REG_PWM_CTL(nr,LM93_PWM_CTL4)); - ctl2 = (ctl2 & 0x0f) | - LM93_PWM_TO_REG(results[0], (ctl4 & 0x07) ? - LM93_PWM_MAP_LO_FREQ : - LM93_PWM_MAP_HI_FREQ) << 4; - if (*nrels_mag >= 2) { - if (results[1]) - ctl2 |= 0x01; - else - ctl2 &= ~0x01; - } - /* save user commanded value */ - data->pwm_override[nr] = - LM93_PWM_FROM_REG(ctl2 >> 4 & 0x0f, - (ctl4 & 0x07) ? LM93_PWM_MAP_LO_FREQ : - LM93_PWM_MAP_HI_FREQ); - lm93_write_byte(client, - LM93_REG_PWM_CTL(nr,LM93_PWM_CTL2), ctl2); - up(&data->update_lock); - } - } -} - -/* PWM FREQ: HZ - REG: 0-7 as mapped below */ -static int lm93_pwm_freq_map[8] = { - 22500, 96, 84, 72, 60, 48, 36, 12 -}; - -static int LM93_PWM_FREQ_FROM_REG(u8 reg) -{ - return lm93_pwm_freq_map[reg & 0x07]; -} - -/* round up to nearest match */ -static u8 LM93_PWM_FREQ_TO_REG(int freq) -{ - int i; - for (i = 7; i > 0; i--) - if (freq <= lm93_pwm_freq_map[i]) - break; - - /* can fall through with i==0 */ - return (u8)i; -} - -/* helper function - must grab data->update_lock before calling - fan is 0-3, indicating fan1-fan4 */ -static void lm93_write_fan_smart_tach(struct i2c_client *client, - struct lm93_data *data, int fan, long value) -{ - /* insert the new mapping and write it out */ - data->sf_tach_to_pwm = lm93_read_byte(client, LM93_REG_SF_TACH_TO_PWM); - data->sf_tach_to_pwm &= ~(0x3 << fan * 2); - data->sf_tach_to_pwm |= value << fan * 2; - lm93_write_byte(client, LM93_REG_SF_TACH_TO_PWM, data->sf_tach_to_pwm); - - /* insert the enable bit and write it out */ - data->sfc2 = lm93_read_byte(client, LM93_REG_SFC2); - if (value) - data->sfc2 |= 1 << fan; - else - data->sfc2 &= ~(1 << fan); - lm93_write_byte(client, LM93_REG_SFC2, data->sfc2); -} - -/* helper function - must grab data->update_lock before calling - pwm is 0-1, indicating pwm1-pwm2 - this disables smart tach for all tach channels bound to the given pwm */ -static void lm93_disable_fan_smart_tach(struct i2c_client *client, - struct lm93_data *data, int pwm) -{ - int mapping = lm93_read_byte(client, LM93_REG_SF_TACH_TO_PWM); - int mask; - - /* collapse the mapping into a mask of enable bits */ - mapping = (mapping >> pwm) & 0x55; - mask = mapping & 0x01; - mask |= (mapping & 0x04) >> 1; - mask |= (mapping & 0x10) >> 2; - mask |= (mapping & 0x40) >> 3; - - /* disable smart tach according to the mask */ - data->sfc2 = lm93_read_byte(client, LM93_REG_SFC2); - data->sfc2 &= ~mask; - lm93_write_byte(client, LM93_REG_SFC2, data->sfc2); -} - -static void lm93_pwm_freq(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results) -{ - struct lm93_data *data = client->data; - int nr = ctl_name - LM93_SYSCTL_PWM1_FREQ; - u8 ctl4; - - if (0 > nr || nr > 1) - return; /* ERROR */ - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - lm93_update_client(client); - ctl4 = data->block9[nr][LM93_PWM_CTL4]; - results[0] = LM93_PWM_FREQ_FROM_REG(ctl4); - *nrels_mag = 1; - } - else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag >= 1) { - down(&data->update_lock); - ctl4 = lm93_read_byte( client, - LM93_REG_PWM_CTL(nr,LM93_PWM_CTL4)); - ctl4 = (ctl4 & 0xf8) | LM93_PWM_FREQ_TO_REG(results[0]); - data->block9[nr][LM93_PWM_CTL4] = ctl4; - - /* ctl4 == 0 -> 22.5KHz -> disable smart tach */ - if (!ctl4) - lm93_disable_fan_smart_tach(client, data, nr); - - lm93_write_byte(client, - LM93_REG_PWM_CTL(nr,LM93_PWM_CTL4), ctl4); - up(&data->update_lock); - } - } -} - -/* GPIO: 0-255, GPIO0 is LSB - * REG: inverted */ -static unsigned LM93_GPI_FROM_REG(u8 reg) -{ - return ~reg & 0xff; -} - -static void lm93_gpio(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct lm93_data *data = client->data; - - if (ctl_name != LM93_SYSCTL_GPIO) - return; /* ERROR */ - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - lm93_update_client(client); - results[0] = LM93_GPI_FROM_REG(data->gpi); - *nrels_mag = 1; - } -} - -static void lm93_temp_auto_base(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results) -{ - struct lm93_data *data = client->data; - int nr = ctl_name - LM93_SYSCTL_TEMP1_AUTO_BASE; - - if (0 > nr || nr > 2) - return; /* ERROR */ - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 1; - else if (operation == SENSORS_PROC_REAL_READ) { - lm93_update_client(client); - results[0] = LM93_TEMP_FROM_REG(data->block10.base[nr]); - *nrels_mag = 1; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - down(&data->update_lock); - if (*nrels_mag >= 1) { - data->block10.base[nr] = LM93_TEMP_TO_REG(results[0]); - lm93_write_byte(client, LM93_REG_TEMP_BASE(nr), - data->block10.base[nr]); - } - up(&data->update_lock); - } -} - -static void lm93_temp_auto_boost(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results) -{ - struct lm93_data *data = client->data; - int nr = ctl_name - LM93_SYSCTL_TEMP1_AUTO_BOOST; - - if (0 > nr || nr > 2) - return; /* ERROR */ - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 1; - else if (operation == SENSORS_PROC_REAL_READ) { - lm93_update_client(client); - results[0] = LM93_TEMP_FROM_REG(data->boost[nr]); - *nrels_mag = 1; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - down(&data->update_lock); - if (*nrels_mag >= 1) { - data->boost[nr] = LM93_TEMP_TO_REG(results[0]); - lm93_write_byte(client, LM93_REG_BOOST(nr), - data->boost[nr]); - } - up(&data->update_lock); - } - -} - -static u8 LM93_AUTO_BOOST_HYST_TO_REG(struct lm93_data *data, long hyst, - int nr, int mode) -{ - u8 reg = LM93_TEMP_OFFSET_TO_REG( - (LM93_TEMP_FROM_REG(data->boost[nr]) - hyst), mode); - - switch (nr) { - case 0: - reg = (data->boost_hyst[0] & 0xf0) | (reg & 0x0f); - break; - case 1: - reg = (reg << 4 & 0xf0) | (data->boost_hyst[0] & 0x0f); - break; - case 2: - reg = (data->boost_hyst[1] & 0xf0) | (reg & 0x0f); - break; - case 3: - default: - reg = (reg << 4 & 0xf0) | (data->boost_hyst[1] & 0x0f); - break; - } - - return reg; -} - -static int LM93_AUTO_BOOST_HYST_FROM_REGS(struct lm93_data *data, int nr, - int mode) -{ - u8 reg; - - switch (nr) { - case 0: - reg = data->boost_hyst[0] & 0x0f; - break; - case 1: - reg = data->boost_hyst[0] >> 4 & 0x0f; - break; - case 2: - reg = data->boost_hyst[1] & 0x0f; - break; - case 3: - default: - reg = data->boost_hyst[1] >> 4 & 0x0f; - break; - } - - return LM93_TEMP_FROM_REG(data->boost[nr]) - - LM93_TEMP_OFFSET_FROM_REG(reg, mode); -} - -static void lm93_temp_auto_boost_hyst(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results) -{ - struct lm93_data *data = client->data; - int nr = ctl_name - LM93_SYSCTL_TEMP1_AUTO_BOOST_HYST; - - if (0 > nr || nr > 2) - return; /* ERROR */ - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 1; - else if (operation == SENSORS_PROC_REAL_READ) { - int mode; - lm93_update_client(client); - - /* mode: 0 => 1C/bit, nonzero => 0.5C/bit */ - mode = LM93_TEMP_OFFSET_MODE_FROM_REG(data->sfc2, nr); - - results[0] = LM93_AUTO_BOOST_HYST_FROM_REGS(data, nr, mode); - *nrels_mag = 1; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag >= 1) { - down(&data->update_lock); - - /* force 0.5C/bit mode */ - data->sfc2 = lm93_read_byte(client, LM93_REG_SFC2); - data->sfc2 |= ((nr < 2) ? 0x10 : 0x20); - lm93_write_byte(client, LM93_REG_SFC2, data->sfc2); - - data->boost_hyst[nr/2] = - LM93_AUTO_BOOST_HYST_TO_REG(data, - results[0], nr, 1); - lm93_write_byte(client, LM93_REG_BOOST_HYST(nr), - data->boost_hyst[nr/2]); - up(&data->update_lock); - } - } -} - -static void lm93_temp_auto_pwm_min(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results) -{ - struct lm93_data *data = client->data; - int nr = ctl_name - LM93_SYSCTL_TEMP1_AUTO_PWM_MIN; - u8 reg, ctl4; - - if (0 > nr || nr > 2) - return; /* ERROR */ - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - lm93_update_client(client); - reg = data->auto_pwm_min_hyst[nr/2] >> 4 & 0x0f; - ctl4 = data->block9[nr][LM93_PWM_CTL4]; - results[0] = LM93_PWM_FROM_REG(reg, (ctl4 & 0x07) ? - LM93_PWM_MAP_LO_FREQ : LM93_PWM_MAP_HI_FREQ); - *nrels_mag = 1; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag >= 1) { - down(&data->update_lock); - reg = lm93_read_byte(client, LM93_REG_PWM_MIN_HYST(nr)); - ctl4 = lm93_read_byte( - client, LM93_REG_PWM_CTL(nr,LM93_PWM_CTL4)); - reg = (reg & 0x0f) | - LM93_PWM_TO_REG(results[0], (ctl4 & 0x07) ? - LM93_PWM_MAP_LO_FREQ : - LM93_PWM_MAP_HI_FREQ) << 4; - - data->auto_pwm_min_hyst[nr/2] = reg; - lm93_write_byte(client, LM93_REG_PWM_MIN_HYST(nr), reg); - up(&data->update_lock); - } - } -} - -static void lm93_temp_auto_offset_hyst(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results) -{ - struct lm93_data *data = client->data; - int nr = ctl_name - LM93_SYSCTL_TEMP1_AUTO_OFFSET_HYST; - - if (0 > nr || nr > 2) - return; /* ERROR */ - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 1; - else if (operation == SENSORS_PROC_REAL_READ) { - int mode; - lm93_update_client(client); - - /* mode: 0 => 1C/bit, nonzero => 0.5C/bit */ - mode = LM93_TEMP_OFFSET_MODE_FROM_REG(data->sfc2, nr); - - results[0] = LM93_TEMP_OFFSET_FROM_REG( - data->auto_pwm_min_hyst[nr/2], mode); - - *nrels_mag = 1; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag >= 1) { - u8 reg; - down(&data->update_lock); - - /* force 0.5C/bit mode */ - data->sfc2 = lm93_read_byte(client, LM93_REG_SFC2); - data->sfc2 |= ((nr < 2) ? 0x10 : 0x20); - lm93_write_byte(client, LM93_REG_SFC2, data->sfc2); - - reg = data->auto_pwm_min_hyst[nr/2]; - reg = (reg & 0xf0) | - (LM93_TEMP_OFFSET_TO_REG(results[0], 1) & 0x0f); - - data->auto_pwm_min_hyst[nr/2] = reg; - lm93_write_byte(client, LM93_REG_PWM_MIN_HYST(nr), reg); - up(&data->update_lock); - } - } -} - -/* some tedious bit-twiddling here to deal with the register format: - - data->sf_tach_to_pwm: (tach to pwm mapping bits) - - bit | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 - T4:P2 T4:P1 T3:P2 T3:P1 T2:P2 T2:P1 T1:P2 T1:P1 - - data->sfc2: (enable bits) - - bit | 3 | 2 | 1 | 0 - T4 T3 T2 T1 -*/ - -static void lm93_fan_smart_tach(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results) -{ - struct lm93_data *data = client->data; - int nr = ctl_name - LM93_SYSCTL_FAN1_SMART_TACH; - - if (0 > nr || nr > 3) - return; /* ERROR */ - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - int mapping; - - lm93_update_client(client); - - /* extract the relevant mapping */ - mapping = (data->sf_tach_to_pwm >> (nr * 2)) & 0x03; - - /* if there's a mapping and it's enabled */ - if (mapping && ((data->sfc2 >> nr) & 0x01)) - results[0] = mapping; - else - results[0] = 0; - - *nrels_mag = 1; - - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag >= 1) { - down(&data->update_lock); - - /* sanity test, ignore the write otherwise */ - if (0 <= results[0] && results[0] <= 2) { - - /* can't enable if pwm freq is 22.5KHz */ - if (results[0]) { - u8 ctl4 = lm93_read_byte(client, - LM93_REG_PWM_CTL(results[0]-1, - LM93_PWM_CTL4)); - if ((ctl4 & 0x07) == 0) - results[0] = 0; - } - - lm93_write_fan_smart_tach(client, data, nr, - results[0]); - } - up(&data->update_lock); - } - } -} - -static void lm93_prochot_short(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results) -{ - struct lm93_data *data = client->data; - - if (ctl_name != LM93_SYSCTL_PROCHOT_SHORT) - return; /* ERROR */ - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - lm93_update_client(client); - results[0] = (data->config & 0x10) ? 1 : 0; - *nrels_mag = 1; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - down(&data->update_lock); - if (*nrels_mag >= 1) { - if (results[0]) - data->config |= 0x10; - else - data->config &= ~0x10; - lm93_write_byte(client, LM93_REG_CONFIG, data->config); - } - up(&data->update_lock); - } -} - -static void lm93_vrdhot(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results) -{ - struct lm93_data *data = client->data; - int nr = ctl_name - LM93_SYSCTL_VRDHOT1; - - if (0 > nr || nr > 1) - return; /* ERROR */ - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - lm93_update_client(client); - results[0] = data->block1.host_status_1 & (1 << (nr+4)) ? 1 : 0; - *nrels_mag = 1; - } -} - -static void lm93_pwm_auto_chan(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results) -{ - struct lm93_data *data = client->data; - int nr = ctl_name - LM93_SYSCTL_PWM1_AUTO_CHANNELS; - - if (0 > nr || nr > 1) - return; /* ERROR */ - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - lm93_update_client(client); - results[0] = data->block9[nr][LM93_PWM_CTL1]; - *nrels_mag = 1; - } - else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag >= 1) { - down(&data->update_lock); - data->block9[nr][LM93_PWM_CTL1] = - SENSORS_LIMIT(results[0], 0, 255); - lm93_write_byte(client, - LM93_REG_PWM_CTL(nr,LM93_PWM_CTL1), - data->block9[nr][LM93_PWM_CTL1]); - up(&data->update_lock); - } - } -} - -static void lm93_pwm_auto_spinup_min(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results) -{ - struct lm93_data *data = client->data; - int nr = ctl_name - LM93_SYSCTL_PWM1_AUTO_SPINUP_MIN; - u8 ctl3, ctl4; - - if (0 > nr || nr > 1) - return; /* ERROR */ - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - lm93_update_client(client); - ctl3 = data->block9[nr][LM93_PWM_CTL3]; - ctl4 = data->block9[nr][LM93_PWM_CTL4]; - results[0] = LM93_PWM_FROM_REG(ctl3 & 0x0f, (ctl4 & 0x07) ? - LM93_PWM_MAP_LO_FREQ : LM93_PWM_MAP_HI_FREQ); - *nrels_mag = 1; - } - else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag >= 1) { - down(&data->update_lock); - ctl3 = lm93_read_byte(client, - LM93_REG_PWM_CTL(nr, LM93_PWM_CTL3)); - ctl4 = lm93_read_byte(client, - LM93_REG_PWM_CTL(nr, LM93_PWM_CTL4)); - ctl3 = (ctl3 & 0xf0) | - LM93_PWM_TO_REG(results[0], (ctl4 & 0x07) ? - LM93_PWM_MAP_LO_FREQ : - LM93_PWM_MAP_HI_FREQ); - data->block9[nr][LM93_PWM_CTL3] = ctl3; - lm93_write_byte(client, - LM93_REG_PWM_CTL(nr, LM93_PWM_CTL3), ctl3); - up(&data->update_lock); - } - } -} - -/* TIME: 1/100 seconds - * REG: 0-7 as mapped below */ -static int lm93_spinup_time_map[8] = { - 0, 10, 25, 40, 70, 100, 200, 400, -}; - -static int LM93_SPINUP_TIME_FROM_REG(u8 reg) -{ - return lm93_spinup_time_map[reg >> 5 & 0x07]; -} - -/* round up to nearest match */ -static u8 LM93_SPINUP_TIME_TO_REG(int time) -{ - int i; - for (i = 0; i < 7; i++) - if (time <= lm93_spinup_time_map[i]) - break; - - /* can fall through with i==8 */ - return (u8)i; -} - -static void lm93_pwm_auto_spinup_time(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results) -{ - struct lm93_data *data = client->data; - int nr = ctl_name - LM93_SYSCTL_PWM1_AUTO_SPINUP_TIME; - - if (0 > nr || nr > 1) - return; /* ERROR */ - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 2; - else if (operation == SENSORS_PROC_REAL_READ) { - lm93_update_client(client); - results[0] = LM93_SPINUP_TIME_FROM_REG( - data->block9[nr][LM93_PWM_CTL3]); - *nrels_mag = 1; - } - else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag >= 1) { - u8 ctl3; - down(&data->update_lock); - ctl3 = lm93_read_byte(client, - LM93_REG_PWM_CTL(nr, LM93_PWM_CTL3)); - ctl3 = (ctl3 & 0x1f) | (LM93_SPINUP_TIME_TO_REG( - results[0]) << 5 & 0xe0); - data->block9[nr][LM93_PWM_CTL3] = ctl3; - lm93_write_byte(client, - LM93_REG_PWM_CTL(nr, LM93_PWM_CTL3), ctl3); - up(&data->update_lock); - } - } -} - -#define LM93_RAMP_MIN 0 -#define LM93_RAMP_MAX 75 - -/* RAMP: 1/100 seconds - REG: 50mS/bit 4-bits right justified */ -static u8 LM93_RAMP_TO_REG(int ramp) -{ - ramp = SENSORS_LIMIT(ramp, LM93_RAMP_MIN, LM93_RAMP_MAX); - return (u8)((ramp + 2) / 5); -} - -static int LM93_RAMP_FROM_REG(u8 reg) -{ - return (reg & 0x0f) * 5; -} - -static void lm93_pwm_auto_ramp(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results) -{ - struct lm93_data *data = client->data; - - if (!(ctl_name == LM93_SYSCTL_PWM_AUTO_PROCHOT_RAMP || - ctl_name == LM93_SYSCTL_PWM_AUTO_VRDHOT_RAMP)) - return; /* ERROR */ - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 2; - else if (operation == SENSORS_PROC_REAL_READ) { - lm93_update_client(client); - if (ctl_name == LM93_SYSCTL_PWM_AUTO_PROCHOT_RAMP) - results[0] = LM93_RAMP_FROM_REG( - data->pwm_ramp_ctl >> 4 & 0x0f); - else - results[0] = LM93_RAMP_FROM_REG( - data->pwm_ramp_ctl & 0x0f); - *nrels_mag = 1; - } - else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag >= 1) { - u8 ramp; - down(&data->update_lock); - ramp = lm93_read_byte(client, LM93_REG_PWM_RAMP_CTL); - if (ctl_name == LM93_SYSCTL_PWM_AUTO_PROCHOT_RAMP) - ramp = (ramp & 0x0f) | (LM93_RAMP_TO_REG( - results[0]) << 4 & 0xf0); - else - ramp = (ramp & 0xf0) | (LM93_RAMP_TO_REG( - results[0]) & 0x0f); - lm93_write_byte(client, LM93_REG_PWM_RAMP_CTL, ramp); - up(&data->update_lock); - } - } -} - -/* These files are created for each detected LM93. This is just a template; - though at first sight, you might think we could use a statically - allocated list, we need some way to get back to the parent - which - is done through one of the 'extra' fields which are initialized - when a new copy is allocated. */ - -#define LM93_SYSCTL_IN(nr) {LM93_SYSCTL_IN##nr, "in" #nr, NULL, 0, \ - 0644, NULL, &i2c_proc_real, &i2c_sysctl_real, NULL, &lm93_in} -#define LM93_SYSCTL_TEMP(nr) {LM93_SYSCTL_TEMP##nr, "temp" #nr, NULL, 0, \ - 0644, NULL, &i2c_proc_real, &i2c_sysctl_real, NULL, &lm93_temp} -#define LM93_SYSCTL_TEMP_AUTO_BASE(nr) {LM93_SYSCTL_TEMP##nr##_AUTO_BASE, \ - "temp" #nr "_auto_base", NULL, 0, 0644, NULL, &i2c_proc_real, \ - &i2c_sysctl_real, NULL, &lm93_temp_auto_base} -#define LM93_SYSCTL_TEMP_AUTO_OFFSETS(nr) {LM93_SYSCTL_TEMP##nr##_AUTO_OFFSETS,\ - "temp" #nr "_auto_offsets", NULL, 0, 0644, NULL, &i2c_proc_real, \ - &i2c_sysctl_real, NULL, &lm93_temp_auto_offsets} -#define LM93_SYSCTL_TEMP_AUTO_BOOST(nr) { LM93_SYSCTL_TEMP##nr##_AUTO_BOOST, \ - "temp" #nr "_auto_boost", NULL, 0, 0644, NULL, &i2c_proc_real, \ - &i2c_sysctl_real, NULL, &lm93_temp_auto_boost} -#define LM93_SYSCTL_TEMP_AUTO_BOOST_HYST(nr) { \ - LM93_SYSCTL_TEMP##nr##_AUTO_BOOST_HYST, "temp" #nr "_auto_boost_hyst", \ - NULL, 0, 0644, NULL, &i2c_proc_real, &i2c_sysctl_real, NULL, \ - &lm93_temp_auto_boost_hyst} -#define LM93_SYSCTL_TEMP_AUTO_PWM_MIN(nr) { \ - LM93_SYSCTL_TEMP##nr##_AUTO_PWM_MIN, "temp" #nr "_auto_pwm_min", \ - NULL, 0, 0644, NULL, &i2c_proc_real, &i2c_sysctl_real, NULL, \ - &lm93_temp_auto_pwm_min} -#define LM93_SYSCTL_TEMP_AUTO_OFFSET_HYST(nr) { \ - LM93_SYSCTL_TEMP##nr##_AUTO_OFFSET_HYST,"temp" #nr "_auto_offset_hyst",\ - NULL, 0, 0644, NULL, &i2c_proc_real, &i2c_sysctl_real, NULL, \ - &lm93_temp_auto_offset_hyst} -#define LM93_SYSCTL_PWM(nr) {LM93_SYSCTL_PWM##nr, "pwm" #nr, NULL, 0, \ - 0644, NULL, &i2c_proc_real, &i2c_sysctl_real, NULL, &lm93_pwm} -#define LM93_SYSCTL_PWM_FREQ(nr) {LM93_SYSCTL_PWM##nr##_FREQ, \ - "pwm" #nr "_freq", NULL, 0, 0644, NULL, &i2c_proc_real, \ - &i2c_sysctl_real, NULL, &lm93_pwm_freq} -#define LM93_SYSCTL_PWM_AUTO_CHAN(nr) {LM93_SYSCTL_PWM##nr##_AUTO_CHANNELS, \ - "pwm" #nr "_auto_channels", NULL, 0, 0644, NULL, &i2c_proc_real, \ - &i2c_sysctl_real, NULL, &lm93_pwm_auto_chan} -#define LM93_SYSCTL_PWM_AUTO_SPINUP_MIN(nr) { \ - LM93_SYSCTL_PWM##nr##_AUTO_SPINUP_MIN, "pwm" #nr "_auto_spinup_min", \ - NULL, 0, 0644, NULL, &i2c_proc_real, &i2c_sysctl_real, NULL, \ - &lm93_pwm_auto_spinup_min} -#define LM93_SYSCTL_PWM_AUTO_SPINUP_TIME(nr) { \ - LM93_SYSCTL_PWM##nr##_AUTO_SPINUP_TIME, "pwm" #nr "_auto_spinup_time", \ - NULL, 0, 0644, NULL, &i2c_proc_real, &i2c_sysctl_real, NULL, \ - &lm93_pwm_auto_spinup_time} -#define LM93_SYSCTL_FAN(nr) {LM93_SYSCTL_FAN##nr, "fan" #nr, NULL, 0, \ - 0644, NULL, &i2c_proc_real, &i2c_sysctl_real, NULL, &lm93_fan} -#define LM93_SYSCTL_VID(nr) {LM93_SYSCTL_VID##nr, "vid" #nr, NULL, 0, \ - 0444, NULL, &i2c_proc_real, &i2c_sysctl_real, NULL, &lm93_vid} -#define LM93_SYSCTL_PROCHOT(nr) {LM93_SYSCTL_PROCHOT##nr, "prochot" #nr, NULL, \ - 0, 0644, NULL, &i2c_proc_real, &i2c_sysctl_real, NULL, &lm93_prochot} -#define LM93_SYSCTL_VRDHOT(nr) {LM93_SYSCTL_VRDHOT##nr, "vrdhot" #nr, NULL, \ - 0, 0444, NULL, &i2c_proc_real, &i2c_sysctl_real, NULL, &lm93_vrdhot} -#define LM93_SYSCTL_FAN_SMART_TACH(nr) {LM93_SYSCTL_FAN##nr##_SMART_TACH, \ - "fan" #nr "_smart_tach", NULL, 0, 0644, NULL, &i2c_proc_real, \ - &i2c_sysctl_real, NULL, &lm93_fan_smart_tach} -static ctl_table lm93_dir_table_template[] = { - LM93_SYSCTL_IN(1), - LM93_SYSCTL_IN(2), - LM93_SYSCTL_IN(3), - LM93_SYSCTL_IN(4), - LM93_SYSCTL_IN(5), - LM93_SYSCTL_IN(6), - LM93_SYSCTL_IN(7), - LM93_SYSCTL_IN(8), - LM93_SYSCTL_IN(9), - LM93_SYSCTL_IN(10), - LM93_SYSCTL_IN(11), - LM93_SYSCTL_IN(12), - LM93_SYSCTL_IN(13), - LM93_SYSCTL_IN(14), - LM93_SYSCTL_IN(15), - LM93_SYSCTL_IN(16), - - LM93_SYSCTL_TEMP(1), - LM93_SYSCTL_TEMP(2), - LM93_SYSCTL_TEMP(3), - - LM93_SYSCTL_TEMP_AUTO_BASE(1), - LM93_SYSCTL_TEMP_AUTO_BASE(2), - LM93_SYSCTL_TEMP_AUTO_BASE(3), - - LM93_SYSCTL_TEMP_AUTO_OFFSETS(1), - LM93_SYSCTL_TEMP_AUTO_OFFSETS(2), - LM93_SYSCTL_TEMP_AUTO_OFFSETS(3), - - LM93_SYSCTL_TEMP_AUTO_BOOST(1), - LM93_SYSCTL_TEMP_AUTO_BOOST(2), - LM93_SYSCTL_TEMP_AUTO_BOOST(3), - - LM93_SYSCTL_TEMP_AUTO_BOOST_HYST(1), - LM93_SYSCTL_TEMP_AUTO_BOOST_HYST(2), - LM93_SYSCTL_TEMP_AUTO_BOOST_HYST(3), - - LM93_SYSCTL_TEMP_AUTO_PWM_MIN(1), - LM93_SYSCTL_TEMP_AUTO_PWM_MIN(2), - LM93_SYSCTL_TEMP_AUTO_PWM_MIN(3), - - LM93_SYSCTL_TEMP_AUTO_OFFSET_HYST(1), - LM93_SYSCTL_TEMP_AUTO_OFFSET_HYST(2), - LM93_SYSCTL_TEMP_AUTO_OFFSET_HYST(3), - - LM93_SYSCTL_FAN(1), - LM93_SYSCTL_FAN(2), - LM93_SYSCTL_FAN(3), - LM93_SYSCTL_FAN(4), - - LM93_SYSCTL_FAN_SMART_TACH(1), - LM93_SYSCTL_FAN_SMART_TACH(2), - LM93_SYSCTL_FAN_SMART_TACH(3), - LM93_SYSCTL_FAN_SMART_TACH(4), - - LM93_SYSCTL_PWM(1), - LM93_SYSCTL_PWM(2), - - LM93_SYSCTL_PWM_FREQ(1), - LM93_SYSCTL_PWM_FREQ(2), - - LM93_SYSCTL_PWM_AUTO_CHAN(1), - LM93_SYSCTL_PWM_AUTO_CHAN(2), - - LM93_SYSCTL_PWM_AUTO_SPINUP_MIN(1), - LM93_SYSCTL_PWM_AUTO_SPINUP_MIN(2), - - LM93_SYSCTL_PWM_AUTO_SPINUP_TIME(1), - LM93_SYSCTL_PWM_AUTO_SPINUP_TIME(2), - - {LM93_SYSCTL_PWM_AUTO_PROCHOT_RAMP, "pwm_auto_prochot_ramp", NULL, 0, - 0644, NULL, &i2c_proc_real, &i2c_sysctl_real, NULL, - &lm93_pwm_auto_ramp}, - - {LM93_SYSCTL_PWM_AUTO_VRDHOT_RAMP, "pwm_auto_vrdhot_ramp", NULL, 0, - 0644, NULL, &i2c_proc_real, &i2c_sysctl_real, NULL, - &lm93_pwm_auto_ramp}, - - LM93_SYSCTL_VID(1), - LM93_SYSCTL_VID(2), - - LM93_SYSCTL_PROCHOT(1), - LM93_SYSCTL_PROCHOT(2), - - {LM93_SYSCTL_PROCHOT_SHORT, "prochot_short", NULL, 0, 0644, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &lm93_prochot_short}, - - {LM93_SYSCTL_PROCHOT_OVERRIDE, "prochot_override", NULL, 0, 0644, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &lm93_prochot_override}, - - {LM93_SYSCTL_PROCHOT_INTERVAL, "prochot_interval", NULL, 0, 0644, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &lm93_prochot_interval}, - - LM93_SYSCTL_VRDHOT(1), - LM93_SYSCTL_VRDHOT(2), - - {LM93_SYSCTL_GPIO, "gpio", NULL, 0, 0444, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &lm93_gpio}, - - {LM93_SYSCTL_ALARMS, "alarms", NULL, 0, 0444, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &lm93_alarms}, - - {0} -}; - -static void lm93_init_client(struct i2c_client *client) -{ - int i; - u8 reg; - - /* configure VID pin input thresholds */ - reg = lm93_read_byte(client, LM93_REG_GPI_VID_CTL); - lm93_write_byte(client, LM93_REG_GPI_VID_CTL, - reg | (vid_agtl ? 0x03 : 0x00)); - - if (init) { - /* enable #ALERT pin */ - reg = lm93_read_byte(client, LM93_REG_CONFIG); - lm93_write_byte(client, LM93_REG_CONFIG, reg | 0x08); - - /* enable ASF mode for BMC status registers */ - reg = lm93_read_byte(client, LM93_REG_STATUS_CONTROL); - lm93_write_byte(client, LM93_REG_STATUS_CONTROL, reg | 0x02); - - /* set sleep state to S0 */ - lm93_write_byte(client, LM93_REG_SLEEP_CONTROL, 0); - - /* unmask #VRDHOT and dynamic VCCP (if nec) error events */ - reg = lm93_read_byte(client, LM93_REG_MISC_ERR_MASK); - reg &= ~0x03; - reg &= ~(vccp_limit_type[0] ? 0x10 : 0); - reg &= ~(vccp_limit_type[1] ? 0x20 : 0); - lm93_write_byte(client, LM93_REG_MISC_ERR_MASK, reg); - } - - /* start monitoring */ - reg = lm93_read_byte(client, LM93_REG_CONFIG); - lm93_write_byte(client, LM93_REG_CONFIG, reg | 0x01); - - /* spin until ready */ - for (i=0; i<20; i++) { - mdelay(10); - if ((lm93_read_byte(client, LM93_REG_CONFIG) & 0x80) == 0x80) - return; - } - - printk(KERN_WARNING "lm93.o: timed out waiting for sensor " - "chip to signal ready!\n"); -} - -/* forward declaration */ -static struct i2c_driver lm93_driver; - -/* This function is called by i2c_detect */ -static int lm93_detect(struct i2c_adapter *adapter, int address, - unsigned short flags, int kind) -{ - int err = 0, func; - struct lm93_data *data; - struct i2c_client *client; - void (*update)(struct lm93_data *, struct i2c_client *); - - /* lm93 is SMBus only */ - if (i2c_is_isa_adapter(adapter)) { - pr_debug("lm93.o: detect failed, " - "cannot attach to legacy adapter!\n"); - goto ERROR0; - } - - /* choose update routine based on bus capabilities */ - func = i2c_get_functionality(adapter); - - if ( ((LM93_SMBUS_FUNC_FULL & func) == LM93_SMBUS_FUNC_FULL) && - (!disable_block) ) { - pr_debug("lm93.o: using SMBus block data transactions\n"); - update = lm93_update_client_full; - } else if ((LM93_SMBUS_FUNC_MIN & func) == LM93_SMBUS_FUNC_MIN) { - pr_debug("lm93.o: disabled SMBus block data transactions\n"); - update = lm93_update_client_min; - } else { - pr_debug("lm93.o: detect failed, " - "smbus byte and/or word data not supported!\n"); - goto ERROR0; - } - - /* OK. For now, we presume we have a valid client. We now create the - client structure, even though we cannot fill it completely yet. - But it allows us to access lm78_{read,write}_value. */ - - if (!(data = kmalloc(sizeof(struct lm93_data), GFP_KERNEL))) { - pr_debug("lm93.o: detect failed, kmalloc failed!\n"); - err = -ENOMEM; - goto ERROR0; - } - - client = &data->client; - client->addr = address; - client->data = data; - client->adapter = adapter; - client->driver = &lm93_driver; - client->flags = 0; - - /* detection */ - if (kind < 0) { - int mfr = lm93_read_byte(client, LM93_REG_MFR_ID); - - if (mfr != 0x01) { - pr_debug("lm93.o: detect failed, " - "bad manufacturer id 0x%02x!\n", mfr); - goto ERROR1; - } - } - - if (kind <= 0) { - int ver = lm93_read_byte(client, LM93_REG_VER); - - if ((ver == LM93_MFR_ID) || (ver == LM93_MFR_ID_PROTOTYPE)) { - kind = lm93; - } else { - pr_debug("lm93.o: detect failed, " - "bad version id 0x%02x!\n", ver); - if (kind == 0) - pr_debug("lm93.o: " - "(ignored 'force' parameter)\n"); - goto ERROR1; - } - } - - /* fill in remaining client fields */ - strcpy(client->name, "LM93 chip"); - client->id = lm93_id++; - pr_debug("lm93.o: assigning ID %d to %s at %d,0x%02x\n", client->id, - client->name, i2c_adapter_id(client->adapter), client->addr); - - /* housekeeping */ - data->valid = 0; - data->update = update; - init_MUTEX(&data->update_lock); - - /* tell the I2C layer a new client has arrived */ - if ((err = i2c_attach_client(client))) - goto ERROR1; - - /* initialize the chip */ - lm93_init_client(client); - - /* register a new directory entry with module sensors */ - if ((data->sysctl_id = i2c_register_entry(client, "lm93", - lm93_dir_table_template, THIS_MODULE)) < 0) { - err = data->sysctl_id; - goto ERROR2; - } - - return 0; - -ERROR2: - i2c_detach_client(client); -ERROR1: - kfree(data); -ERROR0: - return err; -} - -/* This function is called when: - * lm93_driver is inserted (when this module is loaded), for each - available adapter - * when a new adapter is inserted (and lm93_driver is still present) */ -static int lm93_attach_adapter(struct i2c_adapter *adapter) -{ - return i2c_detect(adapter, &addr_data, lm93_detect); -} - -static int lm93_detach_client(struct i2c_client *client) -{ - int err; - struct lm93_data *data = client->data; - - i2c_deregister_entry(data->sysctl_id); - - if ((err = i2c_detach_client(client))) { - printk (KERN_ERR "lm93.o: Client deregistration failed; " - "client not detached.\n"); - return err; - } - kfree(data); - return 0; -} - -static struct i2c_driver lm93_driver = { - .name = "LM93 sensor driver", - .id = I2C_DRIVERID_LM93, - .flags = I2C_DF_NOTIFY, - .attach_adapter = lm93_attach_adapter, - .detach_client = lm93_detach_client, -}; - -static int __init lm93_init(void) -{ - printk(KERN_INFO "lm93.o version %s (%s)\n", LM_VERSION, LM_DATE); - return i2c_add_driver(&lm93_driver); -} - -static void __exit lm93_exit(void) -{ - i2c_del_driver(&lm93_driver); -} - -MODULE_AUTHOR("Mark M. Hoffman "); -MODULE_DESCRIPTION("LM93 driver"); -MODULE_LICENSE("GPL"); - -module_init(lm93_init); -module_exit(lm93_exit); diff --git a/kernel/chips/lm93.h b/kernel/chips/lm93.h deleted file mode 100644 index c61a4c81..00000000 --- a/kernel/chips/lm93.h +++ /dev/null @@ -1,113 +0,0 @@ -/* - lm93.h - Part of lm_sensors, Linux kernel modules for hardware monitoring - - Author/Maintainer: Mark M. Hoffman - Copyright (c) 2004 Utilitek Systems, Inc. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#ifndef LM93_H -#define LM93_H - -/* LM93 REGISTER ADDRESSES */ - -/* miscellaneous */ -#define LM93_REG_MFR_ID 0x3e -#define LM93_REG_VER 0x3f -#define LM93_REG_STATUS_CONTROL 0xe2 -#define LM93_REG_CONFIG 0xe3 -#define LM93_REG_SLEEP_CONTROL 0xe4 - -/* alarm values start here */ -#define LM93_REG_HOST_ERROR_1 0x48 - -/* voltage inputs: in1-in16 (nr => 0-15) */ -#define LM93_REG_IN(nr) (0x56 + (nr)) -#define LM93_REG_IN_MIN(nr) (0x90 + (nr) * 2) -#define LM93_REG_IN_MAX(nr) (0x91 + (nr) * 2) - -/* temperature inputs: temp1-temp4 (nr => 0-3) */ -#define LM93_REG_TEMP(nr) (0x50 + (nr)) -#define LM93_REG_TEMP_MIN(nr) (0x78 + (nr) * 2) -#define LM93_REG_TEMP_MAX(nr) (0x79 + (nr) * 2) - -/* temp[1-4]_auto_boost (nr => 0-3) */ -#define LM93_REG_BOOST(nr) (0x80 + (nr)) - -/* #PROCHOT inputs: prochot1-prochot2 (nr => 0-1) */ -#define LM93_REG_PROCHOT_CUR(nr) (0x67 + (nr) * 2) -#define LM93_REG_PROCHOT_AVG(nr) (0x68 + (nr) * 2) -#define LM93_REG_PROCHOT_MAX(nr) (0xb0 + (nr)) - -/* fan tach inputs: fan1-fan4 (nr => 0-3) */ -#define LM93_REG_FAN(nr) (0x6e + (nr) * 2) -#define LM93_REG_FAN_MIN(nr) (0xb4 + (nr) * 2) - -/* pwm outputs: pwm1-pwm2 (nr => 0-1, reg => 0-3) */ -#define LM93_REG_PWM_CTL(nr,reg) (0xc8 + (reg) + (nr) * 4) -#define LM93_PWM_CTL1 0 -#define LM93_PWM_CTL2 1 -#define LM93_PWM_CTL3 2 -#define LM93_PWM_CTL4 3 - -/* GPIO input state */ -#define LM93_REG_GPI 0x6b - -/* vid inputs: vid1-vid2 (nr => 0-1) */ -#define LM93_REG_VID(nr) (0x6c + (nr)) - -/* vccp1 & vccp2: VID relative inputs (nr => 0-1) */ -#define LM93_REG_VCCP_LIMIT_OFF(nr) (0xb2 + (nr)) - -/* temp[1-4]_auto_boost_hyst */ -#define LM93_REG_BOOST_HYST_12 0xc0 -#define LM93_REG_BOOST_HYST_34 0xc1 -#define LM93_REG_BOOST_HYST(nr) (0xc0 + (nr)/2) - -/* temp[1-4]_auto_pwm_[min|hyst] */ -#define LM93_REG_PWM_MIN_HYST_12 0xc3 -#define LM93_REG_PWM_MIN_HYST_34 0xc4 -#define LM93_REG_PWM_MIN_HYST(nr) (0xc3 + (nr)/2) - -/* prochot_override & prochot_interval */ -#define LM93_REG_PROCHOT_OVERRIDE 0xc6 -#define LM93_REG_PROCHOT_INTERVAL 0xc7 - -/* temp[1-4]_auto_base (nr => 0-3) */ -#define LM93_REG_TEMP_BASE(nr) (0xd0 + (nr)) - -/* temp[1-4]_auto_offsets (step => 0-11) */ -#define LM93_REG_TEMP_OFFSET(step) (0xd4 + (step)) - -/* #PROCHOT & #VRDHOT PWM ramp control */ -#define LM93_REG_PWM_RAMP_CTL 0xbf - -/* miscellaneous */ -#define LM93_REG_SFC1 0xbc -#define LM93_REG_SFC2 0xbd -#define LM93_REG_GPI_VID_CTL 0xbe -#define LM93_REG_SF_TACH_TO_PWM 0xe0 - -/* error masks */ -#define LM93_REG_GPI_ERR_MASK 0xec -#define LM93_REG_MISC_ERR_MASK 0xed - -/* LM93 REGISTER VALUES */ -#define LM93_MFR_ID 0x73 -#define LM93_MFR_ID_PROTOTYPE 0x72 - -#endif /* !defined LM93_H */ - diff --git a/kernel/chips/ltc1710.c b/kernel/chips/ltc1710.c deleted file mode 100644 index f197ec1d..00000000 --- a/kernel/chips/ltc1710.c +++ /dev/null @@ -1,313 +0,0 @@ -/* - ltc1710.c - Part of lm_sensors, Linux kernel modules for hardware - monitoring - Copyright (c) 1999 Frodo Looijaard and - Philip Edelbrock - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -/* A few notes about the LTC1710: - -* The LTC1710 is a dual programmable switch. It can be used to turn - anything on or off anything which consumes less than 300mA of - current and up to 5.5V - -* The LTC1710 is a very, very simple SMBus device with three possible - SMBus addresses (0x58,0x59, or 0x5A). Only SMBus byte writes - (command writes) are supported. - -* Since only writes are supported, READS DON'T WORK! The device - plays dead in the event of a read, so this makes detection a - bit tricky. - -* BTW- I can safely say that this driver has been tested under - every possible case, so there should be no bugs. :') - - --Phil - -*/ - - -#include -#include -#include -#include -#include -#include "version.h" - -MODULE_LICENSE("GPL"); - -/* Addresses to scan */ -static unsigned short normal_i2c[] = { SENSORS_I2C_END }; -static unsigned short normal_i2c_range[] = { 0x58, 0x5a, SENSORS_I2C_END }; -static unsigned int normal_isa[] = { SENSORS_ISA_END }; -static unsigned int normal_isa_range[] = { SENSORS_ISA_END }; - -/* Insmod parameters */ -SENSORS_INSMOD_1(ltc1710); - -/* The LTC1710 registers */ - -/* (No registers. [Wow! This thing is SIMPLE!] ) */ - -/* Initial values */ -#define LTC1710_INIT 0 /* Both off */ - -/* Each client has this additional data */ -struct ltc1710_data { - struct i2c_client client; - int sysctl_id; - - struct semaphore update_lock; - char valid; /* !=0 if following fields are valid */ - unsigned long last_updated; /* In jiffies */ - - u8 status; /* Register values */ -}; - -static int ltc1710_attach_adapter(struct i2c_adapter *adapter); -static int ltc1710_detect(struct i2c_adapter *adapter, int address, - unsigned short flags, int kind); -static int ltc1710_detach_client(struct i2c_client *client); - -static void ltc1710_switch1(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void ltc1710_switch2(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void ltc1710_update_client(struct i2c_client *client); - - -/* This is the driver that will be inserted */ -static struct i2c_driver ltc1710_driver = { - .name = "LTC1710 sensor chip driver", - .id = I2C_DRIVERID_LTC1710, - .flags = I2C_DF_NOTIFY, - .attach_adapter = ltc1710_attach_adapter, - .detach_client = ltc1710_detach_client, -}; - -/* -- SENSORS SYSCTL START -- */ - -#define LTC1710_SYSCTL_SWITCH_1 1000 -#define LTC1710_SYSCTL_SWITCH_2 1001 - -/* -- SENSORS SYSCTL END -- */ - -/* These files are created for each detected LTC1710. This is just a template; - though at first sight, you might think we could use a statically - allocated list, we need some way to get back to the parent - which - is done through one of the 'extra' fields which are initialized - when a new copy is allocated. */ -static ctl_table ltc1710_dir_table_template[] = { - {LTC1710_SYSCTL_SWITCH_1, "switch1", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, <c1710_switch1}, - {LTC1710_SYSCTL_SWITCH_2, "switch2", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, <c1710_switch2}, - {0} -}; - -static int ltc1710_attach_adapter(struct i2c_adapter *adapter) -{ - return i2c_detect(adapter, &addr_data, ltc1710_detect); -} - -/* This function is called by i2c_detect */ -int ltc1710_detect(struct i2c_adapter *adapter, int address, - unsigned short flags, int kind) -{ - int i; - struct i2c_client *new_client; - struct ltc1710_data *data; - int err = 0; - const char *type_name, *client_name; - - /* Make sure we aren't probing the ISA bus!! This is just a safety check - at this moment; i2c_detect really won't call us. */ -#ifdef DEBUG - if (i2c_is_isa_adapter(adapter)) { - printk - ("ltc1710.o: ltc1710_detect called for an ISA bus adapter?!?\n"); - return 0; - } -#endif - - if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE)) - goto ERROR0; - - /* OK. For now, we presume we have a valid client. We now create the - client structure, even though we cannot fill it completely yet. - But it allows us to access ltc1710_{read,write}_value. */ - if (!(data = kmalloc(sizeof(struct ltc1710_data), GFP_KERNEL))) { - err = -ENOMEM; - goto ERROR0; - } - - new_client = &data->client; - new_client->addr = address; - new_client->data = data; - new_client->adapter = adapter; - new_client->driver = <c1710_driver; - new_client->flags = 0; - - /* Now, we would do the remaining detection. But the LTC1710 is plainly - impossible to detect! Stupid chip. */ - - /* Determine the chip type - only one kind supported! */ - if (kind <= 0) - kind = ltc1710; - - if (kind == ltc1710) { - type_name = "ltc1710"; - client_name = "LTC1710 chip"; - } else { -#ifdef DEBUG - printk("ltc1710.o: Internal error: unknown kind (%d)\n", - kind); -#endif - goto ERROR1; - } - - /* Fill in the remaining client fields and put it into the global list */ - strcpy(new_client->name, client_name); - data->valid = 0; - init_MUTEX(&data->update_lock); - - /* Tell the I2C layer a new client has arrived */ - if ((err = i2c_attach_client(new_client))) - goto ERROR3; - - /* Register a new directory entry with module sensors */ - if ((i = i2c_register_entry(new_client, type_name, - ltc1710_dir_table_template, - THIS_MODULE)) < 0) { - err = i; - goto ERROR4; - } - data->sysctl_id = i; - - return 0; - -/* OK, this is not exactly good programming practice, usually. But it is - very code-efficient in this case. */ - - ERROR4: - i2c_detach_client(new_client); - ERROR3: - ERROR1: - kfree(data); - ERROR0: - return err; -} - - -static int ltc1710_detach_client(struct i2c_client *client) -{ - int err; - - i2c_deregister_entry(((struct ltc1710_data *) (client->data))-> - sysctl_id); - - if ((err = i2c_detach_client(client))) { - printk - ("ltc1710.o: Client deregistration failed, client not detached.\n"); - return err; - } - - kfree(client->data); - - return 0; - -} - -static void ltc1710_update_client(struct i2c_client *client) -{ - struct ltc1710_data *data = client->data; - - down(&data->update_lock); - - if ((jiffies - data->last_updated > HZ + HZ / 2) || - (jiffies < data->last_updated) || !data->valid) { - -#ifdef DEBUG - printk("Starting ltc1710 update\n"); -#endif - - /* data->status = i2c_smbus_read_byte(client); - Unfortunately, reads always fail! */ - data->last_updated = jiffies; - data->valid = 1; - } - - up(&data->update_lock); -} - - -void ltc1710_switch1(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results) -{ - struct ltc1710_data *data = client->data; - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - ltc1710_update_client(client); - results[0] = data->status & 1; - *nrels_mag = 1; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag >= 1) { - data->status = (data->status & 2) | results[0]; - i2c_smbus_write_byte(client, data->status); - } - } -} - -void ltc1710_switch2(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results) -{ - struct ltc1710_data *data = client->data; - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - ltc1710_update_client(client); - results[0] = (data->status & 2) >> 1; - *nrels_mag = 1; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag >= 1) { - data->status = - (data->status & 1) | (results[0] << 1); - i2c_smbus_write_byte(client, data->status); - } - } -} - -static int __init sm_ltc1710_init(void) -{ - printk("ltc1710.o version %s (%s)\n", LM_VERSION, LM_DATE); - return i2c_add_driver(<c1710_driver); -} - -static void __exit sm_ltc1710_exit(void) -{ - i2c_del_driver(<c1710_driver); -} - - - -MODULE_AUTHOR - ("Frodo Looijaard and Philip Edelbrock "); -MODULE_DESCRIPTION("LTC1710 driver"); - -module_init(sm_ltc1710_init); -module_exit(sm_ltc1710_exit); diff --git a/kernel/chips/matorb.c b/kernel/chips/matorb.c deleted file mode 100644 index 1e6de8a7..00000000 --- a/kernel/chips/matorb.c +++ /dev/null @@ -1,281 +0,0 @@ -/* - matorb.c - Part of lm_sensors, Linux kernel modules for hardware - monitoring - Copyright (c) 1998, 1999 Frodo Looijaard - and Philip Edelbrock - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - - -#define DEBUG 1 - -#include -#include -#include -#include -#include -#include "version.h" - -MODULE_LICENSE("GPL"); - -/* Addresses to scan */ -static unsigned short normal_i2c[] = { 0x2E, SENSORS_I2C_END }; -static unsigned short normal_i2c_range[] = { SENSORS_I2C_END }; -static unsigned int normal_isa[] = { SENSORS_ISA_END }; -static unsigned int normal_isa_range[] = { SENSORS_ISA_END }; - -/* Insmod parameters */ -SENSORS_INSMOD_1(matorb); - -/* Many MATORB constants specified below */ - - -/* Each client has this additional data */ -struct matorb_data { - struct i2c_client client; - int sysctl_id; - - struct semaphore update_lock; - char valid; /* !=0 if following fields are valid */ - unsigned long last_updated; /* In jiffies */ - -}; - -static int matorb_attach_adapter(struct i2c_adapter *adapter); -static int matorb_detect(struct i2c_adapter *adapter, int address, - unsigned short flags, int kind); -static void matorb_init_client(struct i2c_client *client); -static int matorb_detach_client(struct i2c_client *client); - -static int matorb_write_value(struct i2c_client *client, u8 reg, - u16 value); -static void matorb_disp(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void matorb_update_client(struct i2c_client *client); - - -/* This is the driver that will be inserted */ -static struct i2c_driver matorb_driver = { - .name = "Matrix Orbital LCD driver", - .id = I2C_DRIVERID_MATORB, - .flags = I2C_DF_NOTIFY, - .attach_adapter = matorb_attach_adapter, - .detach_client = matorb_detach_client, -}; - -/* -- SENSORS SYSCTL START -- */ -#define MATORB_SYSCTL_DISP 1000 -/* -- SENSORS SYSCTL END -- */ - -/* These files are created for each detected MATORB. This is just a template; - though at first sight, you might think we could use a statically - allocated list, we need some way to get back to the parent - which - is done through one of the 'extra' fields which are initialized - when a new copy is allocated. */ -static ctl_table matorb_dir_table_template[] = { - {MATORB_SYSCTL_DISP, "disp", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &matorb_disp}, - {0} -}; - -static int matorb_attach_adapter(struct i2c_adapter *adapter) -{ - return i2c_detect(adapter, &addr_data, matorb_detect); -} - -/* This function is called by i2c_detect */ -int matorb_detect(struct i2c_adapter *adapter, int address, - unsigned short flags, int kind) -{ - int i, cur; - struct i2c_client *new_client; - struct matorb_data *data; - int err = 0; - const char *type_name = "matorb"; - const char *client_name = "matorb"; - - /* Make sure we aren't probing the ISA bus!! This is just a safety check - at this moment; i2c_detect really won't call us. */ -#ifdef DEBUG - if (i2c_is_isa_adapter(adapter)) { - printk - ("matorb.o: matorb_detect called for an ISA bus adapter?!?\n"); - return 0; - } -#endif - - if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_WRITE_BYTE | - I2C_FUNC_SMBUS_WRITE_BYTE_DATA)) - goto ERROR0; - - - /* OK. For now, we presume we have a valid client. We now create the - client structure, even though we cannot fill it completely yet. - But it allows us to access matorb_{read,write}_value. */ - if (!(data = kmalloc(sizeof(struct matorb_data), GFP_KERNEL))) { - err = -ENOMEM; - goto ERROR0; - } - - new_client = &data->client; - new_client->addr = address; - new_client->data = data; - new_client->adapter = adapter; - new_client->driver = &matorb_driver; - new_client->flags = 0; - - /* Now, we do the remaining detection. It is lousy. */ - cur = i2c_smbus_write_byte_data(new_client, 0x0FE, 0x58); /* clear screen */ - - printk("matorb.o: debug detect 0x%X\n", cur); - - /* Fill in the remaining client fields and put it into the global list */ - strcpy(new_client->name, client_name); - data->valid = 0; - init_MUTEX(&data->update_lock); - - /* Tell the I2C layer a new client has arrived */ - if ((err = i2c_attach_client(new_client))) - goto ERROR3; - - /* Register a new directory entry with module sensors */ - if ((i = i2c_register_entry(new_client, type_name, - matorb_dir_table_template, - THIS_MODULE)) < 0) { - err = i; - goto ERROR4; - } - data->sysctl_id = i; - - matorb_init_client(new_client); - return 0; - -/* OK, this is not exactly good programming practice, usually. But it is - very code-efficient in this case. */ - - ERROR4: - i2c_detach_client(new_client); - ERROR3: - kfree(data); - ERROR0: - return err; -} - -static int matorb_detach_client(struct i2c_client *client) -{ - int err; - - i2c_deregister_entry(((struct matorb_data *) (client->data))-> - sysctl_id); - - if ((err = i2c_detach_client(client))) { - printk - ("matorb.o: Client deregistration failed, client not detached.\n"); - return err; - } - - kfree(client->data); - - return 0; -} - - -#if 0 -/* All registers are word-sized, except for the configuration register. - MATORB uses a high-byte first convention, which is exactly opposite to - the usual practice. */ -static int matorb_read_value(struct i2c_client *client, u8 reg) -{ - return -1; /* Doesn't support reads */ -} -#endif - -/* All registers are word-sized, except for the configuration register. - MATORB uses a high-byte first convention, which is exactly opposite to - the usual practice. */ -static int matorb_write_value(struct i2c_client *client, u8 reg, u16 value) -{ - if (reg == 0) { - return i2c_smbus_write_byte(client, value); - } else { - return i2c_smbus_write_byte_data(client, reg, value); - } -} - -static void matorb_init_client(struct i2c_client *client) -{ - /* Initialize the MATORB chip */ -} - -static void matorb_update_client(struct i2c_client *client) -{ - struct matorb_data *data = client->data; - - down(&data->update_lock); - - if ((jiffies - data->last_updated > HZ + HZ / 2) || - (jiffies < data->last_updated) || !data->valid) { - -#ifdef DEBUG - printk("Starting matorb update\n"); -#endif - -/* nothing yet */ - data->last_updated = jiffies; - data->valid = 1; - } - - up(&data->update_lock); -} - - -void matorb_disp(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - int i; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - matorb_update_client(client); - results[0] = 0; - *nrels_mag = 3; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - for (i = 1; i <= *nrels_mag; i++) { - matorb_write_value(client, 0, results[i - 1]); - } - } -} - -static int __init sm_matorb_init(void) -{ - printk("matorb.o version %s (%s)\n", LM_VERSION, LM_DATE); - return i2c_add_driver(&matorb_driver); -} - -static void __exit sm_matorb_exit(void) -{ - i2c_del_driver(&matorb_driver); -} - - - -MODULE_AUTHOR - ("Frodo Looijaard and Philip Edelbrock "); -MODULE_DESCRIPTION("MATORB driver"); - -module_init(sm_matorb_init); -module_exit(sm_matorb_exit); diff --git a/kernel/chips/max1619.c b/kernel/chips/max1619.c deleted file mode 100644 index 9553eefd..00000000 --- a/kernel/chips/max1619.c +++ /dev/null @@ -1,498 +0,0 @@ -/* - * max1619.c - Part of lm_sensors, Linux kernel modules for hardware - * monitoring - * Copyright (C) 2004 Alexey Fisher - * Jean Delvare - * - * Copied from lm90.c: - * Copyright (C) 2003-2004 Jean Delvare - * - * The MAX1619 is a sensor chip made by Maxim. It reports up to two - * temperatures (its own plus up to one external one). - * Complete datasheet can be obtained from Maxim's website at: - * http://pdfserv.maxim-ic.com/en/ds/MAX1619.pdf - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include -#include -#include -#include -#include -#include "version.h" - -/* - * Addresses to scan - */ - -static unsigned short normal_i2c[] = { SENSORS_I2C_END }; -static unsigned short normal_i2c_range[] = {0x18, 0x1a, 0x29, 0x2b, - 0x4c, 0x4e, SENSORS_I2C_END }; -static unsigned int normal_isa[] = { SENSORS_ISA_END }; -static unsigned int normal_isa_range[] = { SENSORS_ISA_END }; - -/* - * Insmod parameters - */ - -SENSORS_INSMOD_1(max1619); - -/* - * The max1619 registers - */ - -#define MAX1619_REG_R_CONFIG 0x03 -#define MAX1619_REG_W_CONFIG 0x09 -#define MAX1619_REG_R_CONVRATE 0x04 -#define MAX1619_REG_W_CONVRATE 0x0A -#define MAX1619_REG_R_STATUS 0x02 -#define MAX1619_REG_R_LOCAL_TEMP 0x00 -#define MAX1619_REG_R_REMOTE_TEMP 0x01 -#define MAX1619_REG_R_REMOTE_THIGH 0x07 -#define MAX1619_REG_W_REMOTE_THIGH 0x0d -#define MAX1619_REG_R_REMOTE_TLOW 0x08 -#define MAX1619_REG_W_REMOTE_TLOW 0x0E -#define MAX1619_REG_R_REMOTE_TMAX 0x10 -#define MAX1619_REG_W_REMOTE_TMAX 0x12 -#define MAX1619_REG_R_REMOTE_THYST 0x11 -#define MAX1619_REG_W_REMOTE_THYST 0x13 -#define MAX1619_REG_R_MAN_ID 0xFE -#define MAX1619_REG_R_CHIP_ID 0xFF - -/* - * Conversions - */ - -static int temp_from_reg(int val) -{ - return val & 0x80 ? val-0x100 : val; -} - -static int temp_to_reg(int val) -{ - return val < 0 ? val+0x100 : val; -} - -/* - * Functions declaration - */ - -static int max1619_attach_adapter(struct i2c_adapter *adapter); -static int max1619_detect(struct i2c_adapter *adapter, int address, - unsigned short flags, int kind); -static void max1619_init_client(struct i2c_client *client); -static int max1619_detach_client(struct i2c_client *client); -static void max1619_local_temp(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void max1619_remote_temp(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void max1619_remote_crit(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void max1619_alarms(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); - -/* - * Driver data (common to all clients) - */ - -static struct i2c_driver max1619_driver = { - .name = "MAX1619 sensor driver", - .flags = I2C_DF_NOTIFY, - .attach_adapter = max1619_attach_adapter, - .detach_client = max1619_detach_client -}; - -/* - * Client data (each client gets its own) - */ - -struct max1619_data { - struct i2c_client client; - int sysctl_id; - - struct semaphore update_lock; - char valid; /* zero until following fields are valid */ - unsigned long last_updated; /* in jiffies */ - - /* register values */ - u8 local_temp; - u8 remote_temp, remote_high, remote_low; - u8 remote_hyst, remote_max; - u8 alarms; -}; - -/* - * Proc entries - * These files are created for each detected max1619. - */ - -/* -- SENSORS SYSCTL START -- */ - -#define MAX1619_SYSCTL_LOCAL_TEMP 1200 -#define MAX1619_SYSCTL_REMOTE_TEMP 1201 -#define MAX1619_SYSCTL_REMOTE_CRIT 1202 -#define MAX1619_SYSCTL_ALARMS 1203 - -#define MAX1619_ALARM_REMOTE_THIGH 0x10 -#define MAX1619_ALARM_REMOTE_TLOW 0x08 -#define MAX1619_ALARM_REMOTE_OPEN 0x04 -#define MAX1619_ALARM_REMOTE_OVERT 0x02 - -/* -- SENSORS SYSCTL END -- */ - - -static ctl_table max1619_dir_table_template[] = -{ - {MAX1619_SYSCTL_LOCAL_TEMP, "temp1", NULL, 0, 0444, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &max1619_local_temp}, - {MAX1619_SYSCTL_REMOTE_TEMP, "temp2", NULL, 0, 0644, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &max1619_remote_temp}, - {MAX1619_SYSCTL_REMOTE_CRIT,"temp2_crit", NULL, 0, 0644, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &max1619_remote_crit}, - {MAX1619_SYSCTL_ALARMS, "alarms", NULL, 0, 0444, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &max1619_alarms}, - {0} -}; - -/* - * Real code - */ - -static int max1619_attach_adapter(struct i2c_adapter *adapter) -{ - return i2c_detect(adapter, &addr_data, max1619_detect); -} - -/* - * The following function does more than just detection. If detection - * succeeds, it also registers the new chip. - */ -static int max1619_detect(struct i2c_adapter *adapter, int address, - unsigned short flags, int kind) -{ - struct i2c_client *new_client; - struct max1619_data *data; - int err = 0; - const char *type_name = ""; - const char *client_name = ""; - -#ifdef DEBUG - if (i2c_is_isa_adapter(adapter)) { - printk(KERN_DEBUG "max1619.o: Called for an ISA bus " - "adapter, aborting.\n"); - return 0; - } -#endif - - if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) { -#ifdef DEBUG - printk(KERN_DEBUG "max1619.o: I2C bus doesn't support " - "byte read mode, skipping.\n"); -#endif - return 0; - } - - if (!(data = kmalloc(sizeof(struct max1619_data), GFP_KERNEL))) { - printk(KERN_ERR "max1619.o: Out of memory in " - "max1619_detect (new_client).\n"); - return -ENOMEM; - } - - /* - * The common I2C client data is placed right before the - * MAX1619-specific data. The MAX1619-specific data is pointed to - * by the data field from the I2C client da1ta. - */ - - new_client = &data->client; - new_client->addr = address; - new_client->data = data; - new_client->adapter = adapter; - new_client->driver = &max1619_driver; - new_client->flags = 0; - - /* - * Now we do the remaining detection. A negative kind means that - * the driver was loaded with no force parameter (default), so we - * must both detect and identify the chip. A zero kind means that - * the driver was loaded with the force parameter, the detection - * step shall be skipped. A positive kind means that the driver - * was loaded with the force parameter and a given kind of chip is - * requested, so both the detection and the identification steps - * are skipped. - */ - - if (kind < 0) { - u8 reg_config, reg_convrate, reg_status; - - reg_config = i2c_smbus_read_byte_data(new_client, - MAX1619_REG_R_CONFIG); - reg_convrate = i2c_smbus_read_byte_data(new_client, - MAX1619_REG_R_CONVRATE); - reg_status = i2c_smbus_read_byte_data(new_client, - MAX1619_REG_R_STATUS); - - if ((reg_config & 0x03) != 0x00 - || reg_convrate > 0x07 - || (reg_status & 0x61) != 0x00) { -#ifdef DEBUG - printk(KERN_DEBUG "max1619.o: Detection failed at " - "0x%02x.\n", address); -#endif - goto ERROR1; - } - } - - if (kind <= 0) { - u8 man_id, chip_id; - - man_id = i2c_smbus_read_byte_data(new_client, - MAX1619_REG_R_MAN_ID); - chip_id = i2c_smbus_read_byte_data(new_client, - MAX1619_REG_R_CHIP_ID); - - if ((man_id == 0x4D) && (chip_id == 0x04)) { - kind = max1619; - } - } - - if (kind <= 0) { - printk(KERN_INFO "max1619.o: Unsupported chip.\n"); - goto ERROR1; - } - - if (kind == max1619) { - type_name = "max1619"; - client_name = "MAX1619 chip"; - } else { - printk(KERN_ERR "max1619.o: Unknown kind %d.\n", kind); - goto ERROR1; - } - - /* - * OK, we got a valid chip so we can fill in the remaining client - * fields. - */ - - strcpy(new_client->name, client_name); - data->valid = 0; - init_MUTEX(&data->update_lock); - - /* - * Tell the I2C layer a new client has arrived. - */ - - if ((err = i2c_attach_client(new_client))) { - printk(KERN_ERR "max1619.o: Failed attaching client.\n"); - goto ERROR1; - } - - /* - * Register a new directory entry. - */ - - if ((err = i2c_register_entry(new_client, type_name, - max1619_dir_table_template, THIS_MODULE)) < 0) { - printk(KERN_ERR "max1619.o: Failed registering directory " - "entry.\n"); - goto ERROR2; - } - data->sysctl_id = err; - - /* - * Initialize the MAX1619 chip. - */ - - max1619_init_client(new_client); - return 0; - -ERROR2: - i2c_detach_client(new_client); -ERROR1: - kfree(data); - return err; -} - -static void max1619_init_client(struct i2c_client *client) -{ - u8 config; - - /* - * Start the conversions. - */ - - /* Set conversion rate to 2 Hz */ - i2c_smbus_write_byte_data(client, MAX1619_REG_W_CONVRATE, 5); - - /* Start monitoring */ - config = i2c_smbus_read_byte_data(client, MAX1619_REG_R_CONFIG); - if (config & 0x40) - i2c_smbus_write_byte_data(client, MAX1619_REG_W_CONFIG, - config & 0xBF); -} - - -static int max1619_detach_client(struct i2c_client *client) -{ - int err; - - i2c_deregister_entry(((struct max1619_data *) - (client->data))->sysctl_id); - if ((err = i2c_detach_client(client))) { - printk(KERN_ERR "max1619.o: Client deregistration failed, " - "client not detached.\n"); - return err; - } - - kfree(client->data); - return 0; -} - -static void max1619_update_client(struct i2c_client *client) -{ - struct max1619_data *data = client->data; - - down(&data->update_lock); - - if ((jiffies - data->last_updated > HZ * 2) || - (jiffies < data->last_updated) || !data->valid) { -#ifdef DEBUG - printk(KERN_DEBUG "max1619.o: Updating data.\n"); -#endif - - data->local_temp = i2c_smbus_read_byte_data(client, - MAX1619_REG_R_LOCAL_TEMP); - data->remote_temp = i2c_smbus_read_byte_data(client, - MAX1619_REG_R_REMOTE_TEMP); - data->remote_high = i2c_smbus_read_byte_data(client, - MAX1619_REG_R_REMOTE_THIGH); - data->remote_low = i2c_smbus_read_byte_data(client, - MAX1619_REG_R_REMOTE_TLOW); - data->remote_max = i2c_smbus_read_byte_data(client, - MAX1619_REG_R_REMOTE_TMAX); - data->remote_hyst = i2c_smbus_read_byte_data(client, - MAX1619_REG_R_REMOTE_THYST); - data->alarms = i2c_smbus_read_byte_data(client, - MAX1619_REG_R_STATUS); - - data->last_updated = jiffies; - data->valid = 1; - } - - up(&data->update_lock); -} - -static void max1619_local_temp(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results) -{ - struct max1619_data *data = client->data; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; /* magnitude */ - else if (operation == SENSORS_PROC_REAL_READ) { - max1619_update_client(client); - results[0] = temp_from_reg(data->local_temp); - *nrels_mag = 1; - } - -} - -static void max1619_remote_temp(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results) -{ - struct max1619_data *data = client->data; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; /* magnitude */ - else if (operation == SENSORS_PROC_REAL_READ) { - max1619_update_client(client); - results[0] = temp_from_reg(data->remote_high); - results[1] = temp_from_reg(data->remote_low); - results[2] = temp_from_reg(data->remote_temp); - *nrels_mag = 3; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag >= 1) { - data->remote_high = temp_to_reg(results[0]); - i2c_smbus_write_byte_data(client, - MAX1619_REG_W_REMOTE_THIGH, data->remote_high); - } - if (*nrels_mag >= 2) { - data->remote_low = temp_to_reg(results[1]); - i2c_smbus_write_byte_data(client, - MAX1619_REG_W_REMOTE_TLOW, data->remote_low); - - } - } -} - -static void max1619_remote_crit(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results) -{ - struct max1619_data *data = client->data; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; /* magnitude */ - else if (operation == SENSORS_PROC_REAL_READ) { - max1619_update_client(client); - results[0] = temp_from_reg(data->remote_max); - results[1] = temp_from_reg(data->remote_hyst); - *nrels_mag = 2; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag >= 1) { - data->remote_max = temp_to_reg(results[0]); - i2c_smbus_write_byte_data(client, - MAX1619_REG_W_REMOTE_TMAX, data->remote_max); - } - if (*nrels_mag >= 2) { - data->remote_hyst = temp_to_reg(results[1]); - i2c_smbus_write_byte_data(client, - MAX1619_REG_W_REMOTE_THYST, data->remote_hyst); - } - } -} - -static void max1619_alarms(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results) -{ - struct max1619_data *data = client->data; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; /* magnitude */ - else if (operation == SENSORS_PROC_REAL_READ) { - max1619_update_client(client); - results[0] = data->alarms; - *nrels_mag = 1; - } -} - - -static int __init sm_max1619_init(void) -{ - printk(KERN_INFO "max1619.o version %s (%s)\n", LM_VERSION, LM_DATE); - return i2c_add_driver(&max1619_driver); -} - -static void __exit sm_max1619_exit(void) -{ - i2c_del_driver(&max1619_driver); -} - -MODULE_AUTHOR("Alexey Fisher "); -MODULE_DESCRIPTION("MAX1619 sensor driver"); -MODULE_LICENSE("GPL"); - -module_init(sm_max1619_init); -module_exit(sm_max1619_exit); diff --git a/kernel/chips/max6650.c b/kernel/chips/max6650.c deleted file mode 100644 index c7975a90..00000000 --- a/kernel/chips/max6650.c +++ /dev/null @@ -1,537 +0,0 @@ -/* - * max6650.c - Part of lm_sensors, Linux kernel modules for hardware - * monitoring. - * - * Author: John Morris - * - * Copyright (c) 2003 Spirent Communications - * - * This module has only been tested with the MAX6651 chip. It should - * work with the MAX6650 also, though with reduced functionality. It - * does not yet distinguish max6650 and max6651 chips. - * - * Tha datasheet was last seen at: - * - * http://pdfserv.maxim-ic.com/en/ds/MAX6650-MAX6651.pdf - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include -#include -#include -#include -#include -#include -#include "version.h" - -#ifndef I2C_DRIVERID_MAX6650 -#define I2C_DRIVERID_MAX6650 1044 -#endif - -/* - * Addresses to scan. There are four disjoint possibilities, by pin config. - */ - -static unsigned short normal_i2c[] = {0x1b, 0x1f, 0x48, 0x4b, SENSORS_I2C_END}; -static unsigned short normal_i2c_range[] = { SENSORS_I2C_END }; -static unsigned int normal_isa[] = { SENSORS_ISA_END }; -static unsigned int normal_isa_range[] = { SENSORS_ISA_END }; - -/* - * Insmod parameters - */ - -SENSORS_INSMOD_1(max6650); - -/* - * MAX 6650/6651 registers - */ - -#define MAX6650_REG_SPEED 0x00 -#define MAX6650_REG_CONFIG 0x02 -#define MAX6650_REG_GPIO_DEF 0x04 -#define MAX6650_REG_DAC 0x06 -#define MAX6650_REG_ALARM_EN 0x08 -#define MAX6650_REG_ALARM 0x0A -#define MAX6650_REG_TACH0 0x0C -#define MAX6650_REG_TACH1 0x0E -#define MAX6650_REG_TACH2 0x10 -#define MAX6650_REG_TACH3 0x12 -#define MAX6650_REG_GPIO_STAT 0x14 -#define MAX6650_REG_COUNT 0x16 - -/* - * Config register bits - */ - -#define MAX6650_CFG_MODE_MASK 0x30 -#define MAX6650_CFG_MODE_ON 0x00 -#define MAX6650_CFG_MODE_OFF 0x10 -#define MAX6650_CFG_MODE_CLOSED_LOOP 0x20 -#define MAX6650_CFG_MODE_OPEN_LOOP 0x30 - -static const u8 tach_reg[] = -{ - MAX6650_REG_TACH0, MAX6650_REG_TACH1, - MAX6650_REG_TACH2, MAX6650_REG_TACH3 -}; - -#define MAX6650_INT_CLK 254000 /* Default clock speed - 254 kHz */ - -/* - * Functions declaration - */ - -static void max6650_fan (struct i2c_client *client, int operation, int - ctl_name, int *nrels_mag, long *results); -static void max6650_speed (struct i2c_client *client, int operation, int - ctl_name, int *nrels_mag, long *results); -static void max6650_xdump (struct i2c_client *client, int operation, int - ctl_name, int *nrels_mag, long *results); -static int max6650_detect(struct i2c_adapter *adapter, int address, unsigned - short flags, int kind); -static int max6650_attach_adapter(struct i2c_adapter *adapter); -static int max6650_detach_client(struct i2c_client *client); -static void max6650_init_client(struct i2c_client *client); -static int max6650_read(struct i2c_client *client, u8 reg); - -/* - * Driver data (common to all clients) - */ - - -static struct i2c_driver max6650_driver = { - .name = "MAX6650/1 sensor driver", - .id = I2C_DRIVERID_MAX6650, - .flags = I2C_DF_NOTIFY, - .attach_adapter = max6650_attach_adapter, - .detach_client = max6650_detach_client -}; - -/* - * Client data (each client gets its own) - */ - -struct max6650_data -{ - struct i2c_client client; - int sysctl_id; - struct semaphore update_lock; - char valid; /* zero until following fields are valid */ - unsigned long last_updated; /* in jiffies */ - - /* register values */ - - u8 speed; - u8 config; - u8 tach[4]; - u8 count; -}; - -/* - * Proc entries - * These files are created for each detected max6650. - */ - -/* -- SENSORS SYSCTL START -- */ - -#define MAX6650_SYSCTL_FAN1 1101 -#define MAX6650_SYSCTL_FAN2 1102 -#define MAX6650_SYSCTL_FAN3 1103 -#define MAX6650_SYSCTL_FAN4 1104 -#define MAX6650_SYSCTL_SPEED 1105 -#define MAX6650_SYSCTL_XDUMP 1106 - - -/* -- SENSORS SYSCTL END -- */ - - -static ctl_table max6650_dir_table_template[] = -{ - {MAX6650_SYSCTL_FAN1, "fan1", NULL, 0, 0644, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &max6650_fan}, - {MAX6650_SYSCTL_FAN2, "fan2", NULL, 0, 0644, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &max6650_fan}, - {MAX6650_SYSCTL_FAN3, "fan3", NULL, 0, 0644, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &max6650_fan}, - {MAX6650_SYSCTL_FAN4, "fan4", NULL, 0, 0644, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &max6650_fan}, - {MAX6650_SYSCTL_SPEED, "speed", NULL, 0, 0644, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &max6650_speed}, - {MAX6650_SYSCTL_XDUMP, "xdump", NULL, 0, 0644, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &max6650_xdump}, - {0} -}; - -/* - * Real code - */ - -static int max6650_attach_adapter(struct i2c_adapter *adapter) -{ - return i2c_detect(adapter, &addr_data, max6650_detect); -} - -/* - * The following function does more than just detection. If detection - * succeeds, it also registers the new chip. - */ - -static int max6650_detect(struct i2c_adapter *adapter, int address, unsigned - short flags, int kind) -{ - struct i2c_client *new_client; - struct max6650_data *data; - int err = 0; - const char *type_name = ""; - const char *client_name = ""; - -#ifdef DEBUG - if (i2c_is_isa_adapter(adapter)) { - printk("max6650.o: Called for an ISA bus adapter, aborting.\n"); - return 0; - } -#endif - - if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) { -#ifdef DEBUG - printk("max6650.o: I2C bus doesn't support byte read mode, skipping.\n"); -#endif - return 0; - } - - if (!(data = kmalloc(sizeof(struct max6650_data), GFP_KERNEL))) { - printk("max6650.o: Out of memory in max6650_detect (new_client).\n"); - return -ENOMEM; - } - - /* - * The common I2C client data is placed right before the - * max6650-specific data. The max6650-specific data is pointed to by the - * data field from the I2C client data. - */ - - new_client = &data->client; - new_client->addr = address; - new_client->data = data; - new_client->adapter = adapter; - new_client->driver = &max6650_driver; - new_client->flags = 0; - - /* - * Now we do the remaining detection. A negative kind means that - * the driver was loaded with no force parameter (default), so we - * must both detect and identify the chip (actually there is only - * one possible kind of chip for now, max6650). A zero kind means that - * the driver was loaded with the force parameter, the detection - * step shall be skipped. A positive kind means that the driver - * was loaded with the force parameter and a given kind of chip is - * requested, so both the detection and the identification steps - * are skipped. - * - * Currently I can find no way to distinguish between a MAX6650 and - * a MAX6651. This driver has only been tried on the latter. - */ - - if (kind < 0) { /* detection */ - if ( - (max6650_read(new_client, MAX6650_REG_CONFIG) & 0xC0) || - (max6650_read(new_client, MAX6650_REG_GPIO_STAT) & 0xE0) || - (max6650_read(new_client, MAX6650_REG_ALARM_EN) & 0xE0) || - (max6650_read(new_client, MAX6650_REG_ALARM) & 0xE0) || - (max6650_read(new_client, MAX6650_REG_COUNT) & 0xFC) - ) - { -#ifdef DEBUG - printk("max6650.o: max6650 detection failed at 0x%02x.\n", - address); -#endif - goto ERROR1; - } - } - - if (kind <= 0) { /* identification */ - kind = max6650; - } - - if (kind <= 0) { /* identification failed */ - printk("max6650.o: Unsupported chip.\n"); - goto ERROR1; - } - - if (kind == max6650) { - type_name = "max6650"; - client_name = "max6650 chip"; - } else { - printk("max6650.o: Unknown kind %d.\n", kind); - goto ERROR1; - } - - /* - * OK, we got a valid chip so we can fill in the remaining client - * fields. - */ - - strcpy(new_client->name, client_name); - data->valid = 0; - init_MUTEX(&data->update_lock); - - /* - * Tell the I2C layer a new client has arrived. - */ - - if ((err = i2c_attach_client(new_client))) { -#ifdef DEBUG - printk("max6650.o: Failed attaching client.\n"); -#endif - goto ERROR1; - } - - /* - * Register a new directory entry. - */ - if ((err = i2c_register_entry(new_client, type_name, - max6650_dir_table_template, - THIS_MODULE)) < 0) { -#ifdef DEBUG - printk("max6650.o: Failed registering directory entry.\n"); -#endif - goto ERROR2; - } - data->sysctl_id = err; - - /* - * Initialize the max6650 chip - */ - max6650_init_client(new_client); - return 0; - -ERROR2: - i2c_detach_client(new_client); -ERROR1: - kfree(data); - return err; -} - -static void max6650_init_client(struct i2c_client *client) -{ - /* Nothing to do here - assume the BIOS has initialized the chip */ -} - -static int max6650_detach_client(struct i2c_client *client) -{ - int err; - - i2c_deregister_entry(((struct max6650_data *) (client->data))->sysctl_id); - if ((err = i2c_detach_client(client))) { - printk("max6650.o: Client deregistration failed, " - "client not detached.\n"); - return err; - } - - kfree(client->data); - return 0; -} - -static int max6650_read(struct i2c_client *client, u8 reg) -{ - return i2c_smbus_read_byte_data(client, reg); -} - -static int max6650_write(struct i2c_client *client, u8 reg, u8 value) -{ - return i2c_smbus_write_byte_data(client, reg, value); -} - -static void max6650_update_client(struct i2c_client *client) -{ - int i; - struct max6650_data *data = client->data; - - down(&data->update_lock); - - if ((jiffies - data->last_updated > HZ) || - (jiffies < data->last_updated) || !data->valid) { -#ifdef DEBUG - printk("max6650.o: Updating max6650 data.\n"); -#endif - data->speed = max6650_read (client, MAX6650_REG_SPEED); - data->config = max6650_read (client, MAX6650_REG_CONFIG); - for (i = 0; i < 4; i++) { - data->tach[i] = max6650_read(client, tach_reg[i]); - } - data->count = max6650_read (client, MAX6650_REG_COUNT); - data->last_updated = jiffies; - data->valid = 1; - } - up(&data->update_lock); -} - -static void max6650_fan (struct i2c_client *client, int operation, int - ctl_name, int *nrels_mag, long *results) -{ - int index = ctl_name - MAX6650_SYSCTL_FAN1; - struct max6650_data *data = client->data; - int tcount; /* Tachometer count time, 0.25 second units */ - - if (operation == SENSORS_PROC_REAL_INFO) { - *nrels_mag = 0; - } else if (operation == SENSORS_PROC_REAL_READ) { - max6650_update_client(client); - - /* - * Calculation details: - * - * Each tachometer counts over an interval given by the "count" - * register (0.25, 0.5, 1 or 2 seconds). This module assumes - * that the fans produce two pulses per revolution (this seems - * to be the most common). - */ - - tcount = 1 << data->count; /* 0.25 second units */ - results[0] = (data->tach[index] * 240) / tcount; /* counts per min */ - results[0] /= 2; /* Assume two counts per rev */ - *nrels_mag = 1; - } -} - -/* - * Set the fan speed to the specified RPM (or read back the RPM setting). - * - * The MAX6650/1 will automatically control fan speed when in closed loop - * mode. - * - * Assumptions: - * - * 1) The MAX6650/1 is running from its internal 254kHz clock (perhaps - * this should be made a module parameter). - * - * 2) The prescaler (low three bits of the config register) has already - * been set to an appropriate value. - * - * The relevant equations are given on pages 21 and 22 of the datasheet. - * - * From the datasheet, the relevant equation when in regulation is: - * - * [fCLK / (128 x (KTACH + 1))] = 2 x FanSpeed / KSCALE - * - * where: - * - * fCLK is the oscillator frequency (either the 254kHz internal - * oscillator or the externally applied clock) - * - * KTACH is the value in the speed register - * - * FanSpeed is the speed of the fan in rps - * - * KSCALE is the prescaler value (1, 2, 4, 8, or 16) - * - * When reading, we need to solve for FanSpeed. When writing, we need to - * solve for KTACH. - * - * Note: this tachometer is completely separate from the tachometers - * used to measure the fan speeds. Only one fan's speed (fan1) is - * controlled. - */ - -static void max6650_speed (struct i2c_client *client, int operation, int - ctl_name, int *nrels_mag, long *results) -{ - struct max6650_data *data = client->data; - int kscale, ktach, fclk, rpm; - - if (operation == SENSORS_PROC_REAL_INFO) { - *nrels_mag = 0; - } else if (operation == SENSORS_PROC_REAL_READ) { - /* - * Use the datasheet equation: - * - * FanSpeed = KSCALE x fCLK / [256 x (KTACH + 1)] - * - * then multiply by 60 to give rpm. - */ - - max6650_update_client(client); - - kscale = 1 << (data->config & 7); - ktach = data->speed; - fclk = MAX6650_INT_CLK; - rpm = 60 * kscale * fclk / (256 * (ktach + 1)); - - results[0] = rpm; - *nrels_mag = 1; - } else if (operation == SENSORS_PROC_REAL_WRITE && *nrels_mag >= 1) { - /* - * Divide the required speed by 60 to get from rpm to rps, then - * use the datasheet equation: - * - * KTACH = [(fCLK x KSCALE) / (256 x FanSpeed)] - 1 - */ - - max6650_update_client(client); - - rpm = results[0]; - kscale = 1 << (data->config & 7); - fclk = MAX6650_INT_CLK; - ktach = ((fclk * kscale) / (256 * rpm / 60)) - 1; - - data->speed = ktach; - data->config = (data->config & ~MAX6650_CFG_MODE_MASK) | - MAX6650_CFG_MODE_CLOSED_LOOP; - max6650_write (client, MAX6650_REG_CONFIG, data->config); - max6650_write (client, MAX6650_REG_SPEED, data->speed); - } -} - -/* - * Debug - dump all registers except the tach counts. - */ - -static void max6650_xdump (struct i2c_client *client, int operation, int - ctl_name, int *nrels_mag, long *results) -{ - if (operation == SENSORS_PROC_REAL_INFO) { - *nrels_mag = 0; - } else if (operation == SENSORS_PROC_REAL_READ) { - results[0] = max6650_read (client, MAX6650_REG_SPEED); - results[1] = max6650_read (client, MAX6650_REG_CONFIG); - results[2] = max6650_read (client, MAX6650_REG_GPIO_DEF); - results[3] = max6650_read (client, MAX6650_REG_DAC); - results[4] = max6650_read (client, MAX6650_REG_ALARM_EN); - results[5] = max6650_read (client, MAX6650_REG_ALARM); - results[6] = max6650_read (client, MAX6650_REG_GPIO_STAT); - results[7] = max6650_read (client, MAX6650_REG_COUNT); - *nrels_mag = 8; - } -} - -static int __init sm_max6650_init(void) -{ - printk(KERN_INFO "max6650.o version %s (%s)\n", LM_VERSION, LM_DATE); - return i2c_add_driver(&max6650_driver); -} - -static void __exit sm_max6650_exit(void) -{ - i2c_del_driver(&max6650_driver); -} - -MODULE_AUTHOR("john.morris@spirentcom.com"); -MODULE_DESCRIPTION("max6650 sensor driver"); -MODULE_LICENSE("GPL"); - -module_init(sm_max6650_init); -module_exit(sm_max6650_exit); diff --git a/kernel/chips/maxilife.c b/kernel/chips/maxilife.c deleted file mode 100644 index 7eab4be5..00000000 --- a/kernel/chips/maxilife.c +++ /dev/null @@ -1,1379 +0,0 @@ -/* - maxilife.c - Part of lm_sensors, Linux kernel modules for hardware - monitoring - Copyright (c) 1999-2000 Fons Rademakers - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -/* The is the driver for the HP MaxiLife Health monitoring system - as used in the line of HP Kayak Workstation PC's. - - The driver supports the following MaxiLife firmware versions: - - 0) HP KAYAK XU/XAs (Dual Pentium II Slot 1, Deschutes/Klamath) - 1) HP KAYAK XU (Dual Xeon [Slot 2] 400/450 Mhz) - 2) HP KAYAK XA (Pentium II Slot 1, monoprocessor) - - Currently firmware auto detection is not implemented. To use the - driver load it with the correct option for you Kayak. For example: - - insmod maxilife.o maxi_version=0 | 1 | 2 - - maxi_version=0 is the default - - This version of MaxiLife is called MaxiLife'98 and has been - succeeded by MaxiLife'99, see below. - - The new version of the driver also supports MaxiLife NBA (New BIOS - Architecture). This new MaxiLife controller provides a much cleaner - machine independent abstraction layer to the MaxiLife controller. - Instead of accessing directly registers (different for each revision) - one now accesses the sensors via unique mailbox tokens that do not - change between revisions. Also the quantities are already in physical - units (degrees, rpms, voltages, etc.) and don't need special conversion - formulas. This new MaxiLife is available on the new 2000 machines, - like the Kayak XU800 and XM600. This hardware is also autodetected. -*/ - -static const char *version_str = "2.00 29/2/2000 Fons Rademakers"; - - -#include -#include -#include -#include -#include -#include "version.h" - -MODULE_LICENSE("GPL"); - -#undef AUTODETECT /* try to autodetect MaxiLife version */ -/*#define AUTODETECT*/ -#define NOWRITE /* don't allow writing to MaxiLife registers */ - -#ifdef AUTODETECT -#include -#include -#endif - -/* Addresses to scan */ -static unsigned short normal_i2c[] = { SENSORS_I2C_END }; -static unsigned short normal_i2c_range[] = { 0x10, 0x14, SENSORS_I2C_END }; -static unsigned int normal_isa[] = { SENSORS_ISA_END }; -static unsigned int normal_isa_range[] = { SENSORS_ISA_END }; - -/* Insmod parameters */ -SENSORS_INSMOD_1(maxilife); - -/* Macro definitions */ -#define LOW(MyWord) ((u8) (MyWord)) -#define HIGH(MyWord) ((u8) (((u16)(MyWord) >> 8) & 0xFF)) - -/*----------------- MaxiLife'98 registers and conversion formulas ------------*/ -#define MAXI_REG_TEMP(nr) (0x60 + (nr)) - -#define MAXI_REG_FAN(nr) (0x65 + (nr)) -#define MAXI_REG_FAN_MIN(nr) ((nr)==0 ? 0xb3 : (nr)==1 ? 0xb3 : 0xab) -#define MAXI_REG_FAN_MINAS(nr) ((nr)==0 ? 0xb3 : (nr)==1 ? 0xab : 0xb3) -#define MAXI_REG_FAN_SPEED(nr) ((nr)==0 ? 0xe4 : (nr)==1 ? 0xe5 : 0xe9) - -#define MAXI_REG_PLL 0xb9 -#define MAXI_REG_PLL_MIN 0xba -#define MAXI_REG_PLL_MAX 0xbb - -#define MAXI_REG_VID(nr) ((nr)==0 ? 0xd1 : (nr)==1 ? 0xd9 : \ - (nr)==2 ? 0xd4 : 0xc5) -#define MAXI_REG_VID_MIN(nr) MAXI_REG_VID(nr)+1 -#define MAXI_REG_VID_MAX(nr) MAXI_REG_VID(nr)+2 - -#define MAXI_REG_DIAG_RT1 0x2c -#define MAXI_REG_DIAG_RT2 0x2d - -#define MAXI_REG_BIOS_CTRL 0x2a - -/* Conversions. Rounding and limit checking is only done on the TO_REG - variants. Note that you should be a bit careful with which arguments - these macros are called: arguments may be evaluated more than once. - Fixing this is just not worth it. */ - - /* 0xfe: fan off, 0xff: stopped (alarm) */ - /* 19531 / val * 60 == 1171860 / val */ -#define FAN_FROM_REG(val) ((val)==0xfe ? 0 : (val)==0xff ? -1 : \ - (val)==0x00 ? -1 : (1171860 / (val))) - -static inline u8 FAN_TO_REG(long rpm) -{ - if (rpm == 0) - return 255; - rpm = SENSORS_LIMIT(rpm, 1, 1000000); - return SENSORS_LIMIT((1171860 + rpm / 2) / (rpm), 1, 254); -} - -#define TEMP_FROM_REG(val) ((val) * 5) -#define TEMP_TO_REG(val) (SENSORS_LIMIT((val+2) / 5),0,0xff) -#define PLL_FROM_REG(val) (((val) * 1000) / 32) -#define PLL_TO_REG(val) (SENSORS_LIMIT((((val) * 32 + 500) / 1000),\ - 0,0xff)) -#define VID_FROM_REG(val) ((val) ? (((val) * 27390) / 256) + 3208 : 0) -#define VID_TO_REG(val) (SENSORS_LIMIT((((val) - 3208) * 256) / 27390, \ - 0,255)) -#define ALARMS_FROM_REG(val) (val) - -/*----------------- MaxiLife'99 mailbox and token definitions ----------------*/ -/* MaxiLife mailbox data register map */ -#define MAXI_REG_MBX_STATUS 0x5a -#define MAXI_REG_MBX_CMD 0x5b -#define MAXI_REG_MBX_TOKEN_H 0x5c -#define MAXI_REG_MBX_TOKEN_L 0x5d -#define MAXI_REG_MBX_DATA 0x60 - -/* Mailbox status register definition */ -#define MAXI_STAT_IDLE 0xff -#define MAXI_STAT_OK 0x00 -#define MAXI_STAT_BUSY 0x0b -/* other values not used */ - -/* Mailbox command register opcodes */ -#define MAXI_CMD_READ 0x02 -#define MAXI_CMD_WRITE 0x03 -/* other values not used */ - -/* MaxiLife NBA Hardware monitoring tokens */ - -/* Alarm tokens (0x1xxx) */ -#define MAXI_TOK_ALARM(nr) (0x1000 + (nr)) -#define MAXI_TOK_ALARM_EVENT 0x1000 -#define MAXI_TOK_ALARM_FAN 0x1001 -#define MAXI_TOK_ALARM_TEMP 0x1002 -#define MAXI_TOK_ALARM_VID 0x1003 /* voltages */ -#define MAXI_TOK_ALARM_AVID 0x1004 /* additional voltages */ -#define MAXI_TOK_ALARM_PWR 0x1101 /* power supply glitch */ - -/* Fan status tokens (0x20xx) */ -#define MAXI_TOK_FAN(nr) (0x2000 + (nr)) -#define MAXI_TOK_FAN_CPU 0x2000 -#define MAXI_TOK_FAN_PCI 0x2001 -#define MAXI_TOK_FAN_HDD 0x2002 /* hard disk bay fan */ -#define MAXI_TOK_FAN_SINK 0x2003 /* heatsink */ - -/* Temperature status tokens (0x21xx) */ -#define MAXI_TOK_TEMP(nr) (0x2100 + (nr)) -#define MAXI_TOK_TEMP_CPU1 0x2100 -#define MAXI_TOK_TEMP_CPU2 0x2101 -#define MAXI_TOK_TEMP_PCI 0x2102 /* PCI/ambient temp */ -#define MAXI_TOK_TEMP_HDD 0x2103 /* hard disk bay temp */ -#define MAXI_TOK_TEMP_MEM 0x2104 /* mother board temp */ -#define MAXI_TOK_TEMP_CPU 0x2105 /* CPU reference temp */ - -/* Voltage status tokens (0x22xx) */ -#define MAXI_TOK_VID(nr) (0x2200 + (nr)) -#define MAXI_TOK_VID_12 0x2200 /* +12 volt */ -#define MAXI_TOK_VID_CPU1 0x2201 /* cpu 1 voltage */ -#define MAXI_TOK_VID_CPU2 0x2202 /* cpu 2 voltage */ -#define MAXI_TOK_VID_L2 0x2203 /* level 2 cache voltage */ -#define MAXI_TOK_VID_M12 0x2204 /* -12 volt */ - -/* Additive voltage status tokens (0x23xx) */ -#define MAXI_TOK_AVID(nr) (0x2300 + (nr)) -#define MAXI_TOK_AVID_15 0x2300 /* 1.5 volt */ -#define MAXI_TOK_AVID_18 0x2301 /* 1.8 volt */ -#define MAXI_TOK_AVID_25 0x2302 /* 2.5 volt */ -#define MAXI_TOK_AVID_33 0x2303 /* 3.3 volt */ -#define MAXI_TOK_AVID_5 0x2304 /* 5 volt */ -#define MAXI_TOK_AVID_M5 0x2305 /* -5 volt */ -#define MAXI_TOK_AVID_BAT 0x2306 /* battery voltage */ - -/* Threshold tokens (0x3xxx) */ -#define MAXI_TOK_MIN(token) ((token) + 0x1000) -#define MAXI_TOK_MAX(token) ((token) + 0x1800) - -/* LCD Panel (0x4xxx) */ -#define MAXI_TOK_LCD(nr) (0x4000 + (nr)) -#define MAXI_TOK_LCD_LINE1 0x4000 -#define MAXI_TOK_LCD_LINE2 0x4001 -#define MAXI_TOK_LCD_LINE3 0x4002 -#define MAXI_TOK_LCD_LINE4 0x4003 - - /* 0xfe: fan off, 0xff: stopped (alarm) */ - /* or not available */ -#define FAN99_FROM_REG(val) ((val)==0xfe ? 0 : (val)==0xff ? -1 : ((val)*39)) - - /* when no CPU2 temp is 127 (0x7f) */ -#define TEMP99_FROM_REG(val) ((val)==0x7f ? -1 : (val)==0xff ? -1 : (val)) - -#define VID99_FROM_REG(nr,val) ((val)==0xff ? 0 : \ - (nr)==1 ? ((val) * 608) : \ - (nr)==2 ? ((val) * 160) : \ - (nr)==3 ? ((val) * 160) : \ - (nr)==4 ? (val) /* no formula spcified */ : \ - (nr)==5 ? ((val) * 823 - 149140) : 0) - - -/* The following product codenames apply: - Cristal/Geronimo: HP KAYAK XU/XAs - (Dual Pentium II Slot 1, Deschutes/Klamath) - Cognac: HP KAYAK XU (Dual Xeon [Slot 2] 400/450 Mhz) - Ashaki: HP KAYAK XA (Pentium II Slot 1, monoprocessor) - NBA: New BIOS Architecture, Kayak XU800, XM600, ... */ - -enum maxi_type { cristal, cognac, ashaki, nba }; -enum sensor_type { fan, temp, vid, pll, lcd, alarm }; - -/* For each registered MaxiLife controller, we need to keep some data in - memory. It is dynamically allocated, at the same time when a new MaxiLife - client is allocated. We assume MaxiLife will only be present on the - SMBus and not on the ISA bus. */ -struct maxi_data { - struct i2c_client client; - int sysctl_id; - enum maxi_type type; - - struct semaphore update_lock; - char valid; /* !=0 if following fields are valid */ - unsigned long last_updated; /* In jiffies */ - - u8 fan[4]; /* Register value */ - u8 fan_min[4]; /* Register value */ - u8 fan_speed[4]; /* Register value */ - u8 fan_div[4]; /* Static value */ - u8 temp[6]; /* Register value */ - u8 temp_max[6]; /* Static value */ - u8 temp_hyst[6]; /* Static value */ - u8 pll; /* Register value */ - u8 pll_min; /* Register value */ - u8 pll_max; /* register value */ - u8 vid[5]; /* Register value */ - u8 vid_min[5]; /* Register value */ - u8 vid_max[5]; /* Register value */ - u8 lcd[4][17]; /* Four LCD lines */ - u16 alarms; /* Register encoding, combined */ -}; - - -static int maxi_attach_adapter(struct i2c_adapter *adapter); -static int maxi_detect(struct i2c_adapter *adapter, int address, - unsigned short flags, int kind); -static int maxi_detach_client(struct i2c_client *client); - -static int maxi_read_value(struct i2c_client *client, u8 register); -static int maxi_read_token(struct i2c_client *client, u16 token); -#ifndef NOWRITE -static int maxi_write_value(struct i2c_client *client, u8 register, - u8 value); -#endif -static int maxi_write_token_loop(struct i2c_client *client, u16 token, - u8 len, u8 * values); - -static void maxi_update_client(struct i2c_client *client); -static void maxi99_update_client(struct i2c_client *client, - enum sensor_type sensor, int which); -static void maxi_init_client(struct i2c_client *client); - -static void maxi_fan(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void maxi99_fan(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void maxi_temp(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void maxi99_temp(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void maxi_pll(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void maxi_vid(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void maxi99_vid(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void maxi_lcd(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void maxi_alarms(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); - -/* The driver. I choose to use type i2c_driver, as at is identical to - the smbus_driver. */ -static struct i2c_driver maxi_driver = { - .name = "HP MaxiLife driver", - .id = I2C_DRIVERID_MAXILIFE, - .flags = I2C_DF_NOTIFY, - .attach_adapter = maxi_attach_adapter, - .detach_client = maxi_detach_client, -}; - -/* Default firmware version. Use module option "maxi_version" - to set desired version. Auto detect is not yet working */ -static int maxi_version = cristal; - -/* The /proc/sys entries */ - -/* -- SENSORS SYSCTL START -- */ -#define MAXI_SYSCTL_FAN1 1101 /* Rotations/min */ -#define MAXI_SYSCTL_FAN2 1102 /* Rotations/min */ -#define MAXI_SYSCTL_FAN3 1103 /* Rotations/min */ -#define MAXI_SYSCTL_FAN4 1104 /* Rotations/min */ -#define MAXI_SYSCTL_TEMP1 1201 /* Degrees Celsius */ -#define MAXI_SYSCTL_TEMP2 1202 /* Degrees Celsius */ -#define MAXI_SYSCTL_TEMP3 1203 /* Degrees Celsius */ -#define MAXI_SYSCTL_TEMP4 1204 /* Degrees Celsius */ -#define MAXI_SYSCTL_TEMP5 1205 /* Degrees Celsius */ -#define MAXI_SYSCTL_TEMP6 1206 /* Degrees Celsius */ -#define MAXI_SYSCTL_PLL 1301 /* MHz */ -#define MAXI_SYSCTL_VID1 1401 /* Volts / 6.337, for nba just Volts */ -#define MAXI_SYSCTL_VID2 1402 /* Volts */ -#define MAXI_SYSCTL_VID3 1403 /* Volts */ -#define MAXI_SYSCTL_VID4 1404 /* Volts */ -#define MAXI_SYSCTL_VID5 1405 /* Volts */ -#define MAXI_SYSCTL_LCD1 1501 /* Line 1 of LCD */ -#define MAXI_SYSCTL_LCD2 1502 /* Line 2 of LCD */ -#define MAXI_SYSCTL_LCD3 1503 /* Line 3 of LCD */ -#define MAXI_SYSCTL_LCD4 1504 /* Line 4 of LCD */ -#define MAXI_SYSCTL_ALARMS 2001 /* Bitvector (see below) */ - -#define MAXI_ALARM_VID4 0x0001 -#define MAXI_ALARM_TEMP2 0x0002 -#define MAXI_ALARM_VID1 0x0004 -#define MAXI_ALARM_VID2 0x0008 -#define MAXI_ALARM_VID3 0x0010 -#define MAXI_ALARM_PLL 0x0080 -#define MAXI_ALARM_TEMP4 0x0100 -#define MAXI_ALARM_TEMP5 0x0200 -#define MAXI_ALARM_FAN1 0x1000 -#define MAXI_ALARM_FAN2 0x2000 -#define MAXI_ALARM_FAN3 0x4000 - -#define MAXI_ALARM_FAN 0x0100 /* To be used with MaxiLife'99 */ -#define MAXI_ALARM_VID 0x0200 /* The MSB specifies which sensor */ -#define MAXI_ALARM_TEMP 0x0400 /* in the alarm group failed, i.e.: */ -#define MAXI_ALARM_VADD 0x0800 /* 0x0402 = TEMP2 failed = CPU2 temp */ - -/* -- SENSORS SYSCTL END -- */ - -/* These files are created for each detected MaxiLife processor. - This is just a template; though at first sight, you might think we - could use a statically allocated list, we need some way to get back - to the parent - which is done through one of the 'extra' fields - which are initialized when a new copy is allocated. */ -static ctl_table maxi_dir_table_template[] = { - {MAXI_SYSCTL_FAN1, "fan1", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &maxi_fan}, - {MAXI_SYSCTL_FAN2, "fan2", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &maxi_fan}, - {MAXI_SYSCTL_FAN3, "fan3", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &maxi_fan}, - {MAXI_SYSCTL_FAN4, "fan4", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &maxi_fan}, - {MAXI_SYSCTL_TEMP1, "temp1", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &maxi_temp}, - {MAXI_SYSCTL_TEMP2, "temp2", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &maxi_temp}, - {MAXI_SYSCTL_TEMP3, "temp3", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &maxi_temp}, - {MAXI_SYSCTL_TEMP4, "temp4", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &maxi_temp}, - {MAXI_SYSCTL_TEMP5, "temp5", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &maxi_temp}, - {MAXI_SYSCTL_TEMP6, "temp6", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &maxi_temp}, - {MAXI_SYSCTL_PLL, "pll", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &maxi_pll}, - {MAXI_SYSCTL_VID1, "vid1", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &maxi_vid}, - {MAXI_SYSCTL_VID2, "vid2", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &maxi_vid}, - {MAXI_SYSCTL_VID3, "vid3", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &maxi_vid}, - {MAXI_SYSCTL_VID4, "vid4", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &maxi_vid}, - {MAXI_SYSCTL_VID5, "vid5", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &maxi_vid}, - {MAXI_SYSCTL_LCD1, "lcd1", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &maxi_lcd}, - {MAXI_SYSCTL_LCD2, "lcd2", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &maxi_lcd}, - {MAXI_SYSCTL_LCD3, "lcd3", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &maxi_lcd}, - {MAXI_SYSCTL_LCD4, "lcd4", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &maxi_lcd}, - {MAXI_SYSCTL_ALARMS, "alarms", NULL, 0, 0444, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &maxi_alarms}, - {0} -}; - -/* This function is called when: - - maxi_driver is inserted (when this module is loaded), for each - available adapter - - when a new adapter is inserted (and maxi_driver is still present) */ -static int maxi_attach_adapter(struct i2c_adapter *adapter) -{ - return i2c_detect(adapter, &addr_data, maxi_detect); -} - -/* This function is called by i2c_detect */ -int maxi_detect(struct i2c_adapter *adapter, int address, - unsigned short flags, int kind) -{ - struct i2c_client *new_client; - struct maxi_data *data; - enum maxi_type type = 0; - int i, j, err = 0; - const char *type_name = NULL, *client_name = NULL; - - if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) - goto ERROR0; - - /* OK. For now, we presume we have a valid client. We now create the - client structure, even though we cannot fill it completely yet. - But it allows us to access maxi_{read,write}_value. */ - if (!(data = kmalloc(sizeof(struct maxi_data), GFP_KERNEL))) { - err = -ENOMEM; - goto ERROR0; - } - - /* Fill the new client structure with data */ - new_client = &data->client; - new_client->addr = address; - new_client->data = data; - new_client->adapter = adapter; - new_client->driver = &maxi_driver; - new_client->flags = 0; - - /* Now we do the remaining detection. */ - if (kind < 0) { - if (i2c_smbus_read_byte_data - (new_client, MAXI_REG_MBX_STATUS) < 0) - goto ERROR2; - } - - /* Determine the chip type - only one kind supported */ - if (kind <= 0) - kind = maxilife; - - if (kind == maxilife) { - /* Detect if the machine has a MaxiLife NBA controller. - The right way to perform this check is to do a read/modify/write - on register MbxStatus (5A): - - Read 5A (value 0 for non-NBA firmware, FF (MbxIdle on NBA-firmware) - - Write 55 on 5A, then read back 5A - Non-NBA firmware: value is 55 (reg 5A is a standard writable reg) - NBA firmaware: value is FF (write-protect on MbxStatus active) */ - int stat; - i2c_smbus_write_byte_data(new_client, MAXI_REG_MBX_STATUS, - 0x55); - stat = - i2c_smbus_read_byte_data(new_client, - MAXI_REG_MBX_STATUS); - - /*if (stat == MAXI_STAT_IDLE || stat == MAXI_STAT_OK) */ - if (stat != 0x55) - maxi_version = nba; -#ifdef AUTODETECT - else { - /* The right way to get the platform info is to read the firmware - revision from serial EEPROM (addr=0x54), at offset 0x0045. - This is a string as: - "CG 00.04" -> Cristal [XU] / Geronimo [XAs] - "CO 00.03" -> Cognac [XU] - "AS 00.01" -> Ashaki [XA] */ -#if 0 - int biosctl; - biosctl = - i2c_smbus_read_byte_data(new_client, - MAXI_REG_BIOS_CTRL); - i2c_smbus_write_byte_data(new_client, - MAXI_REG_BIOS_CTRL, - biosctl | 4); - err = eeprom_read_byte_data(adapter, 0x54, 0x45); - i2c_smbus_write_byte_data(new_client, - MAXI_REG_BIOS_CTRL, - biosctl); -#endif - int i; - char *biosmem, *bm; - bm = biosmem = ioremap(0xe0000, 0x20000); - if (biosmem) { - printk("begin of bios search\n"); - for (i = 0; i < 0x20000; i++) { - if (*bm == 'C') { - char *s = bm; - while (s && isprint(*s)) { - printk("%c", *s); - s++; - } - printk("\n"); - if (!strncmp - (bm, "CG 00.04", 8)) { - maxi_version = - cristal; - printk - ("maxilife: found MaxiLife Rev CG 00.04\n"); - break; - } - if (!strncmp - (bm, "CO 00.03", 8)) { - maxi_version = - cognac; - printk - ("maxilife: found MaxiLife Rev CO 00.03\n"); - break; - } - } - if (*bm == 'A' && *(bm + 1) == 'S') { - char *s = bm; - while (s && isprint(*s)) { - printk("%c", *s); - s++; - } - printk("\n"); - if (!strncmp - (bm, "AS 00.01", 8)) { - maxi_version = - ashaki; - printk - ("maxilife: found MaxiLife Rev AS 00.01\n"); - break; - } - } - bm++; - } - printk("end of bios search\n"); - } else - printk("could not map bios memory\n"); - } -#endif - - if (maxi_version == cristal) { - type = cristal; - type_name = "maxilife-cg"; - client_name = "HP MaxiLife Rev CG 00.04"; - printk - ("maxilife: HP KAYAK XU/XAs (Dual Pentium II Slot 1)\n"); - } else if (maxi_version == cognac) { - type = cognac; - type_name = "maxilife-co"; - client_name = "HP MaxiLife Rev CO 00.03"; - printk - ("maxilife: HP KAYAK XU (Dual Xeon Slot 2 400/450 Mhz)\n"); - } else if (maxi_version == ashaki) { - type = ashaki; - type_name = "maxilife-as"; - client_name = "HP MaxiLife Rev AS 00.01"; - printk - ("maxilife: HP KAYAK XA (Pentium II Slot 1, monoprocessor)\n"); - } else if (maxi_version == nba) { - type = nba; - type_name = "maxilife-nba"; - client_name = "HP MaxiLife NBA"; - printk("maxilife: HP KAYAK XU800/XM600\n"); - } else { -#ifdef AUTODETECT - printk - ("maxilife: Warning: probed non-maxilife chip?!? (%x)\n", - err); -#else - printk - ("maxilife: Error: specified wrong maxi_version (%d)\n", - maxi_version); -#endif - goto ERROR2; - } - } - - /* Fill in the remaining client fields and put it into the global list */ - strcpy(new_client->name, client_name); - ((struct maxi_data *) (new_client->data))->type = type; - - for (i = 0; i < 4; i++) - for (j = 0; j < 17; j++) - ((struct maxi_data *) (new_client->data))-> - lcd[i][j] = (u8) 0; - - data->valid = 0; - init_MUTEX(&data->update_lock); - - /* Tell i2c-core that a new client has arrived */ - if ((err = i2c_attach_client(new_client))) - goto ERROR2; - - /* Register a new directory entry with module sensors */ - if ((err = i2c_register_entry(new_client, type_name, - maxi_dir_table_template, - THIS_MODULE)) < 0) - goto ERROR4; - data->sysctl_id = err; - - /* Initialize the MaxiLife chip */ - maxi_init_client(new_client); - return 0; - - /* OK, this is not exactly good programming practice, usually. - But it is very code-efficient in this case. */ - ERROR4: - i2c_detach_client(new_client); - ERROR2: - kfree(data); - ERROR0: - return err; -} - -/* This function is called whenever a client should be removed: - - maxi_driver is removed (when this module is unloaded) - - when an adapter is removed which has a maxi client (and maxi_driver - is still present). */ -static int maxi_detach_client(struct i2c_client *client) -{ - int err; - - i2c_deregister_entry(((struct maxi_data *) (client->data))-> - sysctl_id); - - if ((err = i2c_detach_client(client))) { - printk - ("maxilife: Client deregistration failed, client not detached.\n"); - return err; - } - kfree(client->data); - return 0; -} - -/* Read byte from specified register (-1 in case of error, value otherwise). */ -static int maxi_read_value(struct i2c_client *client, u8 reg) -{ - return i2c_smbus_read_byte_data(client, reg); -} - -/* Read the byte value for a MaxiLife token (-1 in case of error, value otherwise */ -static int maxi_read_token(struct i2c_client *client, u16 token) -{ - u8 lowToken, highToken; - int error, value; - - lowToken = LOW(token); - highToken = HIGH(token); - - /* Set mailbox status register to idle state. */ - error = - i2c_smbus_write_byte_data(client, MAXI_REG_MBX_STATUS, - MAXI_STAT_IDLE); - if (error < 0) - return error; - - /* Check for mailbox idle state. */ - error = i2c_smbus_read_byte_data(client, MAXI_REG_MBX_STATUS); - if (error != MAXI_STAT_IDLE) - return -1; - - /* Write the most significant byte of the token we want to read. */ - error = - i2c_smbus_write_byte_data(client, MAXI_REG_MBX_TOKEN_H, - highToken); - if (error < 0) - return error; - - /* Write the least significant byte of the token we want to read. */ - error = - i2c_smbus_write_byte_data(client, MAXI_REG_MBX_TOKEN_L, - lowToken); - if (error < 0) - return error; - - /* Write the read token opcode to the mailbox. */ - error = - i2c_smbus_write_byte_data(client, MAXI_REG_MBX_CMD, - MAXI_CMD_READ); - if (error < 0) - return error; - - /* Check for transaction completion */ - do { - error = - i2c_smbus_read_byte_data(client, MAXI_REG_MBX_STATUS); - } while (error == MAXI_STAT_BUSY); - if (error != MAXI_STAT_OK) - return -1; - - /* Read the value of the token. */ - value = i2c_smbus_read_byte_data(client, MAXI_REG_MBX_DATA); - if (value == -1) - return -1; - - /* set mailbox status to idle to complete transaction. */ - error = - i2c_smbus_write_byte_data(client, MAXI_REG_MBX_STATUS, - MAXI_STAT_IDLE); - if (error < 0) - return error; - - return value; -} - -#ifndef NOWRITE -/* Write byte to specified register (-1 in case of error, 0 otherwise). */ -static int maxi_write_value(struct i2c_client *client, u8 reg, u8 value) -{ - return i2c_smbus_write_byte_data(client, reg, value); -} -#endif - -/* Write a set of len byte values to MaxiLife token (-1 in case of error, 0 otherwise). */ -int maxi_write_token_loop(struct i2c_client *client, u16 token, u8 len, - u8 * values) -{ - u8 lowToken, highToken, bCounter; - int error; - - lowToken = LOW(token); - highToken = HIGH(token); - - /* Set mailbox status register to idle state. */ - error = - i2c_smbus_write_byte_data(client, MAXI_REG_MBX_STATUS, - MAXI_STAT_IDLE); - if (error < 0) - return error; - - /* Check for mailbox idle state. */ - error = i2c_smbus_read_byte_data(client, MAXI_REG_MBX_STATUS); - if (error != MAXI_STAT_IDLE) - return -1; - - for (bCounter = 0; (bCounter < len && bCounter < 32); bCounter++) { - error = - i2c_smbus_write_byte_data(client, - (u8) (MAXI_REG_MBX_DATA + - bCounter), - values[bCounter]); - if (error < 0) - return error; - } - - /* Write the most significant byte of the token we want to read. */ - error = - i2c_smbus_write_byte_data(client, MAXI_REG_MBX_TOKEN_H, - highToken); - if (error < 0) - return error; - - /* Write the least significant byte of the token we want to read. */ - error = - i2c_smbus_write_byte_data(client, MAXI_REG_MBX_TOKEN_L, - lowToken); - if (error < 0) - return error; - - /* Write the write token opcode to the mailbox. */ - error = - i2c_smbus_write_byte_data(client, MAXI_REG_MBX_CMD, - MAXI_CMD_WRITE); - if (error < 0) - return error; - - /* Check for transaction completion */ - do { - error = - i2c_smbus_read_byte_data(client, MAXI_REG_MBX_STATUS); - } while (error == MAXI_STAT_BUSY); - if (error != MAXI_STAT_OK) - return -1; - - /* set mailbox status to idle to complete transaction. */ - return i2c_smbus_write_byte_data(client, MAXI_REG_MBX_STATUS, - MAXI_STAT_IDLE); -} - -/* Called when we have found a new MaxiLife. */ -static void maxi_init_client(struct i2c_client *client) -{ - struct maxi_data *data = client->data; - - if (data->type == nba) { - strcpy(data->lcd[2], " Linux MaxiLife"); - maxi_write_token_loop(client, MAXI_TOK_LCD(2), - strlen(data->lcd[2]) + 1, - data->lcd[2]); - } -} - -static void maxi_update_client(struct i2c_client *client) -{ - struct maxi_data *data = client->data; - int i; - - if (data->type == nba) { - printk - ("maxi_update_client should never be called by nba\n"); - return; - } - - down(&data->update_lock); - - if ((jiffies - data->last_updated > HZ + HZ / 2) || - (jiffies < data->last_updated) || !data->valid) { - -#ifdef DEBUG - printk("maxilife: Starting MaxiLife update\n"); -#endif - for (i = 0; i < 5; i++) - data->temp[i] = - maxi_read_value(client, MAXI_REG_TEMP(i)); - switch (data->type) { - case cristal: - data->temp[0] = 0; /* not valid */ - data->temp_max[0] = 0; - data->temp_hyst[0] = 0; - data->temp_max[1] = 110; /* max PCI slot temp */ - data->temp_hyst[1] = 100; - data->temp_max[2] = 120; /* max BX chipset temp */ - data->temp_hyst[2] = 110; - data->temp_max[3] = 100; /* max HDD temp */ - data->temp_hyst[3] = 90; - data->temp_max[4] = 120; /* max CPU temp */ - data->temp_hyst[4] = 110; - break; - - case cognac: - data->temp_max[0] = 120; /* max CPU1 temp */ - data->temp_hyst[0] = 110; - data->temp_max[1] = 110; /* max PCI slot temp */ - data->temp_hyst[1] = 100; - data->temp_max[2] = 120; /* max CPU2 temp */ - data->temp_hyst[2] = 110; - data->temp_max[3] = 100; /* max HDD temp */ - data->temp_hyst[3] = 90; - data->temp_max[4] = 120; /* max reference CPU temp */ - data->temp_hyst[4] = 110; - break; - - case ashaki: - data->temp[0] = 0; /* not valid */ - data->temp_max[0] = 0; - data->temp_hyst[0] = 0; - data->temp_max[1] = 110; /* max PCI slot temp */ - data->temp_hyst[1] = 100; - data->temp[2] = 0; /* not valid */ - data->temp_max[2] = 0; - data->temp_hyst[2] = 0; - data->temp_max[3] = 100; /* max HDD temp */ - data->temp_hyst[3] = 90; - data->temp_max[4] = 120; /* max CPU temp */ - data->temp_hyst[4] = 110; - break; - - default: - printk("maxilife: Unknown MaxiLife chip\n"); - } - data->temp[5] = 0; /* only used by MaxiLife'99 */ - data->temp_max[5] = 0; - data->temp_hyst[5] = 0; - - for (i = 0; i < 3; i++) { - data->fan[i] = - maxi_read_value(client, MAXI_REG_FAN(i)); - data->fan_speed[i] = - maxi_read_value(client, MAXI_REG_FAN_SPEED(i)); - data->fan_div[i] = 4; - if (data->type == ashaki) - data->fan_min[i] = - maxi_read_value(client, - MAXI_REG_FAN_MINAS(i)); - else - data->fan_min[i] = - maxi_read_value(client, - MAXI_REG_FAN_MIN(i)); - } - data->fan[3] = 0xff; /* only used by MaxiLife'99 */ - data->fan_speed[3] = 0; - data->fan_div[3] = 4; /* avoid possible /0 */ - data->fan_min[3] = 0; - - data->pll = maxi_read_value(client, MAXI_REG_PLL); - data->pll_min = maxi_read_value(client, MAXI_REG_PLL_MIN); - data->pll_max = maxi_read_value(client, MAXI_REG_PLL_MAX); - - for (i = 0; i < 4; i++) { - data->vid[i] = - maxi_read_value(client, MAXI_REG_VID(i)); - data->vid_min[i] = - maxi_read_value(client, MAXI_REG_VID_MIN(i)); - data->vid_max[i] = - maxi_read_value(client, MAXI_REG_VID_MAX(i)); - } - switch (data->type) { - case cristal: - data->vid[3] = 0; /* no voltage cache L2 */ - data->vid_min[3] = 0; - data->vid_max[3] = 0; - break; - - case cognac: - break; - - case ashaki: - data->vid[1] = 0; /* no voltage CPU 2 */ - data->vid_min[1] = 0; - data->vid_max[1] = 0; - data->vid[3] = 0; /* no voltage cache L2 */ - data->vid_min[3] = 0; - data->vid_max[3] = 0; - break; - - default: - printk("maxilife: Unknown MaxiLife chip\n"); - } - data->vid[4] = 0; /* only used by MaxliLife'99 */ - data->vid_min[4] = 0; - data->vid_max[4] = 0; - - data->alarms = maxi_read_value(client, MAXI_REG_DIAG_RT1) + - (maxi_read_value(client, MAXI_REG_DIAG_RT2) << 8); - - data->last_updated = jiffies; - data->valid = 1; - } - - up(&data->update_lock); -} - -void maxi99_update_client(struct i2c_client *client, - enum sensor_type sensor, int which) -{ - static unsigned long last_updated[6][6]; /* sensor, which */ - struct maxi_data *data = client->data; - - down(&data->update_lock); - - /*maxi_write_token_loop(client, MAXI_TOK_LCD_LINE3, 13, "Linux 2.2.13"); */ - - if ((jiffies - last_updated[sensor][which] > 2 * HZ) || - (jiffies < last_updated[sensor][which] - || !last_updated[sensor][which])) { - - int tmp, i; - - switch (sensor) { - case fan: - for (i = 0; i < 4; i++) { - if (i == which) { - tmp = - maxi_read_token(client, - MAXI_TOK_FAN - (i)); - data->fan[i] = - maxi_read_token(client, - MAXI_TOK_FAN - (i)); - data->fan_speed[i] = - maxi_read_token(client, - MAXI_TOK_MAX - (MAXI_TOK_FAN - (i))); - data->fan_div[i] = 1; - data->fan_min[i] = 0; - } - } - break; - - case temp: - for (i = 0; i < 6; i++) { - if (i == which) { - data->temp[i] = - maxi_read_token(client, - MAXI_TOK_TEMP - (i)); - data->temp_max[i] = - maxi_read_token(client, - MAXI_TOK_MAX - (MAXI_TOK_TEMP - (i))); - data->temp_hyst[i] = - data->temp_max[i] - 5; - } - } - break; - - case vid: - for (i = 0; i < 5; i++) { - if (i == which) { - data->vid[i] = - maxi_read_token(client, - MAXI_TOK_VID - (i)); - data->vid_min[i] = - maxi_read_token(client, - MAXI_TOK_MIN - (MAXI_TOK_VID - (i))); - data->vid_max[i] = - maxi_read_token(client, - MAXI_TOK_MAX - (MAXI_TOK_VID - (i))); - } - } - break; - - case pll: - data->pll = 0; - data->pll_min = 0; - data->pll_max = 0; - break; - - case alarm: - data->alarms = - (maxi_read_token(client, MAXI_TOK_ALARM_EVENT) - << 8); - if (data->alarms) - data->alarms += - data->alarms == - (1 << 8) ? maxi_read_token(client, - MAXI_TOK_ALARM_FAN) - : data->alarms == - (2 << 8) ? maxi_read_token(client, - MAXI_TOK_ALARM_VID) - : data->alarms == - (4 << 8) ? maxi_read_token(client, - MAXI_TOK_ALARM_TEMP) - : data->alarms == - (8 << 8) ? maxi_read_token(client, - MAXI_TOK_ALARM_FAN) - : 0; - break; - - default: - printk("maxilife: Unknown sensor type\n"); - } - - last_updated[sensor][which] = jiffies; - data->valid = 1; - } - - up(&data->update_lock); -} - -/* The next few functions are the call-back functions of the /proc/sys and - sysctl files. Which function is used is defined in the ctl_table in - the extra1 field. - Each function must return the magnitude (power of 10 to divide the data - with) if it is called with operation==SENSORS_PROC_REAL_INFO. It must - put a maximum of *nrels elements in results reflecting the data of this - file, and set *nrels to the number it actually put in it, if operation== - SENSORS_PROC_REAL_READ. Finally, it must get upto *nrels elements from - results and write them to the chip, if operations==SENSORS_PROC_REAL_WRITE. - Note that on SENSORS_PROC_REAL_READ, I do not check whether results is - large enough (by checking the incoming value of *nrels). This is not very - good practice, but as long as you put less than about 5 values in results, - you can assume it is large enough. */ -void maxi_fan(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct maxi_data *data = client->data; - int nr; - - if (data->type == nba) { - maxi99_fan(client, operation, ctl_name, nrels_mag, - results); - return; - } - - nr = ctl_name - MAXI_SYSCTL_FAN1 + 1; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - maxi_update_client(client); - results[0] = FAN_FROM_REG(data->fan_min[nr - 1]); - results[1] = data->fan_div[nr - 1]; - results[2] = FAN_FROM_REG(data->fan[nr - 1]); - *nrels_mag = 3; - } else if (operation == SENSORS_PROC_REAL_WRITE) { -#ifndef NOWRITE - if (*nrels_mag >= 1) { - data->fan_min[nr - 1] = FAN_TO_REG(results[0]); - maxi_write_value(client, MAXI_REG_FAN_MIN(nr), - data->fan_min[nr - 1]); - } -#endif - } -} - -void maxi99_fan(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct maxi_data *data = client->data; - int nr; - - nr = ctl_name - MAXI_SYSCTL_FAN1 + 1; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - maxi99_update_client(client, fan, nr - 1); - results[0] = FAN99_FROM_REG(data->fan_min[nr - 1]); /* min rpm */ - results[1] = data->fan_div[nr - 1]; /* divisor */ - results[2] = FAN99_FROM_REG(data->fan[nr - 1]); /* rpm */ - *nrels_mag = 3; - } else if (operation == SENSORS_PROC_REAL_WRITE) { -#ifndef NOWRITE - /* still to do */ - if (*nrels_mag >= 1) { - data->fan_min[nr - 1] = FAN_TO_REG(results[0]); - maxi_write_value(client, MAXI_REG_FAN_MIN(nr), - data->fan_min[nr - 1]); - } -#endif - } -} - -void maxi_temp(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct maxi_data *data = client->data; - int nr; - - if (data->type == nba) { - maxi99_temp(client, operation, ctl_name, nrels_mag, - results); - return; - } - - nr = ctl_name - MAXI_SYSCTL_TEMP1 + 1; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 1; - else if (operation == SENSORS_PROC_REAL_READ) { - maxi_update_client(client); - results[0] = TEMP_FROM_REG(data->temp_max[nr - 1]); - results[1] = TEMP_FROM_REG(data->temp_hyst[nr - 1]); - results[2] = TEMP_FROM_REG(data->temp[nr - 1]); - *nrels_mag = 3; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - /* temperature range can not be changed */ - } -} - -void maxi99_temp(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct maxi_data *data = client->data; - int nr; - - nr = ctl_name - MAXI_SYSCTL_TEMP1 + 1; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - maxi99_update_client(client, temp, nr - 1); - results[0] = TEMP99_FROM_REG(data->temp_max[nr - 1]); - results[1] = TEMP99_FROM_REG(data->temp_hyst[nr - 1]); - results[2] = TEMP99_FROM_REG(data->temp[nr - 1]); - *nrels_mag = 3; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - /* temperature range can not be changed */ - } -} - -void maxi_pll(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct maxi_data *data = client->data; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 2; - else if (operation == SENSORS_PROC_REAL_READ) { - if (data->type == nba) - maxi99_update_client(client, pll, 0); - else - maxi_update_client(client); - results[0] = PLL_FROM_REG(data->pll_min); - results[1] = PLL_FROM_REG(data->pll_max); - results[2] = PLL_FROM_REG(data->pll); - *nrels_mag = 3; - } else if (operation == SENSORS_PROC_REAL_WRITE) { -#ifndef NOWRITE - if (*nrels_mag >= 1) { - data->pll_min = PLL_TO_REG(results[0]); - maxi_write_value(client, MAXI_REG_PLL_MIN, - data->pll_min); - } - if (*nrels_mag >= 2) { - data->pll_max = PLL_TO_REG(results[1]); - maxi_write_value(client, MAXI_REG_PLL_MAX, - data->pll_max); - } -#endif - } -} - -void maxi_vid(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct maxi_data *data = client->data; - int nr; - - if (data->type == nba) { - maxi99_vid(client, operation, ctl_name, nrels_mag, - results); - return; - } - - nr = ctl_name - MAXI_SYSCTL_VID1 + 1; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 4; - else if (operation == SENSORS_PROC_REAL_READ) { - maxi_update_client(client); - results[0] = VID_FROM_REG(data->vid_min[nr - 1]); - results[1] = VID_FROM_REG(data->vid_max[nr - 1]); - results[2] = VID_FROM_REG(data->vid[nr - 1]); - *nrels_mag = 3; - } else if (operation == SENSORS_PROC_REAL_WRITE) { -#ifndef NOWRITE - if (*nrels_mag >= 1) { - data->vid_min[nr - 1] = VID_TO_REG(results[0]); - maxi_write_value(client, MAXI_REG_VID_MIN(nr), - data->vid_min[nr - 1]); - } - if (*nrels_mag >= 2) { - data->vid_max[nr - 1] = VID_TO_REG(results[1]); - maxi_write_value(client, MAXI_REG_VID_MAX(nr), - data->vid_max[nr - 1]); - } -#endif - } -} - -void maxi99_vid(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct maxi_data *data = client->data; - int nr = ctl_name - MAXI_SYSCTL_VID1 + 1; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 4; - else if (operation == SENSORS_PROC_REAL_READ) { - maxi99_update_client(client, vid, nr - 1); - results[0] = VID99_FROM_REG(nr, data->vid_min[nr - 1]); - results[1] = VID99_FROM_REG(nr, data->vid_max[nr - 1]); - results[2] = VID99_FROM_REG(nr, data->vid[nr - 1]); - *nrels_mag = 3; - } else if (operation == SENSORS_PROC_REAL_WRITE) { -#ifndef NOWRITE - /* still to do */ - if (*nrels_mag >= 1) { - data->vid_min[nr - 1] = VID_TO_REG(results[0]); - maxi_write_value(client, MAXI_REG_VID_MIN(nr), - data->vid_min[nr - 1]); - } - if (*nrels_mag >= 2) { - data->vid_max[nr - 1] = VID_TO_REG(results[1]); - maxi_write_value(client, MAXI_REG_VID_MAX(nr), - data->vid_max[nr - 1]); - } -#endif - } -} - -void maxi_lcd(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - /* Allows writing and reading from LCD display */ - - struct maxi_data *data = client->data; - int nr; - - if (data->type != nba) - return; - - nr = ctl_name - MAXI_SYSCTL_LCD1 + 1; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - results[0] = *((long *) &data->lcd[nr - 1][0]); - results[1] = *((long *) &data->lcd[nr - 1][4]); - results[2] = *((long *) &data->lcd[nr - 1][8]); - results[3] = *((long *) &data->lcd[nr - 1][12]); - *nrels_mag = 4; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - /* - Writing a string to line 3 of the LCD can be done like: - echo -n "Linux MaxiLife" | od -A n -l > \ - /proc/sys/dev/sensors/maxilife-nba-i2c-0-14/lcd3 - */ - if (*nrels_mag >= 1) - *((long *) &data->lcd[nr - 1][0]) = results[0]; - if (*nrels_mag >= 2) - *((long *) &data->lcd[nr - 1][4]) = results[1]; - if (*nrels_mag >= 3) - *((long *) &data->lcd[nr - 1][8]) = results[2]; - if (*nrels_mag >= 4) - *((long *) &data->lcd[nr - 1][12]) = results[3]; - maxi_write_token_loop(client, MAXI_TOK_LCD(nr - 1), - strlen(data->lcd[nr - 1]) + 1, - data->lcd[nr - 1]); -#if 0 - if (*nrels_mag >= 1) - printk("nr=%d, result[0] = %.4s\n", nr, - (char *) &results[0]); - if (*nrels_mag >= 2) - printk("nr=%d, result[1] = %.4s\n", nr, - (char *) &results[1]); - if (*nrels_mag >= 3) - printk("nr=%d, result[2] = %.4s\n", nr, - (char *) &results[2]); - if (*nrels_mag >= 4) - printk("nr=%d, result[3] = %.4s\n", nr, - (char *) &results[3]); -#endif - } - -} - -void maxi_alarms(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct maxi_data *data = client->data; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - if (data->type == nba) - maxi99_update_client(client, alarm, 0); - else - maxi_update_client(client); - results[0] = ALARMS_FROM_REG(data->alarms); - *nrels_mag = 1; - } -} - -static int __init sm_maxilife_init(void) -{ - printk("maxilife: Version %s (lm_sensors %s (%s))\n", version_str, - LM_VERSION, LM_DATE); - return i2c_add_driver(&maxi_driver); -} - -static void __exit sm_maxilife_exit(void) -{ - i2c_del_driver(&maxi_driver); -} - - - -MODULE_AUTHOR("Fons Rademakers "); -MODULE_DESCRIPTION("HP MaxiLife driver"); -MODULE_PARM(maxi_version, "i"); -MODULE_PARM_DESC(maxi_version, "MaxiLife firmware version"); - -module_init(sm_maxilife_init); -module_exit(sm_maxilife_exit); diff --git a/kernel/chips/mic74.c b/kernel/chips/mic74.c deleted file mode 100644 index b04a6bbe..00000000 --- a/kernel/chips/mic74.c +++ /dev/null @@ -1,378 +0,0 @@ -/* - mic74.c - Intended to become part of lm_sensors, Linux - kernel modules for hardware monitoring - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -/* Supports Micrel MIC74 */ - -/* - A couple notes about the MIC74: -*/ - -#include -#include -#include -#include -#include -#include "version.h" - -MODULE_LICENSE("GPL"); - -/* Addresses to scan */ -static unsigned short normal_i2c[] = { SENSORS_I2C_END }; -static unsigned short normal_i2c_range[] = { 0x20, 0x27, SENSORS_I2C_END }; -static unsigned int normal_isa[] = { SENSORS_ISA_END }; -static unsigned int normal_isa_range[] = { SENSORS_ISA_END }; - -/* Insmod parameters */ -SENSORS_INSMOD_1(mic74); - -/* The mic74 registers */ - -#define MIC74_REG_CONFIG 0x00 -#define MIC74_REG_DATA_DIR 0x01 -#define MIC74_REG_OUT_CFG 0x02 -#define MIC74_REG_STATUS 0x03 -#define MIC74_REG_INT_MASK 0x04 -#define MIC74_REG_DATA 0x05 -#define MIC74_REG_FAN_SPEED 0x06 - -/* Initial values */ -/* All registers are 0, except for MIC74_REG_DATA which is 0xFF */ - -/* For each registered MIC74, we need to keep some data in memory. It is - dynamically allocated, at the same time when a new mic74 client is - allocated. */ -struct mic74_data { - int sysctl_id; - enum chips type; - - struct semaphore update_lock; - char valid; /* !=0 if following fields are valid */ - unsigned long last_updated; /* In jiffies */ - - u8 config; /* Register value */ - u8 dataDir; /* Register value */ - u8 outCfg; /* Register value */ - u8 status; /* Register value */ - u8 intMask; /* Register value */ - u8 data; /* Register value */ - u8 fanSpeed; /* Register value */ -}; - -static int mic74_attach_adapter(struct i2c_adapter *adapter); -static int mic74_detect(struct i2c_adapter *adapter, int address, - unsigned short flags, int kind); -static int mic74_detach_client(struct i2c_client *client); - -static int mic74_read_value(struct i2c_client *client, u8 register); -static int mic74_write_value(struct i2c_client *client, u8 register, - u8 value); -static void mic74_update_client(struct i2c_client *client); -static void mic74_init_client(struct i2c_client *client); - -static void mic74_reg_rw(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results); -static void mic74_reg_ro(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results); - -/* I choose here for semi-static MIC74 allocation. Complete dynamic - allocation could also be used; the code needed for this would probably - take more memory than the datastructure takes now. */ -static int mic74_id; - -static struct i2c_driver mic74_driver = { - .name = "MIC74 sensor driver", - .flags = I2C_DF_NOTIFY, - .attach_adapter = mic74_attach_adapter, - .detach_client = mic74_detach_client -}; - -/* -- SENSORS SYSCTL START -- */ -#define MIC74_SYSCTL_REG0 1000 -#define MIC74_SYSCTL_REG1 1001 -#define MIC74_SYSCTL_REG2 1002 -#define MIC74_SYSCTL_REG3 1003 -#define MIC74_SYSCTL_REG4 1004 -#define MIC74_SYSCTL_REG5 1005 -#define MIC74_SYSCTL_REG6 1006 -/* -- SENSORS SYSCTL END -- */ - -/* The /proc/sys entries */ -/* These files are created for each detected MIC74. This is just a template; - though at first sight, you might think we could use a statically - allocated list, we need some way to get back to the parent - which - is done through one of the 'extra' fields which are initialized - when a new copy is allocated. */ -static ctl_table mic74_dir_table_template[] = { - {MIC74_SYSCTL_REG0, /* ctl_name */ - "dev_cfg", /* procname */ - NULL, /* data */ - 0, /* maxlen */ - 0644, /* mode */ - NULL, /* child */ - &i2c_proc_real, /* proc_handler */ - &i2c_sysctl_real, /* strategy */ - NULL, /* de */ - &mic74_reg_rw }, /* extra1, extra2 is by default NULL? */ - {MIC74_SYSCTL_REG1, "dir", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &mic74_reg_rw }, - {MIC74_SYSCTL_REG2, "out_cfg", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &mic74_reg_rw }, - {MIC74_SYSCTL_REG3, "status", NULL, 0, 0444, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &mic74_reg_ro }, - {MIC74_SYSCTL_REG4, "int_mask", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &mic74_reg_rw }, - {MIC74_SYSCTL_REG5, "data", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &mic74_reg_rw }, - {MIC74_SYSCTL_REG6, "fan_speed", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &mic74_reg_rw }, - {0} -}; - -int mic74_attach_adapter(struct i2c_adapter *adapter) -{ - return i2c_detect(adapter, &addr_data, mic74_detect); -} - -static int mic74_detect(struct i2c_adapter *adapter, int address, - unsigned short flags, int kind) -{ - int i; - struct i2c_client *new_client; - struct mic74_data *data; - int err = 0; - const char *type_name = ""; - const char *client_name = ""; - - if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) - goto ERROR0; - - /* OK. For now, we presume we have a valid client. We now create the - client structure, even though we cannot fill it completely yet. - But it allows us to access mic74_{read,write}_value. */ - - if (!(new_client = kmalloc(sizeof(struct i2c_client) + - sizeof(struct mic74_data), - GFP_KERNEL))) { - err = -ENOMEM; - goto ERROR0; - } - - data = (struct mic74_data *) (new_client + 1); - new_client->addr = address; - new_client->data = data; - new_client->adapter = adapter; - new_client->driver = &mic74_driver; - new_client->flags = 0; -#ifdef CONFIG_AMAZON - /* make sure we can search for the client later */ - new_client->flags |= I2C_CLIENT_ALLOW_USE; -#endif - - /* Determine the chip type - only one kind */ - if (kind <= 0) - kind = mic74; - - if (kind == mic74) { - type_name = "mic74"; - client_name = "MIC74 chip"; - } - else { - goto ERROR1; - } - - /* Fill in the remaining client fields and put it into the global list */ - strcpy(new_client->name, client_name); - data->type = kind; - - new_client->id = mic74_id++; - data->valid = 0; - init_MUTEX(&data->update_lock); - - /* Tell the I2C layer a new client has arrived */ - if ((err = i2c_attach_client(new_client))) - goto ERROR3; - - /* Register a new directory entry with module sensors */ - if ((i = i2c_register_entry(new_client, - type_name, - mic74_dir_table_template, - THIS_MODULE)) < 0) { - err = i; - goto ERROR4; - } - data->sysctl_id = i; - - /* Initialize the MIC74 chip */ - mic74_init_client(new_client); - return 0; - -/* OK, this is not exactly good programming practice, usually. But it is - very code-efficient in this case. */ - - ERROR4: - i2c_detach_client(new_client); - ERROR3: - ERROR1: - kfree(new_client); - ERROR0: - printk("mic74.o: mic74_detect failed\n"); - return err; -} - -int mic74_detach_client(struct i2c_client *client) -{ - int err; - - i2c_deregister_entry(((struct mic74_data *) (client->data))-> - sysctl_id); - - if ((err = i2c_detach_client(client))) { - printk - ("mic74.o: Client deregistration failed, client not detached.\n"); - return err; - } - - kfree(client); - return 0; -} - -int mic74_read_value(struct i2c_client *client, u8 reg) -{ - return 0xFF & i2c_smbus_read_byte_data(client, reg); -} - -int mic74_write_value(struct i2c_client *client, u8 reg, u8 value) -{ - return i2c_smbus_write_byte_data(client, reg, value); -} - -/* Called when we have found a new MIC74. */ -void mic74_init_client(struct i2c_client *client) -{ - /* don't init, defaults are fine */ -} - -void mic74_update_client(struct i2c_client *client) -{ - struct mic74_data *data = client->data; - - down(&data->update_lock); - - if ((jiffies - data->last_updated > HZ) || - (jiffies < data->last_updated) || - !data->valid) { - -#ifdef DEBUG - printk("Starting mic74 update\n"); -#endif - data->config = mic74_read_value(client, MIC74_REG_CONFIG); - data->dataDir = mic74_read_value(client, MIC74_REG_DATA_DIR); - data->outCfg = mic74_read_value(client, MIC74_REG_OUT_CFG); - data->status = mic74_read_value(client, MIC74_REG_STATUS); - data->intMask = mic74_read_value(client, MIC74_REG_INT_MASK); - data->data = mic74_read_value(client, MIC74_REG_DATA); - data->fanSpeed = mic74_read_value(client, MIC74_REG_FAN_SPEED); - - data->last_updated = jiffies; - data->valid = 1; - } - - up(&data->update_lock); -} - - -void mic74_reg_rw(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct mic74_data *data = client->data; - - int nr = ctl_name - MIC74_SYSCTL_REG0; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - - mic74_update_client(client); - - switch (nr) { - case 0: - results[0] = data->config; - break; - case 1: - results[0] = data->dataDir; - break; - case 2: - results[0] = data->outCfg; - break; - case 3: - results[0] = data->status; - break; - case 4: - results[0] = data->intMask; - break; - case 5: - results[0] = data->data; - break; - case 6: - results[0] = data->fanSpeed; - break; - } - - *nrels_mag = 1; - } - else if (operation == SENSORS_PROC_REAL_WRITE) { - - if (*nrels_mag >= 1) - mic74_write_value(client, - (u8)nr, - (u8)(results[0] & 0xFF)); - } -} - -/* This is identical to the above except that it has now - WRITE code and it calls the _rw routine above for a READ */ -void mic74_reg_ro(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - - mic74_reg_rw(client, operation, ctl_name, - nrels_mag, results); - *nrels_mag = 1; - } -} - -static int __init sensors_mic74_init(void) -{ - printk("mic74.o version %s (%s)\n", LM_VERSION, LM_DATE); - return(i2c_add_driver(&mic74_driver)); -} - -static void __init mic74_cleanup(void) -{ - i2c_del_driver(&mic74_driver); -} - -MODULE_AUTHOR("zebo25/MDS"); -MODULE_DESCRIPTION("MIC74 driver"); - -module_init(sensors_mic74_init); -module_exit(mic74_cleanup); diff --git a/kernel/chips/mtp008.c b/kernel/chips/mtp008.c deleted file mode 100644 index 2d1d9de7..00000000 --- a/kernel/chips/mtp008.c +++ /dev/null @@ -1,1098 +0,0 @@ -/* - mtp008.c - Part of lm_sensors, Linux kernel modules for hardware - monitoring - Copyright (C) 2001, 2004 Kris Van Hees - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include -#include -#include -#include -#include -#include "version.h" - -MODULE_LICENSE("GPL"); - -/* Addresses to scan */ -static unsigned short normal_i2c[] = {SENSORS_I2C_END}; -static unsigned short normal_i2c_range[] = {0x2c, 0x2e, SENSORS_I2C_END}; -static unsigned int normal_isa[] = {SENSORS_ISA_END}; -static unsigned int normal_isa_range[] = {SENSORS_ISA_END}; - -/* Insmod parameters */ -SENSORS_INSMOD_1(mtp008); - -/* The MTP008 registers */ -/* in0 .. in6 */ -#define MTP008_REG_IN(nr) (0x20 + (nr)) -#define MTP008_REG_IN_MAX(nr) (0x2b + (nr) * 2) -#define MTP008_REG_IN_MIN(nr) (0x2c + (nr) * 2) - -/* temp1 */ -#define MTP008_REG_TEMP 0x27 -#define MTP008_REG_TEMP_MAX 0x39 -#define MTP008_REG_TEMP_MIN 0x3a - -/* fan1 .. fan3 */ -#define MTP008_REG_FAN(nr) (0x27 + (nr)) -#define MTP008_REG_FAN_MIN(nr) (0x3a + (nr)) - -#define MTP008_REG_CONFIG 0x40 -#define MTP008_REG_INT_STAT1 0x41 -#define MTP008_REG_INT_STAT2 0x42 - -#define MTP008_REG_SMI_MASK1 0x43 -#define MTP008_REG_SMI_MASK2 0x44 - -#define MTP008_REG_NMI_MASK1 0x45 -#define MTP008_REG_NMI_MASK2 0x46 - -#define MTP008_REG_VID_FANDIV 0x47 - -#define MTP008_REG_I2C_ADDR 0x48 - -#define MTP008_REG_RESET_VID4 0x49 - -#define MTP008_REG_OVT_PROP 0x50 - -#define MTP008_REG_BEEP_CTRL1 0x51 -#define MTP008_REG_BEEP_CTRL2 0x52 - -/* pwm1 .. pwm3 nr range 1-3 */ -#define MTP008_REG_PWM_CTRL(nr) (0x52 + (nr)) - -#define MTP008_REG_PIN_CTRL1 0x56 -#define MTP008_REG_PIN_CTRL2 0x57 - -#define MTP008_REG_CHIPID 0x58 - -/* - * Pin control register configuration constants. - */ -#define MTP008_CFG_VT1_PII 0x08 -#define MTP008_CFG_VT2_AIN 0x00 -#define MTP008_CFG_VT2_VT 0x03 -#define MTP008_CFG_VT2_PII 0x04 -#define MTP008_CFG_VT2_MASK 0x06 -#define MTP008_CFG_VT3_VT 0x01 - -/* sensor pin types */ -#define VOLTAGE 1 -#define THERMISTOR 2 -#define PIIDIODE 3 - -/* - * Conversion routines and macros. Limit checking is only done on - * the TO_REG variants. - * - * Note that IN values are expressed as 100 times the actual voltage to avoid - * having to use floating point values. As such, IN values are between 0 and - * 409 (0V to 4.096V). - */ -#define IN_TO_REG(val) (SENSORS_LIMIT((((val) * 10 + 8) / 16), 0, 255)) -#define IN_FROM_REG(val) (((val) * 16 + 5) / 10) - -/* - * The fan cotation count (as stored in the register) is calculated using the - * following formula: - * count = (22.5K * 60) / (rpm * div) = 1350000 / (rpm * div) - * and the rpm is therefore: - * rpm = 1350000 / (count * div) - */ -static inline u8 FAN_TO_REG(long rpm, int div) -{ - if (rpm == 0) - return 255; - - rpm = SENSORS_LIMIT(rpm, 1, 1000000); - - return SENSORS_LIMIT( - (1350000 + rpm * div / 2) / (rpm * div), - 1, 254 - ); -} - -#define FAN_FROM_REG(val, div) ((val) == 0 ? -1 \ - : (val) == 255 ? 0 \ - : 1350000 / \ - ((val) * (div)) \ - ) - -/* - * Temperatures are stored as two's complement values of the Celsius value. It - * actually uses 10 times the Celsius value to avoid using floating point - * values. - */ -#define TEMP_TO_REG(val) ( \ - (val) < 0 \ - ? SENSORS_LIMIT(((val) - 5) / 10, 0, 255) \ - : SENSORS_LIMIT(((val) + 5) / 10, 0, 255) \ - ) -#define TEMP_FROM_REG(val) ( \ - ( \ - (val) > 0x80 ? (val) - 0x100 \ - : (val) \ - ) * 10 \ - ) - -/* - * VCORE voltage: - * 0x00 to 0x0f = 2.05 to 1.30 (0.05 per unit) - * 0x10 to 0x1e = 3.50 to 2.10 (0.10 per unit) - * 0x1f = No CPU - */ -#define VID_FROM_REG(val) ((val) == 0x1f \ - ? 0 \ - : (val) < 0x10 ? 205 - (val) * 5 \ - : 510 - (val) * 10) - -/* - * Fan divider. - */ -#define DIV_FROM_REG(val) (1 << (val)) -#define DIV_TO_REG(val) ((val) == 8 ? 3 \ - : (val) == 4 ? 2 \ - : (val) == 2 ? 1 \ - : 0) - -/* - * Alarms (interrupt status). - */ -#define ALARMS_FROM_REG(val) (val) - -/* - * Beep controls. - */ -#define BEEPS_FROM_REG(val) (val) -#define BEEPS_TO_REG(val) (val) - -/* - * PWM control. nr range 1 to 3 - */ -#define PWM_FROM_REG(val) (val) -#define PWM_TO_REG(val) (val) -#define PWMENABLE_FROM_REG(nr, val) (((val) >> ((nr) + 3)) & 1) - -/* - * For each registered MTP008, we need to keep some data in memory. The - * structure itself is dynamically allocated, at the same time when a new - * mtp008 client is allocated. - */ -struct mtp008_data { - struct i2c_client client; - int sysctl_id; - enum chips type; - - struct semaphore update_lock; - char valid; /* !=0 if fields are valid */ - unsigned long last_updated; /* In jiffies */ - - u8 in[7]; /* Register value */ - u8 in_max[7]; /* Register value */ - u8 in_min[7]; /* Register value */ - u8 temp; /* Register value */ - u8 temp_max; /* Register value */ - u8 temp_min; /* Register value */ - u8 fan[3]; /* Register value */ - u8 fan_min[3]; /* Register value */ - u8 vid; /* Register encoding */ - u8 fan_div[3]; /* Register encoding */ - u16 alarms; /* Register encoding */ - u16 beeps; /* Register encoding */ - u8 pwm[4]; /* Register value */ - u8 sens[3]; /* 1 = Analog input, - 2 = Thermistor, - 3 = PII/Celeron diode */ - u8 pwmenable; /* Register 0x57 value */ -}; - -static int mtp008_attach_adapter(struct i2c_adapter *adapter); -static int mtp008_detect(struct i2c_adapter *adapter, int address, - unsigned short flags, int kind); -static int mtp008_detach_client(struct i2c_client *client); - -static int mtp008_read_value(struct i2c_client *client, u8 register); -static int mtp008_write_value(struct i2c_client *client, u8 register, u8 value); -static void mtp008_update_client(struct i2c_client *client); -static void mtp008_init_client(struct i2c_client *client); - -static void mtp008_in(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void mtp008_fan(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void mtp008_temp(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void mtp008_temp_add(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void mtp008_vid(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void mtp008_fan_div(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void mtp008_alarms(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void mtp008_beep(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void mtp008_pwm(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void mtp008_sens(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void mtp008_getsensortype(struct mtp008_data *data, u8 inp); - -static struct i2c_driver mtp008_driver = -{ - .name = "MTP008 sensor driver", - .id = I2C_DRIVERID_MTP008, - .flags = I2C_DF_NOTIFY, - .attach_adapter = mtp008_attach_adapter, - .detach_client = mtp008_detach_client, -}; - -/* -- SENSORS SYSCTL START -- */ -#define MTP008_SYSCTL_IN0 1000 /* Volts * 100 */ -#define MTP008_SYSCTL_IN1 1001 -#define MTP008_SYSCTL_IN2 1002 -#define MTP008_SYSCTL_IN3 1003 -#define MTP008_SYSCTL_IN4 1004 -#define MTP008_SYSCTL_IN5 1005 -#define MTP008_SYSCTL_IN6 1006 -#define MTP008_SYSCTL_FAN1 1101 /* Rotations/min */ -#define MTP008_SYSCTL_FAN2 1102 -#define MTP008_SYSCTL_FAN3 1103 -#define MTP008_SYSCTL_TEMP1 1200 /* Degrees Celsius * 10 */ -#define MTP008_SYSCTL_TEMP2 1201 /* Degrees Celsius * 10 */ -#define MTP008_SYSCTL_TEMP3 1202 /* Degrees Celsius * 10 */ -#define MTP008_SYSCTL_VID 1300 /* Volts * 100 */ -#define MTP008_SYSCTL_PWM1 1401 -#define MTP008_SYSCTL_PWM2 1402 -#define MTP008_SYSCTL_PWM3 1403 -#define MTP008_SYSCTL_SENS1 1501 /* 1, 2, or Beta (3000-5000) */ -#define MTP008_SYSCTL_SENS2 1502 -#define MTP008_SYSCTL_SENS3 1503 -#define MTP008_SYSCTL_FAN_DIV 2000 /* 1, 2, 4 or 8 */ -#define MTP008_SYSCTL_ALARMS 2001 /* bitvector */ -#define MTP008_SYSCTL_BEEP 2002 /* bitvector */ - -#define MTP008_ALARM_IN0 0x0001 -#define MTP008_ALARM_IN1 0x0002 -#define MTP008_ALARM_IN2 0x0004 -#define MTP008_ALARM_IN3 0x0008 -#define MTP008_ALARM_IN4 0x0100 -#define MTP008_ALARM_IN5 0x0200 -#define MTP008_ALARM_IN6 0x0400 -#define MTP008_ALARM_FAN1 0x0040 -#define MTP008_ALARM_FAN2 0x0080 -#define MTP008_ALARM_FAN3 0x0800 -#define MTP008_ALARM_TEMP1 0x0010 -#define MTP008_ALARM_TEMP2 0x0100 -#define MTP008_ALARM_TEMP3 0x0200 - -/* -- SENSORS SYSCTL END -- */ - -/* The /proc/sys entries */ -/* These files are created for each detected chip. This is just a template; - though at first sight, you might think we could use a statically - allocated list, we need some way to get back to the parent - which - is done through one of the 'extra' fields which are initialized - when a new copy is allocated. */ - -static ctl_table mtp008_dir_table_template[] = -{ - {MTP008_SYSCTL_IN0, "in0", NULL, 0, 0644, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &mtp008_in}, - {MTP008_SYSCTL_IN1, "in1", NULL, 0, 0644, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &mtp008_in}, - {MTP008_SYSCTL_IN2, "in2", NULL, 0, 0644, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &mtp008_in}, - {MTP008_SYSCTL_IN3, "in3", NULL, 0, 0644, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &mtp008_in}, - {MTP008_SYSCTL_IN4, "in4", NULL, 0, 0644, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &mtp008_in}, - {MTP008_SYSCTL_IN5, "in5", NULL, 0, 0644, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &mtp008_in}, - {MTP008_SYSCTL_IN6, "in6", NULL, 0, 0644, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &mtp008_in}, - {MTP008_SYSCTL_FAN1, "fan1", NULL, 0, 0644, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &mtp008_fan}, - {MTP008_SYSCTL_FAN2, "fan2", NULL, 0, 0644, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &mtp008_fan}, - {MTP008_SYSCTL_FAN3, "fan3", NULL, 0, 0644, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &mtp008_fan}, - {MTP008_SYSCTL_TEMP1, "temp1", NULL, 0, 0644, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &mtp008_temp}, - {MTP008_SYSCTL_TEMP2, "temp2", NULL, 0, 0644, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &mtp008_temp_add}, - {MTP008_SYSCTL_TEMP3, "temp3", NULL, 0, 0644, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &mtp008_temp_add}, - {MTP008_SYSCTL_VID, "vid", NULL, 0, 0444, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &mtp008_vid}, - {MTP008_SYSCTL_FAN_DIV, "fan_div", NULL, 0, 0644, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &mtp008_fan_div}, - {MTP008_SYSCTL_ALARMS, "alarms", NULL, 0, 0444, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &mtp008_alarms}, - {MTP008_SYSCTL_BEEP, "beep", NULL, 0, 0644, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &mtp008_beep}, - {MTP008_SYSCTL_PWM1, "pwm1", NULL, 0, 0644, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &mtp008_pwm}, - {MTP008_SYSCTL_PWM2, "pwm2", NULL, 0, 0644, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &mtp008_pwm}, - {MTP008_SYSCTL_PWM3, "pwm3", NULL, 0, 0644, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &mtp008_pwm}, - {MTP008_SYSCTL_SENS1, "sensor1", NULL, 0, 0644, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &mtp008_sens}, - {MTP008_SYSCTL_SENS2, "sensor2", NULL, 0, 0644, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &mtp008_sens}, - {MTP008_SYSCTL_SENS3, "sensor3", NULL, 0, 0644, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &mtp008_sens}, - {0} -}; - -/* This function is called when: - * mtp008_driver is inserted (when this module is loaded), for each available - * adapter when a new adapter is inserted (and mtp008_driver is still present) - */ -static int mtp008_attach_adapter(struct i2c_adapter *adapter) -{ - struct i2c_client_address_data mtp008_addr_data; - - mtp008_addr_data.normal_i2c = addr_data.normal_i2c; - mtp008_addr_data.normal_i2c_range = addr_data.normal_i2c_range; - mtp008_addr_data.probe = addr_data.probe; - mtp008_addr_data.probe_range = addr_data.probe_range; - mtp008_addr_data.ignore = addr_data.ignore; - mtp008_addr_data.ignore_range = addr_data.ignore_range; - mtp008_addr_data.force = addr_data.forces->force; - - return i2c_probe(adapter, &mtp008_addr_data, mtp008_detect); -} - -int mtp008_detect(struct i2c_adapter *adapter, int address, - unsigned short flags, int kind) -{ - const char *type_name = ""; - const char *client_name = ""; - int is_isa, err, sysid; - struct i2c_client *new_client; - struct mtp008_data *data; - - err = 0; - - is_isa = i2c_is_isa_adapter(adapter); - if (is_isa || - !i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) - goto ERROR0; - - /* - * We presume we have a valid client. We now create the client - * structure, even though we cannot fill it completely yet. But it - * allows us to use mtp008_(read|write)_value(). - */ - if (!(data = kmalloc(sizeof(struct mtp008_data), GFP_KERNEL))) { - err = -ENOMEM; - goto ERROR0; - } - - new_client = &data->client; - new_client->addr = address; - new_client->data = data; - new_client->adapter = adapter; - new_client->driver = &mtp008_driver; - new_client->flags = 0; - - /* - * Remaining detection. - */ - if (kind < 0) { - if (mtp008_read_value(new_client, MTP008_REG_CHIPID) != 0xac) - goto ERROR1; - } - /* - * Fill in the remaining client fields and put it into the global list. - */ - type_name = "mtp008"; - client_name = "MTP008 chip"; - strcpy(new_client->name, client_name); - data->type = kind; - data->valid = 0; - init_MUTEX(&data->update_lock); - - /* - * Tell the I2C layer that a new client has arrived. - */ - if ((err = i2c_attach_client(new_client))) - goto ERROR1; - - /* - * Register a new directory entry with the sensors module. - */ - if ((sysid = i2c_register_entry(new_client, type_name, - mtp008_dir_table_template, - THIS_MODULE)) < 0) { - err = sysid; - goto ERROR2; - } - data->sysctl_id = sysid; - - /* - * Initialize the MTP008 chip. - */ - mtp008_init_client(new_client); - - return 0; - - /* - * Error handling. Bad programming practise but very code efficient. - */ - ERROR2: - i2c_detach_client(new_client); - ERROR1: - kfree(data); - - ERROR0: - return err; -} - -static int mtp008_detach_client(struct i2c_client *client) -{ - int err; - - i2c_deregister_entry( - ((struct mtp008_data *) (client->data))->sysctl_id); - - if ((err = i2c_detach_client(client))) { - printk("mtp008.o: Deregistration failed, " - "client not detached.\n"); - return err; - } - kfree(client->data); - - return 0; -} - - -static int mtp008_read_value(struct i2c_client *client, u8 reg) -{ - return i2c_smbus_read_byte_data(client, reg) & 0xff; -} - -static int mtp008_write_value(struct i2c_client *client, u8 reg, u8 value) -{ - return i2c_smbus_write_byte_data(client, reg, value); -} - -/* Called when we have found a new MTP008. */ -static void mtp008_init_client(struct i2c_client *client) -{ - u8 save1, save2; - struct mtp008_data *data; - - data = client->data; - - /* - * Initialize the Myson MTP008 hardware monitoring chip. - * Save the pin settings that the BIOS hopefully set. - */ - save1 = mtp008_read_value(client, MTP008_REG_PIN_CTRL1); - save2 = mtp008_read_value(client, MTP008_REG_PIN_CTRL2); - mtp008_write_value(client, MTP008_REG_CONFIG, - (mtp008_read_value(client, MTP008_REG_CONFIG) & 0x7f) | 0x80); - mtp008_write_value(client, MTP008_REG_PIN_CTRL1, save1); - mtp008_write_value(client, MTP008_REG_PIN_CTRL2, save2); - - mtp008_getsensortype(data, save2); - - - /* - * Start monitoring. - */ - mtp008_write_value( - client, MTP008_REG_CONFIG, - (mtp008_read_value(client, MTP008_REG_CONFIG) & 0xf7) | 0x01 - ); -} - -static void mtp008_update_client(struct i2c_client *client) -{ - int i; - u8 inp; - struct mtp008_data *data; - - data = client->data; - - down(&data->update_lock); - - if ((jiffies - data->last_updated > HZ + HZ / 2) || - (jiffies < data->last_updated) || !data->valid) { -#ifdef DEBUG - printk("Starting MTP008 update\n"); -#endif - - /* - * Read in the analog inputs. We're reading AIN4 and AIN5 as - * regular analog inputs, even though they may have been - * configured as temperature readings instead. Interpretation - * of these values is done elsewhere. - */ - for (i = 0; i < 7; i++) { - data->in[i] = - mtp008_read_value(client, MTP008_REG_IN(i)); - data->in_max[i] = - mtp008_read_value(client, MTP008_REG_IN_MAX(i)); - data->in_min[i] = - mtp008_read_value(client, MTP008_REG_IN_MIN(i)); - } - - /* - * Read the temperature sensor. - */ - data->temp = mtp008_read_value(client, MTP008_REG_TEMP); - data->temp_max = mtp008_read_value(client, MTP008_REG_TEMP_MAX); - data->temp_min = mtp008_read_value(client, MTP008_REG_TEMP_MIN); - - /* - * Read the first 2 fan dividers and the VID setting. Read the - * third fan divider from a different register. - */ - inp = mtp008_read_value(client, MTP008_REG_VID_FANDIV); - data->vid = inp & 0x0f; - data->vid |= (mtp008_read_value(client, - MTP008_REG_RESET_VID4) & 0x01) << 4; - - data->fan_div[0] = (inp >> 4) & 0x03; - data->fan_div[1] = inp >> 6; - data->fan_div[2] = - mtp008_read_value(client, MTP008_REG_PIN_CTRL1) >> 6; - - /* - * Read the interrupt status registers. - */ - data->alarms = - (mtp008_read_value(client, - MTP008_REG_INT_STAT1) & 0xdf) | - (mtp008_read_value(client, - MTP008_REG_INT_STAT2) & 0x0f) << 8; - - /* - * Read the beep control registers. - */ - data->beeps = - (mtp008_read_value(client, - MTP008_REG_BEEP_CTRL1) & 0xdf) | - (mtp008_read_value(client, - MTP008_REG_BEEP_CTRL2) & 0x8f) << 8; - - /* - * Read the sensor configuration. - */ - inp = mtp008_read_value(client, MTP008_REG_PIN_CTRL2); - mtp008_getsensortype(data, inp); - data->pwmenable = inp; - - /* - * Read the PWM registers if enabled. - */ - for (i = 1; i <= 3; i++) - { - if(PWMENABLE_FROM_REG(i, inp)) - data->pwm[i-1] = mtp008_read_value(client, - MTP008_REG_PWM_CTRL(i)); - else - data->pwm[i-1] = 255; - } - - /* - * Read the fan sensors. Skip 3 if PWM1 enabled. - */ - for (i = 1; i <= 3; i++) { - if(i == 3 && PWMENABLE_FROM_REG(1, inp)) { - data->fan[2] = 0; - data->fan_min[2] = 0; - } else { - data->fan[i-1] = mtp008_read_value(client, - MTP008_REG_FAN(i)); - data->fan_min[i-1] = mtp008_read_value(client, - MTP008_REG_FAN_MIN(i)); - } - } - - data->last_updated = jiffies; - data->valid = 1; - } - up(&data->update_lock); -} - -static void mtp008_getsensortype(struct mtp008_data *data, u8 inp) -{ - inp &= 0x0f; - data->sens[0] = (inp >> 3) + 2; /* 2 or 3 */ - data->sens[1] = ((inp >> 1) & 0x03) + 1; /* 1, 2 or 3 */ - data->sens[2] = (inp & 0x01) + 1; /* 1 or 2 */ -} - -/* The next few functions are the call-back functions of the /proc/sys and - sysctl files. Which function is used is defined in the ctl_table in - the extra1 field. - Each function must return the magnitude (power of 10 to divide the date - with) if it is called with operation==SENSORS_PROC_REAL_INFO. It must - put a maximum of *nrels elements in results reflecting the data of this - file, and set *nrels to the number it actually put in it, if operation== - SENSORS_PROC_REAL_READ. Finally, it must get upto *nrels elements from - results and write them to the chip, if operations==SENSORS_PROC_REAL_WRITE. - Note that on SENSORS_PROC_REAL_READ, I do not check whether results is - large enough (by checking the incoming value of *nrels). This is not very - good practice, but as long as you put less than about 5 values in results, - you can assume it is large enough. */ -void mtp008_in(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - int nr; - struct mtp008_data *data; - - nr = ctl_name - MTP008_SYSCTL_IN0; - data = client->data; - - switch (operation) { - case SENSORS_PROC_REAL_INFO: - *nrels_mag = 2; - - break; - case SENSORS_PROC_REAL_READ: - mtp008_update_client(client); - - if((nr != 4 && nr != 5) || data->sens[nr - 3] == VOLTAGE) { - results[0] = IN_FROM_REG(data->in_min[nr]); - results[1] = IN_FROM_REG(data->in_max[nr]); - results[2] = IN_FROM_REG(data->in[nr]); - } else { - results[0] = 0; - results[1] = 0; - results[2] = 0; - } - - *nrels_mag = 3; - - break; - case SENSORS_PROC_REAL_WRITE: - if((nr != 4 && nr != 5) || data->sens[nr - 3] == VOLTAGE) { - if (*nrels_mag >= 1) { - data->in_min[nr] = IN_TO_REG(results[0]); - mtp008_write_value(client, MTP008_REG_IN_MIN(nr), - data->in_min[nr]); - } - if (*nrels_mag >= 2) { - data->in_max[nr] = IN_TO_REG(results[1]); - mtp008_write_value(client, MTP008_REG_IN_MAX(nr), - data->in_max[nr]); - } - } - } -} - -void mtp008_fan(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - int nr; - struct mtp008_data *data; - - nr = ctl_name - MTP008_SYSCTL_FAN1; - data = client->data; - - switch (operation) { - case SENSORS_PROC_REAL_INFO: - *nrels_mag = 0; - - break; - case SENSORS_PROC_REAL_READ: - mtp008_update_client(client); - - results[0] = FAN_FROM_REG(data->fan_min[nr], - DIV_FROM_REG(data->fan_div[nr])); - results[1] = FAN_FROM_REG(data->fan[nr], - DIV_FROM_REG(data->fan_div[nr])); - - *nrels_mag = 2; - - break; - case SENSORS_PROC_REAL_WRITE: - if (*nrels_mag >= 1) { - data->fan_min[nr] = - FAN_TO_REG(results[0], - DIV_FROM_REG(data->fan_div[nr])); - mtp008_write_value(client, MTP008_REG_FAN_MIN(nr + 1), - data->fan_min[nr]); - } - } -} - -void mtp008_temp(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct mtp008_data *data; - - data = client->data; - - switch (operation) { - case SENSORS_PROC_REAL_INFO: - *nrels_mag = 1; - - break; - case SENSORS_PROC_REAL_READ: - mtp008_update_client(client); - - results[0] = TEMP_FROM_REG(data->temp_max); - results[1] = TEMP_FROM_REG(data->temp_min); - results[2] = TEMP_FROM_REG(data->temp); - *nrels_mag = 3; - - break; - case SENSORS_PROC_REAL_WRITE: - if (*nrels_mag >= 1) { - data->temp_max = TEMP_TO_REG(results[0]); - mtp008_write_value(client, MTP008_REG_TEMP_MAX, - data->temp_max); - } - if (*nrels_mag >= 2) { - data->temp_min = TEMP_TO_REG(results[1]); - mtp008_write_value(client, MTP008_REG_TEMP_MIN, - data->temp_min); - } - } -} - -void mtp008_temp_add(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - int nr; - struct mtp008_data *data; - - nr = 3 + ctl_name - MTP008_SYSCTL_TEMP1; /* AIN4 or AIN5 */ - data = client->data; - - switch (operation) { - case SENSORS_PROC_REAL_INFO: - *nrels_mag = 1; - - break; - case SENSORS_PROC_REAL_READ: - mtp008_update_client(client); - - if(data->sens[nr - 3] != VOLTAGE) { - results[0] = TEMP_FROM_REG(data->in_max[nr]); - results[1] = TEMP_FROM_REG(data->in_min[nr]); - results[2] = TEMP_FROM_REG(data->in[nr]); - } else { - results[0] = 0; - results[1] = 0; - results[2] = 0; - } - *nrels_mag = 3; - - break; - case SENSORS_PROC_REAL_WRITE: - if(data->sens[nr - 3] != VOLTAGE) { - if (*nrels_mag >= 1) { - data->in_max[nr] = TEMP_TO_REG(results[0]); - mtp008_write_value(client, - MTP008_REG_IN_MAX(nr), - data->in_max[nr]); - } - if (*nrels_mag >= 2) { - data->in_min[nr] = TEMP_TO_REG(results[1]); - mtp008_write_value(client, - MTP008_REG_IN_MIN(nr), - data->in_min[nr]); - } - } - } -} - -void mtp008_vid(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct mtp008_data *data; - - data = client->data; - - switch (operation) { - case SENSORS_PROC_REAL_INFO: - *nrels_mag = 2; - - break; - case SENSORS_PROC_REAL_READ: - mtp008_update_client(client); - - results[0] = VID_FROM_REG(data->vid); - - *nrels_mag = 1; - } -} - -void mtp008_fan_div(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results) -{ - struct mtp008_data *data; - u8 val; - - data = client->data; - - switch (operation) { - case SENSORS_PROC_REAL_INFO: - *nrels_mag = 0; - - break; - case SENSORS_PROC_REAL_READ: - mtp008_update_client(client); - - results[0] = DIV_FROM_REG(data->fan_div[0]); - results[1] = DIV_FROM_REG(data->fan_div[1]); - results[2] = DIV_FROM_REG(data->fan_div[2]); - - *nrels_mag = 3; - - break; - case SENSORS_PROC_REAL_WRITE: - if (*nrels_mag >= 3) { - data->fan_div[2] = DIV_TO_REG(results[2]); - val = mtp008_read_value(client, MTP008_REG_PIN_CTRL1); - val = (val & 0x3f) | (data->fan_div[2] & 0x03) << 6; - mtp008_write_value(client, MTP008_REG_PIN_CTRL1, val); - } - if (*nrels_mag >= 1) { - val = mtp008_read_value(client, MTP008_REG_VID_FANDIV); - if (*nrels_mag >= 2) { - data->fan_div[1] = DIV_TO_REG(results[1]); - val = (val & 0x3f) | - (data->fan_div[1] & 0x03) << 6; - } - data->fan_div[0] = DIV_TO_REG(results[0]); - val = (val & 0xcf) | (data->fan_div[0] & 0x03) << 4; - mtp008_write_value(client, MTP008_REG_VID_FANDIV, val); - } - } -} - -void mtp008_alarms(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct mtp008_data *data; - - data = client->data; - - switch (operation) { - case SENSORS_PROC_REAL_INFO: - *nrels_mag = 0; - - break; - case SENSORS_PROC_REAL_READ: - mtp008_update_client(client); - - results[0] = ALARMS_FROM_REG(data->alarms); - - *nrels_mag = 1; - } -} - -void mtp008_beep(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct mtp008_data *data; - - data = client->data; - - switch (operation) { - case SENSORS_PROC_REAL_INFO: - *nrels_mag = 0; - - break; - case SENSORS_PROC_REAL_READ: - mtp008_update_client(client); - - results[0] = BEEPS_FROM_REG(data->beeps); - - *nrels_mag = 1; - - break; - case SENSORS_PROC_REAL_WRITE: - if (*nrels_mag >= 1) { - data->beeps = BEEPS_TO_REG(results[0]) & 0xdf8f; - - mtp008_write_value(client, MTP008_REG_BEEP_CTRL1, - data->beeps & 0xff); - mtp008_write_value(client, MTP008_REG_BEEP_CTRL2, - data->beeps >> 8); - } - } -} - -void mtp008_pwm(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - int nr; - struct mtp008_data *data; - - nr = ctl_name - MTP008_SYSCTL_PWM1; - data = client->data; - - switch (operation) { - case SENSORS_PROC_REAL_INFO: - *nrels_mag = 0; - - break; - case SENSORS_PROC_REAL_READ: - mtp008_update_client(client); - - results[0] = PWM_FROM_REG(data->pwm[nr]); - results[1] = PWMENABLE_FROM_REG(nr + 1, data->pwmenable); - *nrels_mag = 2; - - break; - case SENSORS_PROC_REAL_WRITE: - if (*nrels_mag >= 1) { - if (*nrels_mag >= 2) { - if(results[1]) - data->pwmenable |= 0x10 << nr; - else - data->pwmenable &= ~(0x10 << nr); - mtp008_write_value(client, MTP008_REG_PIN_CTRL2, - data->pwmenable); - } - data->pwm[nr] = PWM_TO_REG(results[0]); - mtp008_write_value(client, MTP008_REG_PWM_CTRL(nr), - data->pwm[nr]); - } - } -} - -void mtp008_sens(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - const char *opts = ""; - int nr; - u8 tmp; - struct mtp008_data *data; - - nr = 1 + ctl_name - MTP008_SYSCTL_SENS1; - data = client->data; - - switch (operation) { - case SENSORS_PROC_REAL_INFO: - *nrels_mag = 0; - - break; - case SENSORS_PROC_REAL_READ: - results[0] = data->sens[nr - 1]; - - *nrels_mag = 1; - - break; - case SENSORS_PROC_REAL_WRITE: - if (*nrels_mag >= 1) { - tmp = mtp008_read_value(client, MTP008_REG_PIN_CTRL2); - - switch (nr) { - case 1: /* VT or PII */ - opts = "2 or 3"; - - switch (results[0]) { - case THERMISTOR: - mtp008_write_value( - client, MTP008_REG_PIN_CTRL2, - tmp & ~MTP008_CFG_VT1_PII); - data->sens[0] = 2; - return; - case PIIDIODE: - mtp008_write_value( - client, MTP008_REG_PIN_CTRL2, - tmp | MTP008_CFG_VT1_PII); - data->sens[0] = 3; - return; - } - - break; - case 2: /* AIN, VT or PII */ - tmp &= ~MTP008_CFG_VT2_MASK; - opts = "1, 2 or 3"; - - switch (results[0]) { - case VOLTAGE: - mtp008_write_value( - client, MTP008_REG_PIN_CTRL2, - tmp | MTP008_CFG_VT2_AIN); - data->sens[1] = 1; - return; - case THERMISTOR: - mtp008_write_value( - client, MTP008_REG_PIN_CTRL2, - tmp | MTP008_CFG_VT2_VT); - data->sens[1] = 2; - return; - case PIIDIODE: - mtp008_write_value( - client, MTP008_REG_PIN_CTRL2, - tmp | MTP008_CFG_VT2_PII); - data->sens[1] = 3; - return; - } - - break; - case 3: /* AIN or VT */ - opts = "1 or 2"; - - switch (results[0]) { - case VOLTAGE: - mtp008_write_value( - client, MTP008_REG_PIN_CTRL2, - tmp & ~MTP008_CFG_VT3_VT); - data->sens[2] = 1; - return; - case THERMISTOR: - mtp008_write_value( - client, MTP008_REG_PIN_CTRL2, - tmp | MTP008_CFG_VT3_VT); - data->sens[2] = 2; - return; - } - - break; - } - - printk("mtp008.o: Invalid sensor type %ld " - "for sensor %d; must be %s.\n", - results[0], nr, opts); - } - } -} - -static int __init sm_mtp008_init(void) -{ - printk("mtp008.o version %s (%s)\n", LM_VERSION, LM_DATE); - return i2c_add_driver(&mtp008_driver); -} - -static void __exit sm_mtp008_exit(void) -{ - i2c_del_driver(&mtp008_driver); -} - - - -MODULE_AUTHOR("Frodo Looijaard , " - "Philip Edelbrock , " - "and Kris Van Hees "); -MODULE_DESCRIPTION("MTP008 driver"); - -module_init(sm_mtp008_init); -module_exit(sm_mtp008_exit); diff --git a/kernel/chips/pc87360.c b/kernel/chips/pc87360.c deleted file mode 100644 index 19f1d279..00000000 --- a/kernel/chips/pc87360.c +++ /dev/null @@ -1,1350 +0,0 @@ -/* - * pc87360.c - Part of lm_sensors, Linux kernel modules - * for hardware monitoring - * Copyright (C) 2004 Jean Delvare - * - * Copied from smsc47m1.c: - * Copyright (C) 2002 Mark D. Studebaker - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - * - * Supports the following chips: - * - * Chip #vin #fan #pwm #temp devid - * PC87360 - 2 2 - 0xE1 - * PC87363 - 2 2 - 0xE8 - * PC87364 - 3 3 - 0xE4 - * PC87365 11 3 3 2 0xE5 - * PC87366 11 3 3 3-4 0xE9 - * - * This driver assumes that no more than one chip is present, and the - * standard Super-I/O address is used (0x2E/0x2F). - */ - -#include -#include -#include -#include -#include -#include -#include -#include "version.h" -#include "sensors_vid.h" - -static unsigned short normal_i2c[] = { SENSORS_I2C_END }; -static unsigned short normal_i2c_range[] = { SENSORS_I2C_END }; -static unsigned int normal_isa[] = { 0x0000, SENSORS_ISA_END }; -static unsigned int normal_isa_range[] = { SENSORS_ISA_END }; -static struct i2c_force_data forces[] = {{NULL}}; -static u8 devid; -static unsigned int extra_isa[] = { 0x0000, 0x0000, 0x0000 }; -static u8 confreg[4]; - -enum chips { any_chip, pc87360, pc87363, pc87364, pc87365, pc87366 }; -static struct i2c_address_data addr_data = { - .normal_i2c = normal_i2c, - .normal_i2c_range = normal_i2c_range, - .normal_isa = normal_isa, - .normal_isa_range = normal_isa_range, - .probe = normal_i2c, /* cheat */ - .probe_range = normal_i2c_range, /* cheat */ - .ignore = normal_i2c, /* cheat */ - .ignore_range = normal_i2c_range, /* cheat */ - .forces = forces, -}; - -static int init = 1; -MODULE_PARM(init, "i"); -MODULE_PARM_DESC(init, - "Chip initialization level:\n" - " 0: None\n" - "*1: Forcibly enable internal voltage and temperature channels, except in9\n" - " 2: Forcibly enable all voltage and temperature channels, except in9\n" - " 3: Forcibly enable all voltage and temperature channels, including in9"); - -/* - * Super-I/O registers and operations - */ - -#define DEV 0x07 /* Register: Logical device select */ -#define DEVID 0x20 /* Register: Device ID */ -#define ACT 0x30 /* Register: Device activation */ -#define BASE 0x60 /* Register: Base address */ - -#define FSCM 0x09 /* Logical device: fans */ -#define VLM 0x0d /* Logical device: voltages */ -#define TMS 0x0e /* Logical device: temperatures */ -static const u8 logdev[3] = { FSCM, VLM, TMS }; - -#define LD_FAN 0 -#define LD_IN 1 -#define LD_TEMP 2 - -static inline void superio_outb(int sioaddr, int reg, int val) -{ - outb(reg, sioaddr); - outb(val, sioaddr+1); -} - -static inline int superio_inb(int sioaddr, int reg) -{ - outb(reg, sioaddr); - return inb(sioaddr+1); -} - -static inline void superio_exit(int sioaddr) -{ - outb(0x02, sioaddr); - outb(0x02, sioaddr+1); -} - -/* - * Logical devices - */ - -#define PC87360_EXTENT 0x10 -#define PC87365_REG_BANK 0x09 -#define NO_BANK 0xff - -/* - * Fan registers and conversions - */ - -/* nr has to be 0 or 1 (PC87360/87363) or 2 (PC87364/87365/87366) */ -#define PC87360_REG_PRESCALE(nr) (0x00 + 2 * (nr)) -#define PC87360_REG_PWM(nr) (0x01 + 2 * (nr)) -#define PC87360_REG_FAN_MIN(nr) (0x06 + 3 * (nr)) -#define PC87360_REG_FAN(nr) (0x07 + 3 * (nr)) -#define PC87360_REG_FAN_STATUS(nr) (0x08 + 3 * (nr)) - -#define FAN_FROM_REG(val,div) ((val)==0?0: \ - 480000/((val)*(div))) -#define FAN_TO_REG(val,div) ((val)<=100?0: \ - 480000/((val)*(div))) -#define FAN_DIV_FROM_REG(val) (1 << ((val >> 5) & 0x03)) -#define FAN_DIV_TO_REG(val) ((val)==8?0x60:(val)==4?0x40: \ - (val)==1?0x00:0x20) -#define FAN_STATUS_FROM_REG(val) ((val) & 0x07) - -#define FAN_CONFIG_MONITOR(val,nr) (((val) >> (2 + nr * 3)) & 1) -#define FAN_CONFIG_CONTROL(val,nr) (((val) >> (3 + nr * 3)) & 1) -#define FAN_CONFIG_INVERT(val,nr) (((val) >> (4 + nr * 3)) & 1) - -#define PWM_FROM_REG(val,inv) ((inv) ? 255 - (val) : (val)) -static inline u8 PWM_TO_REG(int val, int inv) -{ - if (inv) - val = 255 - val; - if (val < 0) - return 0; - if (val > 255) - return 255; - return val; -} - -/* - * Voltage registers and conversions - */ - -#define PC87365_REG_IN_CONVRATE 0x07 -#define PC87365_REG_IN_CONFIG 0x08 -#define PC87365_REG_IN 0x0B -#define PC87365_REG_IN_MIN 0x0D -#define PC87365_REG_IN_MAX 0x0C -#define PC87365_REG_IN_STATUS 0x0A -#define PC87365_REG_IN_ALARMS1 0x00 -#define PC87365_REG_IN_ALARMS2 0x01 -#define PC87365_REG_VID 0x06 - -#define IN_FROM_REG(val,ref) (((val) * (ref) + 128) / 256) -#define IN_TO_REG(val,ref) ((val)<0 ? 0 : \ - (val)*256>=(ref)*255 ? 255: \ - ((val) * 256 + (ref) / 2) / (ref)) - -/* - * Temperature registers and conversions - */ - -#define PC87365_REG_TEMP_CONFIG 0x08 -#define PC87365_REG_TEMP 0x0B -#define PC87365_REG_TEMP_MIN 0x0D -#define PC87365_REG_TEMP_MAX 0x0C -#define PC87365_REG_TEMP_CRIT 0x0E -#define PC87365_REG_TEMP_STATUS 0x0A -#define PC87365_REG_TEMP_ALARMS 0x00 - -#define TEMP_FROM_REG(val) ((val)&0x80 ? (val) - 0x100 : (val)) -#define TEMP_TO_REG(val) ((val)<-55 ? 201 : (val)>127 ? 0x7F : \ - (val)<0 ? (val) + 0x100 : (val)) - -struct pc87360_data { - struct i2c_client client; - struct semaphore lock; - int sysctl_id; - int address[3]; - - struct semaphore update_lock; - char valid; /* !=0 if following fields are valid */ - unsigned long last_updated; /* In jiffies */ - - u8 fannr, innr, tempnr; - - u8 fan[3]; /* Register value */ - u8 fan_min[3]; /* Register value */ - u8 fan_status[3]; /* Register value */ - u8 pwm[3]; /* Register value */ - u16 fan_conf; /* Configuration register values, combined */ - - u16 in_vref; /* 10mV/bit */ - u8 in[14]; /* Register value */ - u8 in_min[14]; /* Register value */ - u8 in_max[14]; /* Register value */ - u8 in_crit[3]; /* Register value */ - u8 in_status[14]; /* Register value */ - u16 in_alarms; /* Register values, combined, masked */ - u8 vid_conf; /* Configuration register value */ - u8 vrm; - u8 vid; /* Register value */ - - u8 temp[3]; /* Register value */ - u8 temp_min[3]; /* Register value */ - u8 temp_max[3]; /* Register value */ - u8 temp_crit[3]; /* Register value */ - u8 temp_status[3]; /* Register value */ - u8 temp_alarms; /* Register value, masked */ -}; - - -static int pc87360_attach_adapter(struct i2c_adapter *adapter); -static int pc87360_detect(struct i2c_adapter *adapter, int address, - unsigned short flags, int kind); -static int pc87360_detach_client(struct i2c_client *client); - -static int pc87360_read_value(struct pc87360_data *data, u8 ldi, u8 bank, - u8 reg); -static void pc87360_write_value(struct pc87360_data *data, u8 ldi, u8 bank, - u8 reg, u8 value); -static void pc87360_init_client(struct i2c_client *client, int use_thermistors); -static void pc87360_update_client(struct i2c_client *client); - - -void pc87365_alarms(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results); - -static void pc87360_fan(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void pc87360_fan_status(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void pc87360_fan_div(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void pc87360_pwm(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); - -void pc87365_in(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results); -void pc87365_in_status(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results); -void pc87365_vid(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results); -void pc87365_vrm(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results); - -void pc87365_temp(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results); -void pc87365_temp_status(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results); - -static struct i2c_driver pc87360_driver = { - .name = "PC8736x hardware monitor", - .flags = I2C_DF_NOTIFY, - .attach_adapter = pc87360_attach_adapter, - .detach_client = pc87360_detach_client, -}; - -/* -- SENSORS SYSCTL START -- */ - -#define PC87365_SYSCTL_ALARMS 100 /* bit field */ - -#define PC87360_SYSCTL_FAN1 1101 /* Rotations/min */ -#define PC87360_SYSCTL_FAN2 1102 -#define PC87360_SYSCTL_FAN3 1103 /* not for PC87360/PC87363 */ -#define PC87360_SYSCTL_FAN_DIV 1201 /* 1, 2, 4 or 8 */ -#define PC87360_SYSCTL_FAN1_STATUS 1301 /* bit field */ -#define PC87360_SYSCTL_FAN2_STATUS 1302 -#define PC87360_SYSCTL_FAN3_STATUS 1303 /* not for PC87360/PC87363 */ -#define PC87360_SYSCTL_PWM1 1401 /* 0-255 */ -#define PC87360_SYSCTL_PWM2 1402 -#define PC87360_SYSCTL_PWM3 1403 /* not for PC87360/PC87363 */ - -#define PC87360_STATUS_FAN_READY 0x01 -#define PC87360_STATUS_FAN_LOW 0x02 -#define PC87360_STATUS_FAN_OVERFLOW 0x04 - -#define PC87365_SYSCTL_IN0 2100 /* mV */ -#define PC87365_SYSCTL_IN1 2101 -#define PC87365_SYSCTL_IN2 2102 -#define PC87365_SYSCTL_IN3 2103 -#define PC87365_SYSCTL_IN4 2104 -#define PC87365_SYSCTL_IN5 2105 -#define PC87365_SYSCTL_IN6 2106 -#define PC87365_SYSCTL_IN7 2107 -#define PC87365_SYSCTL_IN8 2108 -#define PC87365_SYSCTL_IN9 2109 -#define PC87365_SYSCTL_IN10 2110 -#define PC87365_SYSCTL_TEMP4 2111 /* not for PC87365 */ -#define PC87365_SYSCTL_TEMP5 2112 /* not for PC87365 */ -#define PC87365_SYSCTL_TEMP6 2113 /* not for PC87365 */ -#define PC87365_SYSCTL_IN0_STATUS 2300 /* bit field */ -#define PC87365_SYSCTL_IN1_STATUS 2301 -#define PC87365_SYSCTL_IN2_STATUS 2302 -#define PC87365_SYSCTL_IN3_STATUS 2303 -#define PC87365_SYSCTL_IN4_STATUS 2304 -#define PC87365_SYSCTL_IN5_STATUS 2305 -#define PC87365_SYSCTL_IN6_STATUS 2306 -#define PC87365_SYSCTL_IN7_STATUS 2307 -#define PC87365_SYSCTL_IN8_STATUS 2308 -#define PC87365_SYSCTL_IN9_STATUS 2309 -#define PC87365_SYSCTL_IN10_STATUS 2310 -#define PC87365_SYSCTL_TEMP4_STATUS 2311 /* not for PC87365 */ -#define PC87365_SYSCTL_TEMP5_STATUS 2312 /* not for PC87365 */ -#define PC87365_SYSCTL_TEMP6_STATUS 2313 /* not for PC87365 */ - -#define PC87365_SYSCTL_VID 2400 -#define PC87365_SYSCTL_VRM 2401 - -#define PC87365_STATUS_IN_MIN 0x02 -#define PC87365_STATUS_IN_MAX 0x04 - -#define PC87365_SYSCTL_TEMP1 3101 /* degrees Celsius */ -#define PC87365_SYSCTL_TEMP2 3102 -#define PC87365_SYSCTL_TEMP3 3103 /* not for PC87365 */ -#define PC87365_SYSCTL_TEMP1_STATUS 3301 /* bit field */ -#define PC87365_SYSCTL_TEMP2_STATUS 3302 -#define PC87365_SYSCTL_TEMP3_STATUS 3303 /* not for PC87365 */ - -#define PC87365_STATUS_TEMP_MIN 0x02 -#define PC87365_STATUS_TEMP_MAX 0x04 -#define PC87365_STATUS_TEMP_CRIT 0x08 -#define PC87365_STATUS_TEMP_OPEN 0x40 - -/* -- SENSORS SYSCTL END -- */ - -static ctl_table pc87360_dir_table_template[] = { /* PC87363 and PC87364 too */ - {PC87360_SYSCTL_FAN1, "fan1", NULL, 0, 0644, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &pc87360_fan}, - {PC87360_SYSCTL_FAN2, "fan2", NULL, 0, 0644, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &pc87360_fan}, - {PC87360_SYSCTL_FAN3, "fan3", NULL, 0, 0644, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &pc87360_fan}, - {PC87360_SYSCTL_FAN_DIV, "fan_div", NULL, 0, 0644, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &pc87360_fan_div}, - {PC87360_SYSCTL_FAN1_STATUS, "fan1_status", NULL, 0, 0444, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &pc87360_fan_status}, - {PC87360_SYSCTL_FAN2_STATUS, "fan2_status", NULL, 0, 0444, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &pc87360_fan_status}, - {PC87360_SYSCTL_FAN3_STATUS, "fan3_status", NULL, 0, 0444, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &pc87360_fan_status}, - {PC87360_SYSCTL_PWM1, "pwm1", NULL, 0, 0644, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &pc87360_pwm}, - {PC87360_SYSCTL_PWM2, "pwm2", NULL, 0, 0644, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &pc87360_pwm}, - {PC87360_SYSCTL_PWM3, "pwm3", NULL, 0, 0644, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &pc87360_pwm}, - {0} -}; - -static ctl_table pc87365_dir_table_template[] = { /* PC87366 too */ - {PC87365_SYSCTL_ALARMS, "alarms", NULL, 0, 0444, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &pc87365_alarms}, - {PC87360_SYSCTL_FAN1, "fan1", NULL, 0, 0644, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &pc87360_fan}, - {PC87360_SYSCTL_FAN2, "fan2", NULL, 0, 0644, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &pc87360_fan}, - {PC87360_SYSCTL_FAN3, "fan3", NULL, 0, 0644, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &pc87360_fan}, - {PC87360_SYSCTL_FAN_DIV, "fan_div", NULL, 0, 0644, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &pc87360_fan_div}, - {PC87360_SYSCTL_FAN1_STATUS, "fan1_status", NULL, 0, 0444, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &pc87360_fan_status}, - {PC87360_SYSCTL_FAN2_STATUS, "fan2_status", NULL, 0, 0444, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &pc87360_fan_status}, - {PC87360_SYSCTL_FAN3_STATUS, "fan3_status", NULL, 0, 0444, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &pc87360_fan_status}, - {PC87360_SYSCTL_PWM1, "pwm1", NULL, 0, 0644, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &pc87360_pwm}, - {PC87360_SYSCTL_PWM2, "pwm2", NULL, 0, 0644, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &pc87360_pwm}, - {PC87360_SYSCTL_PWM3, "pwm3", NULL, 0, 0644, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &pc87360_pwm}, - {PC87365_SYSCTL_IN0, "in0", NULL, 0, 0644, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &pc87365_in}, - {PC87365_SYSCTL_IN1, "in1", NULL, 0, 0644, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &pc87365_in}, - {PC87365_SYSCTL_IN2, "in2", NULL, 0, 0644, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &pc87365_in}, - {PC87365_SYSCTL_IN3, "in3", NULL, 0, 0644, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &pc87365_in}, - {PC87365_SYSCTL_IN4, "in4", NULL, 0, 0644, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &pc87365_in}, - {PC87365_SYSCTL_IN5, "in5", NULL, 0, 0644, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &pc87365_in}, - {PC87365_SYSCTL_IN6, "in6", NULL, 0, 0644, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &pc87365_in}, - {PC87365_SYSCTL_IN7, "in7", NULL, 0, 0644, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &pc87365_in}, - {PC87365_SYSCTL_IN8, "in8", NULL, 0, 0644, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &pc87365_in}, - {PC87365_SYSCTL_IN9, "in9", NULL, 0, 0644, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &pc87365_in}, - {PC87365_SYSCTL_IN10, "in10", NULL, 0, 0644, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &pc87365_in}, - {PC87365_SYSCTL_IN0_STATUS, "in0_status", NULL, 0, 0444, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &pc87365_in_status}, - {PC87365_SYSCTL_IN1_STATUS, "in1_status", NULL, 0, 0444, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &pc87365_in_status}, - {PC87365_SYSCTL_IN2_STATUS, "in2_status", NULL, 0, 0444, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &pc87365_in_status}, - {PC87365_SYSCTL_IN3_STATUS, "in3_status", NULL, 0, 0444, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &pc87365_in_status}, - {PC87365_SYSCTL_IN4_STATUS, "in4_status", NULL, 0, 0444, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &pc87365_in_status}, - {PC87365_SYSCTL_IN5_STATUS, "in5_status", NULL, 0, 0444, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &pc87365_in_status}, - {PC87365_SYSCTL_IN6_STATUS, "in6_status", NULL, 0, 0444, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &pc87365_in_status}, - {PC87365_SYSCTL_IN7_STATUS, "in7_status", NULL, 0, 0444, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &pc87365_in_status}, - {PC87365_SYSCTL_IN8_STATUS, "in8_status", NULL, 0, 0444, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &pc87365_in_status}, - {PC87365_SYSCTL_IN9_STATUS, "in9_status", NULL, 0, 0444, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &pc87365_in_status}, - {PC87365_SYSCTL_IN10_STATUS, "in10_status", NULL, 0, 0444, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &pc87365_in_status}, - {PC87365_SYSCTL_TEMP1, "temp1", NULL, 0, 0644, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &pc87365_temp}, - {PC87365_SYSCTL_TEMP2, "temp2", NULL, 0, 0644, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &pc87365_temp}, - {PC87365_SYSCTL_TEMP3, "temp3", NULL, 0, 0644, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &pc87365_temp}, - {PC87365_SYSCTL_TEMP4, "temp4", NULL, 0, 0644, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &pc87365_in}, - {PC87365_SYSCTL_TEMP5, "temp5", NULL, 0, 0644, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &pc87365_in}, - {PC87365_SYSCTL_TEMP6, "temp6", NULL, 0, 0644, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &pc87365_in}, - {PC87365_SYSCTL_TEMP1_STATUS, "temp1_status", NULL, 0, 0444, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &pc87365_temp_status}, - {PC87365_SYSCTL_TEMP2_STATUS, "temp2_status", NULL, 0, 0444, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &pc87365_temp_status}, - {PC87365_SYSCTL_TEMP3_STATUS, "temp3_status", NULL, 0, 0444, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &pc87365_temp_status}, - {PC87365_SYSCTL_TEMP4_STATUS, "temp4_status", NULL, 0, 0444, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &pc87365_in_status}, - {PC87365_SYSCTL_TEMP5_STATUS, "temp5_status", NULL, 0, 0444, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &pc87365_in_status}, - {PC87365_SYSCTL_TEMP6_STATUS, "temp6_status", NULL, 0, 0444, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &pc87365_in_status}, - {PC87365_SYSCTL_VID, "vid", NULL, 0, 0444, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &pc87365_vid}, - {PC87365_SYSCTL_VRM, "vrm", NULL, 0, 0644, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &pc87365_vrm}, - {0} -}; - -static int pc87360_attach_adapter(struct i2c_adapter *adapter) -{ - return i2c_detect(adapter, &addr_data, pc87360_detect); -} - -static int __init pc87360_find(int sioaddr, u8 *devid, int *address) -{ - u16 val; - int i; - int nrdev; /* logical device count */ - - /* No superio_enter */ - - /* Identify device */ - val = superio_inb(sioaddr, DEVID); - switch (val) { - case 0xE1: /* PC87360 */ - case 0xE8: /* PC87363 */ - case 0xE4: /* PC87364 */ - nrdev = 1; - break; - case 0xE5: /* PC87365 */ - case 0xE9: /* PC87366 */ - nrdev = 3; - break; - default: - superio_exit(sioaddr); - return -ENODEV; - } - /* Remember the device id */ - *devid = val; - - for (i = 0; i < nrdev; i++) { - /* select logical device */ - superio_outb(sioaddr, DEV, logdev[i]); - - val = superio_inb(sioaddr, ACT); - if (!(val & 0x01)) { - printk(KERN_INFO "pc87360.o: Device 0x%02x not " - "activated\n", logdev[i]); - continue; - } - - val = (superio_inb(sioaddr, BASE) << 8) - | superio_inb(sioaddr, BASE + 1); - if (!val) { - printk(KERN_INFO "pc87360.o: Base address not set for " - "device 0x%02x\n", logdev[i]); - continue; - } - - address[i] = val; - - if (i==0) { /* Fans */ - confreg[0] = superio_inb(sioaddr, 0xF0); - confreg[1] = superio_inb(sioaddr, 0xF1); - -#ifdef DEBUG - printk(KERN_DEBUG "pc87360.o: Fan 1: mon=%d " - "ctrl=%d inv=%d\n", (confreg[0]>>2)&1, - (confreg[0]>>3)&1, (confreg[0]>>4)&1); - printk(KERN_DEBUG "pc87360.o: Fan 2: mon=%d " - "ctrl=%d inv=%d\n", (confreg[0]>>5)&1, - (confreg[0]>>6)&1, (confreg[0]>>7)&1); - printk(KERN_DEBUG "pc87360.o: Fan 3: mon=%d " - "ctrl=%d inv=%d\n", confreg[1]&1, - (confreg[1]>>1)&1, (confreg[1]>>2)&1); -#endif - } else if (i==1) { /* Voltages */ - /* Are we using thermistors? */ - if (*devid == 0xE9) { /* PC87366 */ - /* These registers are not logical-device - specific, just that we won't need them if - we don't use the VLM device */ - confreg[2] = superio_inb(sioaddr, 0x2B); - confreg[3] = superio_inb(sioaddr, 0x25); - - if (confreg[2] & 0x40) { - printk(KERN_INFO "pc87360.o: Using " - "thermistors for temperature " - "monitoring\n"); - } - if (confreg[3] & 0xE0) { - printk(KERN_INFO "pc87360.o: VID " - "inputs routed (mode %u)\n", - confreg[3] >> 5); - } - } - } - } - - superio_exit(sioaddr); - return 0; -} - -/* We don't really care about the address. - Read from extra_isa instead. */ -int pc87360_detect(struct i2c_adapter *adapter, int address, - unsigned short flags, int kind) -{ - int i; - struct i2c_client *new_client; - struct pc87360_data *data; - int err = 0; - const char *type_name = "pc87360"; - const char *client_name = "PC8736x chip"; - ctl_table *template = pc87360_dir_table_template; - int use_thermistors = 0; - - if (!i2c_is_isa_adapter(adapter)) { - return 0; - } - - for (i = 0; i < 3; i++) { - if (extra_isa[i] - && check_region(extra_isa[i], PC87360_EXTENT)) { - printk(KERN_ERR "pc87360.o: Region 0x%x-0x%x already " - "in use!\n", extra_isa[i], - extra_isa[i]+PC87360_EXTENT-1); - return -ENODEV; - } - } - - if (!(data = kmalloc(sizeof(struct pc87360_data), GFP_KERNEL))) { - return -ENOMEM; - } - memset(data, 0x00, sizeof(struct pc87360_data)); - - new_client = &data->client; - new_client->addr = address; - init_MUTEX(&data->lock); - new_client->data = data; - new_client->adapter = adapter; - new_client->driver = &pc87360_driver; - new_client->flags = 0; - - data->fannr = 2; - data->innr = 0; - data->tempnr = 0; - - switch (devid) { - case 0xe8: - type_name = "pc87363"; - break; - case 0xe4: - type_name = "pc87364"; - data->fannr = 3; - break; - case 0xe5: - type_name = "pc87365"; - template = pc87365_dir_table_template; - data->fannr = extra_isa[0] ? 3 : 0; - data->innr = extra_isa[1] ? 11 : 0; - data->tempnr = extra_isa[2] ? 2 : 0; - break; - case 0xe9: - type_name = "pc87366"; - template = pc87365_dir_table_template; - data->fannr = extra_isa[0] ? 3 : 0; - data->innr = extra_isa[1] ? 14 : 0; - data->tempnr = extra_isa[2] ? 3 : 0; - break; - } - - /* Retrieve the fans configuration from Super-I/O space */ - if (data->fannr) - data->fan_conf = confreg[0] | (confreg[1] << 8); - - for (i = 0; i < 3; i++) { - if ((data->address[i] = extra_isa[i])) { - request_region(extra_isa[i], PC87360_EXTENT, "pc87360"); - } - } - strcpy(new_client->name, client_name); - data->valid = 0; - init_MUTEX(&data->update_lock); - - if ((err = i2c_attach_client(new_client))) - goto ERROR1; - - /* Use the correct reference voltage - Unless both the VLM and the TMS logical devices agree to - use an external Vref, the internal one is used. */ - if (data->innr) { - i = pc87360_read_value(data, LD_IN, NO_BANK, - PC87365_REG_IN_CONFIG); - if (data->tempnr) { - i &= pc87360_read_value(data, LD_TEMP, NO_BANK, - PC87365_REG_TEMP_CONFIG); - } - data->in_vref = (i&0x02) ? 3025 : 2966; -#ifdef DEBUG - printk(KERN_DEBUG "pc87360.o: Using %s reference voltage\n", - (i&0x02) ? "external" : "internal"); -#endif - - data->vid_conf = confreg[3]; - data->vrm = 90; - } - - /* Fan clock dividers may be needed before any data is read */ - for (i = 0; i < data->fannr; i++) { - if (FAN_CONFIG_MONITOR(data->fan_conf, i)) - data->fan_status[i] = pc87360_read_value(data, - LD_FAN, NO_BANK, - PC87360_REG_FAN_STATUS(i)); - } - - if (init > 0) { - if (devid == 0xe9 && data->address[1]) /* PC87366 */ - use_thermistors = confreg[2] & 0x40; - - pc87360_init_client(new_client, use_thermistors); - } - - if ((i = i2c_register_entry((struct i2c_client *) new_client, - type_name, template, THIS_MODULE)) < 0) { - err = i; - goto ERROR2; - } - data->sysctl_id = i; - - return 0; - -ERROR2: - i2c_detach_client(new_client); -ERROR1: - for (i = 0; i < 3; i++) { - if (data->address[i]) { - release_region(data->address[i], PC87360_EXTENT); - } - } - kfree(data); - return err; -} - -static int pc87360_detach_client(struct i2c_client *client) -{ - struct pc87360_data *data = client->data; - int i, err; - - i2c_deregister_entry(data->sysctl_id); - - if ((err = i2c_detach_client(client))) { - printk(KERN_ERR "pc87360.o: Client deregistration failed, " - "client not detached.\n"); - return err; - } - - for (i = 0; i < 3; i++) { - if (data->address[i]) { - release_region(data->address[i], PC87360_EXTENT); - } - } - kfree(client->data); - - return 0; -} - -/* ldi is the logical device index - bank is for voltages and temperatures only */ -static int pc87360_read_value(struct pc87360_data *data, u8 ldi, u8 bank, - u8 reg) -{ - int res; - - down(&(data->lock)); - if (bank != NO_BANK) { - outb_p(bank, data->address[ldi] + PC87365_REG_BANK); - } - res = inb_p(data->address[ldi] + reg); - up(&(data->lock)); - return res; -} - -static void pc87360_write_value(struct pc87360_data *data, u8 ldi, u8 bank, - u8 reg, u8 value) -{ - down(&(data->lock)); - if (bank != NO_BANK) { - outb_p(bank, data->address[ldi] + PC87365_REG_BANK); - } - outb_p(value, data->address[ldi] + reg); - up(&(data->lock)); -} - -static void pc87360_init_client(struct i2c_client *client, int use_thermistors) -{ - struct pc87360_data *data = client->data; - int i, nr; - const u8 init_in[14] = { 2, 2, 2, 2, 2, 2, 2, 1, 1, 3, 1, 2, 2, 2 }; - const u8 init_temp[3] = { 2, 2, 1 }; - u8 reg; - - if (init >= 2 && data->innr) { - reg = pc87360_read_value(data, LD_IN, NO_BANK, - PC87365_REG_IN_CONVRATE); - printk(KERN_INFO "pc87360.o: VLM conversion set to " - "1s period, 160us delay\n"); - pc87360_write_value(data, LD_IN, NO_BANK, - PC87365_REG_IN_CONVRATE, - (reg & 0xC0) | 0x11); - } - - nr = data->innr < 11 ? data->innr : 11; - for (i=0; i= init_in[i]) { - /* Forcibly enable voltage channel */ - reg = pc87360_read_value(data, LD_IN, i, - PC87365_REG_IN_STATUS); - if (!(reg & 0x01)) { -#ifdef DEBUG - printk(KERN_DEBUG "pc87360.o: Forcibly " - "enabling in%d\n", i); -#endif - pc87360_write_value(data, LD_IN, i, - PC87365_REG_IN_STATUS, - (reg & 0x68) | 0x87); - } - } - } - - /* We can't blindly trust the Super-I/O space configuration bit, - most BIOS won't set it properly */ - for (i=11; iinnr; i++) { - reg = pc87360_read_value(data, LD_IN, i, - PC87365_REG_TEMP_STATUS); - use_thermistors = use_thermistors || (reg & 0x01); - } - - i = use_thermistors ? 2 : 0; - for (; itempnr; i++) { - if (init >= init_temp[i]) { - /* Forcibly enable temperature channel */ - reg = pc87360_read_value(data, LD_TEMP, i, - PC87365_REG_TEMP_STATUS); - if (!(reg & 0x01)) { -#ifdef DEBUG - printk(KERN_DEBUG "pc87360.o: Forcibly " - "enabling temp%d\n", i+1); -#endif - pc87360_write_value(data, LD_TEMP, i, - PC87365_REG_TEMP_STATUS, - 0xCF); - } - } - } - - if (use_thermistors) { - for (i=11; iinnr; i++) { - if (init >= init_in[i]) { - /* The pin may already be used by thermal - diodes */ - reg = pc87360_read_value(data, LD_TEMP, (i-11)/2, - PC87365_REG_TEMP_STATUS); - if (reg & 0x01) { -#ifdef DEBUG - printk(KERN_DEBUG "pc87360.o: Skipping " - "temp%d, pin already in use by " - "temp%d\n", i-7, (i-11)/2); -#endif - continue; - } - - /* Forcibly enable thermistor channel */ - reg = pc87360_read_value(data, LD_IN, i, - PC87365_REG_IN_STATUS); - if (!(reg & 0x01)) { -#ifdef DEBUG - printk(KERN_DEBUG "pc87360.o: Forcibly " - "enabling temp%d\n", i-7); -#endif - pc87360_write_value(data, LD_IN, i, - PC87365_REG_TEMP_STATUS, - (reg & 0x60) | 0x8F); - } - } - } - } - - if (data->innr) { - reg = pc87360_read_value(data, LD_IN, NO_BANK, - PC87365_REG_IN_CONFIG); - if (reg & 0x01) { -#ifdef DEBUG - printk(KERN_DEBUG "pc87360.o: Forcibly " - "enabling monitoring (VLM)\n"); -#endif - pc87360_write_value(data, LD_IN, NO_BANK, - PC87365_REG_IN_CONFIG, - reg & 0xFE); - } - } - - if (data->tempnr) { - reg = pc87360_read_value(data, LD_TEMP, NO_BANK, - PC87365_REG_TEMP_CONFIG); - if (reg & 0x01) { -#ifdef DEBUG - printk(KERN_DEBUG "pc87360.o: Forcibly " - "enabling monitoring (TMS)\n"); -#endif - pc87360_write_value(data, LD_TEMP, NO_BANK, - PC87365_REG_TEMP_CONFIG, - reg & 0xFE); - } - - if (init >= 2) { - /* Chip config as documented by National Semi. */ - pc87360_write_value(data, LD_TEMP, 0xF, 0xA, 0x08); - /* We voluntarily omit the bank here, in case the - sequence itself matters. It shouldn't be a problem, - since nobody else is supposed to access the - device at that point. */ - pc87360_write_value(data, LD_TEMP, NO_BANK, 0xB, 0x04); - pc87360_write_value(data, LD_TEMP, NO_BANK, 0xC, 0x35); - pc87360_write_value(data, LD_TEMP, NO_BANK, 0xD, 0x05); - pc87360_write_value(data, LD_TEMP, NO_BANK, 0xE, 0x05); - } - } -} - -static void pc87360_autodiv(struct pc87360_data *data, int nr) -{ - u8 old_min = data->fan_min[nr]; - - /* Increase clock divider if needed and possible */ - if ((data->fan_status[nr] & 0x04) /* overflow flag */ - || (data->fan[nr] >= 224)) { /* next to overflow */ - if ((data->fan_status[nr] & 0x60) != 0x60) { - data->fan_status[nr] += 0x20; - data->fan_min[nr] >>= 1; - data->fan[nr] >>= 1; -#ifdef DEBUG - printk(KERN_DEBUG "pc87360.o: Increasing " - "clock divider to %d for fan %d\n", - FAN_DIV_FROM_REG(data->fan_status[nr]), - nr+1); -#endif - } - } else { - /* Decrease clock divider if possible */ - while (!(data->fan_min[nr] & 0x80) /* fan min "nails" divider */ - && data->fan[nr] < 85 /* bad accuracy */ - && (data->fan_status[nr] & 0x60) != 0x00) { - data->fan_status[nr] -= 0x20; - data->fan_min[nr] <<= 1; - data->fan[nr] <<= 1; -#ifdef DEBUG - printk(KERN_DEBUG "pc87360.o: Decreasing " - "clock divider to %d for fan %d\n", - FAN_DIV_FROM_REG(data->fan_status[nr]), - nr+1); -#endif - } - } - - /* Write new fan min if it changed */ - if (old_min != data->fan_min[nr]) { - pc87360_write_value(data, LD_FAN, NO_BANK, - PC87360_REG_FAN_MIN(nr), - data->fan_min[nr]); - } -} - -static void pc87360_update_client(struct i2c_client *client) -{ - struct pc87360_data *data = client->data; - u8 i; - - down(&data->update_lock); - - if ((jiffies - data->last_updated > HZ * 2) || - (jiffies < data->last_updated) || !data->valid) { -#ifdef DEBUG - printk(KERN_DEBUG "pc87360.o: Data update\n"); -#endif - - /* Fans */ - for (i = 0; i < data->fannr; i++) { - if (FAN_CONFIG_MONITOR(data->fan_conf, i)) { - data->fan_status[i] = pc87360_read_value(data, - LD_FAN, NO_BANK, - PC87360_REG_FAN_STATUS(i)); - data->fan[i] = pc87360_read_value(data, LD_FAN, - NO_BANK, PC87360_REG_FAN(i)); - data->fan_min[i] = pc87360_read_value(data, - LD_FAN, NO_BANK, - PC87360_REG_FAN_MIN(i)); - /* Change clock divider if needed */ - pc87360_autodiv(data, i); - /* Clear bits and write new divider */ - pc87360_write_value(data, LD_FAN, NO_BANK, - PC87360_REG_FAN_STATUS(i), - data->fan_status[i]); - } - data->pwm[i] = pc87360_read_value(data, LD_FAN, - NO_BANK, PC87360_REG_PWM(i)); - } - - /* Voltages */ - for (i = 0; i < data->innr; i++) { - data->in_status[i] = pc87360_read_value(data, LD_IN, i, - PC87365_REG_IN_STATUS); - /* Clear bits */ - pc87360_write_value(data, LD_IN, i, - PC87365_REG_IN_STATUS, - data->in_status[i]); - if ((data->in_status[i] & 0x81) == 0x81) { - data->in[i] = pc87360_read_value(data, LD_IN, - i, PC87365_REG_IN); - } - if (data->in_status[i] & 0x01) { - data->in_min[i] = pc87360_read_value(data, - LD_IN, i, - PC87365_REG_IN_MIN); - data->in_max[i] = pc87360_read_value(data, - LD_IN, i, - PC87365_REG_IN_MAX); - if (i >= 11) - data->in_crit[i-11] = - pc87360_read_value(data, LD_IN, - i, PC87365_REG_TEMP_CRIT); - } - } - if (data->innr) { - data->in_alarms = pc87360_read_value(data, LD_IN, - NO_BANK, PC87365_REG_IN_ALARMS1) - | ((pc87360_read_value(data, LD_IN, - NO_BANK, PC87365_REG_IN_ALARMS2) - & 0x07) << 8); - data->vid = (data->vid_conf & 0xE0) ? - pc87360_read_value(data, LD_IN, - NO_BANK, PC87365_REG_VID) : 0x1F; - } - - /* Temperatures */ - for (i = 0; i < data->tempnr; i++) { - data->temp_status[i] = pc87360_read_value(data, - LD_TEMP, i, - PC87365_REG_TEMP_STATUS); - /* Clear bits */ - pc87360_write_value(data, LD_TEMP, i, - PC87365_REG_TEMP_STATUS, - data->temp_status[i]); - if ((data->temp_status[i] & 0x81) == 0x81) { - data->temp[i] = pc87360_read_value(data, - LD_TEMP, i, - PC87365_REG_TEMP); - } - if (data->temp_status[i] & 0x01) { - data->temp_min[i] = pc87360_read_value(data, - LD_TEMP, i, - PC87365_REG_TEMP_MIN); - data->temp_max[i] = pc87360_read_value(data, - LD_TEMP, i, - PC87365_REG_TEMP_MAX); - data->temp_crit[i] = pc87360_read_value(data, - LD_TEMP, i, - PC87365_REG_TEMP_CRIT); - } - } - if (data->tempnr) { - data->temp_alarms = pc87360_read_value(data, LD_TEMP, - NO_BANK, PC87365_REG_TEMP_ALARMS) - & 0x3F; - } - - data->last_updated = jiffies; - data->valid = 1; - } - - up(&data->update_lock); -} - - -void pc87365_alarms(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct pc87360_data *data = client->data; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - pc87360_update_client(client); - results[0] = data->in_alarms; - results[1] = data->temp_alarms; - *nrels_mag = 2; - } -} - -void pc87360_fan(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct pc87360_data *data = client->data; - int nr = ctl_name - PC87360_SYSCTL_FAN1; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - pc87360_update_client(client); - results[0] = FAN_FROM_REG(data->fan_min[nr], - FAN_DIV_FROM_REG(data->fan_status[nr])); - results[1] = FAN_FROM_REG(data->fan[nr], - FAN_DIV_FROM_REG(data->fan_status[nr])); - *nrels_mag = 2; - } - /* We ignore National's recommendation */ - else if (operation == SENSORS_PROC_REAL_WRITE) { - if (nr >= data->fannr) - return; - if (*nrels_mag >= 1) { - int fan_min = FAN_TO_REG(results[0], - FAN_DIV_FROM_REG(data->fan_status[nr])); - /* If it wouldn't fit, change clock divisor */ - while (fan_min > 255 - && (data->fan_status[nr] & 0x60) != 0x60) { - fan_min >>= 1; - data->fan[nr] >>= 1; - data->fan_status[nr] += 0x20; - } - data->fan_min[nr] = fan_min > 255 ? 255 : fan_min; - pc87360_write_value(data, LD_FAN, NO_BANK, - PC87360_REG_FAN_MIN(nr), - data->fan_min[nr]); - /* Write new divider, preserve alarm bits */ - pc87360_write_value(data, LD_FAN, NO_BANK, - PC87360_REG_FAN_STATUS(nr), - data->fan_status[nr] & 0xF9); - } - } -} - -void pc87360_fan_div(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results) -{ - struct pc87360_data *data = client->data; - int i; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - pc87360_update_client(client); - for (i = 0; i < data->fannr; i++) { - results[i] = FAN_DIV_FROM_REG(data->fan_status[i]); - } - for (; i < 3; i++) { - results[i] = 0; - } - *nrels_mag = 3; - } -} - -void pc87360_pwm(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct pc87360_data *data = client->data; - int nr = ctl_name - PC87360_SYSCTL_PWM1; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - pc87360_update_client(client); - results[0] = PWM_FROM_REG(data->pwm[nr], - FAN_CONFIG_INVERT(data->fan_conf, nr)); - results[1] = FAN_CONFIG_CONTROL(data->fan_conf, nr); - *nrels_mag = 2; - } - else if (operation == SENSORS_PROC_REAL_WRITE) { - if (nr >= data->fannr) - return; - if (*nrels_mag >= 1) { - data->pwm[nr] = PWM_TO_REG(results[0], - FAN_CONFIG_INVERT(data->fan_conf, nr)); - pc87360_write_value(data, LD_FAN, NO_BANK, - PC87360_REG_PWM(nr), - data->pwm[nr]); - } - } -} - -void pc87360_fan_status(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct pc87360_data *data = client->data; - int nr = ctl_name - PC87360_SYSCTL_FAN1_STATUS; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - pc87360_update_client(client); - results[0] = FAN_STATUS_FROM_REG(data->fan_status[nr]); - *nrels_mag = 1; - } -} - -void pc87365_in(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct pc87360_data *data = client->data; - int nr = ctl_name - PC87365_SYSCTL_IN0; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 3; - else if (operation == SENSORS_PROC_REAL_READ) { - pc87360_update_client(client); - results[0] = IN_FROM_REG(data->in_min[nr], data->in_vref); - results[1] = IN_FROM_REG(data->in_max[nr], data->in_vref); - if (nr < 11) { - *nrels_mag = 3; - } else { - results[2] = IN_FROM_REG(data->in_crit[nr-11], - data->in_vref); - *nrels_mag = 4; - } - results[(*nrels_mag)-1] = IN_FROM_REG(data->in[nr], - data->in_vref); - } - else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag >= 1) { - data->in_min[nr] = IN_TO_REG(results[0], - data->in_vref); - pc87360_write_value(data, LD_IN, nr, - PC87365_REG_IN_MIN, - data->in_min[nr]); - } - if (*nrels_mag >= 2) { - data->in_max[nr] = IN_TO_REG(results[1], - data->in_vref); - pc87360_write_value(data, LD_IN, nr, - PC87365_REG_IN_MAX, - data->in_max[nr]); - } - if (*nrels_mag >= 3 && nr >= 11) { - data->in_crit[nr-11] = IN_TO_REG(results[2], - data->in_vref); - pc87360_write_value(data, LD_IN, nr, - PC87365_REG_TEMP_CRIT, - data->in_crit[nr-11]); - } - } -} - -void pc87365_in_status(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct pc87360_data *data = client->data; - int nr = ctl_name - PC87365_SYSCTL_IN0_STATUS; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - pc87360_update_client(client); - results[0] = data->in_status[nr]; - *nrels_mag = 1; - } -} - -void pc87365_vid(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct pc87360_data *data = client->data; - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 3; - else if (operation == SENSORS_PROC_REAL_READ) { - pc87360_update_client(client); - results[0] = vid_from_reg(data->vid & 0x1f, data->vrm); - *nrels_mag = 1; - } -} - -void pc87365_vrm(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct pc87360_data *data = client->data; - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 1; - else if (operation == SENSORS_PROC_REAL_READ) { - results[0] = data->vrm; - *nrels_mag = 1; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag >= 1) - data->vrm = results[0]; - } -} - -void pc87365_temp(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct pc87360_data *data = client->data; - int nr = ctl_name - PC87365_SYSCTL_TEMP1; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - pc87360_update_client(client); - results[0] = TEMP_FROM_REG(data->temp_max[nr]); - results[1] = TEMP_FROM_REG(data->temp_min[nr]); - results[2] = TEMP_FROM_REG(data->temp_crit[nr]); - results[3] = TEMP_FROM_REG(data->temp[nr]); - *nrels_mag = 4; - } - else if (operation == SENSORS_PROC_REAL_WRITE) { - if (nr >= data->tempnr) - return; - if (*nrels_mag >= 1) { - data->temp_max[nr] = TEMP_TO_REG(results[0]); - pc87360_write_value(data, LD_TEMP, nr, - PC87365_REG_TEMP_MAX, - data->temp_max[nr]); - } - if (*nrels_mag >= 2) { - data->temp_min[nr] = TEMP_TO_REG(results[1]); - pc87360_write_value(data, LD_TEMP, nr, - PC87365_REG_TEMP_MIN, - data->temp_min[nr]); - } - if (*nrels_mag >= 3) { - data->temp_crit[nr] = TEMP_TO_REG(results[2]); - pc87360_write_value(data, LD_TEMP, nr, - PC87365_REG_TEMP_CRIT, - data->temp_crit[nr]); - } - } -} - -void pc87365_temp_status(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct pc87360_data *data = client->data; - int nr = ctl_name - PC87365_SYSCTL_TEMP1_STATUS; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - pc87360_update_client(client); - results[0] = data->temp_status[nr]; - *nrels_mag = 1; - } -} - - -static int __init pc87360_init(void) -{ - int i; - - printk(KERN_INFO "pc87360.o version %s (%s)\n", LM_VERSION, LM_DATE); - - if (pc87360_find(0x2e, &devid, extra_isa) - && pc87360_find(0x4e, &devid, extra_isa)) { - printk(KERN_WARNING "pc87360.o: PC8736x not detected, " - "module not inserted.\n"); - return -ENODEV; - } - - /* Arbitrarily pick one of the addresses */ - for (i = 0; i < 3; i++) { - if (extra_isa[i] != 0x0000) { - normal_isa[0] = extra_isa[i]; - break; - } - } - - if (normal_isa[0] == 0x0000) { - printk(KERN_WARNING "pc87360.o: No active logical device, " - "module not inserted.\n"); - return -ENODEV; - - } - - return i2c_add_driver(&pc87360_driver); -} - -static void __exit pc87360_exit(void) -{ - i2c_del_driver(&pc87360_driver); -} - - -MODULE_AUTHOR("Jean Delvare "); -MODULE_DESCRIPTION("PC8736x hardware monitor"); -MODULE_LICENSE("GPL"); - -module_init(pc87360_init); -module_exit(pc87360_exit); diff --git a/kernel/chips/pca9540.c b/kernel/chips/pca9540.c deleted file mode 100644 index 8ec5c29b..00000000 --- a/kernel/chips/pca9540.c +++ /dev/null @@ -1,241 +0,0 @@ -/* - * pca9540.c - Part of lm_sensors, Linux kernel modules for hardware - * monitoring - * Copyright (c) 2004 Jean Delvare - * - * Based on pcf8574.c from the same project by Frodo Looijaard, - * Philip Edelbrock, Dan Eaton and Aurelien Jarno. - * - * The PCA9540 is a 2-channel I2C multiplexer made by Philips - * Semiconductors. It is controlled via the I2C bus itself. - * The SCL/SDA upstream pair fans out to two SCL/SDA downstream - * pairs, or channels. Only one SCL/SDA channel is selected at a - * time, determined by the contents of the programmable control - * register. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include -#include -#include -#include -#include -#include "version.h" - -MODULE_LICENSE("GPL"); - -/* Addresses to scan */ -static unsigned short normal_i2c[] = { 0x70, SENSORS_I2C_END }; -static unsigned short normal_i2c_range[] = { SENSORS_I2C_END }; -static unsigned int normal_isa[] = { SENSORS_ISA_END }; -static unsigned int normal_isa_range[] = { SENSORS_ISA_END }; - -/* Insmod parameters */ -SENSORS_INSMOD_1(pca9540); - -/* Each client has this additional data */ -struct pca9540_data { - struct i2c_client client; - int sysctl_id; - - struct semaphore update_lock; - - u8 control; /* Register value */ -}; - -static int pca9540_attach_adapter(struct i2c_adapter *adapter); -static int pca9540_detect(struct i2c_adapter *adapter, int address, - unsigned short flags, int kind); -static int pca9540_detach_client(struct i2c_client *client); -static void pca9540_update_client(struct i2c_client *client); - -static void pca9540_channel(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); - -/* This is the driver that will be inserted */ -static struct i2c_driver pca9540_driver = { - .name = "PCA9540 chip driver", - .flags = I2C_DF_NOTIFY, - .attach_adapter = pca9540_attach_adapter, - .detach_client = pca9540_detach_client, -}; - - -/* -- SENSORS SYSCTL START -- */ - -#define PCA9540_SYSCTL_CHANNEL 1000 - -/* -- SENSORS SYSCTL END -- */ - -static ctl_table pca9540_dir_table_template[] = { - {PCA9540_SYSCTL_CHANNEL, "channel", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &pca9540_channel}, - {0} -}; - -static int pca9540_attach_adapter(struct i2c_adapter *adapter) -{ - return i2c_detect(adapter, &addr_data, pca9540_detect); -} - -/* This function is called by i2c_detect. */ -int pca9540_detect(struct i2c_adapter *adapter, int address, - unsigned short flags, int kind) -{ - int i; - struct i2c_client *new_client; - struct pca9540_data *data; - int err = 0; - - if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE)) - goto ERROR0; - - /* OK. For now, we presume we have a valid client. We now create the - client structure, even though we cannot fill it completely yet. */ - if (!(data = kmalloc(sizeof(struct pca9540_data), GFP_KERNEL))) { - err = -ENOMEM; - goto ERROR0; - } - - new_client = &data->client; - new_client->addr = address; - new_client->data = data; - new_client->adapter = adapter; - new_client->driver = &pca9540_driver; - new_client->flags = 0; - - /* The detection is very weak. */ - if (kind < 0) { - u8 reg = i2c_smbus_read_byte(new_client); - if ((reg & 0xfa) != 0x00 - || reg != i2c_smbus_read_byte(new_client) - || reg != i2c_smbus_read_byte(new_client) - || reg != i2c_smbus_read_byte(new_client)) - goto ERROR1; - } - - kind = pca9540; - - /* Fill in the remaining client fields and put it into the global list */ - strcpy(new_client->name, "PCA9540 chip"); - init_MUTEX(&data->update_lock); - - /* Tell the I2C layer a new client has arrived */ - if ((err = i2c_attach_client(new_client))) - goto ERROR1; - - /* Register a new directory entry with module sensors */ - if ((i = i2c_register_entry(new_client, "pca9540", - pca9540_dir_table_template, - THIS_MODULE)) < 0) { - err = i; - goto ERROR2; - } - data->sysctl_id = i; - - /* Initialize the PCA9540 chip: nothing needed */ - - return 0; - -/* OK, this is not exactly good programming practice, usually. But it is - very code-efficient in this case. */ - - ERROR2: - i2c_detach_client(new_client); - ERROR1: - kfree(data); - ERROR0: - return err; -} - -static int pca9540_detach_client(struct i2c_client *client) -{ - int err; - - i2c_deregister_entry(((struct pca9540_data *) (client->data))->sysctl_id); - - if ((err = i2c_detach_client(client))) { - printk(KERN_ERR "pca9540.o: Client deregistration failed, " - "client not detached.\n"); - return err; - } - - kfree(client->data); - - return 0; -} - -static void pca9540_update_client(struct i2c_client *client) -{ - struct pca9540_data *data = client->data; - - down(&data->update_lock); - -#ifdef DEBUG - printk(KERN_DEBUG "pca9540.o: Starting update.\n"); -#endif - data->control = i2c_smbus_read_byte(client) & 0x07; - - up(&data->update_lock); -} - - -void pca9540_channel(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results) -{ - struct pca9540_data *data = client->data; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - pca9540_update_client(client); - switch(data->control) { - case 4: results[0] = 1; break; - case 5: results[0] = 2; break; - default: results[0] = 0; - } - *nrels_mag = 1; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag >= 1) { - switch(results[0]) { - case 1: data->control = 4; break; - case 2: data->control = 5; break; - case 0: data->control = 0; break; - default: return; /* invalid value */ - } - i2c_smbus_write_byte(client, data->control); - } - } -} - - -static int __init pca9540_init(void) -{ - printk("pca9540.o version %s (%s)\n", LM_VERSION, LM_DATE); - return i2c_add_driver(&pca9540_driver); -} - -static void __exit pca9540_exit(void) -{ - i2c_del_driver(&pca9540_driver); -} - - -MODULE_AUTHOR("Jean Delvare "); -MODULE_DESCRIPTION("PCA9540 driver"); - -module_init(pca9540_init); -module_exit(pca9540_exit); diff --git a/kernel/chips/pca954x.c b/kernel/chips/pca954x.c deleted file mode 100644 index db3a336c..00000000 --- a/kernel/chips/pca954x.c +++ /dev/null @@ -1,836 +0,0 @@ -/* - * pca954x.c - Part of lm_sensors, Linux kernel modules for hardware - * monitoring - * This module supports the PCA954x series of I2C multiplexer/switch chips - * made by Philips Semiconductors. This includes the - * PCA9540, PCA9542, PCA9543, PCA9544, PCA9545, PCA9546, and PCA9548. - * - * Copyright (c) 2004 Google, Inc. (Ken Harrenstien) - * - * Based on: - * i2c-virtual_cb.c from Brian Kuschak - * and - * pca9540.c from Jean Delvare , which was - * based on pcf8574.c from the same project by Frodo Looijaard, - * Philip Edelbrock, Dan Eaton and Aurelien Jarno. - * - * These chips are all controlled via the I2C bus itself, and all have a - * single 8-bit register (normally at 0x70). The upstream "parent" bus fans - * out to two, four, or eight downstream busses or channels; which of these - * are selected is determined by the chip type and register contents. A - * mux can select only one sub-bus at a time; a switch can select any - * combination simultaneously. - * - * See Documentation/i2c/virtual_i2c for details on the virtual bus/adapter - * mechanism. - * - ********************************************************************* - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include -#include -#include -#include -#include -#include "i2c-virtual.h" -#include "version.h" - -MODULE_LICENSE("GPL"); - -#define DEBUG 1 /* XXX: Comment out before release? */ -#ifdef DEBUG -# define DBG(x) if (pca954x_debug > 0) { x; } else -#else -# define DBG(x) {} -#endif - -#define PCA954X_NCHANS 8 /* Max # of channels (PCA9548) */ - -/* Addresses to scan */ -static unsigned short normal_i2c[] = { /*0x70,*/ SENSORS_I2C_END }; -static unsigned short normal_i2c_range[] = { SENSORS_I2C_END }; -static unsigned int normal_isa[] = { SENSORS_ISA_END }; -static unsigned int normal_isa_range[] = { SENSORS_ISA_END }; - -/* Insmod/modprobe parameters */ - -/* Chip type must normally be specified using a parameter of the form - "force_pca9544=0,0x70" - The following declares the possible types. -*/ -SENSORS_INSMOD_7(pca9540,pca9542,pca9543,pca9544,pca9545,pca9546,pca9548); - -static int pca954x_debug; -MODULE_PARM(pca954x_debug, "i"); -MODULE_PARM_DESC(pca954x_debug, "Debug output level (0 = none)"); - -#if 0 /* Considered adding this, but too many issues. See doc. */ -static int pca954x_selmask[32]; /* Max # chips supported, sigh */ -MODULE_PARM(pca954x_selmask, "1-32i"); -MODULE_PARM_DESC(pca954x_selmask, "List of selmask settings for each mux/swi"); -#endif - -/* Provide specs for the PCA954x types we know about - */ -static struct pca954x_chipdef { - enum chips type; - const char *type_name; - int pcanum; - int nchans; - enum muxtype { pca954x_ismux=0, pca954x_isswi } muxtype; -} pca954x_chipdefs[] = { - { pca9540, "pca9540", 9540, 2, pca954x_ismux }, - { pca9542, "pca9542", 9542, 2, pca954x_ismux }, - { pca9543, "pca9543", 9543, 2, pca954x_isswi }, - { pca9544, "pca9544", 9544, 4, pca954x_ismux }, - { pca9545, "pca9545", 9545, 4, pca954x_isswi }, - { pca9546, "pca9546", 9546, 4, pca954x_isswi }, - { pca9548, "pca9548", 9548, 8, pca954x_isswi }, -}; -#define PCA954X_MUX_ENA 0x04 /* Mux enable bit */ - -/* Each client has this additional data. - Note the two conventions for identifying a chip's channel (sub-bus): - "channel" 0 to N-1, where N is the number of channels supported - "bitmask" 1 to 1 << N-1, so bit 0 is channel 0. - This use of "channel" is consistent with that in the Philips PCA954X doc. - */ -struct pca954x_data { - struct i2c_client client; - int sysctl_id; - enum chips type; - enum muxtype muxtype; - int pcanum; /* PCA chip number */ - int nchans; /* # of channels (busses) this chip controls */ - int nchmask; /* Mask of all channels */ - - struct semaphore update_lock; - int selmask; /* Bitmask of chans OK to leave on (chn1 == bit0) */ - int curmask; /* Bitmask of chans currently selected */ - - u8 regval; /* Current chip register value */ - u8 origval; /* Original value at initialization */ - - struct i2c_adapter *virt_adapters[PCA954X_NCHANS]; -}; - -static int pca954x_attach_adapter(struct i2c_adapter *adapter); -static int pca954x_detect(struct i2c_adapter *adapter, int address, - unsigned short flags, int kind); -static int pca954x_detach_client(struct i2c_client *client); -static void pca954x_pe_busses(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void pca954x_pe_debug(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void pca954x_pe_regval(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void pca954x_pe_selbus(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void pca954x_pe_selmask(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void pca954x_pe_type(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void pca954x_set_selmask(struct i2c_client *client, int mask); -static u8 pca954x_mask2val(struct i2c_client *client, int mask); -static int pca954x_val2mask(struct i2c_client *client, u8 val); - -static int pca954x_select_mux(struct i2c_adapter *adap, - struct i2c_mux_ctrl *mux); -static int pca954x_deselect_mux(struct i2c_adapter *adap, - struct i2c_mux_ctrl *mux); -static int pca954x_select_chan(struct i2c_adapter *adap, - struct i2c_client *client, unsigned long chan); -static int pca954x_xfer(struct i2c_adapter *adap, - struct i2c_client *client, - int read_write, u8 *val); - - -/* This is the driver that will be inserted */ -static struct i2c_driver pca954x_driver = { - .name = "PCA954X I2C mux/switch driver", - .flags = I2C_DF_NOTIFY, - .attach_adapter = pca954x_attach_adapter, - .detach_client = pca954x_detach_client, -}; - - -/* -- SENSORS SYSCTL START -- */ - -#define PCA954X_SYSCTL_BUSSES 1000 -#define PCA954X_SYSCTL_DEBUG 1001 -#define PCA954X_SYSCTL_REGVAL 1002 -#define PCA954X_SYSCTL_SELBUS 1003 -#define PCA954X_SYSCTL_SELMASK 1004 -#define PCA954X_SYSCTL_TYPE 1005 - -/* -- SENSORS SYSCTL END -- */ - -static ctl_table pca954x_dir_table_template[] = { - {PCA954X_SYSCTL_BUSSES, "busses", NULL, 0, 0444, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &pca954x_pe_busses}, - {PCA954X_SYSCTL_DEBUG, "debug", NULL, 0, 0644, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &pca954x_pe_debug}, - {PCA954X_SYSCTL_REGVAL, "regval", NULL, 0, 0444, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &pca954x_pe_regval}, - {PCA954X_SYSCTL_SELBUS, "selbus", NULL, 0, 0644, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &pca954x_pe_selbus}, - {PCA954X_SYSCTL_SELMASK, "selmask", NULL, 0, 0644, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &pca954x_pe_selmask}, - {PCA954X_SYSCTL_TYPE, "type", NULL, 0, 0444, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &pca954x_pe_type}, - {0} -}; - -static int pca954x_id = 0; - -static int __init pca954x_init(void) -{ - printk("pca954x.o version %s (%s)\n", LM_VERSION, LM_DATE); - - /* Because we've set I2C_DF_NOTIFY in our driver struct, - * this call results in calling pca954x_attach_adapter() for - * every adapter currently known, both real and virtual. - */ - return i2c_add_driver(&pca954x_driver); -} - -static void __exit pca954x_exit(void) -{ - i2c_del_driver(&pca954x_driver); -} - -/* This function is called whenever a new bus/adapter is added, OR when - the driver itself is added (for all existing adapters), to see if - the driver can find a chip address it's responsible for. - */ -static int pca954x_attach_adapter(struct i2c_adapter *adapter) -{ - DBG(printk(KERN_DEBUG "%s: %0lX\n", - __FUNCTION__, (unsigned long)adapter)); - - /* Apply standard lookup via parameters or probing. - "addr_data" is defined by the SENSORS_INSMOD_n macro. - */ - return i2c_detect(adapter, &addr_data, pca954x_detect); -} - -/* This function is called by i2c_detect and must be of type - "i2c_found_addr_proc" as defined in i2c-proc.h. - For the PCA954x series this should only happen due to "force" parameters - given to insmod/modprobe, as there is no way to autodetect what flavor - of chip we have (and the differences matter!) - - Thus, we should never get a "kind" of -1. - - Note the unique potential for infinite recursion here because we are - creating new adapters (one for each muxed virtual bus). This will cause - our attach_adapter() function to be called twice for each new adapter, - because: - - (1) The call to i2c_add_adapter results in calling the attach_adapter() - function of all known chip drivers, including this one. - - (2) Because normally this is first called via i2c_add_driver calling - i2c_add_adapter, each new virtual bus/adapter created here will create - a new entry in i2c-core's master adapter list at a point that hasn't - yet been reached by i2c_add_driver's scan, and thus i2c_add_driver - will cause yet another call to our attach_adapter for each of these - new bus/adapters. - - Each call to our attach_adapter() causes another call to i2c_detect, - which would detect the mux all over again if an actual probe was made. - - This is prevented in two ways. The first line of defense is - i2c_check_addr() which is called by both i2c-proc.c:i2c_detect() - and i2c-core.c:i2c_probe() to make sure a bus/addr pair has not already - been seen; that function now knows how to verify this on all parent - busses as well. - - The second line of defense is to never put anything in the "normal_i2c" - or "normal_i2c_range" tables that would induce i2c_detect() to probe - a PCA954x address. - */ -int pca954x_detect(struct i2c_adapter *adapter, int address, - unsigned short flags, int kind) -{ - int i, n; - struct i2c_client *client; - struct pca954x_data *data; - const char *type_name = ""; - int err = 0; - - DBG(printk(KERN_DEBUG "%s: %0lX %0x %0x %d\n", - __FUNCTION__, (unsigned long)adapter, - address, flags, kind)); - - /* XXX: Remove this after verifying that no more recursion - is happening! - */ - if (adapter->algo->id == I2C_ALGO_VIRT) { - - printk(KERN_ERR "%s: Avoiding recursion! %0lX %0x %0x %d\n", - __FUNCTION__, (unsigned long)adapter, - address, flags, kind); - goto ERROR0; - } - - if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE)) - goto ERROR0; - - /* OK. For now, we presume we have a valid client. We now create the - client structure, even though we cannot fill it completely yet. */ - if (!(data = kmalloc(sizeof(struct pca954x_data), GFP_KERNEL))) { - err = -ENOMEM; - goto ERROR0; - } - memset(data, 0, sizeof(struct pca954x_data)); - - client = &data->client; - client->addr = address; - client->data = data; - client->adapter = adapter; - client->driver = &pca954x_driver; - client->flags = 0; - - /* The detection is very weak. In fact, we have no way of - * telling what kind of mux/swi is there, and the differences matter, - * so if asked to figure it out we just complain instead. - */ - if (kind < 0) { - printk(KERN_ERR "%s: Attempted ill-advised probe at addr %0x", - __FUNCTION__, address); - goto ERROR1; - } - - /* Read the mux register at addr. This does two things: it verifies - that the mux is in fact present, and fetches its current - contents for possible use with a future deselect algorithm. - */ - if ((i = i2c_smbus_read_byte(client)) < 0) { - printk(KERN_WARNING - "i2c-%d: pca954x.o failed to read reg at %0x", - i2c_adapter_id(adapter), address); - goto ERROR1; - } - data->origval = i; - - if (kind == any_chip) { - printk(KERN_WARNING - "i2c-%d: pca954x.o needs advice on chip type -" - " wildly guessing %0x is a PCA9540", - i2c_adapter_id(adapter), address); - kind = pca9540; /* Make "any" default to PCA9540 */ - } - - /* Look up in table */ - for (i = sizeof(pca954x_chipdefs)/sizeof(pca954x_chipdefs[0]); - --i >= 0;) { - if (pca954x_chipdefs[i].type == kind) - break; - } - if (i < 0) { - printk(KERN_ERR "%s: Internal error: unknown kind (%d)\n", - __FUNCTION__, kind); - goto ERROR1; - } - data->type = kind; - type_name = pca954x_chipdefs[i].type_name; - data->pcanum = pca954x_chipdefs[i].pcanum; - data->nchans = pca954x_chipdefs[i].nchans; - data->muxtype = pca954x_chipdefs[i].muxtype; - data->nchmask = (1 << data->nchans) - 1; - - /* Now that we know the mux/swi type, we can analyze the - pca954x_selmask parameter, if one was specified. - - XXX: Not yet. Still uncertain whether there is a good way - to initialize selmask and still continue to detect other chips - correctly on the right busses, or whether the original reg - setting (origval) should be retained in case BIOS depends on it. - */ - - /* Fill in remaining client fields and put it into the global list */ - snprintf(client->name, sizeof(client->name), - "PCA%d I2C %d-chan %s chip", - data->pcanum, data->nchans, - (data->muxtype == pca954x_ismux ? "mux" : "switch")); - client->id = pca954x_id++; - init_MUTEX(&data->update_lock); - - /* Tell the I2C layer a new client has arrived */ - if ((err = i2c_attach_client(client))) - goto ERROR1; - - /* Register new /proc directory entries with module sensors */ - if ((i = i2c_register_entry(client, type_name, - pca954x_dir_table_template, - THIS_MODULE)) < 0) { - err = i; - goto ERROR2; - } - data->sysctl_id = i; - - /* Initialize the PCA954X chip. - For now, force unselected. This had better happen BEFORE any - other sensors modules are loaded, or their chip addresses will - stop working if they were actually behind the mux chip. - */ - pca954x_set_selmask(client, 0); - - /* Now create virtual busses and adapters for them */ - -#ifdef I2C_REQUIRE_ARBITRATION - /* This doesn't actually do anything yet; kept as a - placeholder from the original i2c-virtual_cb.c - */ - adapter->algo->acquire_exclusive = &acquire_shared_bus; - adapter->algo->release_exclusive = &release_shared_bus; -#endif - - DBG(printk(KERN_DEBUG "%s: creating %d virt busses\n", - __FUNCTION__, data->nchans)); - - for (i = 0, n = 0; i < data->nchans; ++i) { - struct i2c_adapter *virt; - virt = i2c_virt_create_adapter(adapter, client, i, - &pca954x_select_mux, - &pca954x_deselect_mux); - if ((data->virt_adapters[i] = virt) != NULL) - ++n; - } - printk("i2c-%d: Registered %d of %d virtual busses for I2C mux %s\n", - i2c_adapter_id(adapter), n, i, type_name); - - return 0; - - ERROR2: - i2c_detach_client(client); - ERROR1: - kfree(data); - ERROR0: - return err; -} - -static int pca954x_detach_client(struct i2c_client *client) -{ - struct pca954x_data *data = (struct pca954x_data *)(client->data); - int i, err; - - DBG(printk(KERN_DEBUG "%s: %0lX\n", - __FUNCTION__, (unsigned long)client)); - - /* Must flush everything attached to our channels! - */ - for (i = 0; i < data->nchans; ++i) { - if (data->virt_adapters[i]) { - err = i2c_virt_remove_adapter(data->virt_adapters[i]); - if (err != 0) { - printk(KERN_ERR "pca954x.o: Bus deregistration failed, " - "client not detached.\n"); - return err; - } - data->virt_adapters[i] = NULL; - } - } - - i2c_deregister_entry(data->sysctl_id); - - if ((err = i2c_detach_client(client))) { - printk(KERN_ERR "pca954x.o: Client deregistration failed, " - "client not detached.\n"); - return err; - } - - kfree(client->data); - - return 0; -} - - -/* Implement /proc "regval" - the actual contents of the chip register. - * This is READ-ONLY. - */ -void pca954x_pe_regval(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results) -{ - struct pca954x_data *data = client->data; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { -#if 0 /* XXX: For now, always use cached value */ - static void pca954x_update_client(struct i2c_client *client); - pca954x_update_client(client); -#endif - results[0] = data->regval; - *nrels_mag = 1; - } -} - -/* Implement /proc "debug" - a non-zero value enables debug output, if - * the code was compiled with it. This actually applies to all mux chips, - * not just a single instance, but that's OK. - */ -void pca954x_pe_debug(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results) -{ - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - results[0] = pca954x_debug; - *nrels_mag = 1; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag >= 1) { - pca954x_debug = results[0]; - } - } -} - -/* Implement /proc "busses" - list of (virtual) adapter IDs that constitute - the busses that this chip connects to. - This is READ-ONLY. - */ -void pca954x_pe_busses(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results) -{ - struct pca954x_data *data = client->data; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - int i, lasti; - if ((lasti = data->nchans) > *nrels_mag) - lasti = *nrels_mag; - for (i = 0; i < lasti; ++i) { - results[i] = i2c_adapter_id(data->virt_adapters[i]); - } - *nrels_mag = lasti; - } -} - -/* Implement /proc "selmask" - the value specifies the current default - * channel mask. Sub-bus 0 == bit 0. - # A value of 0 means "none" - */ -void pca954x_pe_selmask(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results) -{ - struct pca954x_data *data = client->data; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - results[0] = data->selmask; - *nrels_mag = 1; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag >= 1) { - pca954x_set_selmask(client, results[0]); - } - } -} - - -/* Implement /proc "selbus" - the list of values is considered to be virtual - adapter IDs, as an alternative representation of the select mask. - No values at all means "none". - */ -void pca954x_pe_selbus(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results) -{ - struct pca954x_data *data = client->data; - int i, nres; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - for (i = 0, nres = 0; i < data->nchans; ++i) { - if ((data->selmask & (1<virt_adapters[i]); - ++nres; - } - } - *nrels_mag = nres; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - int newmask = 0; - for (nres = 0; nres < *nrels_mag; ++nres) { - /* Ugly, but shouldn't happen very often */ - for (i = 0; i < data->nchans; ++i) { - if (results[nres] - == i2c_adapter_id(data->virt_adapters[i])) { - newmask |= (1<data; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - if (*nrels_mag >= 3) { - results[0] = data->pcanum; - results[1] = data->muxtype; - results[2] = data->nchans; - *nrels_mag = 3; - } - } -} - - -/* Set default select mask. - Since this can be executed while something else is using the mux or - one of its sub-busses, the main consideration is making sure we don't - mess up anything in progress. - - This is accomplished by locking the parent bus that the mux resides on, - and then calling our internal write function. - - It would not work to just call i2c_smbus_write_byte() because - by the time that returns, the values we're trying to update - could already be wrong. This can happen if something else grabs - the bus and writes to the mux (eg for doing I/O to a sub-bus - device), leading to a race condition for updating - selmask, regval, and curmask. - - It doesn't help to use an update_lock for those values because - you still have to contend with other threads trying to select - sub-busses and would encounter deadlocks. - - */ -static void pca954x_set_selmask(struct i2c_client *client, int mask) -{ - struct pca954x_data *data = client->data; - - DBG(printk(KERN_DEBUG - "%s: Locking bus %d mux %d (%0lX) " - "for write of selmask %0x\n", - __FUNCTION__, i2c_adapter_id(client->adapter), - client->id, (unsigned long)client, mask)); - - down(&client->adapter->bus); - DBG(printk(KERN_DEBUG "%s: Starting write.\n", __FUNCTION__)); - data->selmask = (mask & data->nchmask); - (void) pca954x_select_chan(client->adapter, client, -1); - up(&client->adapter->bus); - - DBG(printk(KERN_DEBUG "%s: Unlocked mux (%0lX) for write.\n", - __FUNCTION__, (unsigned long)client)); -} - -#if 0 /* Not needed at the moment; see pca954x_pe_regval() */ - -/* Read pca954x register into cached value - */ -static void pca954x_update_client(struct i2c_client *client) -{ - struct pca954x_data *data = client->data; - - DBG(printk(KERN_DEBUG - "%s: Locking bus %d mux %d (%0lX) for read\n", - __FUNCTION__, i2c_adapter_id(client->adapter), - client->id, (unsigned long)client)); - - down(&client->adapter->bus); - DBG(printk(KERN_DEBUG "%s: Starting read.\n", __FUNCTION__)); - pca954x_xfer(client->adapter, client, I2C_SMBUS_READ, &data->regval); - data->curmask = pca954x_val2mask(client, data->regval); - up(&client->adapter->bus); - - DBG(printk(KERN_DEBUG "%s: Unlocked mux (%0lX) for read.\n", - __FUNCTION__, (unsigned long)client)); -} -#endif - - -static u8 pca954x_mask2val(struct i2c_client *client, int mask) -{ - struct pca954x_data *data = (struct pca954x_data *)(client->data); - int i; - - mask &= data->nchmask; /* Sanitize mask */ - if (mask == 0) - return 0; /* Deselecting all, turn off */ - if (data->muxtype == pca954x_isswi) - return mask; /* Switch, can enable all at once! */ - - /* Mux, can only pick one. Select lowest chan bit */ - for (i=0; (mask & (1<data); - - if (data->muxtype == pca954x_isswi) - return val & data->nchmask; /* Switch val is == mask */ - - /* Mux - mask off low bits to get 0-based chan # as bit shift */ - if (val & PCA954X_MUX_ENA) - return 1 << (val & (data->nchans-1)); - return 0; -} - -/***************************************************************************** - * All of the following functions should only be called after the parent - * adapter bus semaphore (adapter->bus) has been acquired, so we cannot - * call the high-level i2c_smbus_write_byte() function -- it will deadlock - * attempting to acquire the same bus lock. Instead do directly what it - * would do, by means of pca954x_xfer(). Sigh! - * - * These functions are allowed to block. - * - *****************************************************************************/ - - -static int pca954x_select_mux(struct i2c_adapter *adap, - struct i2c_mux_ctrl *mux) -{ - return pca954x_select_chan(adap, mux->client, mux->value); -} - -static int pca954x_deselect_mux(struct i2c_adapter *adap, - struct i2c_mux_ctrl *mux) -{ - return pca954x_select_chan(adap, mux->client, -1); -} - -/* Select channel. - * PCA954x I2C-controlled bus mux/switch chips mainly differ in - * whether the chip is a mux or a switch: - * Mux: value addressed, only 1 bus can be selected. - * Swi: bitmask selected, any/all busses can be selected. - */ -static int pca954x_select_chan(struct i2c_adapter *adap, - struct i2c_client *client, - unsigned long chan) -{ - struct pca954x_data *data = (struct pca954x_data *)(client->data); - int maskbit; - u8 newregval; - int ret; - - if (chan == -1) { /* Op: clever deselect (to selmask) */ - if ((data->muxtype == pca954x_ismux) - && (data->curmask & data->selmask)) { - /* If mux, and current chan allowed by selmask, do nothing */ - newregval = data->regval; /* No change */ - } else { - /* Anything else just reverts to selmask */ - newregval = pca954x_mask2val(client, data->selmask); - } - - } else { /* Op: select chan */ - maskbit = 1 << chan; - if (maskbit & data->curmask) { /* If already selected, */ - newregval = data->regval; /* no change */ - } else if ((data->muxtype == pca954x_ismux) - || !(maskbit & data->selmask)) { - newregval = pca954x_mask2val(client, maskbit); - } else - newregval = pca954x_mask2val(client, data->selmask); - } - - /* Only clobber control reg when value changes, to avoid - unnecessary mux writes. For safety and initialization, - ALWAYS force the write if 0 is desired. - */ - ret = (!newregval || (data->regval != newregval)); - DBG(printk(KERN_DEBUG - "%s: Mux %d: chan %d, val %02x - %s\n", - __FUNCTION__, - client->id, (int)chan, newregval, - (ret ? "writing" : "skipping" ) )); - if (ret) { - ret = pca954x_xfer(adap, client, I2C_SMBUS_WRITE, &newregval); - - if (ret < 0) { - printk(KERN_ERR "%s: I2C mux %d select failed " - "(addr=%02x, val=%02x, err=%d)!\n", - __FUNCTION__, client->id, - client->addr, newregval, ret); - } else { - data->regval = newregval; - data->curmask = pca954x_val2mask(client, newregval); - } - } - return ret; -} - - -static int pca954x_xfer(struct i2c_adapter *adap, - struct i2c_client *client, - int read_write, u8 *val) -{ - int ret; - - if (adap->algo->master_xfer) { - /* Use I2C transfer */ - struct i2c_msg msg; - char buf[1]; - - msg.addr = client->addr; - msg.flags = (read_write == I2C_SMBUS_READ ? I2C_M_RD : 0); - msg.len = 1; - buf[0] = *val; - msg.buf = buf; - ret = adap->algo->master_xfer(adap, &msg, 1); - if (!ret && (read_write == I2C_SMBUS_READ)) - *val = buf[0]; - - } else if (adap->algo->smbus_xfer) { - /* Use SMBus transfer */ - union i2c_smbus_data data; - ret = adap->algo->smbus_xfer(adap, - client->addr, - client->flags & I2C_M_TEN, - read_write, - *val, - I2C_SMBUS_BYTE, &data); - if (!ret && (read_write == I2C_SMBUS_READ)) - *val = data.byte; - } else { - printk(KERN_ERR "%s: no smbus_xfer or master_xfer for " - "adapter %0lX, client %0lX\n", - __FUNCTION__, (unsigned long)adap, (unsigned long)client); - ret = -1; - } - return ret; -} - - -/* ------------------ */ - -MODULE_AUTHOR("Ken Harrenstien "); -MODULE_DESCRIPTION("PCA954X I2C mux/switch driver"); - -module_init(pca954x_init); -module_exit(pca954x_exit); diff --git a/kernel/chips/pcf8574.c b/kernel/chips/pcf8574.c deleted file mode 100644 index 7026065b..00000000 --- a/kernel/chips/pcf8574.c +++ /dev/null @@ -1,304 +0,0 @@ -/* - pcf8574.c - Part of lm_sensors, Linux kernel modules for hardware - monitoring - Copyright (c) 2000 Frodo Looijaard , - Philip Edelbrock , - Dan Eaton - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -/* A few notes about the PCF8574: - -* The PCF8574 is an 8-bit I/O expander for the I2C bus produced by - Philips Semiconductors. It is designed to provide a byte I2C - interface to up to 8 separate devices. - -* The PCF8574 appears as a very simple SMBus device which can be - read from or written to with SMBUS byte read/write accesses. - -* Because of the general purpose nature of this device, it will most - likely be necessary to customize the /proc interface to suit the - specific application. - - --Dan - -*/ - - -#include -#include -#include -#include -#include -#include "version.h" - -MODULE_LICENSE("GPL"); - -/* Addresses to scan */ -static unsigned short normal_i2c[] = { SENSORS_I2C_END }; -static unsigned short normal_i2c_range[] = { 0x20, 0x27, 0x38, 0x3f, SENSORS_I2C_END }; -static unsigned int normal_isa[] = { SENSORS_ISA_END }; -static unsigned int normal_isa_range[] = { SENSORS_ISA_END }; - -/* Insmod parameters */ -SENSORS_INSMOD_2(pcf8574, pcf8574a); - -/* The PCF8574 registers */ - -/* (No registers. [Wow! This thing is SIMPLE!] ) */ - -/* Initial values */ -#define PCF8574_INIT 255 /* All outputs on (input mode) */ - -/* Each client has this additional data */ -struct pcf8574_data { - struct i2c_client client; - int sysctl_id; - - struct semaphore update_lock; - - u8 read, write; /* Register values */ -}; - -static int pcf8574_attach_adapter(struct i2c_adapter *adapter); -static int pcf8574_detect(struct i2c_adapter *adapter, int address, - unsigned short flags, int kind); -static int pcf8574_detach_client(struct i2c_client *client); - -static void pcf8574_read(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void pcf8574_write(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void pcf8574_update_client(struct i2c_client *client); -static void pcf8574_init_client(struct i2c_client *client); - -/* This is the driver that will be inserted */ -static struct i2c_driver pcf8574_driver = { - .name = "PCF8574 sensor chip driver", - .id = I2C_DRIVERID_PCF8574, - .flags = I2C_DF_NOTIFY, - .attach_adapter = pcf8574_attach_adapter, - .detach_client = pcf8574_detach_client, -}; - - -/* -- SENSORS SYSCTL START -- */ -#define PCF8574_SYSCTL_READ 1000 -#define PCF8574_SYSCTL_WRITE 1001 - -/* -- SENSORS SYSCTL END -- */ - -/* These files are created for each detected PCF8574. This is just a template; - though at first sight, you might think we could use a statically - allocated list, we need some way to get back to the parent - which - is done through one of the 'extra' fields which are initialized - when a new copy is allocated. */ -static ctl_table pcf8574_dir_table_template[] = { - {PCF8574_SYSCTL_READ, "read", NULL, 0, 0444, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &pcf8574_read}, - {PCF8574_SYSCTL_WRITE, "write", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &pcf8574_write}, - {0} -}; - -static int pcf8574_attach_adapter(struct i2c_adapter *adapter) -{ - return i2c_detect(adapter, &addr_data, pcf8574_detect); -} - -/* This function is called by i2c_detect */ -static int pcf8574_detect(struct i2c_adapter *adapter, int address, - unsigned short flags, int kind) -{ - int i; - struct i2c_client *new_client; - struct pcf8574_data *data; - int err = 0; - const char *type_name, *client_name; - - /* Make sure we aren't probing the ISA bus!! This is just a safety check - at this moment; i2c_detect really won't call us. */ -#ifdef DEBUG - if (i2c_is_isa_adapter(adapter)) { - printk - ("pcf8574.o: pcf8574_detect called for an ISA bus adapter?!?\n"); - return 0; - } -#endif - - if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE)) - goto ERROR0; - - /* OK. For now, we presume we have a valid client. We now create the - client structure, even though we cannot fill it completely yet. */ - if (!(data = kmalloc(sizeof(struct pcf8574_data), GFP_KERNEL))) { - err = -ENOMEM; - goto ERROR0; - } - - new_client = &data->client; - new_client->addr = address; - new_client->data = data; - new_client->adapter = adapter; - new_client->driver = &pcf8574_driver; - new_client->flags = 0; - - /* Now, we would do the remaining detection. But the PCF8574 is plainly - impossible to detect! Stupid chip. */ - - /* Determine the chip type */ - if (kind <= 0) { - if (address >= 0x38 && address <= 0x3f) - kind = pcf8574a; - else - kind = pcf8574; - } - - if (kind == pcf8574a) { - type_name = "pcf8574a"; - client_name = "PCF8574A chip"; - } else { - type_name = "pcf8574"; - client_name = "PCF8574 chip"; - } - - /* Fill in the remaining client fields and put it into the global list */ - strcpy(new_client->name, client_name); - init_MUTEX(&data->update_lock); - - /* Tell the I2C layer a new client has arrived */ - if ((err = i2c_attach_client(new_client))) - goto ERROR1; - - /* Register a new directory entry with module sensors */ - if ((i = i2c_register_entry(new_client, type_name, - pcf8574_dir_table_template, - THIS_MODULE)) < 0) { - err = i; - goto ERROR2; - } - data->sysctl_id = i; - - /* Initialize the PCF8574 chip */ - pcf8574_init_client(new_client); - return 0; - -/* OK, this is not exactly good programming practice, usually. But it is - very code-efficient in this case. */ - - ERROR2: - i2c_detach_client(new_client); - ERROR1: - kfree(data); - ERROR0: - return err; -} - -static int pcf8574_detach_client(struct i2c_client *client) -{ - int err; - - i2c_deregister_entry(((struct pcf8574_data *) (client->data))-> - sysctl_id); - - if ((err = i2c_detach_client(client))) { - printk("pcf8574.o: Client deregistration failed, " - "client not detached.\n"); - return err; - } - - kfree(client->data); - - return 0; -} - -/* Called when we have found a new PCF8574. */ -static void pcf8574_init_client(struct i2c_client *client) -{ - struct pcf8574_data *data = client->data; - data->write = PCF8574_INIT; - i2c_smbus_write_byte(client, data->write); -} - - -static void pcf8574_update_client(struct i2c_client *client) -{ - struct pcf8574_data *data = client->data; - - down(&data->update_lock); - -#ifdef DEBUG - printk("Starting pcf8574 update\n"); -#endif - - data->read = i2c_smbus_read_byte(client); - - up(&data->update_lock); -} - - -void pcf8574_read(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results) -{ - struct pcf8574_data *data = client->data; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - pcf8574_update_client(client); - results[0] = data->read; - *nrels_mag = 1; - } -} -void pcf8574_write(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results) -{ - struct pcf8574_data *data = client->data; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - results[0] = data->write; - *nrels_mag = 1; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag >= 1) { - data->write = results[0]; - i2c_smbus_write_byte(client, data->write); - } - } -} - - -static int __init sm_pcf8574_init(void) -{ - printk("pcf8574.o version %s (%s)\n", LM_VERSION, LM_DATE); - return i2c_add_driver(&pcf8574_driver); -} - -static void __exit sm_pcf8574_exit(void) -{ - i2c_del_driver(&pcf8574_driver); -} - - -MODULE_AUTHOR("Frodo Looijaard , " - "Philip Edelbrock , " - "Dan Eaton and " - "Aurelien Jarno "); -MODULE_DESCRIPTION("PCF8574 driver"); - -module_init(sm_pcf8574_init); -module_exit(sm_pcf8574_exit); diff --git a/kernel/chips/pcf8591.c b/kernel/chips/pcf8591.c deleted file mode 100644 index 6f6de4c9..00000000 --- a/kernel/chips/pcf8591.c +++ /dev/null @@ -1,443 +0,0 @@ -/* - pcf8591.c - Part of lm_sensors, Linux kernel modules for hardware - monitoring - Copyright (c) 2001 Aurelien Jarno - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#include -#include -#include -#include -#include -#include "version.h" - -/* Addresses to scan */ -static unsigned short normal_i2c[] = { SENSORS_I2C_END }; -static unsigned short normal_i2c_range[] = { 0x48, 0x4f, SENSORS_I2C_END }; -static unsigned int normal_isa[] = { SENSORS_ISA_END }; -static unsigned int normal_isa_range[] = { SENSORS_ISA_END }; - -/* Insmod parameters */ -SENSORS_INSMOD_1(pcf8591); - -/* The PCF8591 control byte */ -/* 7 6 5 4 3 2 1 0 */ -/* | 0 |AOEF| AIP | 0 |AINC| AICH | */ - -#define PCF8591_CONTROL_BYTE_AOEF 0x40 /* Analog Output Enable Flag */ - /* (analog output active if 1) */ - -#define PCF8591_CONTROL_BYTE_AIP 0x30 /* Analog Input Programming */ - /* 0x00 = four single ended inputs */ - /* 0x10 = three differential inputs */ - /* 0x20 = single ended and differential mixed */ - /* 0x30 = two differential inputs */ - -#define PCF8591_CONTROL_BYTE_AINC 0x04 /* Autoincrement Flag */ - /* (switch on if 1) */ - -#define PCF8591_CONTROL_BYTE_AICH 0x03 /* Analog Output Enable Flag */ - /* 0x00 = channel 0 */ - /* 0x01 = channel 1 */ - /* 0x02 = channel 2 */ - /* 0x03 = channel 3 */ - - -/* Initial values */ -#define PCF8591_INIT_CONTROL_BYTE (PCF8591_CONTROL_BYTE_AOEF | PCF8591_CONTROL_BYTE_AINC) - /* DAC out enabled, four single ended inputs, autoincrement */ - -#define PCF8591_INIT_AOUT 0 /* DAC out = 0 */ - - -/* Conversions. */ -#define REG_TO_SIGNED(reg) (reg & 0x80)?(reg - 256):(reg) - /* Convert signed 8 bit value to signed value */ - - -struct pcf8591_data { - struct i2c_client client; - int sysctl_id; - - struct semaphore update_lock; - char valid; /* !=0 if following fields are valid */ - unsigned long last_updated; /* In jiffies */ - - u8 control_byte; - u8 ch[4]; - u8 aout; -}; - -static int pcf8591_attach_adapter(struct i2c_adapter *adapter); -static int pcf8591_detect(struct i2c_adapter *adapter, int address, - unsigned short flags, int kind); -static int pcf8591_detach_client(struct i2c_client *client); - -static void pcf8591_update_client(struct i2c_client *client); -static void pcf8591_init_client(struct i2c_client *client); - -static void pcf8591_ain_conf(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void pcf8591_ain(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void pcf8591_aout_enable(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void pcf8591_aout(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); - - -/* This is the driver that will be inserted */ -static struct i2c_driver pcf8591_driver = { - .name = "PCF8591 sensor chip driver", - .id = I2C_DRIVERID_PCF8591, - .flags = I2C_DF_NOTIFY, - .attach_adapter = pcf8591_attach_adapter, - .detach_client = pcf8591_detach_client, -}; - -/* The /proc/sys entries */ - -/* -- SENSORS SYSCTL START -- */ -#define PCF8591_SYSCTL_AIN_CONF 1000 /* Analog input configuration */ -#define PCF8591_SYSCTL_CH0 1001 /* Input channel 1 */ -#define PCF8591_SYSCTL_CH1 1002 /* Input channel 2 */ -#define PCF8591_SYSCTL_CH2 1003 /* Input channel 3 */ -#define PCF8591_SYSCTL_CH3 1004 /* Input channel 4 */ -#define PCF8591_SYSCTL_AOUT_ENABLE 1005 /* Analog output enable flag */ -#define PCF8591_SYSCTL_AOUT 1006 /* Analog output */ -/* -- SENSORS SYSCTL END -- */ - -/* These files are created for each detected PCF8591. This is just a template; - though at first sight, you might think we could use a statically - allocated list, we need some way to get back to the parent - which - is done through one of the 'extra' fields which are initialized - when a new copy is allocated. */ -static ctl_table pcf8591_dir_table_template[] = { - {PCF8591_SYSCTL_AIN_CONF, "ain_conf", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &pcf8591_ain_conf}, - {PCF8591_SYSCTL_CH0, "ch0", NULL, 0, 0444, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &pcf8591_ain}, - {PCF8591_SYSCTL_CH1, "ch1", NULL, 0, 0444, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &pcf8591_ain}, - {PCF8591_SYSCTL_CH2, "ch2", NULL, 0, 0444, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &pcf8591_ain}, - {PCF8591_SYSCTL_CH3, "ch3", NULL, 0, 0444, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &pcf8591_ain}, - {PCF8591_SYSCTL_AOUT_ENABLE, "aout_enable", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &pcf8591_aout_enable}, - {PCF8591_SYSCTL_AOUT, "aout", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &pcf8591_aout}, - {0} -}; - - -/* This function is called when: - * pcf8591_driver is inserted (when this module is loaded), for each - available adapter - * when a new adapter is inserted (and pcf8591_driver is still present) */ -static int pcf8591_attach_adapter(struct i2c_adapter *adapter) -{ - return i2c_detect(adapter, &addr_data, pcf8591_detect); -} - -/* This function is called by i2c_detect */ -static int pcf8591_detect(struct i2c_adapter *adapter, int address, - unsigned short flags, int kind) -{ - int i; - struct i2c_client *new_client; - struct pcf8591_data *data; - int err = 0; - - const char *type_name = ""; - const char *client_name = ""; - - /* Make sure we aren't probing the ISA bus!! This is just a safety check at this moment; i2c_detect really won't call us. */ -#ifdef DEBUG - if (i2c_is_isa_adapter(adapter)) { - printk - (KERN_ERR "pcf8591.o: pcf8591_detect called for an ISA bus adapter?!?\n"); - return 0; - } -#endif - - if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE - | I2C_FUNC_SMBUS_WRITE_BYTE_DATA)) - goto ERROR0; - - /* OK. For now, we presume we have a valid client. We now create the - client structure, even though we cannot fill it completely yet. */ - if (!(data = kmalloc(sizeof(struct pcf8591_data), GFP_KERNEL))) { - err = -ENOMEM; - goto ERROR0; - } - - new_client = &data->client; - new_client->addr = address; - new_client->data = data; - new_client->adapter = adapter; - new_client->driver = &pcf8591_driver; - new_client->flags = 0; - - /* Now, we would do the remaining detection. But the PCF8591 is plainly - impossible to detect! Stupid chip. */ - - /* Determine the chip type - only one kind supported! */ - if (kind <= 0) - kind = pcf8591; - - type_name = "pcf8591"; - client_name = "PCF8591 chip"; - - /* Fill in the remaining client fields and put it into the global list */ - strcpy(new_client->name, client_name); - data->valid = 0; - init_MUTEX(&data->update_lock); - - /* Tell the I2C layer a new client has arrived */ - if ((err = i2c_attach_client(new_client))) - goto ERROR3; - - /* Register a new directory entry with module sensors */ - if ((i = i2c_register_entry(new_client, - type_name, - pcf8591_dir_table_template, - THIS_MODULE)) < 0) { - err = i; - goto ERROR4; - } - data->sysctl_id = i; - - /* Initialize the PCF8591 chip */ - pcf8591_init_client(new_client); - return 0; - -/* OK, this is not exactly good programming practice, usually. But it is - very code-efficient in this case. */ - - ERROR4: - i2c_detach_client(new_client); - ERROR3: - kfree(data); - ERROR0: - return err; -} - -static int pcf8591_detach_client(struct i2c_client *client) -{ - int err; - - i2c_deregister_entry(((struct pcf8591_data *) (client->data))-> - sysctl_id); - - if ((err = i2c_detach_client(client))) { - printk - (KERN_ERR "pcf8591.o: Client deregistration failed, client not detached.\n"); - return err; - } - - kfree(client->data); - - return 0; -} - -/* Called when we have found a new PCF8591. */ -static void pcf8591_init_client(struct i2c_client *client) -{ - struct pcf8591_data *data = client->data; - data->control_byte = PCF8591_INIT_CONTROL_BYTE; - data->aout = PCF8591_INIT_AOUT; - - i2c_smbus_write_byte_data(client, data->control_byte, data->aout); -} - -static void pcf8591_update_client(struct i2c_client *client) -{ - struct pcf8591_data *data = client->data; - - down(&data->update_lock); - - if ((jiffies - data->last_updated > HZ + HZ / 2) || - (jiffies < data->last_updated) || !data->valid) { - -#ifdef DEBUG - printk(KERN_DEBUG "Starting pcf8591 update\n"); -#endif - - i2c_smbus_write_byte(client, data->control_byte); - i2c_smbus_read_byte(client); /* The first byte transmitted contains the */ - /* conversion code of the previous read cycled */ - /* FLUSH IT ! */ - - - /* Number of byte to read to signed depend on the analog input mode */ - data->ch[0] = i2c_smbus_read_byte(client); - data->ch[1] = i2c_smbus_read_byte(client); - /* In all case, read at least two values */ - - if ((data->control_byte & PCF8591_CONTROL_BYTE_AIP) != 0x30) - data->ch[2] = i2c_smbus_read_byte(client); - /* Read the third value if not in "two differential inputs" mode */ - - if ((data->control_byte & PCF8591_CONTROL_BYTE_AIP) == 0x00) - data->ch[3] = i2c_smbus_read_byte(client); - /* Read the fourth value only in "four single ended inputs" mode */ - - data->last_updated = jiffies; - data->valid = 1; - } - - up(&data->update_lock); -} - -/* The next few functions are the call-back functions of the /proc/sys and - sysctl files. Which function is used is defined in the ctl_table in - the extra1 field. */ -void pcf8591_ain_conf(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct pcf8591_data *data = client->data; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - results[0] = (data->control_byte & PCF8591_CONTROL_BYTE_AIP) >> 4; - *nrels_mag = 1; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag >= 1) { - if (results[0] >= 0 && results[0] <= 3) - { - data->control_byte &= ~PCF8591_CONTROL_BYTE_AIP; - data->control_byte |= (results[0] << 4); - i2c_smbus_write_byte(client, data->control_byte); - data->valid = 0; - } - } - } -} - -void pcf8591_ain(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct pcf8591_data *data = client->data; - int nr = ctl_name - PCF8591_SYSCTL_CH0; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - pcf8591_update_client(client); - - /* Number of data to show and conversion to signed depend on */ - /* the analog input mode */ - - switch(nr) { - case 0: - if (((data->control_byte & PCF8591_CONTROL_BYTE_AIP) == 0) - | ((data->control_byte & PCF8591_CONTROL_BYTE_AIP) == 2)) - results[0] = data->ch[0]; /* single ended */ - else - results[0] = REG_TO_SIGNED(data->ch[0]);/* differential */ - break; - case 1: - if (((data->control_byte & PCF8591_CONTROL_BYTE_AIP) == 0) - | ((data->control_byte & PCF8591_CONTROL_BYTE_AIP) == 2)) - results[0] = data->ch[1]; /* single ended */ - else - results[0] = REG_TO_SIGNED(data->ch[1]);/* differential */ - break; - case 2: - if ((data->control_byte & PCF8591_CONTROL_BYTE_AIP) == 3) - results[0] = 0; /* channel not used */ - else if ((data->control_byte & PCF8591_CONTROL_BYTE_AIP) == 0) - results[0] = data->ch[2]; /* single ended */ - else - results[0] = REG_TO_SIGNED(data->ch[2]);/* differential */ - break; - case 3: - if (((data->control_byte & PCF8591_CONTROL_BYTE_AIP) == 0) - | ((data->control_byte & PCF8591_CONTROL_BYTE_AIP) == 2)) - results[0] = data->ch[3]; /* single ended */ - else - results[0] = 0; /* channel not used */ - break; - } - *nrels_mag = 1; - } -} - -void pcf8591_aout_enable(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct pcf8591_data *data = client->data; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - results[0] = !(!(data->control_byte & PCF8591_CONTROL_BYTE_AOEF)); - *nrels_mag = 1; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag >= 1) { - if (results[0]) - data->control_byte |= PCF8591_CONTROL_BYTE_AOEF; - else - data->control_byte &= ~PCF8591_CONTROL_BYTE_AOEF; - - i2c_smbus_write_byte(client, data->control_byte); - } - } -} - -void pcf8591_aout(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct pcf8591_data *data = client->data; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - results[0] = data->aout; - *nrels_mag = 1; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag >= 1) { - if (results[0] >= 0 && results[0] <= 255) /* ignore values outside DAC range */ - { - data->aout = results[0]; - i2c_smbus_write_byte_data(client, data->control_byte, data->aout); - } - } - } -} - -static int __init sm_pcf8591_init(void) -{ - printk(KERN_INFO "pcf8591.o version %s (%s)\n", LM_VERSION, LM_DATE); - return i2c_add_driver(&pcf8591_driver); -} - -static void __exit sm_pcf8591_exit(void) -{ - i2c_del_driver(&pcf8591_driver); -} - - - -MODULE_AUTHOR("Aurelien Jarno "); -MODULE_DESCRIPTION("PCF8591 driver"); -MODULE_LICENSE("GPL"); - -module_init(sm_pcf8591_init); -module_exit(sm_pcf8591_exit); diff --git a/kernel/chips/saa1064.c b/kernel/chips/saa1064.c deleted file mode 100644 index 500c740c..00000000 --- a/kernel/chips/saa1064.c +++ /dev/null @@ -1,427 +0,0 @@ -/* - saa1064.c - Part of lm_sensors, Linux kernel modules for hardware - monitoring - Copyright (c) 2003 Sascha Volkenandt - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -/* A few notes about the SAA1064: - -* The SAA1064 is a driver for 4-digit led displays produced by Philips - Semiconductors. It can be found in HiFi equipment with such displays. - I've found it inside a Kathrein analogue sat-receiver :-). - -* The SAA1064 is quite simple to handle, it receives an address byte, - telling which register is addressed, followed by up to five data - bytes (according to the data sheet), while with each byte the register - address is increased by one, wrapping from 7 to 0. - -* NOTE: This device doesn NOT have eight read-write registers, but eight - write-only registers, and one read-only status byte (with no register - address). - -*/ - -#include -#include -#include -#include -#include -#include "version.h" - -MODULE_LICENSE("GPL"); - -/* Addresses to scan */ -static unsigned short normal_i2c[] = { SENSORS_I2C_END }; -static unsigned short normal_i2c_range[] = { 0x38, 0x3b, SENSORS_I2C_END }; -static unsigned int normal_isa[] = { SENSORS_ISA_END }; -static unsigned int normal_isa_range[] = { SENSORS_ISA_END }; - -/* Insmod parameters */ -SENSORS_INSMOD_1(saa1064); - -/* The SAA1064 registers - Registers: - 0 Control register - 1 Digit 1 - 2 Digit 2 - 3 Digit 3 - 4 Digit 4 -*/ - -#define SAA1064_REG_CONTROL 0x00 -#define SAA1064_REG_DIGIT0 0x01 -#define SAA1064_REG_DIGIT1 0x02 -#define SAA1064_REG_DIGIT2 0x03 -#define SAA1064_REG_DIGIT3 0x04 - -/* Control byte: - Bit 0 Dynamic mode - 1 Blank digits 1+3 (reversed) - 2 Blank digits 2+4 (reversed) - 3 Testmode (all digits on) - 4 Add 3mA output current to led's - 5 Add 6mA output current to led's - 6 Add 12mA output current to led's - 7 Unused, set to 0 -*/ - -#define SAA1064_CTRL_DYNAMIC 0x01 -#define SAA1064_CTRL_BLANK13 0x02 -#define SAA1064_CTRL_BLANK24 0x04 -#define SAA1064_CTRL_TEST 0x08 -#define SAA1064_CTRL_BRIGHT 0x70 - -/* Status byte: - The MSB set to 1 indicates powerloss since last read-out */ -#define SAA1064_STAT_PWRLOSS 0x80 - -/* Get a bit from the control-byte. Except for BRIGHT, these return - zero/non-zero in a boolean fashion. BRIGHT returns a 3-bit value - specifying the brightness */ -#define SAA1064_CTRL_GET_DYNAMIC(c) (((c) & SAA1064_CTRL_DYNAMIC)>0) -#define SAA1064_CTRL_GET_BLANK13(c) (((c) & SAA1064_CTRL_BLANK13)>0) -#define SAA1064_CTRL_GET_BLANK24(c) (((c) & SAA1064_CTRL_BLANK24)>0) -#define SAA1064_CTRL_GET_TEST(c) (((c) & SAA1064_CTRL_TEST)>0) -#define SAA1064_CTRL_GET_BRIGHT(c) (((c) & SAA1064_CTRL_BRIGHT)>>4) - -/* Get THE bit from the status byte. The LSB set to 1 indicates powerloss - since last read-out */ -#define SAA1064_STAT_GET_PWRLOSS(s) (((s) & SAA1064_STAT_PWRLOSS)>0) - -/* Set a bit in the control-byte to val and return the modified byte. - Except for BRIGHT, val is evaluated in a boolean fashion. */ -#define SAA1064_CTRL_SET_DYNAMIC(c,val) ((val)>0 \ - ? (c) | SAA1064_CTRL_DYNAMIC : (c) & ~SAA1064_CTRL_DYNAMIC) -#define SAA1064_CTRL_SET_BLANK13(c,val) ((val)>0 \ - ? (c) | SAA1064_CTRL_BLANK13 : (c) & ~SAA1064_CTRL_BLANK13) -#define SAA1064_CTRL_SET_BLANK24(c,val) ((val)>0 \ - ? (c) | SAA1064_CTRL_BLANK24 : (c) & ~SAA1064_CTRL_BLANK24) -#define SAA1064_CTRL_SET_TEST(c,val) ((val)>0 \ - ? (c) | SAA1064_CTRL_TEST : (c) & ~SAA1064_CTRL_TEST) -#define SAA1064_CTRL_SET_BRIGHT(c,val) (((c) & ~SAA1064_CTRL_BRIGHT) \ - | (((val) << 4) & SAA1064_CTRL_BRIGHT)) - -/* Initial values */ -#define SAA1064_INIT 0x7f /* All digits on (testmode), full brightness */ - -/* Each client has this additional data */ -struct saa1064_data { - struct i2c_client client; - int sysctl_id; - - struct semaphore update_lock; - char valid; /* !=0 if following fields are valid */ - unsigned long last_updated; /* In jiffies */ - - u8 control; /* Control reg */ - u8 digits[4]; /* Digits regs */ - u8 status; /* Status byte (read) */ -}; - -static int saa1064_attach_adapter(struct i2c_adapter *adapter); -static int saa1064_detect(struct i2c_adapter *adapter, int address, - unsigned short flags, int kind); -static int saa1064_detach_client(struct i2c_client *client); - -static void saa1064_bright(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void saa1064_test(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void saa1064_disp(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void saa1064_refresh(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void saa1064_update_client(struct i2c_client *client); -static void saa1064_init_client(struct i2c_client *client); - -/* This is the driver that will be inserted */ -static struct i2c_driver saa1064_driver = { - .name = "SAA1064 sensor chip driver", - .id = I2C_DRIVERID_SAA1064, - .flags = I2C_DF_NOTIFY, - .attach_adapter = saa1064_attach_adapter, - .detach_client = saa1064_detach_client, -}; - -/* -- SENSORS SYSCTL START -- */ - -#define SAA1064_SYSCTL_BRIGHT 1000 /* Brightness, 0-7 */ -#define SAA1064_SYSCTL_TEST 1001 /* Testmode (on = all digits lit) */ -#define SAA1064_SYSCTL_DISP 1005 /* four eight bit values */ -#define SAA1064_SYSCTL_REFRESH 1006 /* refresh digits in case of powerloss */ - -/* -- SENSORS SYSCTL END -- */ - -/* These files are created for each detected SAA1064. This is just a template; - though at first sight, you might think we could use a statically - allocated list, we need some way to get back to the parent - which - is done through one of the 'extra' fields which are initialized - when a new copy is allocated. */ -static ctl_table saa1064_dir_table_template[] = { - {SAA1064_SYSCTL_BRIGHT, "bright", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &saa1064_bright}, - {SAA1064_SYSCTL_TEST, "test", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &saa1064_test}, - {SAA1064_SYSCTL_DISP, "disp", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &saa1064_disp}, - {SAA1064_SYSCTL_REFRESH, "refresh", NULL, 0, 0444, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &saa1064_refresh}, - {0} -}; - -static int saa1064_attach_adapter(struct i2c_adapter *adapter) -{ - return i2c_detect(adapter, &addr_data, saa1064_detect); -} - -/* This function is called by i2c_detect */ -static int saa1064_detect(struct i2c_adapter *adapter, int address, - unsigned short flags, int kind) -{ - int i; - struct i2c_client *new_client; - struct saa1064_data *data; - int err = 0; - const char *type_name, *client_name; - - /* Make sure we aren't probing the ISA bus!! This is just a safety check - at this moment; i2c_detect really won't call us. */ -#ifdef DEBUG - if (i2c_is_isa_adapter(adapter)) { - printk - ("saa1064.o: saa1064_detect called for an ISA bus adapter?!?\n"); - return 0; - } -#endif - - if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_READ_BYTE - | I2C_FUNC_SMBUS_WRITE_BYTE_DATA | I2C_FUNC_SMBUS_WRITE_I2C_BLOCK)) - goto ERROR0; - - /* OK. For now, we presume we have a valid client. We now create the - client structure, even though we cannot fill it completely yet. - But it allows us to access i2c_smbus_read_byte */ - if (!(data = kmalloc(sizeof(struct saa1064_data), GFP_KERNEL))) { - err = -ENOMEM; - goto ERROR0; - } - - new_client = &data->client; - new_client->addr = address; - new_client->data = data; - new_client->adapter = adapter; - new_client->driver = &saa1064_driver; - new_client->flags = 0; - - if (kind < 0) { - if ((i2c_smbus_read_byte(new_client) & ~SAA1064_STAT_PWRLOSS) != 0x00 - || i2c_smbus_read_byte(new_client) != 0x00 - || i2c_smbus_read_byte(new_client) != 0x00 - || i2c_smbus_read_byte(new_client) != 0x00) - goto ERROR1; - } - - /* If detection was requested, it has also passed til now. Only one chip, - so no further evaluation of kind. */ - kind = saa1064; - type_name = "saa1064"; - client_name = "SAA1064 chip"; - - /* Fill in the remaining client fields and put it into the global list */ - strcpy(new_client->name, client_name); - data->valid = 0; - init_MUTEX(&data->update_lock); - - /* Tell the I2C layer a new client has arrived */ - if ((err = i2c_attach_client(new_client))) - goto ERROR3; - - /* Register a new directory entry with module sensors */ - if ((i = i2c_register_entry(new_client, type_name, - saa1064_dir_table_template, - THIS_MODULE)) < 0) { - err = i; - goto ERROR4; - } - data->sysctl_id = i; - -#ifdef DEBUG - printk("saa1064.o: Module initialization complete.\n"); -#endif - - /* Initialize the SAA1064 chip */ - saa1064_init_client(new_client); - return 0; - -/* OK, this is not exactly good programming practice, usually. But it is - very code-efficient in this case. */ - - ERROR4: - i2c_detach_client(new_client); - ERROR3: - ERROR1: - kfree(data); - ERROR0: - return err; -} - - -int saa1064_detach_client(struct i2c_client *client) -{ - int err; - - i2c_deregister_entry(((struct saa1064_data *) (client->data))-> - sysctl_id); - - if ((err = i2c_detach_client(client))) { - printk - ("saa1064.o: Client deregistration failed, client not detached.\n"); - return err; - } - - kfree(client->data); - - return 0; -} - -/* Called when we have found a new SAA1064. */ -void saa1064_init_client(struct i2c_client *client) -{ - struct saa1064_data *data = client->data; - data->control = SAA1064_INIT; - memset(data->digits, 0x00, 4); - - i2c_smbus_write_byte_data(client, SAA1064_REG_CONTROL, data->control); - i2c_smbus_write_i2c_block_data(client, SAA1064_REG_DIGIT0, 4, data->digits); -} - -/* Update status byte, and write registers in case a powerloss occurred */ -static void saa1064_update_client(struct i2c_client *client) -{ - struct saa1064_data *data = client->data; - - down(&data->update_lock); - - if ((jiffies - data->last_updated > 5*HZ) || - (jiffies < data->last_updated) || !data->valid) { - -#ifdef DEBUG - printk("saa1064.o: starting saa1064 update\n"); -#endif - - data->status = i2c_smbus_read_byte(client); - if (SAA1064_STAT_GET_PWRLOSS(data->status)) { - i2c_smbus_write_byte_data(client, SAA1064_REG_CONTROL, data->control); - i2c_smbus_write_i2c_block_data(client, SAA1064_REG_DIGIT0, 4, data->digits); - } - - data->last_updated = jiffies; - data->valid = 1; - } - - up(&data->update_lock); -} - - -static void saa1064_bright(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results) -{ - struct saa1064_data *data = client->data; - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - results[0] = SAA1064_CTRL_GET_BRIGHT(data->control); - *nrels_mag = 1; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag >= 1) { - data->control = SAA1064_CTRL_SET_BRIGHT(data->control, results[0]); - i2c_smbus_write_byte_data(client, SAA1064_REG_CONTROL, data->control); - } - } -} - - -static void saa1064_test(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results) -{ - struct saa1064_data *data = client->data; - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - results[0] = SAA1064_CTRL_GET_TEST(data->control); - *nrels_mag = 1; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag >= 1) { - data->control = SAA1064_CTRL_SET_TEST(data->control, results[0]); - i2c_smbus_write_byte_data(client, SAA1064_REG_CONTROL, data->control); - } - } -} - - -static void saa1064_disp(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results) -{ - struct saa1064_data *data = client->data; - int i; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - for (i = 0; i < 4; ++i) - results[i] = (long)data->digits[i]; - *nrels_mag = 4; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - for (i = 0; i < max(*nrels_mag, 4); ++i) - data->digits[i] = (u8)results[i]; - i2c_smbus_write_i2c_block_data(client, SAA1064_REG_DIGIT0, 4, data->digits); - } -} - - -static void saa1064_refresh(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results) -{ - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - saa1064_update_client(client); - *nrels_mag = 0; - } -} - - -static int __init sensors_saa1064_init(void) -{ - printk("saa1064.o version %s (%s)\n", LM_VERSION, LM_DATE); - return i2c_add_driver(&saa1064_driver); -} - - -static void __exit sensors_saa1064_exit(void) -{ - i2c_del_driver(&saa1064_driver); -} - - - -MODULE_AUTHOR("Sascha Volkenandt "); -MODULE_DESCRIPTION("SAA1064 driver"); - -module_init(sensors_saa1064_init); -module_exit(sensors_saa1064_exit); - diff --git a/kernel/chips/sis5595.c b/kernel/chips/sis5595.c deleted file mode 100644 index 88960186..00000000 --- a/kernel/chips/sis5595.c +++ /dev/null @@ -1,720 +0,0 @@ -/* - sis5595.c - Part of lm_sensors, Linux kernel modules - for hardware monitoring - - Copyright (c) 1998 - 2001 Frodo Looijaard , - Kyösti Mälkki , and - Mark D. Studebaker - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -/* - SiS southbridge has a LM78-like chip integrated on the same IC. - This driver is a customized copy of lm78.c - - Supports following revisions: - Version PCI ID PCI Revision - 1 1039/0008 AF or less - 2 1039/0008 B0 or greater - - Note: these chips contain a 0008 device which is incompatible with the - 5595. We recognize these by the presence of the listed - "blacklist" PCI ID and refuse to load. - - NOT SUPPORTED PCI ID BLACKLIST PCI ID - 540 0008 0540 - 550 0008 0550 - 5513 0008 5511 - 5581 0008 5597 - 5582 0008 5597 - 5597 0008 5597 - 5598 0008 5597/5598 - 630 0008 0630 - 645 0008 0645 - 730 0008 0730 - 735 0008 0735 -*/ - -#include -#include -#include -#include -#include -#include -#include -#include -#include "version.h" - -MODULE_LICENSE("GPL"); - -/* If force_addr is set to anything different from 0, we forcibly enable - the device at the given address. */ -static int force_addr = 0; -MODULE_PARM(force_addr, "i"); -MODULE_PARM_DESC(force_addr, - "Initialize the base address of the sensors"); - -/* Addresses to scan. - Note that we can't determine the ISA address until we have initialized - our module */ -static unsigned short normal_i2c[] = { SENSORS_I2C_END }; -static unsigned short normal_i2c_range[] = { SENSORS_I2C_END }; -static unsigned int normal_isa[] = { 0x0000, SENSORS_ISA_END }; -static unsigned int normal_isa_range[] = { SENSORS_ISA_END }; - -/* Insmod parameters */ -SENSORS_INSMOD_1(sis5595); - -static int blacklist[] = { - PCI_DEVICE_ID_SI_540, - PCI_DEVICE_ID_SI_550, - PCI_DEVICE_ID_SI_630, - PCI_DEVICE_ID_SI_645, - PCI_DEVICE_ID_SI_730, - PCI_DEVICE_ID_SI_735, - PCI_DEVICE_ID_SI_5511, /* 5513 chip has the 0008 device but - that ID shows up in other chips so we - use the 5511 ID for recognition */ - PCI_DEVICE_ID_SI_5597, - PCI_DEVICE_ID_SI_5598, - 0 }; - -/* Many SIS5595 constants specified below */ - -/* Length of ISA address segment */ -#define SIS5595_EXTENT 8 -/* PCI Config Registers */ -#define SIS5595_BASE_REG 0x68 -#define SIS5595_PIN_REG 0x7A -#define SIS5595_ENABLE_REG 0x7B - -/* Where are the ISA address/data registers relative to the base address */ -#define SIS5595_ADDR_REG_OFFSET 5 -#define SIS5595_DATA_REG_OFFSET 6 - -/* The SIS5595 registers */ -#define SIS5595_REG_IN_MAX(nr) (0x2b + (nr) * 2) -#define SIS5595_REG_IN_MIN(nr) (0x2c + (nr) * 2) -#define SIS5595_REG_IN(nr) (0x20 + (nr)) - -#define SIS5595_REG_FAN_MIN(nr) (0x3a + (nr)) -#define SIS5595_REG_FAN(nr) (0x27 + (nr)) - -/* On the first version of the chip, the temp registers are separate. - On the second version, - TEMP pin is shared with IN4, configured in PCI register 0x7A. - The registers are the same as well. - OVER and HYST are really MAX and MIN. */ - -#define REV2MIN 0xb0 -#define SIS5595_REG_TEMP (( data->revision) >= REV2MIN) ? \ - SIS5595_REG_IN(4) : 0x27 -#define SIS5595_REG_TEMP_OVER (( data->revision) >= REV2MIN) ? \ - SIS5595_REG_IN_MAX(4) : 0x39 -#define SIS5595_REG_TEMP_HYST (( data->revision) >= REV2MIN) ? \ - SIS5595_REG_IN_MIN(4) : 0x3a - -#define SIS5595_REG_CONFIG 0x40 -#define SIS5595_REG_ALARM1 0x41 -#define SIS5595_REG_ALARM2 0x42 -#define SIS5595_REG_FANDIV 0x47 - -/* Conversions. Limit checking is only done on the TO_REG - variants. Note that you should be a bit careful with which arguments - these macros are called: arguments may be evaluated more than once. - Fixing this is just not worth it. */ - -#define IN_TO_REG(val) (SENSORS_LIMIT((((val) * 10 + 8)/16),0,255)) -#define IN_FROM_REG(val) (((val) * 16 + 5) / 10) - -static inline u8 FAN_TO_REG(long rpm, int div) -{ - if (rpm <= 0) - return 255; - return SENSORS_LIMIT((1350000 + rpm * div / 2) / (rpm * div), 1, - 254); -} - -#define FAN_FROM_REG(val,div) ((val)==0?-1:(val)==255?0:1350000/((val)*(div))) - -/* Version 1 datasheet temp=.83*reg + 52.12 */ -#define TEMP_FROM_REG(val) (((((val)>=0x80?(val)-0x100:(val))*83)+5212)/10) -/* inverse 1.20*val - 62.77 */ -#define TEMP_TO_REG(val) (SENSORS_LIMIT(((val)<0?\ - ((((val)*12)-6327)/100):\ - ((((val)*12)-6227)/100)),0,255)) - -#define DIV_FROM_REG(val) (1 << (val)) -#define DIV_TO_REG(val) ((val)==8?3:(val)==4?2:(val)==1?0:1) - -/* For the SIS5595, we need to keep some data in memory. It is - dynamically allocated, at the time when the new sis5595 client is - allocated. */ -struct sis5595_data { - struct i2c_client client; - struct semaphore lock; - int sysctl_id; - - struct semaphore update_lock; - char valid; /* !=0 if following fields are valid */ - unsigned long last_updated; /* In jiffies */ - char maxins; /* == 3 if temp enabled, otherwise == 4 */ - u8 revision; /* Reg. value */ - - u8 in[5]; /* Register value */ - u8 in_max[5]; /* Register value */ - u8 in_min[5]; /* Register value */ - u8 fan[2]; /* Register value */ - u8 fan_min[2]; /* Register value */ - u8 temp; /* Register value */ - u8 temp_over; /* Register value */ - u8 temp_hyst; /* Register value */ - u8 fan_div[2]; /* Register encoding, shifted right */ - u16 alarms; /* Register encoding, combined */ -}; - -static struct pci_dev *s_bridge; /* pointer to the (only) sis5595 */ - -static int sis5595_attach_adapter(struct i2c_adapter *adapter); -static int sis5595_detect(struct i2c_adapter *adapter, int address, - unsigned short flags, int kind); -static int sis5595_detach_client(struct i2c_client *client); - -static int sis5595_read_value(struct i2c_client *client, u8 register); -static int sis5595_write_value(struct i2c_client *client, u8 register, - u8 value); -static void sis5595_update_client(struct i2c_client *client); -static void sis5595_init_client(struct i2c_client *client); - - -static void sis5595_in(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void sis5595_fan(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void sis5595_temp(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void sis5595_alarms(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void sis5595_fan_div(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); - -/* The driver. I choose to use type i2c_driver, as at is identical to both - smbus_driver and isa_driver, and clients could be of either kind */ -static struct i2c_driver sis5595_driver = { - .name = "SiS 5595", - .id = I2C_DRIVERID_SIS5595, - .flags = I2C_DF_NOTIFY, - .attach_adapter = sis5595_attach_adapter, - .detach_client = sis5595_detach_client, -}; - -/* The /proc/sys entries */ - -/* -- SENSORS SYSCTL START -- */ -#define SIS5595_SYSCTL_IN0 1000 /* Volts * 100 */ -#define SIS5595_SYSCTL_IN1 1001 -#define SIS5595_SYSCTL_IN2 1002 -#define SIS5595_SYSCTL_IN3 1003 -#define SIS5595_SYSCTL_IN4 1004 -#define SIS5595_SYSCTL_FAN1 1101 /* Rotations/min */ -#define SIS5595_SYSCTL_FAN2 1102 -#define SIS5595_SYSCTL_TEMP 1200 /* Degrees Celsius * 10 */ -#define SIS5595_SYSCTL_FAN_DIV 2000 /* 1, 2, 4 or 8 */ -#define SIS5595_SYSCTL_ALARMS 2001 /* bitvector */ - -#define SIS5595_ALARM_IN0 0x01 -#define SIS5595_ALARM_IN1 0x02 -#define SIS5595_ALARM_IN2 0x04 -#define SIS5595_ALARM_IN3 0x08 -#define SIS5595_ALARM_BTI 0x20 -#define SIS5595_ALARM_FAN1 0x40 -#define SIS5595_ALARM_FAN2 0x80 -#define SIS5595_ALARM_IN4 0x8000 -#define SIS5595_ALARM_TEMP 0x8000 - -/* -- SENSORS SYSCTL END -- */ - -/* These files are created for each detected SIS5595. This is just a template; - though at first sight, you might think we could use a statically - allocated list, we need some way to get back to the parent - which - is done through one of the 'extra' fields which are initialized - when a new copy is allocated. */ -static ctl_table sis5595_dir_table_template[] = { - {SIS5595_SYSCTL_IN0, "in0", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &sis5595_in}, - {SIS5595_SYSCTL_IN1, "in1", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &sis5595_in}, - {SIS5595_SYSCTL_IN2, "in2", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &sis5595_in}, - {SIS5595_SYSCTL_IN3, "in3", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &sis5595_in}, - {SIS5595_SYSCTL_IN4, "in4", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &sis5595_in}, - {SIS5595_SYSCTL_FAN1, "fan1", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &sis5595_fan}, - {SIS5595_SYSCTL_FAN2, "fan2", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &sis5595_fan}, - {SIS5595_SYSCTL_TEMP, "temp", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &sis5595_temp}, - {SIS5595_SYSCTL_FAN_DIV, "fan_div", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &sis5595_fan_div}, - {SIS5595_SYSCTL_ALARMS, "alarms", NULL, 0, 0444, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &sis5595_alarms}, - {0} -}; - -/* This is called when the module is loaded */ -static int sis5595_attach_adapter(struct i2c_adapter *adapter) -{ - return i2c_detect(adapter, &addr_data, sis5595_detect); -} - -/* Locate SiS bridge and correct base address for SIS5595 */ -static int __init sis5595_find_sis(int *address) -{ - u16 val; - int *i; - - if (!pci_present()) - return -ENODEV; - - if (!(s_bridge = - pci_find_device(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_503, - NULL))) - return -ENODEV; - - /* Look for imposters */ - for(i = blacklist; *i != 0; i++) { - if (pci_find_device(PCI_VENDOR_ID_SI, *i, NULL)) { - printk("sis5595.o: Error: Looked for SIS5595 but found unsupported device %.4X\n", *i); - return -ENODEV; - } - } - - if (PCIBIOS_SUCCESSFUL != - pci_read_config_word(s_bridge, SIS5595_BASE_REG, &val)) - return -ENODEV; - - *address = val & ~(SIS5595_EXTENT - 1); - if (*address == 0 && force_addr == 0) { - printk("sis5595.o: base address not set - upgrade BIOS or use force_addr=0xaddr\n"); - return -ENODEV; - } - if (force_addr) - *address = force_addr; /* so detect will get called */ - - return 0; -} - -int sis5595_detect(struct i2c_adapter *adapter, int address, - unsigned short flags, int kind) -{ - int i; - struct i2c_client *new_client; - struct sis5595_data *data; - int err = 0; - const char *type_name = "sis5595"; - const char *client_name = "SIS5595 chip"; - char val; - u16 a; - - /* Make sure we are probing the ISA bus!! */ - if (!i2c_is_isa_adapter(adapter)) { - printk - ("sis5595.o: sis5595_detect called for an I2C bus adapter?!?\n"); - return 0; - } - - if(force_addr) - address = force_addr & ~(SIS5595_EXTENT - 1); - if (check_region(address, SIS5595_EXTENT)) { - printk("sis5595.o: region 0x%x already in use!\n", address); - return -ENODEV; - } - if(force_addr) { - printk("sis5595.o: forcing ISA address 0x%04X\n", address); - if (PCIBIOS_SUCCESSFUL != - pci_write_config_word(s_bridge, SIS5595_BASE_REG, address)) - return -ENODEV; - if (PCIBIOS_SUCCESSFUL != - pci_read_config_word(s_bridge, SIS5595_BASE_REG, &a)) - return -ENODEV; - if ((a & ~(SIS5595_EXTENT - 1)) != address) { - /* doesn't work for some chips? */ - printk("sis5595.o: force address failed\n"); - return -ENODEV; - } - } - - if (PCIBIOS_SUCCESSFUL != - pci_read_config_byte(s_bridge, SIS5595_ENABLE_REG, &val)) - return -ENODEV; - if((val & 0x80) == 0) { - printk("sis5595.o: enabling sensors\n"); - if (PCIBIOS_SUCCESSFUL != - pci_write_config_byte(s_bridge, SIS5595_ENABLE_REG, - val | 0x80)) - return -ENODEV; - if (PCIBIOS_SUCCESSFUL != - pci_read_config_byte(s_bridge, SIS5595_ENABLE_REG, &val)) - return -ENODEV; - if((val & 0x80) == 0) { /* doesn't work for some chips! */ - printk("sis5595.o: sensors enable failed - not supported?\n"); - return -ENODEV; - } - } - - if (!(data = kmalloc(sizeof(struct sis5595_data), GFP_KERNEL))) { - return -ENOMEM; - } - - new_client = &data->client; - new_client->addr = address; - init_MUTEX(&data->lock); - new_client->data = data; - new_client->adapter = adapter; - new_client->driver = &sis5595_driver; - new_client->flags = 0; - - /* Reserve the ISA region */ - request_region(address, SIS5595_EXTENT, type_name); - - /* Check revision and pin registers to determine whether 4 or 5 voltages */ - pci_read_config_byte(s_bridge, PCI_REVISION_ID, &(data->revision)); - /* 4 voltages, 1 temp */ - data->maxins = 3; - if (data->revision >= REV2MIN) { - pci_read_config_byte(s_bridge, SIS5595_PIN_REG, &val); - if (!(val & 0x80)) - /* 5 voltages, no temp */ - data->maxins = 4; - } - - /* Fill in the remaining client fields and put it into the global list */ - strcpy(new_client->name, client_name); - data->valid = 0; - init_MUTEX(&data->update_lock); - - /* Tell the I2C layer a new client has arrived */ - if ((err = i2c_attach_client(new_client))) - goto ERROR3; - - /* Register a new directory entry with module sensors */ - if ((i = i2c_register_entry((struct i2c_client *) new_client, - type_name, - sis5595_dir_table_template, - THIS_MODULE)) < 0) { - err = i; - goto ERROR4; - } - data->sysctl_id = i; - - /* Initialize the SIS5595 chip */ - sis5595_init_client(new_client); - return 0; - - ERROR4: - i2c_detach_client(new_client); - ERROR3: - release_region(address, SIS5595_EXTENT); - kfree(data); - return err; -} - -static int sis5595_detach_client(struct i2c_client *client) -{ - int err; - - i2c_deregister_entry(((struct sis5595_data *) (client->data))-> - sysctl_id); - - if ((err = i2c_detach_client(client))) { - printk - ("sis5595.o: Client deregistration failed, client not detached.\n"); - return err; - } - - release_region(client->addr, SIS5595_EXTENT); - kfree(client->data); - - return 0; -} - - -/* ISA access must be locked explicitly. - There are some ugly typecasts here, but the good news is - they should - nowhere else be necessary! */ -static int sis5595_read_value(struct i2c_client *client, u8 reg) -{ - int res; - - down(&(((struct sis5595_data *) (client->data))->lock)); - outb_p(reg, client->addr + SIS5595_ADDR_REG_OFFSET); - res = inb_p(client->addr + SIS5595_DATA_REG_OFFSET); - up(&(((struct sis5595_data *) (client->data))->lock)); - return res; -} - -static int sis5595_write_value(struct i2c_client *client, u8 reg, u8 value) -{ - down(&(((struct sis5595_data *) (client->data))->lock)); - outb_p(reg, client->addr + SIS5595_ADDR_REG_OFFSET); - outb_p(value, client->addr + SIS5595_DATA_REG_OFFSET); - up(&(((struct sis5595_data *) (client->data))->lock)); - return 0; -} - -/* Called when we have found a new SIS5595. */ -static void sis5595_init_client(struct i2c_client *client) -{ - u8 reg; - - /* Start monitoring */ - reg = i2c_smbus_read_byte_data(client, SIS5595_REG_CONFIG); - sis5595_write_value(client, SIS5595_REG_CONFIG, (reg|0x01)&0x7F); -} - -static void sis5595_update_client(struct i2c_client *client) -{ - struct sis5595_data *data = client->data; - int i; - - down(&data->update_lock); - - if ((jiffies - data->last_updated > HZ + HZ / 2) || - (jiffies < data->last_updated) || !data->valid) { - - for (i = 0; i <= data->maxins; i++) { - data->in[i] = - sis5595_read_value(client, SIS5595_REG_IN(i)); - data->in_min[i] = - sis5595_read_value(client, - SIS5595_REG_IN_MIN(i)); - data->in_max[i] = - sis5595_read_value(client, - SIS5595_REG_IN_MAX(i)); - } - for (i = 1; i <= 2; i++) { - data->fan[i - 1] = - sis5595_read_value(client, SIS5595_REG_FAN(i)); - data->fan_min[i - 1] = - sis5595_read_value(client, - SIS5595_REG_FAN_MIN(i)); - } - if(data->maxins == 3) { - data->temp = - sis5595_read_value(client, SIS5595_REG_TEMP); - data->temp_over = - sis5595_read_value(client, SIS5595_REG_TEMP_OVER); - data->temp_hyst = - sis5595_read_value(client, SIS5595_REG_TEMP_HYST); - } - i = sis5595_read_value(client, SIS5595_REG_FANDIV); - data->fan_div[0] = (i >> 4) & 0x03; - data->fan_div[1] = i >> 6; - data->alarms = - sis5595_read_value(client, SIS5595_REG_ALARM1) | - (sis5595_read_value(client, SIS5595_REG_ALARM2) << 8); - data->last_updated = jiffies; - data->valid = 1; - } - - up(&data->update_lock); -} - - -/* The next few functions are the call-back functions of the /proc/sys and - sysctl files. Which function is used is defined in the ctl_table in - the extra1 field. - Each function must return the magnitude (power of 10 to divide the date - with) if it is called with operation==SENSORS_PROC_REAL_INFO. It must - put a maximum of *nrels elements in results reflecting the data of this - file, and set *nrels to the number it actually put in it, if operation== - SENSORS_PROC_REAL_READ. Finally, it must get upto *nrels elements from - results and write them to the chip, if operations==SENSORS_PROC_REAL_WRITE. - Note that on SENSORS_PROC_REAL_READ, I do not check whether results is - large enough (by checking the incoming value of *nrels). This is not very - good practice, but as long as you put less than about 5 values in results, - you can assume it is large enough. */ - -/* Return 0 for in4 and disallow writes if pin used for temp */ -void sis5595_in(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct sis5595_data *data = client->data; - int nr = ctl_name - SIS5595_SYSCTL_IN0; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 2; - else if (operation == SENSORS_PROC_REAL_READ) { - if(nr <= 3 || data->maxins == 4) { - sis5595_update_client(client); - results[0] = IN_FROM_REG(data->in_min[nr]); - results[1] = IN_FROM_REG(data->in_max[nr]); - results[2] = IN_FROM_REG(data->in[nr]); - } else { - results[0] = 0; - results[1] = 0; - results[2] = 0; - } - *nrels_mag = 3; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if(nr <= 3 || data->maxins == 4) { - if (*nrels_mag >= 1) { - data->in_min[nr] = IN_TO_REG(results[0]); - sis5595_write_value(client, - SIS5595_REG_IN_MIN(nr), data->in_min[nr]); - } - if (*nrels_mag >= 2) { - data->in_max[nr] = IN_TO_REG(results[1]); - sis5595_write_value(client, - SIS5595_REG_IN_MAX(nr), data->in_max[nr]); - } - } - } -} - -void sis5595_fan(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct sis5595_data *data = client->data; - int nr = ctl_name - SIS5595_SYSCTL_FAN1 + 1; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - sis5595_update_client(client); - results[0] = FAN_FROM_REG(data->fan_min[nr - 1], - DIV_FROM_REG(data->fan_div[nr - 1])); - results[1] = FAN_FROM_REG(data->fan[nr - 1], - DIV_FROM_REG(data->fan_div[nr - 1])); - *nrels_mag = 2; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag >= 1) { - data->fan_min[nr - 1] = FAN_TO_REG(results[0], - DIV_FROM_REG - (data-> - fan_div[nr-1])); - sis5595_write_value(client, - SIS5595_REG_FAN_MIN(nr), - data->fan_min[nr - 1]); - } - } -} - - -/* Return 0 for temp and disallow writes if pin used for in4 */ -void sis5595_temp(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct sis5595_data *data = client->data; - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 1; - else if (operation == SENSORS_PROC_REAL_READ) { - if(data->maxins == 3) { - sis5595_update_client(client); - results[0] = TEMP_FROM_REG(data->temp_over); - results[1] = TEMP_FROM_REG(data->temp_hyst); - results[2] = TEMP_FROM_REG(data->temp); - } else { - results[0] = 0; - results[1] = 0; - results[2] = 0; - } - *nrels_mag = 3; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if(data->maxins == 3) { - if (*nrels_mag >= 1) { - data->temp_over = TEMP_TO_REG(results[0]); - sis5595_write_value(client, - SIS5595_REG_TEMP_OVER, data->temp_over); - } - if (*nrels_mag >= 2) { - data->temp_hyst = TEMP_TO_REG(results[1]); - sis5595_write_value(client, - SIS5595_REG_TEMP_HYST, data->temp_hyst); - } - } - } -} - -void sis5595_alarms(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct sis5595_data *data = client->data; - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - sis5595_update_client(client); - results[0] = data->alarms; - *nrels_mag = 1; - } -} - -void sis5595_fan_div(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results) -{ - struct sis5595_data *data = client->data; - int old; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - sis5595_update_client(client); - results[0] = DIV_FROM_REG(data->fan_div[0]); - results[1] = DIV_FROM_REG(data->fan_div[1]); - *nrels_mag = 2; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - old = sis5595_read_value(client, SIS5595_REG_FANDIV); - if (*nrels_mag >= 2) { - data->fan_div[1] = DIV_TO_REG(results[1]); - old = (old & 0x3f) | (data->fan_div[1] << 6); - } - if (*nrels_mag >= 1) { - data->fan_div[0] = DIV_TO_REG(results[0]); - old = (old & 0xcf) | (data->fan_div[0] << 4); - sis5595_write_value(client, SIS5595_REG_FANDIV, old); - } - } -} - -static int __init sm_sis5595_init(void) -{ - int addr; - - printk("sis5595.o version %s (%s)\n", LM_VERSION, LM_DATE); - - if (sis5595_find_sis(&addr)) { - printk("sis5595.o: SIS5595 not detected, module not inserted.\n"); - return -ENODEV; - } - normal_isa[0] = addr; - - return i2c_add_driver(&sis5595_driver); -} - -static void __exit sm_sis5595_exit(void) -{ - i2c_del_driver(&sis5595_driver); -} - - - -MODULE_AUTHOR("Kyösti Mälkki "); -MODULE_DESCRIPTION("SiS 5595 Sensor device"); - -module_init(sm_sis5595_init); -module_exit(sm_sis5595_exit); diff --git a/kernel/chips/smartbatt.c b/kernel/chips/smartbatt.c deleted file mode 100644 index 7dd145de..00000000 --- a/kernel/chips/smartbatt.c +++ /dev/null @@ -1,546 +0,0 @@ -/* - smartbatt.c - Part of lm_sensors, Linux kernel modules for hardware - monitoring - Copyright (c) 2002 M. D. Studebaker - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - - With GPL code from: - battery.c - Copyright (C) 2000 Linuxcare, Inc. - battery.h - Copyright (C) 2000 Hypercore Software Design, Ltd. -*/ - -#include -#include -#include -#include -#include -#include "version.h" - - -/* Addresses to scan */ -static unsigned short normal_i2c[] = { SENSORS_I2C_END }; -static unsigned short normal_i2c_range[] = { 0x0b, SENSORS_I2C_END }; -static unsigned int normal_isa[] = { SENSORS_ISA_END }; -static unsigned int normal_isa_range[] = { SENSORS_ISA_END }; - -/* Insmod parameters */ -SENSORS_INSMOD_1(smartbatt); - -/* The SMARTBATT registers */ -#define SMARTBATT_REG_MODE 0x03 -#define SMARTBATT_REG_TEMP 0x08 -#define SMARTBATT_REG_V 0x09 -#define SMARTBATT_REG_I 0x0a -#define SMARTBATT_REG_AVGI 0x0b -#define SMARTBATT_REG_RELCHG 0x0d -#define SMARTBATT_REG_ABSCHG 0x0e -#define SMARTBATT_REG_REMCAP 0x0f -#define SMARTBATT_REG_CHGCAP 0x10 -#define SMARTBATT_REG_RUNTIME_E 0x11 -#define SMARTBATT_REG_AVGTIME_E 0x12 -#define SMARTBATT_REG_AVGTIME_F 0x13 -#define SMARTBATT_REG_CHGI 0x14 -#define SMARTBATT_REG_CHGV 0x15 -#define SMARTBATT_REG_STATUS 0x16 -#define SMARTBATT_REG_CYCLECT 0x17 -#define SMARTBATT_REG_DESCAP 0x18 -#define SMARTBATT_REG_DESV 0x19 -#define SMARTBATT_REG_DATE 0x1b -#define SMARTBATT_REG_SERIAL 0x1c -#define SMARTBATT_REG_MANUF 0x20 -#define SMARTBATT_REG_NAME 0x21 -#define SMARTBATT_REG_CHEM 0x22 - -#define BATTERY_STRING_MAX 64 -#define COMM_TIMEOUT 16 - - -/* Each client has this additional data */ -struct smartbatt_data { - struct i2c_client client; - int sysctl_id; - - struct semaphore update_lock; - char valid; /* !=0 if following fields are valid */ - unsigned long last_updated; /* In jiffies */ -#if 0 - char manufacturer[BATTERY_STRING_MAX]; - char device[BATTERY_STRING_MAX]; - char chemistry[BATTERY_STRING_MAX]; -#endif - int serial; - struct { - unsigned int day:5; /* Day (1-31) */ - unsigned int month:4; /* Month (1-12) */ - unsigned int year:7; /* Year (1980 + 0-127) */ - } manufacture_date; - u16 mode, temp, v, i, avgi; /* Register values */ - u16 relchg, abschg, remcap, chgcap; /* Register values */ - u16 rte, ate, atf, chgi, chgv; /* Register values */ - u16 status, cyclect, descap, desv; /* Register values */ -}; - -static int smartbatt_attach_adapter(struct i2c_adapter *adapter); -static int smartbatt_detect(struct i2c_adapter *adapter, int address, - unsigned short flags, int kind); -static void smartbatt_init_client(struct i2c_client *client); -static int smartbatt_detach_client(struct i2c_client *client); - -static int smartbatt_read(struct i2c_client *client, u8 reg); -#if 0 -static int smartbatt_write_value(struct i2c_client *client, u8 reg, u16 value); -#endif -static void smartbatt_temp(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void smartbatt_i(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void smartbatt_v(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void smartbatt_time(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void smartbatt_alarms(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void smartbatt_charge(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void smartbatt_status(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void smartbatt_error(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void smartbatt_update_client(struct i2c_client *client); - - -/* This is the driver that will be inserted */ -static struct i2c_driver smartbatt_driver = { - .name = "Smart Battery chip driver", - .id = I2C_DRIVERID_SMARTBATT, - .flags = I2C_DF_NOTIFY, - .attach_adapter = smartbatt_attach_adapter, - .detach_client = smartbatt_detach_client, -}; - - -/* -- SENSORS SYSCTL START -- */ - -/* Status Register Bits */ -/* * * * * * Alarm Bits * * * * */ -#define SMARTBATT_OVER_CHARGED_ALARM 0x8000 -#define SMARTBATT_TERMINATE_CHARGE_ALARM 0x4000 -#define SMARTBATT_OVER_TEMP_ALARM 0x1000 -#define SMARTBATT_TERMINATE_DISCHARGE_ALARM 0x0800 -#define SMARTBATT_REMAINING_CAPACITY_ALARM 0x0200 -#define SMARTBATT_REMAINING_TIME_ALARM 0x0100 -/* * * * * * Status Bits * * * * */ -#define SMARTBATT_INITIALIZED 0x0080 -#define SMARTBATT_DISCHARGING 0x0040 -#define SMARTBATT_FULLY_CHARGED 0x0020 -#define SMARTBATT_FULLY_DISCHARGED 0x0010 -/* * * * * * Error Bits * * * * */ -#define SMARTBATT_OK 0x0000 -#define SMARTBATT_BUSY 0x0001 -#define SMARTBATT_RESERVED_COMMAND 0x0002 -#define SMARTBATT_UNSUPPORTED_COMMAND 0x0003 -#define SMARTBATT_ACCESS_DENIED 0x0004 -#define SMARTBATT_OVER_UNDERFLOW 0x0005 -#define SMARTBATT_BAD_SIZE 0x0006 -#define SMARTBATT_UNKNOWN_ERROR 0x0007 - -#define SMARTBATT_ALARM (SMARTBATT_OVER_CHARGED_ALARM \ - | SMARTBATT_TERMINATE_CHARGE_ALARM | SMARTBATT_OVER_TEMP_ALARM \ - | SMARTBATT_TERMINATE_DISCHARGE_ALARM \ - | SMARTBATT_REMAINING_CAPACITY_ALARM \ - | SMARTBATT_REMAINING_TIME_ALARM) - -#define SMARTBATT_STATUS (SMARTBATT_INITIALIZED | SMARTBATT_DISCHARGING \ - | SMARTBATT_FULLY_CHARGED | SMARTBATT_FULLY_DISCHARGED ) - -#define SMARTBATT_ERROR (SMARTBATT_BUSY | SMARTBATT_RESERVED_COMMAND \ - | SMARTBATT_UNSUPPORTED_COMMAND | SMARTBATT_ACCESS_DENIED \ - | SMARTBATT_OVER_UNDERFLOW | SMARTBATT_BAD_SIZE\ - | SMARTBATT_UNKNOWN_ERROR) - - -#define SMARTBATT_SYSCTL_I 1001 -#define SMARTBATT_SYSCTL_V 1002 -#define SMARTBATT_SYSCTL_TEMP 1003 -#define SMARTBATT_SYSCTL_TIME 1004 -#define SMARTBATT_SYSCTL_ALARMS 1005 -#define SMARTBATT_SYSCTL_STATUS 1006 -#define SMARTBATT_SYSCTL_ERROR 1007 -#define SMARTBATT_SYSCTL_CHARGE 1008 - -/* -- SENSORS SYSCTL END -- */ - -/* These files are created for each detected SMARTBATT. This is just a template; - though at first sight, you might think we could use a statically - allocated list, we need some way to get back to the parent - which - is done through one of the 'extra' fields which are initialized - when a new copy is allocated. */ -static ctl_table smartbatt_dir_table_template[] = { - {SMARTBATT_SYSCTL_I, "i", NULL, 0, 0444, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &smartbatt_i}, - {SMARTBATT_SYSCTL_V, "v", NULL, 0, 0444, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &smartbatt_v}, - {SMARTBATT_SYSCTL_TEMP, "temp", NULL, 0, 0444, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &smartbatt_temp}, - {SMARTBATT_SYSCTL_TIME, "time", NULL, 0, 0444, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &smartbatt_time}, - {SMARTBATT_SYSCTL_ALARMS, "alarms", NULL, 0, 0444, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &smartbatt_alarms}, - {SMARTBATT_SYSCTL_STATUS, "status", NULL, 0, 0444, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &smartbatt_status}, - {SMARTBATT_SYSCTL_ERROR, "error", NULL, 0, 0444, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &smartbatt_error}, - {SMARTBATT_SYSCTL_CHARGE, "charge", NULL, 0, 0444, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &smartbatt_charge}, - {0} -}; - -static int smartbatt_attach_adapter(struct i2c_adapter *adapter) -{ - return i2c_detect(adapter, &addr_data, smartbatt_detect); -} - -/* This function is called by i2c_detect */ -int smartbatt_detect(struct i2c_adapter *adapter, int address, - unsigned short flags, int kind) -{ - int i; - struct i2c_client *new_client; - struct smartbatt_data *data; - int err = 0; - const char *type_name, *client_name; - - /* Make sure we aren't probing the ISA bus!! This is just a safety check - at this moment; i2c_detect really won't call us. */ -#ifdef DEBUG - if (i2c_is_isa_adapter(adapter)) { - printk - ("smartbatt.o: smartbatt_detect called for an ISA bus adapter?!?\n"); - return 0; - } -#endif - - if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_WORD_DATA)) - goto ERROR0; - - /* OK. For now, we presume we have a valid client. We now create the - client structure, even though we cannot fill it completely yet. - But it allows us to access smartbatt_{read,write}_value. */ - if (!(data = kmalloc(sizeof(struct smartbatt_data), GFP_KERNEL))) { - err = -ENOMEM; - goto ERROR0; - } - - new_client = &data->client; - new_client->addr = address; - new_client->data = data; - new_client->adapter = adapter; - new_client->driver = &smartbatt_driver; - new_client->flags = 0; - - /* Lousy detection. Check the temp, voltage, and current registers */ - if (kind < 0) { - for (i = 0x08; i <= 0x0a; i++) - if (i2c_smbus_read_word_data(new_client, i) == 0xffff) - goto ERROR1; - } - - kind = smartbatt; - type_name = "smartbatt"; - client_name = "Smart Battery"; - - /* Fill in the remaining client fields and put it into the global list */ - strcpy(new_client->name, client_name); - data->valid = 0; - init_MUTEX(&data->update_lock); - - /* Tell the I2C layer a new client has arrived */ - if ((err = i2c_attach_client(new_client))) - goto ERROR3; - - /* Register a new directory entry with module sensors */ - if ((i = i2c_register_entry(new_client, type_name, - smartbatt_dir_table_template, - THIS_MODULE)) < 0) { - err = i; - goto ERROR4; - } - data->sysctl_id = i; - - smartbatt_init_client(new_client); - return 0; - -/* OK, this is not exactly good programming practice, usually. But it is - very code-efficient in this case. */ - - ERROR4: - i2c_detach_client(new_client); - ERROR3: - ERROR1: - kfree(data); - ERROR0: - return err; -} - -static int smartbatt_detach_client(struct i2c_client *client) -{ - int err; - - i2c_deregister_entry(((struct smartbatt_data *) (client->data))-> - sysctl_id); - - if ((err = i2c_detach_client(client))) { - printk - ("smartbatt.o: Client deregistration failed, client not detached.\n"); - return err; - } - - kfree(client->data); - - return 0; -} - -static int smartbatt_read(struct i2c_client *client, u8 reg) -{ - int n = COMM_TIMEOUT; - int val; - do { - val = i2c_smbus_read_word_data(client, reg); - } while ((val == -1) && (n-- > 0)); - return val; -} - -#if 0 -static int smartbatt_write_value(struct i2c_client *client, u8 reg, u16 value) -{ - /* Why swap bytes? */ - return i2c_smbus_write_word_data(client, reg, swab16(value)); -} -#endif - -#define COMM_TIMEOUT 16 -static void get_battery_info(struct i2c_client *client) -{ - struct smartbatt_data *data = client->data; - int val; - - down(&data->update_lock); - data->chgcap = smartbatt_read(client, SMARTBATT_REG_CHGCAP); - data->descap = smartbatt_read(client, SMARTBATT_REG_DESCAP); - data->desv = smartbatt_read(client, SMARTBATT_REG_DESV); - /* ManufactureDate */ - val = smartbatt_read(client, SMARTBATT_REG_DATE); - data->manufacture_date.day=val & 0x1F; - data->manufacture_date.month=(val >> 5) & 0x0F; - data->manufacture_date.year=(val >> 9) & 0x7F; - - /* SerialNumber */ - data->serial = smartbatt_read(client, SMARTBATT_REG_SERIAL); -#if 0 - /* ManufacturerName */ - n=COMM_TIMEOUT; - do { - val = i2c_smbus_read_block_data(client, 0x20, data->manufacturer); - } while ((val == -1) && (n-- > 0)); - data->manufacturer[val]=0; - - /* DeviceName */ - n=COMM_TIMEOUT; - do { - val = i2c_smbus_read_block_data(client, 0x21, data->device); - } while ((val == -1) && (n-- > 0)); - data->device[val]=0; - - /* DeviceChemistry */ - n=COMM_TIMEOUT; - do { - val = i2c_smbus_read_block_data(client, 0x22, data->chemistry); - } while ((val == -1) && (n-- > 0)); - data->chemistry[val]=0; -#endif - up(&data->update_lock); - -} - -static void smartbatt_init_client(struct i2c_client *client) -{ - get_battery_info( client ); -} - -static void smartbatt_update_client(struct i2c_client *client) -{ - struct smartbatt_data *data = client->data; - - down(&data->update_lock); - - if ((jiffies - data->last_updated > HZ + HZ / 2) || - (jiffies < data->last_updated) || !data->valid) { - data->mode = smartbatt_read(client, SMARTBATT_REG_MODE); - data->temp = smartbatt_read(client, SMARTBATT_REG_TEMP); - data->i = smartbatt_read(client, SMARTBATT_REG_I); - data->avgi = smartbatt_read(client, SMARTBATT_REG_AVGI); - data->v = smartbatt_read(client, SMARTBATT_REG_V); - data->chgi = smartbatt_read(client, SMARTBATT_REG_CHGI); - data->chgv = smartbatt_read(client, SMARTBATT_REG_CHGV); - data->ate = smartbatt_read(client, SMARTBATT_REG_AVGTIME_E); - data->atf = smartbatt_read(client, SMARTBATT_REG_AVGTIME_F); - data->rte = smartbatt_read(client, SMARTBATT_REG_RUNTIME_E); - data->status = smartbatt_read(client, SMARTBATT_REG_STATUS); - data->cyclect = smartbatt_read(client, SMARTBATT_REG_CYCLECT); - data->relchg = smartbatt_read(client, SMARTBATT_REG_RELCHG); - data->abschg = smartbatt_read(client, SMARTBATT_REG_ABSCHG); - data->remcap = smartbatt_read(client, SMARTBATT_REG_REMCAP); - data->last_updated = jiffies; - data->valid = 1; - } - - up(&data->update_lock); -} - - -void smartbatt_temp(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct smartbatt_data *data = client->data; - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 1; - else if (operation == SENSORS_PROC_REAL_READ) { - smartbatt_update_client(client); - results[0] = data->temp - 2731; /* convert from Kelvin */ - *nrels_mag = 1; - } -} - -void smartbatt_i(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct smartbatt_data *data = client->data; - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 3; - else if (operation == SENSORS_PROC_REAL_READ) { - smartbatt_update_client(client); - results[0] = data->chgi; - results[1] = data->avgi; - results[2] = data->i; - *nrels_mag = 3; - } -} - -void smartbatt_v(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct smartbatt_data *data = client->data; - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 3; - else if (operation == SENSORS_PROC_REAL_READ) { - smartbatt_update_client(client); - results[0] = data->chgv; - results[1] = data->v; - *nrels_mag = 2; - } -} - -void smartbatt_time(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct smartbatt_data *data = client->data; - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - smartbatt_update_client(client); - results[0] = data->ate; - results[1] = data->atf; - results[2] = data->rte; - *nrels_mag = 3; - } -} - -void smartbatt_alarms(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct smartbatt_data *data = client->data; - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - smartbatt_update_client(client); - results[0] = data->status & SMARTBATT_ALARM; - *nrels_mag = 1; - } -} - -void smartbatt_status(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct smartbatt_data *data = client->data; - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - smartbatt_update_client(client); - results[0] = data->status & SMARTBATT_STATUS; - *nrels_mag = 1; - } -} - -void smartbatt_error(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct smartbatt_data *data = client->data; - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - smartbatt_update_client(client); - results[0] = data->status & SMARTBATT_ERROR; - *nrels_mag = 1; - } -} - -void smartbatt_charge(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct smartbatt_data *data = client->data; - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - smartbatt_update_client(client); - results[0] = data->relchg; - results[1] = data->abschg; - results[2] = data->chgi; - results[3] = data->chgv; - *nrels_mag = 4; - } -} - -static int __init sm_smartbatt_init(void) -{ - printk("smartbatt.o version %s (%s)\n", LM_VERSION, LM_DATE); - return i2c_add_driver(&smartbatt_driver); -} - -static void __exit sm_smartbatt_exit(void) -{ - i2c_del_driver(&smartbatt_driver); -} - - - -MODULE_AUTHOR("M. Studebaker "); -MODULE_DESCRIPTION("Smart Battery driver"); -MODULE_LICENSE("GPL"); - -module_init(sm_smartbatt_init); -module_exit(sm_smartbatt_exit); diff --git a/kernel/chips/smbus-arp.c b/kernel/chips/smbus-arp.c deleted file mode 100644 index e4610078..00000000 --- a/kernel/chips/smbus-arp.c +++ /dev/null @@ -1,478 +0,0 @@ -/* - smbus-arp.c - Part of lm_sensors, Linux kernel modules for hardware - monitoring - Copyright (c) 2002 Mark D. Studebaker - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#include -#include -#include -#include -#include -#include "version.h" - -#define DEBUG 1 - -/* So that the module will still compile without i2c-2.6.4; - if inserted, it will just put out a message and exit in that case */ -#ifdef I2C_CLIENT_PEC -#define I2C_PEC_SUPPORTED -#else -#define I2C_DRIVERID_ARP 902 /* SMBus ARP Client */ -#endif - -/* Addresses to scan */ -#define ARP_ADDRESS 0x61 -static unsigned short normal_i2c[] = { ARP_ADDRESS, SENSORS_I2C_END }; -static unsigned short normal_i2c_range[] = { SENSORS_I2C_END }; -static unsigned int normal_isa[] = { SENSORS_ISA_END }; -static unsigned int normal_isa_range[] = { SENSORS_ISA_END }; - -/* Insmod parameters */ -SENSORS_INSMOD_1(arp); - -static int reset; -MODULE_PARM(reset, "i"); -MODULE_PARM_DESC(reset, - "Send an ARP Reset Device message to each bus"); - -/* ARP Commands */ -#define ARP_PREPARE 0x01 -#define ARP_RESET_DEV 0x02 -#define ARP_GET_UDID_GEN 0x03 -#define ARP_ASSIGN_ADDR 0x04 - -/* UDID Fields */ -#define ARP_CAPAB 0 -#define ARP_VER 1 -#define ARP_VEND 2 -#define ARP_DEV 4 -#define ARP_INT 6 -#define ARP_SUBVEND 8 -#define ARP_SUBDEV 10 -#define ARP_SPECID 12 - -#define UDID_LENGTH 0x11 - -static u8 reserved[] = -/* As defined by SMBus Spec. Appendix C */ - {0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x28, - 0x37, ARP_ADDRESS, -/* As defined by SMBus Spec. Sect. 5.2 */ - 0x01, 0x02, 0x03, 0x04, 0x05, - 0x06, 0x07, 0x78, 0x79, 0x7a, 0x7b, - 0x7c, 0x7d, 0x7e, 0x7f, -/* Common PC addresses (bad idea) */ - 0x2d, 0x48, 0x49, /* sensors */ - 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* eeproms */ - 0x69, /* clock chips */ -/* Must end in 0 which is also reserved */ - 0x00}; - -#define SMBUS_ADDRESS_SIZE 0x80 -#define ARP_FREE 0 -#define ARP_RESERVED 1 -#define ARP_BUSY 2 - -#define ARP_MAX_DEVICES 8 -struct arp_device { - int status; - u8 udid[UDID_LENGTH]; - u8 dev_cap; - u8 dev_ver; - u16 dev_vid; - u16 dev_did; - u16 dev_int; - u16 dev_svid; - u16 dev_sdid; - u32 dev_vsid; - u8 saddr; -}; - -/* Each client has this additional data */ -struct arp_data { - struct i2c_client client; - int sysctl_id; - - struct semaphore update_lock; - char valid; /* !=0 if following fields are valid */ - unsigned long last_updated; /* In jiffies */ - - u8 address_pool[SMBUS_ADDRESS_SIZE]; - struct arp_device dev[ARP_MAX_DEVICES]; -}; - - -static int smbusarp_attach_adapter(struct i2c_adapter *adapter); -static int smbusarp_detect(struct i2c_adapter *adapter, int address, - unsigned short flags, int kind); -static int smbusarp_detach_client(struct i2c_client *client); - -static int smbusarp_init_client(struct i2c_client *client); -static void smbusarp_contents(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); - -static struct i2c_driver smbusarp_driver = { - .name = "SMBUS ARP", - .id = I2C_DRIVERID_ARP, - .flags = I2C_DF_NOTIFY, - .attach_adapter = smbusarp_attach_adapter, - .detach_client = smbusarp_detach_client, -}; - -/* -- SENSORS SYSCTL START -- */ -#define ARP_SYSCTL1 1000 -#define ARP_SYSCTL2 1001 -#define ARP_SYSCTL3 1002 -#define ARP_SYSCTL4 1003 -#define ARP_SYSCTL5 1004 -#define ARP_SYSCTL6 1005 -#define ARP_SYSCTL7 1006 -#define ARP_SYSCTL8 1007 - -/* -- SENSORS SYSCTL END -- */ - -static ctl_table smbusarp_dir_table_template[] = { - {ARP_SYSCTL1, "0", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &smbusarp_contents}, - {ARP_SYSCTL2, "1", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &smbusarp_contents}, - {ARP_SYSCTL3, "2", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &smbusarp_contents}, - {ARP_SYSCTL4, "3", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &smbusarp_contents}, - {ARP_SYSCTL5, "4", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &smbusarp_contents}, - {ARP_SYSCTL6, "5", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &smbusarp_contents}, - {ARP_SYSCTL7, "6", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &smbusarp_contents}, - {ARP_SYSCTL8, "7", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &smbusarp_contents}, - {0} -}; - -static int smbusarp_attach_adapter(struct i2c_adapter *adapter) -{ - return i2c_detect(adapter, &addr_data, smbusarp_detect); -} - -/* This function is called by i2c_detect */ -int smbusarp_detect(struct i2c_adapter *adapter, int address, - unsigned short flags, int kind) -{ - int i; - struct i2c_client *new_client; - struct arp_data *data; - int err = 0; - const char *type_name, *client_name; - - /* must support block data w/ HW PEC or SW PEC */ - if ((!i2c_check_functionality(adapter, - I2C_FUNC_SMBUS_BLOCK_DATA | I2C_FUNC_SMBUS_HWPEC_CALC)) && - (!i2c_check_functionality(adapter, - I2C_FUNC_SMBUS_BLOCK_DATA | I2C_FUNC_I2C))) - return(0); - - if (!(data = kmalloc(sizeof(struct arp_data), GFP_KERNEL))) { - return(-ENOMEM); - } - - new_client = &data->client; - new_client->addr = address; - new_client->data = data; - new_client->adapter = adapter; - new_client->driver = &smbusarp_driver; -#ifdef I2C_PEC_SUPPORTED - new_client->flags = I2C_CLIENT_PEC; -#else - new_client->flags = 0; -#endif - - type_name = "arp"; - client_name = "SMBUS ARP client"; - - strcpy(new_client->name, client_name); - data->valid = 0; - init_MUTEX(&data->update_lock); - - if ((err = i2c_attach_client(new_client))) - goto ERROR1; - - if ((i = i2c_register_entry(new_client, type_name, - smbusarp_dir_table_template, - THIS_MODULE)) < 0) { - err = i; - goto ERROR4; - } - data->sysctl_id = i; - smbusarp_init_client(new_client); - return 0; - - ERROR4: - i2c_detach_client(new_client); - ERROR1: - kfree(data); - return err; -} - -static int smbusarp_detach_client(struct i2c_client *client) -{ - int err; - - i2c_deregister_entry(((struct arp_data *) (client->data))-> - sysctl_id); - - if ((err = i2c_detach_client(client))) { - printk - (KERN_ERR "smbus-arp.o: Client deregistration failed, client not detached.\n"); - return err; - } - - kfree(client->data); - - return 0; -} - - -static u8 choose_addr(u8 * pool) -{ - int i; - - for(i = 0; i < 0x7f; i++) { - if(pool[i] == ARP_FREE) - return ((u8) i); - } - return 0xff; -} - -static int smbusarp_init_client(struct i2c_client *client) -{ - int ret = -1; -#ifdef I2C_PEC_SUPPORTED - struct arp_data *data = client->data; - u8 blk[I2C_SMBUS_BLOCK_MAX]; - u8 *r; - u8 addr; - int i; - int found = 0; - int newdev = 0; - - for(i = 0; i < ARP_MAX_DEVICES; i++) - data->dev[i].status = ARP_FREE; - - for(i = 0; i < SMBUS_ADDRESS_SIZE; i++) - data->address_pool[i] = ARP_FREE; - - r = reserved; - do { - data->address_pool[*r] = ARP_RESERVED; - } while(*r++); - - for (i = 0; i < I2C_CLIENT_MAX ; i++) - if (client->adapter->clients[i]) - data->address_pool[client->adapter->clients[i]->addr] = - ARP_BUSY; - - if(reset) - i2c_smbus_write_byte(client, ARP_RESET_DEV); - ret = i2c_smbus_write_byte(client, ARP_PREPARE); - if(ret < 0) { -#ifdef DEBUG - printk(KERN_DEBUG "smbus-arp.o: No ARP response on adapter 0x%X\n", client->adapter->id); -#endif - return(-1); /* Packet wasn't acked */ - } - while(1) { - ret = i2c_smbus_read_block_data(client, ARP_GET_UDID_GEN, blk); - if(ret != UDID_LENGTH) { -#ifdef DEBUG - printk(KERN_DEBUG "smbus-arp.o: No/Bad UDID response %d on adapter 0x%X\n", ret, client->adapter->id); -#endif - if(found) - return(found); - else - return(-1); /* Bad response */ - } -#ifdef DEBUG - printk(KERN_DEBUG "smbus-arp.o: Good UDID response on adapter 0x%X\n", client->adapter->id); - printk(KERN_DEBUG " Cap. 0x%02x Rev. 0x%02x Vend. 0x%02x%02x Dev. 0x%02x%02x\n", blk[0], blk[1], blk[2], blk[3], blk[4], blk[5]); - printk(KERN_DEBUG " Int. 0x%02x%02x Subvend. 0x%02x%02x Subdev. 0x%02x%02x Spec. 0x%02x%02x%02x%02x\n", blk[6], blk[7], blk[8], blk[9], blk[10], blk[11], blk[12], blk[13], blk[14], blk[15]); -#endif -/* clean up this... */ - found++; - do{ - if(data->dev[newdev].status == ARP_FREE) - break; - } while(++newdev < ARP_MAX_DEVICES); - if(newdev == ARP_MAX_DEVICES) { - printk(KERN_WARNING "smbus-arp.o: No more slots available\n"); - return(-1); - } - - /* check device slave addr */ - addr = blk[16]; - if(addr != 0xFF) { - addr >>= 1; - if(blk[0] & 0xC0) { - if(data->address_pool[addr] == ARP_FREE) { -#ifdef DEBUG - printk(KERN_DEBUG " Requested free Non-fixed Address 0x%02x\n", addr); -#endif - } else { -#ifdef DEBUG - printk(KERN_DEBUG " Requested busy Non-fixed Address 0x%02x\n", addr); -#endif - if((addr = - choose_addr(data->address_pool)) == - 0xff) { - printk(KERN_WARNING "smbus-arp.o: Address pool exhausted\n"); - return(-1); - } - } - } else { -#ifdef DEBUG - printk(KERN_DEBUG " Fixed Address 0x%02x\n", addr); -#endif - } - } else { -#ifdef DEBUG - printk(KERN_DEBUG " No Address\n"); -#endif - if((addr = choose_addr(data->address_pool)) == 0xff) { - printk(KERN_WARNING "smbus-arp.o: Address pool exhausted\n"); - return(-1); - } - - } - /* store things both ways */ - for(i = 0; i < UDID_LENGTH; i++) - data->dev[newdev].udid[i] = blk[i]; - data->dev[newdev].saddr = addr; - data->dev[newdev].status = ARP_BUSY; - data->dev[newdev].dev_cap = blk[0]; - data->dev[newdev].dev_ver = blk[1]; - data->dev[newdev].dev_vid = (blk[2] << 8) | blk[3]; - data->dev[newdev].dev_did = (blk[4] << 8) | blk[5]; - data->dev[newdev].dev_int = (blk[6] << 8) | blk[7]; - data->dev[newdev].dev_svid = (blk[8] << 8) | blk[9]; - data->dev[newdev].dev_sdid = (blk[10] << 8) | blk[11]; - data->dev[newdev].dev_vsid = (blk[12] << 24) | (blk[13] << 16) | - (blk[14] << 8) | blk[15] ; - - blk[16] = addr << 1; - ret = i2c_smbus_write_block_data(client, ARP_ASSIGN_ADDR, - UDID_LENGTH, blk); - if(ret) { -#ifdef DEBUG - printk(KERN_DEBUG " Bad response, address 0x%02x not assigned\n", addr); -#endif - } else { - data->address_pool[addr] = ARP_BUSY; -#ifdef DEBUG - printk(KERN_DEBUG " Assigned address 0x%02x\n", addr); -#endif - } - /* retry? */ - - } /* while 1 */ -#else - printk(KERN_WARNING "smbus-arp.o: A client responded to the ARP address but " - "your kernel does not support SMBus ARP/PEC!\n"); - ret = -EPERM; -#endif - return(ret); -} - - -/* reassign address on writex */ -void smbusarp_contents(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results) -{ - int nr = ctl_name - ARP_SYSCTL1; - struct arp_data *data = client->data; - int ret; - u8 save; - u8 a; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - if(data->dev[nr].status == ARP_BUSY) { - results[0] = data->dev[nr].saddr; - results[1] = data->dev[nr].dev_cap; - results[2] = data->dev[nr].dev_ver; - results[3] = data->dev[nr].dev_vid; - results[4] = data->dev[nr].dev_did; - results[5] = data->dev[nr].dev_int; - results[6] = data->dev[nr].dev_svid; - results[7] = data->dev[nr].dev_sdid; - results[8] = data->dev[nr].dev_vsid; - *nrels_mag = 9; - } else { - *nrels_mag = 0; - } - } else if (operation == SENSORS_PROC_REAL_WRITE) { - a = results[0]; - if(*nrels_mag >= 1 && - a < SMBUS_ADDRESS_SIZE && - data->dev[nr].status == ARP_BUSY && - data->address_pool[a] == ARP_FREE) { - save = data->dev[nr].udid[16]; - data->dev[nr].udid[16] = a << 1; - ret = i2c_smbus_write_block_data(client, ARP_ASSIGN_ADDR, - UDID_LENGTH, data->dev[nr].udid); - if(ret) { - data->dev[nr].udid[16] = save; -#ifdef DEBUG - printk(KERN_DEBUG "smbus-arp Bad response, address 0x%02x not assigned\n", a); -#endif - } else { - data->dev[nr].saddr = a; - data->address_pool[a] = ARP_BUSY; -#ifdef DEBUG - printk(KERN_DEBUG "smbus-arp Assigned address 0x%02x\n", a); -#endif - } - } else { - printk(KERN_WARNING "smbus-arp Bad address 0x%02x\n", a); - } - } -} - -static int __init sm_smbusarp_init(void) -{ - printk("smbus-arp.o version %s (%s)\n", LM_VERSION, LM_DATE); -/* magic force invocation */ - force_arp[0] = -1; - force_arp[1] = ARP_ADDRESS; - return i2c_add_driver(&smbusarp_driver); -} - -static void __exit sm_smbusarp_exit(void) -{ - i2c_del_driver(&smbusarp_driver); -} - - - -MODULE_AUTHOR("Mark D. Studebaker "); -MODULE_DESCRIPTION("SMBUS ARP Driver"); -MODULE_LICENSE("GPL"); - -module_init(sm_smbusarp_init); -module_exit(sm_smbusarp_exit); diff --git a/kernel/chips/smsc47m1.c b/kernel/chips/smsc47m1.c deleted file mode 100644 index e464e9c9..00000000 --- a/kernel/chips/smsc47m1.c +++ /dev/null @@ -1,603 +0,0 @@ -/* - smsc47m1.c - Part of lm_sensors, Linux kernel modules - for hardware monitoring - - Copyright (c) 2002 Mark D. Studebaker - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#include -#include -#include -#include -#include -#include -#include -#include "version.h" - -static int force_addr = 0; -MODULE_PARM(force_addr, "i"); -MODULE_PARM_DESC(force_addr, - "Initialize the base address of the sensors"); - -static unsigned short normal_i2c[] = { SENSORS_I2C_END }; -static unsigned short normal_i2c_range[] = { SENSORS_I2C_END }; -static unsigned int normal_isa[] = { 0x0000, SENSORS_ISA_END }; -static unsigned int normal_isa_range[] = { SENSORS_ISA_END }; - -SENSORS_INSMOD_2(smsc47m1, smsc47m2); -static u8 devid; - -/* modified from kernel/include/traps.c */ -#define REG 0x2e /* The register to read/write */ -#define DEV 0x07 /* Register: Logical device select */ -#define VAL 0x2f /* The value to read/write */ -#define PME 0x0a /* The device with the fan registers in it */ -#define DEVID 0x20 /* Register: Device ID */ - -static inline void -superio_outb(int reg, int val) -{ - outb(reg, REG); - outb(val, VAL); -} - -static inline int -superio_inb(int reg) -{ - outb(reg, REG); - return inb(VAL); -} - -static inline void -superio_select(void) -{ - outb(DEV, REG); - outb(PME, VAL); -} - -static inline void -superio_enter(void) -{ - outb(0x55, REG); -} - -static inline void -superio_exit(void) -{ - outb(0xAA, REG); -} - -/* - * SMSC LPC47M10x/LPC47M112/LPC47M13x (device id 0x59), LPC47M14x - * (device id 0x5F) and LPC47B27x (device id 0x51) have fan control. - * The 47M15x and 47M192 chips "with hardware monitoring block" - * can do much more besides (device id 0x60). - * The LPC47M997 is undocumented, but seems to be compatible with - * the LPC47M192, and has the same device id. - * The LPC47M292 (device id 0x6B) is somewhat compatible, but it - * supports a 3rd fan, and the pin configuration registers are - * unfortunately different. - */ -#define SMSC_DEVID_MATCH(id) ((id) == 0x51 || (id) == 0x59 || \ - (id) == 0x5F || (id) == 0x60 || \ - (id) == 0x6B) - -#define SMSC_ACT_REG 0x30 -#define SMSC_BASE_REG 0x60 - -#define SMSC_EXTENT 0x80 - -#define SMSC47M1_REG_ALARM1 0x04 -#define SMSC47M1_REG_TPIN2 0x33 -#define SMSC47M1_REG_TPIN1 0x34 -#define SMSC47M1_REG_PPIN(nr) (0x37 - (nr)) -#define SMSC47M1_REG_FANDIV 0x58 - -static const u8 SMSC47M1_REG_PWM[3] = { 0x56, 0x57, 0x69 }; -static const u8 SMSC47M1_REG_FAN[3] = { 0x59, 0x5a, 0x6b }; -static const u8 SMSC47M1_REG_FAN_MIN[3] = { 0x5b, 0x5c, 0x6c }; - -#define SMSC47M2_REG_ALARM6 0x09 -#define SMSC47M2_REG_TPIN3 0x2d -#define SMSC47M2_REG_TPIN2 0x37 -#define SMSC47M2_REG_TPIN1 0x38 -#define SMSC47M2_REG_FANDIV3 0x6a - -static inline u8 MIN_TO_REG(long rpm, int div) -{ - if (rpm == 0) - return 0; - rpm = SENSORS_LIMIT(rpm, 1, 1000000); - return SENSORS_LIMIT(192 - ((983040 + rpm * div / 2) / (rpm * div)), - 0, 191); -} - -#define MIN_FROM_REG(val,div) ((val)>=192?0: \ - 983040/((192-(val))*(div))) -#define FAN_FROM_REG(val,div,preload) ((val)==0?-1:(val)==255?0: \ - 983040/(((val)-preload)*(div))) -#define DIV_FROM_REG(val) (1 << (val)) -#define DIV_TO_REG(val) ((val)==8?3:(val)==4?2:(val)==1?0:1) -/* reg is 6 middle bits; /proc is 8 bits */ -#define PWM_FROM_REG(val) (((val) << 1) & 0xfc) -#define PWM_TO_REG(val) (((SENSORS_LIMIT((val), 0, 255)) >> 1) & 0x7e) - -struct smsc47m1_data { - struct i2c_client client; - int sysctl_id; - enum chips type; - - struct semaphore update_lock; - char valid; /* !=0 if following fields are valid */ - unsigned long last_updated; /* In jiffies */ - - u8 fan[3]; /* Register value */ - u8 fan_min[3]; /* Register value */ - u8 fan_div[3]; /* Register encoding, shifted right */ - u8 alarms; /* Register encoding */ - u8 pwm[3]; /* Register value (bit 0 is disable) */ -}; - - -static int smsc47m1_attach_adapter(struct i2c_adapter *adapter); -static int smsc47m1_detect(struct i2c_adapter *adapter, int address, - unsigned short flags, int kind); -static int smsc47m1_detach_client(struct i2c_client *client); -static void smsc47m1_update_client(struct i2c_client *client); -static void smsc47m1_init_client(struct i2c_client *client); - - -static void smsc47m1_fan(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void smsc47m1_alarms(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void smsc47m1_fan_div(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void smsc47m1_pwm(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); - -static struct i2c_driver smsc47m1_driver = { - .name = "SMSC 47M1xx fan monitor", - .id = I2C_DRIVERID_SMSC47M1, - .flags = I2C_DF_NOTIFY, - .attach_adapter = smsc47m1_attach_adapter, - .detach_client = smsc47m1_detach_client, -}; - -/* -- SENSORS SYSCTL START -- */ -#define SMSC47M1_SYSCTL_FAN1 1101 /* Rotations/min */ -#define SMSC47M1_SYSCTL_FAN2 1102 -#define SMSC47M1_SYSCTL_FAN3 1103 -#define SMSC47M1_SYSCTL_PWM1 1401 -#define SMSC47M1_SYSCTL_PWM2 1402 -#define SMSC47M1_SYSCTL_PWM3 1403 -#define SMSC47M1_SYSCTL_FAN_DIV 2000 /* 1, 2, 4 or 8 */ -#define SMSC47M1_SYSCTL_ALARMS 2004 /* bitvector */ - -#define SMSC47M1_ALARM_FAN1 0x0001 -#define SMSC47M1_ALARM_FAN2 0x0002 -#define SMSC47M1_ALARM_FAN3 0x0004 - -/* -- SENSORS SYSCTL END -- */ - -static ctl_table smsc47m1_dir_table_template[] = { - {SMSC47M1_SYSCTL_FAN1, "fan1", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &smsc47m1_fan}, - {SMSC47M1_SYSCTL_FAN2, "fan2", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &smsc47m1_fan}, - {SMSC47M1_SYSCTL_FAN_DIV, "fan_div", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &smsc47m1_fan_div}, - {SMSC47M1_SYSCTL_ALARMS, "alarms", NULL, 0, 0444, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &smsc47m1_alarms}, - {SMSC47M1_SYSCTL_PWM1, "pwm1", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &smsc47m1_pwm}, - {SMSC47M1_SYSCTL_PWM2, "pwm2", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &smsc47m1_pwm}, - {0} -}; - -static ctl_table smsc47m2_dir_table_template[] = { - {SMSC47M1_SYSCTL_FAN1, "fan1", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &smsc47m1_fan}, - {SMSC47M1_SYSCTL_FAN2, "fan2", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &smsc47m1_fan}, - {SMSC47M1_SYSCTL_FAN3, "fan3", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &smsc47m1_fan}, - {SMSC47M1_SYSCTL_FAN_DIV, "fan_div", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &smsc47m1_fan_div}, - {SMSC47M1_SYSCTL_ALARMS, "alarms", NULL, 0, 0444, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &smsc47m1_alarms}, - {SMSC47M1_SYSCTL_PWM1, "pwm1", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &smsc47m1_pwm}, - {SMSC47M1_SYSCTL_PWM2, "pwm2", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &smsc47m1_pwm}, - {SMSC47M1_SYSCTL_PWM3, "pwm3", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &smsc47m1_pwm}, - {0} -}; - -static int smsc47m1_attach_adapter(struct i2c_adapter *adapter) -{ - return i2c_detect(adapter, &addr_data, smsc47m1_detect); -} - -static int __init smsc47m1_find(int *address) -{ - u16 val; - - superio_enter(); - devid = superio_inb(DEVID); - if (!SMSC_DEVID_MATCH(devid)) { - superio_exit(); - return -ENODEV; - } - - superio_select(); - val = (superio_inb(SMSC_BASE_REG) << 8) | - superio_inb(SMSC_BASE_REG + 1); - *address = val & ~(SMSC_EXTENT - 1); - if (*address == 0 && force_addr == 0) { - printk("smsc47m1.o: base address not set - use force_addr=0xaddr\n"); - superio_exit(); - return -ENODEV; - } - if (force_addr) - *address = force_addr; /* so detect will get called */ - - superio_exit(); - return 0; -} - -int smsc47m1_detect(struct i2c_adapter *adapter, int address, - unsigned short flags, int kind) -{ - int i; - struct i2c_client *new_client; - struct smsc47m1_data *data; - int err = 0; - const char *type_name; - const char *client_name; - - if (!i2c_is_isa_adapter(adapter)) { - return 0; - } - - if(force_addr) - address = force_addr & ~(SMSC_EXTENT - 1); - if (check_region(address, SMSC_EXTENT)) { - printk("smsc47m1.o: region 0x%x already in use!\n", address); - return -ENODEV; - } - if(force_addr) { - printk("smsc47m1.o: forcing ISA address 0x%04X\n", address); - superio_enter(); - superio_select(); - superio_outb(SMSC_BASE_REG, address >> 8); - superio_outb(SMSC_BASE_REG+1, address & 0xff); - superio_exit(); - } - - if (!(data = kmalloc(sizeof(struct smsc47m1_data), GFP_KERNEL))) { - return -ENOMEM; - } - - switch (devid) { - case 0x51: - kind = smsc47m1; - type_name = "smsc47m1"; - client_name = "LPC47B27x chip"; - break; - case 0x5F: - kind = smsc47m1; - type_name = "smsc47m1"; - client_name = "LPC47M14x chip"; - break; - case 0x60: - kind = smsc47m1; - type_name = "smsc47m1"; - client_name = "LPC47M192 chip"; - break; - case 0x6B: - kind = smsc47m2; - type_name = "smsc47m2"; - client_name = "LPC47M292 chip"; - break; - default: - kind = smsc47m1; - type_name = "smsc47m1"; - client_name = "LPC47M1xx chip"; - } - - new_client = &data->client; - new_client->addr = address; - new_client->data = data; - new_client->adapter = adapter; - new_client->driver = &smsc47m1_driver; - new_client->flags = 0; - - request_region(address, SMSC_EXTENT, "smsc47m1-fans"); - strcpy(new_client->name, client_name); - data->type = kind; - data->valid = 0; - init_MUTEX(&data->update_lock); - - if ((err = i2c_attach_client(new_client))) - goto ERROR3; - - if ((i = i2c_register_entry((struct i2c_client *) new_client, - type_name, - kind == smsc47m2 ? - smsc47m2_dir_table_template : - smsc47m1_dir_table_template, - THIS_MODULE)) < 0) { - err = i; - goto ERROR4; - } - data->sysctl_id = i; - - smsc47m1_init_client(new_client); - return 0; - - ERROR4: - i2c_detach_client(new_client); - ERROR3: - release_region(address, SMSC_EXTENT); - kfree(data); - return err; -} - -static int smsc47m1_detach_client(struct i2c_client *client) -{ - int err; - - i2c_deregister_entry(((struct smsc47m1_data *) (client->data))-> - sysctl_id); - - if ((err = i2c_detach_client(client))) { - printk - ("smsc47m1.o: Client deregistration failed, client not detached.\n"); - return err; - } - - release_region(client->addr, SMSC_EXTENT); - kfree(client->data); - - return 0; -} - -static inline int smsc47m1_read_value(struct i2c_client *client, u8 reg) -{ - return inb_p(client->addr + reg); -} - -static inline void smsc47m1_write_value(struct i2c_client *client, u8 reg, - u8 value) -{ - outb_p(value, client->addr + reg); -} - -static void smsc47m1_init_client(struct i2c_client *client) -{ - struct smsc47m1_data *data = client->data; - u8 reg; - - switch (data->type) { - case smsc47m2: - /* For the new LPC47M292 chip, I prefer to play it safe and - only report the pin configuration */ - reg = smsc47m1_read_value(client, SMSC47M2_REG_TPIN1); - if ((reg & 0x0d) != 0x09) - printk(KERN_NOTICE "smsc47m1: GP35 not configured for " - "fan input, ignore fan1 values\n"); - reg = smsc47m1_read_value(client, SMSC47M2_REG_TPIN2); - if ((reg & 0x0d) != 0x09) - printk(KERN_NOTICE "smsc47m1: GP34 not configured for " - "fan input, ignore fan2 values\n"); - reg = smsc47m1_read_value(client, SMSC47M2_REG_TPIN3); - if ((reg & 0x0d) != 0x0d) - printk(KERN_NOTICE "smsc47m1: GP33 not configured for " - "fan input, ignore fan3 values\n"); - break; - default: - /* configure pins for tach function */ - smsc47m1_write_value(client, SMSC47M1_REG_TPIN1, 0x05); - smsc47m1_write_value(client, SMSC47M1_REG_TPIN2, 0x05); - } -} - -static void smsc47m1_update_client(struct i2c_client *client) -{ - struct smsc47m1_data *data = client->data; - - down(&data->update_lock); - - if ((jiffies - data->last_updated > HZ + HZ / 2) || - (jiffies < data->last_updated) || !data->valid) { - int i, fan_nr; - fan_nr = data->type == smsc47m2 ? 3 : 2; - - for (i = 0; i < fan_nr; i++) { - data->fan[i] = - smsc47m1_read_value(client, SMSC47M1_REG_FAN[i]); - data->fan_min[i] = - smsc47m1_read_value(client, SMSC47M1_REG_FAN_MIN[i]); - data->pwm[i] = - smsc47m1_read_value(client, SMSC47M1_REG_PWM[i]); - } - - i = smsc47m1_read_value(client, SMSC47M1_REG_FANDIV); - data->fan_div[0] = (i >> 4) & 0x03; - data->fan_div[1] = i >> 6; - data->alarms = - smsc47m1_read_value(client, SMSC47M1_REG_ALARM1) >> 6; - if(data->alarms) - smsc47m1_write_value(client, SMSC47M1_REG_ALARM1, 0xc0); - - if (fan_nr >= 3) { - data->fan_div[2] = (smsc47m1_read_value(client, - SMSC47M2_REG_FANDIV3) >> 4) & 0x03; - data->alarms |= (smsc47m1_read_value(client, - SMSC47M2_REG_ALARM6) & 0x40) >> 4; - if (data->alarms & 0x04) - smsc47m1_write_value(client, - SMSC47M2_REG_ALARM6, - 0x40); - } - - data->last_updated = jiffies; - data->valid = 1; - } - - up(&data->update_lock); -} - - -void smsc47m1_fan(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct smsc47m1_data *data = client->data; - int nr = ctl_name - SMSC47M1_SYSCTL_FAN1; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - smsc47m1_update_client(client); - results[0] = MIN_FROM_REG(data->fan_min[nr], - DIV_FROM_REG(data->fan_div[nr])); - results[1] = FAN_FROM_REG(data->fan[nr], - DIV_FROM_REG(data->fan_div[nr]), - data->fan_min[nr]); - *nrels_mag = 2; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag >= 1) { - data->fan_min[nr] = MIN_TO_REG(results[0], - DIV_FROM_REG(data->fan_div[nr])); - smsc47m1_write_value(client, SMSC47M1_REG_FAN_MIN[nr], - data->fan_min[nr]); - } - } -} - - -void smsc47m1_alarms(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct smsc47m1_data *data = client->data; - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - smsc47m1_update_client(client); - results[0] = data->alarms; - *nrels_mag = 1; - } -} - -void smsc47m1_fan_div(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results) -{ - struct smsc47m1_data *data = client->data; - int old; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - smsc47m1_update_client(client); - results[0] = DIV_FROM_REG(data->fan_div[0]); - results[1] = DIV_FROM_REG(data->fan_div[1]); - *nrels_mag = 2; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - old = smsc47m1_read_value(client, SMSC47M1_REG_FANDIV); - if (*nrels_mag >= 3 && data->type == smsc47m2) { - data->fan_div[2] = DIV_TO_REG(results[2]); - smsc47m1_write_value(client, SMSC47M2_REG_FANDIV3, - (smsc47m1_read_value(client, - SMSC47M2_REG_FANDIV3) & 0xcf) - | (data->fan_div[2] << 4)); - } - if (*nrels_mag >= 2) { - data->fan_div[1] = DIV_TO_REG(results[1]); - old = (old & 0x3f) | (data->fan_div[1] << 6); - } - if (*nrels_mag >= 1) { - data->fan_div[0] = DIV_TO_REG(results[0]); - old = (old & 0xcf) | (data->fan_div[0] << 4); - smsc47m1_write_value(client, SMSC47M1_REG_FANDIV, old); - } - } -} - -void smsc47m1_pwm(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct smsc47m1_data *data = client->data; - int nr = ctl_name - SMSC47M1_SYSCTL_PWM1; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - smsc47m1_update_client(client); - results[0] = PWM_FROM_REG(data->pwm[nr]); - results[1] = !(data->pwm[nr] & 0x01); - *nrels_mag = 2; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag >= 1) { - data->pwm[nr] = smsc47m1_read_value(client, - SMSC47M1_REG_PWM[nr]) & 0x81; - data->pwm[nr] |= PWM_TO_REG(results[0]); - if (*nrels_mag >= 2) { - if (results[1]) { - /* enable PWM */ - data->pwm[nr] &= 0xfe; - } else { - /* disable PWM */ - data->pwm[nr] |= 0x01; - } - } - smsc47m1_write_value(client, SMSC47M1_REG_PWM[nr], - data->pwm[nr]); - } - } -} - -static int __init sm_smsc47m1_init(void) -{ - int addr; - - printk("smsc47m1.o version %s (%s)\n", LM_VERSION, LM_DATE); - - if (smsc47m1_find(&addr)) { - printk("smsc47m1.o: SMSC 47M1xx not detected, module not inserted.\n"); - return -ENODEV; - } - normal_isa[0] = addr; - - return i2c_add_driver(&smsc47m1_driver); -} - -static void __exit sm_smsc47m1_exit(void) -{ - i2c_del_driver(&smsc47m1_driver); -} - - - -MODULE_AUTHOR("Mark D. Studebaker "); -MODULE_DESCRIPTION("SMSC 47M1xx Fan sensors"); -MODULE_LICENSE("GPL"); - -module_init(sm_smsc47m1_init); -module_exit(sm_smsc47m1_exit); diff --git a/kernel/chips/thmc50.c b/kernel/chips/thmc50.c deleted file mode 100644 index 301019b1..00000000 --- a/kernel/chips/thmc50.c +++ /dev/null @@ -1,491 +0,0 @@ -/* - thmc50.c - Part of lm_sensors, Linux kernel modules for hardware - monitoring - Copyright (c) 1998, 1999 Frodo Looijaard and - Philip Edelbrock - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#define DEBUG 1 - -#include -#include -#include -#include -#include -#include "version.h" - -MODULE_LICENSE("GPL"); - -/* Addresses to scan */ -static unsigned short normal_i2c[] = { SENSORS_I2C_END }; -static unsigned short normal_i2c_range[] = { 0x2C, 0x2E, SENSORS_I2C_END }; -static unsigned int normal_isa[] = { SENSORS_ISA_END }; -static unsigned int normal_isa_range[] = { SENSORS_ISA_END }; - -/* Insmod parameters */ -SENSORS_INSMOD_1(thmc50); - -/* Many THMC50 constants specified below */ - -/* The THMC50 registers */ -#define THMC50_REG_TEMP 0x27 -#define THMC50_REG_CONF 0x40 -#define THMC50_REG_TEMP_HYST 0x3A -#define THMC50_REG_TEMP_OS 0x39 - -#define THMC50_REG_TEMP_TRIP 0x13 -#define THMC50_REG_TEMP_REMOTE_TRIP 0x14 -#define THMC50_REG_TEMP_DEFAULT_TRIP 0x17 -#define THMC50_REG_TEMP_REMOTE_DEFAULT_TRIP 0x18 -#define THMC50_REG_ANALOG_OUT 0x19 -#define THMC50_REG_REMOTE_TEMP 0x26 -#define THMC50_REG_REMOTE_TEMP_HYST 0x38 -#define THMC50_REG_REMOTE_TEMP_OS 0x37 - -#define THMC50_REG_INTER 0x41 -#define THMC50_REG_INTER_MIRROR 0x4C -#define THMC50_REG_INTER_MASK 0x43 - -#define THMC50_REG_COMPANY_ID 0x3E -#define THMC50_REG_DIE_CODE 0x3F - - -/* Conversions. Rounding and limit checking is only done on the TO_REG - variants. Note that you should be a bit careful with which arguments - these macros are called: arguments may be evaluated more than once. - Fixing this is just not worth it. */ -#define TEMP_FROM_REG(val) ((val>127)?val - 0x0100:val) -#define TEMP_TO_REG(val) ((val<0)?0x0100+val:val) - -/* Each client has this additional data */ -struct thmc50_data { - struct i2c_client client; - int sysctl_id; - - struct semaphore update_lock; - char valid; /* !=0 if following fields are valid */ - unsigned long last_updated; /* In jiffies */ - - u16 temp, temp_os, temp_hyst, - remote_temp, remote_temp_os, remote_temp_hyst, - inter, inter_mask, die_code, analog_out; /* Register values */ -}; - -static int thmc50_attach_adapter(struct i2c_adapter *adapter); -static int thmc50_detect(struct i2c_adapter *adapter, int address, - unsigned short flags, int kind); -static void thmc50_init_client(struct i2c_client *client); -static int thmc50_detach_client(struct i2c_client *client); - -static int thmc50_read_value(struct i2c_client *client, u8 reg); -static int thmc50_write_value(struct i2c_client *client, u8 reg, - u16 value); -static void thmc50_temp(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void thmc50_remote_temp(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, - long *results); -static void thmc50_inter(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void thmc50_inter_mask(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void thmc50_die_code(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void thmc50_analog_out(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void thmc50_update_client(struct i2c_client *client); - - -/* This is the driver that will be inserted */ -static struct i2c_driver thmc50_driver = { - .name = "THMC50 sensor chip driver", - .id = I2C_DRIVERID_THMC50, - .flags = I2C_DF_NOTIFY, - .attach_adapter = thmc50_attach_adapter, - .detach_client = thmc50_detach_client, -}; - -/* -- SENSORS SYSCTL START -- */ - -#define THMC50_SYSCTL_TEMP 1200 /* Degrees Celsius */ -#define THMC50_SYSCTL_REMOTE_TEMP 1201 /* Degrees Celsius */ -#define THMC50_SYSCTL_INTER 1202 -#define THMC50_SYSCTL_INTER_MASK 1203 -#define THMC50_SYSCTL_DIE_CODE 1204 -#define THMC50_SYSCTL_ANALOG_OUT 1205 - -/* -- SENSORS SYSCTL END -- */ - -/* These files are created for each detected THMC50. This is just a template; - though at first sight, you might think we could use a statically - allocated list, we need some way to get back to the parent - which - is done through one of the 'extra' fields which are initialized - when a new copy is allocated. */ -static ctl_table thmc50_dir_table_template[] = { - {THMC50_SYSCTL_TEMP, "temp1", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &thmc50_temp}, - {THMC50_SYSCTL_REMOTE_TEMP, "temp2", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &thmc50_remote_temp}, - {THMC50_SYSCTL_INTER, "inter", NULL, 0, 0444, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &thmc50_inter}, - {THMC50_SYSCTL_INTER_MASK, "inter_mask", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &thmc50_inter_mask}, - {THMC50_SYSCTL_DIE_CODE, "die_code", NULL, 0, 0444, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &thmc50_die_code}, - {THMC50_SYSCTL_ANALOG_OUT, "analog_out", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &thmc50_analog_out}, - {0} -}; - - -static int thmc50_attach_adapter(struct i2c_adapter *adapter) -{ - return i2c_detect(adapter, &addr_data, thmc50_detect); -} - -/* This function is called by i2c_detect */ -int thmc50_detect(struct i2c_adapter *adapter, int address, - unsigned short flags, int kind) -{ - int company, i; - struct i2c_client *new_client; - struct thmc50_data *data; - int err = 0; - const char *type_name, *client_name; - -#ifdef DEBUG - printk("thmc50.o: Probing for THMC50 at 0x%2X on bus %d\n", - address, adapter->id); -#endif - - /* Make sure we aren't probing the ISA bus!! This is just a safety check - at this moment; i2c_detect really won't call us. */ -#ifdef DEBUG - if (i2c_is_isa_adapter(adapter)) { - printk - ("thmc50.o: thmc50_detect called for an ISA bus adapter?!?\n"); - return 0; - } -#endif - - if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) - goto ERROR0; - - /* OK. For now, we presume we have a valid client. We now create the - client structure, even though we cannot fill it completely yet. - But it allows us to access thmc50_{read,write}_value. */ - if (!(data = kmalloc(sizeof(struct thmc50_data), GFP_KERNEL))) { - err = -ENOMEM; - goto ERROR0; - } - - new_client = &data->client; - new_client->addr = address; - new_client->data = data; - new_client->adapter = adapter; - new_client->driver = &thmc50_driver; - new_client->flags = 0; - - /* Now, we do the remaining detection. */ - company = - i2c_smbus_read_byte_data(new_client, THMC50_REG_COMPANY_ID); - - if (company != 0x49) { -#ifdef DEBUG - printk - ("thmc50.o: Detect of THMC50 failed (reg 3E: 0x%X)\n", - company); -#endif - goto ERROR1; - } - - /* Determine the chip type - only one kind supported! */ - kind = thmc50; - - if (kind == thmc50) { - type_name = "thmc50"; - client_name = "THMC50 chip"; - } else { -#ifdef DEBUG - printk("thmc50.o: Internal error: unknown kind (%d)\n", - kind); -#endif - goto ERROR1; - } - - /* Fill in the remaining client fields and put it into the global list */ - strcpy(new_client->name, client_name); - data->valid = 0; - init_MUTEX(&data->update_lock); - - /* Tell the I2C layer a new client has arrived */ - if ((err = i2c_attach_client(new_client))) - goto ERROR3; - - /* Register a new directory entry with module sensors */ - if ((i = i2c_register_entry(new_client, type_name, - thmc50_dir_table_template, - THIS_MODULE)) < 0) { - err = i; - goto ERROR4; - } - data->sysctl_id = i; - - thmc50_init_client(new_client); - return 0; - -/* OK, this is not exactly good programming practice, usually. But it is - very code-efficient in this case. */ - - ERROR4: - i2c_detach_client(new_client); - ERROR3: - ERROR1: - kfree(data); - ERROR0: - return err; -} - -static int thmc50_detach_client(struct i2c_client *client) -{ - int err; - - i2c_deregister_entry(((struct thmc50_data *) (client->data))-> - sysctl_id); - - if ((err = i2c_detach_client(client))) { - printk - ("thmc50.o: Client deregistration failed, client not detached.\n"); - return err; - } - - kfree(client->data); - - return 0; -} - - -/* All registers are word-sized, except for the configuration register. - THMC50 uses a high-byte first convention, which is exactly opposite to - the usual practice. */ -static int thmc50_read_value(struct i2c_client *client, u8 reg) -{ - return i2c_smbus_read_byte_data(client, reg); -} - -/* All registers are word-sized, except for the configuration register. - THMC50 uses a high-byte first convention, which is exactly opposite to - the usual practice. */ -static int thmc50_write_value(struct i2c_client *client, u8 reg, u16 value) -{ - return i2c_smbus_write_byte_data(client, reg, value); -} - -static void thmc50_init_client(struct i2c_client *client) -{ - thmc50_write_value(client, THMC50_REG_CONF, 1); -} - -static void thmc50_update_client(struct i2c_client *client) -{ - struct thmc50_data *data = client->data; - - down(&data->update_lock); - - if ((jiffies - data->last_updated > HZ + HZ / 2) || - (jiffies < data->last_updated) || !data->valid) { - -#ifdef DEBUG - printk("Starting thmc50 update\n"); -#endif - - data->temp = thmc50_read_value(client, THMC50_REG_TEMP); - data->temp_os = - thmc50_read_value(client, THMC50_REG_TEMP_OS); - data->temp_hyst = - thmc50_read_value(client, THMC50_REG_TEMP_HYST); - data->remote_temp = - thmc50_read_value(client, THMC50_REG_REMOTE_TEMP); - data->remote_temp_os = - thmc50_read_value(client, THMC50_REG_REMOTE_TEMP_OS); - data->remote_temp_hyst = - thmc50_read_value(client, THMC50_REG_REMOTE_TEMP_HYST); - data->inter = thmc50_read_value(client, THMC50_REG_INTER); - data->inter_mask = - thmc50_read_value(client, THMC50_REG_INTER_MASK); - data->die_code = - thmc50_read_value(client, THMC50_REG_DIE_CODE); - data->analog_out = - thmc50_read_value(client, THMC50_REG_ANALOG_OUT); - data->last_updated = jiffies; - data->valid = 1; - } - - up(&data->update_lock); -} - - -void thmc50_temp(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct thmc50_data *data = client->data; - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - thmc50_update_client(client); - results[0] = TEMP_FROM_REG(data->temp_os); - results[1] = TEMP_FROM_REG(data->temp_hyst); - results[2] = TEMP_FROM_REG(data->temp); - *nrels_mag = 3; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag >= 1) { - data->temp_os = TEMP_TO_REG(results[0]); - thmc50_write_value(client, THMC50_REG_TEMP_OS, - data->temp_os); - } - if (*nrels_mag >= 2) { - data->temp_hyst = TEMP_TO_REG(results[1]); - thmc50_write_value(client, THMC50_REG_TEMP_HYST, - data->temp_hyst); - } - } -} - - -void thmc50_remote_temp(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results) -{ - struct thmc50_data *data = client->data; - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - thmc50_update_client(client); - results[0] = TEMP_FROM_REG(data->remote_temp_os); - results[1] = TEMP_FROM_REG(data->remote_temp_hyst); - results[2] = TEMP_FROM_REG(data->remote_temp); - *nrels_mag = 3; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag >= 1) { - data->remote_temp_os = TEMP_TO_REG(results[0]); - thmc50_write_value(client, - THMC50_REG_REMOTE_TEMP_OS, - data->remote_temp_os); - } - if (*nrels_mag >= 2) { - data->remote_temp_hyst = TEMP_TO_REG(results[1]); - thmc50_write_value(client, - THMC50_REG_REMOTE_TEMP_HYST, - data->remote_temp_hyst); - } - } -} - - -void thmc50_inter(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct thmc50_data *data = client->data; - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - thmc50_update_client(client); - results[0] = data->inter; - *nrels_mag = 1; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - printk("thmc50.o: No writes to Interrupt register!\n"); - } -} - - -void thmc50_inter_mask(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results) -{ - struct thmc50_data *data = client->data; - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - thmc50_update_client(client); - results[0] = data->inter_mask; - *nrels_mag = 1; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag >= 1) { - data->inter_mask = results[0]; - thmc50_write_value(client, THMC50_REG_INTER_MASK, - data->inter_mask); - } - } -} - - -void thmc50_die_code(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results) -{ - struct thmc50_data *data = client->data; - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - thmc50_update_client(client); - results[0] = data->die_code; - *nrels_mag = 1; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - printk("thmc50.o: No writes to Die-Code register!\n"); - } -} - - -void thmc50_analog_out(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results) -{ - struct thmc50_data *data = client->data; - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - thmc50_update_client(client); - results[0] = data->analog_out; - *nrels_mag = 1; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag >= 1) { - data->analog_out = results[0]; - thmc50_write_value(client, THMC50_REG_ANALOG_OUT, - data->analog_out); - } - } -} - - - - -static int __init sm_thmc50_init(void) -{ - printk("thmc50.o version %s (%s)\n", LM_VERSION, LM_DATE); - - return i2c_add_driver(&thmc50_driver); -} - -static void __exit sm_thmc50_exit(void) -{ - i2c_del_driver(&thmc50_driver); -} - - - -MODULE_AUTHOR - ("Frodo Looijaard and Philip Edelbrock "); -MODULE_DESCRIPTION("THMC50 driver"); - -module_init(sm_thmc50_init); -module_exit(sm_thmc50_exit); diff --git a/kernel/chips/via686a.c b/kernel/chips/via686a.c deleted file mode 100644 index fdf79c1b..00000000 --- a/kernel/chips/via686a.c +++ /dev/null @@ -1,841 +0,0 @@ -/* - via686a.c - Part of lm_sensors, Linux kernel modules - for hardware monitoring - - Copyright (c) 1998 - 2002 Frodo Looijaard , - Kyösti Mälkki , - Mark Studebaker , - and Bob Dougherty - (Some conversion-factor data were contributed by Jonathan Teh Soon Yew - and Alex van Kaam .) - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -/* - Supports the Via VT82C686A, VT82C686B south bridges. - Reports all as a 686A. - See doc/chips/via686a for details. - Warning - only supports a single device. -*/ - -#include -#include -#include -#include -#include -#include -#include -#include "version.h" -#include "sensors_compat.h" - - -/* If force_addr is set to anything different from 0, we forcibly enable - the device at the given address. */ -static int force_addr = 0; -MODULE_PARM(force_addr, "i"); -MODULE_PARM_DESC(force_addr, - "Initialize the base address of the sensors"); - -/* Addresses to scan. - Note that we can't determine the ISA address until we have initialized - our module */ -static unsigned short normal_i2c[] = { SENSORS_I2C_END }; -static unsigned short normal_i2c_range[] = { SENSORS_I2C_END }; -static unsigned int normal_isa[] = { 0x0000, SENSORS_ISA_END }; -static unsigned int normal_isa_range[] = { SENSORS_ISA_END }; - -/* Insmod parameters */ -SENSORS_INSMOD_1(via686a); - -/* - The Via 686a southbridge has a LM78-like chip integrated on the same IC. - This driver is a customized copy of lm78.c -*/ - -/* Many VIA686A constants specified below */ - -/* Length of ISA address segment */ -#define VIA686A_EXTENT 0x80 -#define VIA686A_BASE_REG 0x70 -#define VIA686A_ENABLE_REG 0x74 - -/* The VIA686A registers */ -/* ins numbered 0-4 */ -#define VIA686A_REG_IN_MAX(nr) (0x2b + ((nr) * 2)) -#define VIA686A_REG_IN_MIN(nr) (0x2c + ((nr) * 2)) -#define VIA686A_REG_IN(nr) (0x22 + (nr)) - -/* fans numbered 1-2 */ -#define VIA686A_REG_FAN_MIN(nr) (0x3a + (nr)) -#define VIA686A_REG_FAN(nr) (0x28 + (nr)) - -// the following values are as speced by VIA: -static const u8 regtemp[] = { 0x20, 0x21, 0x1f }; -static const u8 regover[] = { 0x39, 0x3d, 0x1d }; -static const u8 reghyst[] = { 0x3a, 0x3e, 0x1e }; - -/* temps numbered 1-3 */ -#define VIA686A_REG_TEMP(nr) (regtemp[(nr) - 1]) -#define VIA686A_REG_TEMP_OVER(nr) (regover[(nr) - 1]) -#define VIA686A_REG_TEMP_HYST(nr) (reghyst[(nr) - 1]) -#define VIA686A_REG_TEMP_LOW1 0x4b // bits 7-6 -#define VIA686A_REG_TEMP_LOW23 0x49 // 2 = bits 5-4, 3 = bits 7-6 - -#define VIA686A_REG_ALARM1 0x41 -#define VIA686A_REG_ALARM2 0x42 -#define VIA686A_REG_FANDIV 0x47 -#define VIA686A_REG_CONFIG 0x40 -// The following register sets temp interrupt mode (bits 1-0 for temp1, -// 3-2 for temp2, 5-4 for temp3). Modes are: -// 00 interrupt stays as long as value is out-of-range -// 01 interrupt is cleared once register is read (default) -// 10 comparator mode- like 00, but ignores hysteresis -// 11 same as 00 -#define VIA686A_REG_TEMP_MODE 0x4b -// We'll just assume that you want to set all 3 simultaneously: -#define VIA686A_TEMP_MODE_MASK 0x3F -#define VIA686A_TEMP_MODE_CONTINUOUS (0x00) - -/* Conversions. Limit checking is only done on the TO_REG - variants. */ - -/********* VOLTAGE CONVERSIONS (Bob Dougherty) ********/ -// From HWMon.cpp (Copyright 1998-2000 Jonathan Teh Soon Yew): -// voltagefactor[0]=1.25/2628; (2628/1.25=2102.4) // Vccp -// voltagefactor[1]=1.25/2628; (2628/1.25=2102.4) // +2.5V -// voltagefactor[2]=1.67/2628; (2628/1.67=1573.7) // +3.3V -// voltagefactor[3]=2.6/2628; (2628/2.60=1010.8) // +5V -// voltagefactor[4]=6.3/2628; (2628/6.30=417.14) // +12V -// in[i]=(data[i+2]*25.0+133)*voltagefactor[i]; -// That is: -// volts = (25*regVal+133)*factor -// regVal = (volts/factor-133)/25 -// (These conversions were contributed by Jonathan Teh Soon Yew -// ) -static inline u8 IN_TO_REG(long val, int inNum) -{ - /* To avoid floating point, we multiply constants by 10 (100 for +12V). - Rounding is done (120500 is actually 133000 - 12500). - Remember that val is expressed in 0.01V/bit, which is why we divide - by an additional 1000 (10000 for +12V): 100 for val and 10 (100) - for the constants. */ - if (inNum <= 1) - return (u8) - SENSORS_LIMIT((val * 21024 - 120500) / 25000, 0, 255); - else if (inNum == 2) - return (u8) - SENSORS_LIMIT((val * 15737 - 120500) / 25000, 0, 255); - else if (inNum == 3) - return (u8) - SENSORS_LIMIT((val * 10108 - 120500) / 25000, 0, 255); - else - return (u8) - SENSORS_LIMIT((val * 41714 - 1205000) / 250000, 0, 255); -} - -static inline long IN_FROM_REG(u8 val, int inNum) -{ - /* To avoid floating point, we multiply constants by 10 (100 for +12V). - We also multiply them by 100 because we want 0.01V/bit for the - output value. Rounding is done. */ - if (inNum <= 1) - return (long) ((25000 * val + 133000 + 21024 / 2) / 21024); - else if (inNum == 2) - return (long) ((25000 * val + 133000 + 15737 / 2) / 15737); - else if (inNum == 3) - return (long) ((25000 * val + 133000 + 10108 / 2) / 10108); - else - return (long) ((250000 * val + 1330000 + 41714 / 2) / 41714); -} - -/********* FAN RPM CONVERSIONS ********/ -// Higher register values = slower fans (the fan's strobe gates a counter). -// But this chip saturates back at 0, not at 255 like all the other chips. -// So, 0 means 0 RPM -static inline u8 FAN_TO_REG(long rpm, int div) -{ - if (rpm == 0) - return 0; - rpm = SENSORS_LIMIT(rpm, 1, 1000000); - return SENSORS_LIMIT((1350000 + rpm * div / 2) / (rpm * div), 1, 255); -} - -#define FAN_FROM_REG(val,div) ((val)==0?0:(val)==255?0:1350000/((val)*(div))) - -/******** TEMP CONVERSIONS (Bob Dougherty) *********/ -// linear fits from HWMon.cpp (Copyright 1998-2000 Jonathan Teh Soon Yew) -// if(temp<169) -// return double(temp)*0.427-32.08; -// else if(temp>=169 && temp<=202) -// return double(temp)*0.582-58.16; -// else -// return double(temp)*0.924-127.33; -// -// A fifth-order polynomial fits the unofficial data (provided by Alex van -// Kaam ) a bit better. It also give more reasonable -// numbers on my machine (ie. they agree with what my BIOS tells me). -// Here's the fifth-order fit to the 8-bit data: -// temp = 1.625093e-10*val^5 - 1.001632e-07*val^4 + 2.457653e-05*val^3 - -// 2.967619e-03*val^2 + 2.175144e-01*val - 7.090067e+0. -// -// (2000-10-25- RFD: thanks to Uwe Andersen for -// finding my typos in this formula!) -// -// Alas, none of the elegant function-fit solutions will work because we -// aren't allowed to use floating point in the kernel and doing it with -// integers doesn't provide enough precision. So we'll do boring old -// look-up table stuff. The unofficial data (see below) have effectively -// 7-bit resolution (they are rounded to the nearest degree). I'm assuming -// that the transfer function of the device is monotonic and smooth, so a -// smooth function fit to the data will allow us to get better precision. -// I used the 5th-order poly fit described above and solved for -// VIA register values 0-255. I *10 before rounding, so we get tenth-degree -// precision. (I could have done all 1024 values for our 10-bit readings, -// but the function is very linear in the useful range (0-80 deg C), so -// we'll just use linear interpolation for 10-bit readings.) So, tempLUT -// is the temp at via register values 0-255: -static const s16 tempLUT[] = - { -709, -688, -667, -646, -627, -607, -589, -570, -553, -536, -519, - -503, -487, -471, -456, -442, -428, -414, -400, -387, -375, - -362, -350, -339, -327, -316, -305, -295, -285, -275, -265, - -255, -246, -237, -229, -220, -212, -204, -196, -188, -180, - -173, -166, -159, -152, -145, -139, -132, -126, -120, -114, - -108, -102, -96, -91, -85, -80, -74, -69, -64, -59, -54, -49, - -44, -39, -34, -29, -25, -20, -15, -11, -6, -2, 3, 7, 12, 16, - 20, 25, 29, 33, 37, 42, 46, 50, 54, 59, 63, 67, 71, 75, 79, 84, - 88, 92, 96, 100, 104, 109, 113, 117, 121, 125, 130, 134, 138, - 142, 146, 151, 155, 159, 163, 168, 172, 176, 181, 185, 189, - 193, 198, 202, 206, 211, 215, 219, 224, 228, 232, 237, 241, - 245, 250, 254, 259, 263, 267, 272, 276, 281, 285, 290, 294, - 299, 303, 307, 312, 316, 321, 325, 330, 334, 339, 344, 348, - 353, 357, 362, 366, 371, 376, 380, 385, 390, 395, 399, 404, - 409, 414, 419, 423, 428, 433, 438, 443, 449, 454, 459, 464, - 469, 475, 480, 486, 491, 497, 502, 508, 514, 520, 526, 532, - 538, 544, 551, 557, 564, 571, 578, 584, 592, 599, 606, 614, - 621, 629, 637, 645, 654, 662, 671, 680, 689, 698, 708, 718, - 728, 738, 749, 759, 770, 782, 793, 805, 818, 830, 843, 856, - 870, 883, 898, 912, 927, 943, 958, 975, 991, 1008, 1026, 1044, - 1062, 1081, 1101, 1121, 1141, 1162, 1184, 1206, 1229, 1252, - 1276, 1301, 1326, 1352, 1378, 1406, 1434, 1462 -}; - -/* the original LUT values from Alex van Kaam - (for via register values 12-240): -{-50,-49,-47,-45,-43,-41,-39,-38,-37,-35,-34,-33,-32,-31, --30,-29,-28,-27,-26,-25,-24,-24,-23,-22,-21,-20,-20,-19,-18,-17,-17,-16,-15, --15,-14,-14,-13,-12,-12,-11,-11,-10,-9,-9,-8,-8,-7,-7,-6,-6,-5,-5,-4,-4,-3, --3,-2,-2,-1,-1,0,0,1,1,1,3,3,3,4,4,4,5,5,5,6,6,7,7,8,8,9,9,9,10,10,11,11,12, -12,12,13,13,13,14,14,15,15,16,16,16,17,17,18,18,19,19,20,20,21,21,21,22,22, -22,23,23,24,24,25,25,26,26,26,27,27,27,28,28,29,29,30,30,30,31,31,32,32,33, -33,34,34,35,35,35,36,36,37,37,38,38,39,39,40,40,41,41,42,42,43,43,44,44,45, -45,46,46,47,48,48,49,49,50,51,51,52,52,53,53,54,55,55,56,57,57,58,59,59,60, -61,62,62,63,64,65,66,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,83,84, -85,86,88,89,91,92,94,96,97,99,101,103,105,107,109,110}; -*/ - -// Here's the reverse LUT. I got it by doing a 6-th order poly fit (needed -// an extra term for a good fit to these inverse data!) and then -// solving for each temp value from -50 to 110 (the useable range for -// this chip). Here's the fit: -// viaRegVal = -1.160370e-10*val^6 +3.193693e-08*val^5 - 1.464447e-06*val^4 -// - 2.525453e-04*val^3 + 1.424593e-02*val^2 + 2.148941e+00*val +7.275808e+01) -// Note that n=161: -static const u8 viaLUT[] = - { 12, 12, 13, 14, 14, 15, 16, 16, 17, 18, 18, 19, 20, 20, 21, 22, 23, - 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 35, 36, 37, 39, 40, - 41, 43, 45, 46, 48, 49, 51, 53, 55, 57, 59, 60, 62, 64, 66, - 69, 71, 73, 75, 77, 79, 82, 84, 86, 88, 91, 93, 95, 98, 100, - 103, 105, 107, 110, 112, 115, 117, 119, 122, 124, 126, 129, - 131, 134, 136, 138, 140, 143, 145, 147, 150, 152, 154, 156, - 158, 160, 162, 164, 166, 168, 170, 172, 174, 176, 178, 180, - 182, 183, 185, 187, 188, 190, 192, 193, 195, 196, 198, 199, - 200, 202, 203, 205, 206, 207, 208, 209, 210, 211, 212, 213, - 214, 215, 216, 217, 218, 219, 220, 221, 222, 222, 223, 224, - 225, 226, 226, 227, 228, 228, 229, 230, 230, 231, 232, 232, - 233, 233, 234, 235, 235, 236, 236, 237, 237, 238, 238, 239, - 239, 240 -}; - -/* Converting temps to (8-bit) hyst and over registers - No interpolation here. - The +50 is because the temps start at -50 */ -static inline u8 TEMP_TO_REG(long val) -{ - return viaLUT[val <= -500 ? 0 : val >= 1100 ? 160 : - (val < 0 ? val - 5 : val + 5) / 10 + 50]; -} - -/* for 8-bit temperature hyst and over registers */ -#define TEMP_FROM_REG(val) (tempLUT[(val)]) - -/* for 10-bit temperature readings */ -// You might _think_ this is too long to inline, but's it's really only -// called once... -static inline long TEMP_FROM_REG10(u16 val) -{ - // the temp values are already *10, so we don't need to do that. - long temp; - u16 eightBits = val >> 2; - u16 twoBits = val & 3; - - /* no interpolation for these */ - if (twoBits == 0 || eightBits == 255) - return (long) tempLUT[eightBits]; - - /* do some linear interpolation */ - temp = (4 - twoBits) * tempLUT[eightBits] - + twoBits * tempLUT[eightBits + 1]; - /* achieve rounding */ - return (temp < 0 ? temp - 2 : temp + 2) / 4; -} - -#define ALARMS_FROM_REG(val) (val) - -#define DIV_FROM_REG(val) (1 << (val)) -#define DIV_TO_REG(val) ((val)==8?3:(val)==4?2:(val)==1?0:1) - -/* For the VIA686A, we need to keep some data in memory. - The structure is dynamically allocated, at the same time when a new - via686a client is allocated. */ -struct via686a_data { - struct i2c_client client; - struct semaphore lock; - int sysctl_id; - - struct semaphore update_lock; - char valid; /* !=0 if following fields are valid */ - unsigned long last_updated; /* In jiffies */ - - u8 in[5]; /* Register value */ - u8 in_max[5]; /* Register value */ - u8 in_min[5]; /* Register value */ - u8 fan[2]; /* Register value */ - u8 fan_min[2]; /* Register value */ - u16 temp[3]; /* Register value 10 bit */ - u8 temp_over[3]; /* Register value */ - u8 temp_hyst[3]; /* Register value */ - u8 fan_div[2]; /* Register encoding, shifted right */ - u16 alarms; /* Register encoding, combined */ -}; - -static struct pci_dev *s_bridge; /* pointer to the (only) via686a */ - -static int via686a_attach_adapter(struct i2c_adapter *adapter); -static int via686a_detect(struct i2c_adapter *adapter, int address, - unsigned short flags, int kind); -static int via686a_detach_client(struct i2c_client *client); - -static int via686a_read_value(struct i2c_client *client, u8 register); -static void via686a_write_value(struct i2c_client *client, u8 register, - u8 value); -static void via686a_update_client(struct i2c_client *client); -static void via686a_init_client(struct i2c_client *client); - - -static void via686a_in(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void via686a_fan(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void via686a_temp(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void via686a_alarms(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void via686a_fan_div(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); - -/* The driver. I choose to use type i2c_driver, as at is identical to both - smbus_driver and isa_driver, and clients could be of either kind */ -static struct i2c_driver via686a_driver = { - .name = "VIA 686A", - .id = I2C_DRIVERID_VIA686A, - .flags = I2C_DF_NOTIFY, - .attach_adapter = via686a_attach_adapter, - .detach_client = via686a_detach_client, -}; - - - -/* The /proc/sys entries */ - -/* -- SENSORS SYSCTL START -- */ -#define VIA686A_SYSCTL_IN0 1000 -#define VIA686A_SYSCTL_IN1 1001 -#define VIA686A_SYSCTL_IN2 1002 -#define VIA686A_SYSCTL_IN3 1003 -#define VIA686A_SYSCTL_IN4 1004 -#define VIA686A_SYSCTL_FAN1 1101 -#define VIA686A_SYSCTL_FAN2 1102 -#define VIA686A_SYSCTL_TEMP 1200 -#define VIA686A_SYSCTL_TEMP2 1201 -#define VIA686A_SYSCTL_TEMP3 1202 -#define VIA686A_SYSCTL_FAN_DIV 2000 -#define VIA686A_SYSCTL_ALARMS 2001 - -#define VIA686A_ALARM_IN0 0x01 -#define VIA686A_ALARM_IN1 0x02 -#define VIA686A_ALARM_IN2 0x04 -#define VIA686A_ALARM_IN3 0x08 -#define VIA686A_ALARM_TEMP 0x10 -#define VIA686A_ALARM_FAN1 0x40 -#define VIA686A_ALARM_FAN2 0x80 -#define VIA686A_ALARM_IN4 0x100 -#define VIA686A_ALARM_TEMP2 0x800 -#define VIA686A_ALARM_CHAS 0x1000 -#define VIA686A_ALARM_TEMP3 0x8000 - -/* -- SENSORS SYSCTL END -- */ - -/* These files are created for each detected VIA686A. This is just a template; - though at first sight, you might think we could use a statically - allocated list, we need some way to get back to the parent - which - is done through one of the 'extra' fields which are initialized - when a new copy is allocated. */ -static ctl_table via686a_dir_table_template[] = { - {VIA686A_SYSCTL_IN0, "in0", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &via686a_in}, - {VIA686A_SYSCTL_IN1, "in1", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &via686a_in}, - {VIA686A_SYSCTL_IN2, "in2", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &via686a_in}, - {VIA686A_SYSCTL_IN3, "in3", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &via686a_in}, - {VIA686A_SYSCTL_IN4, "in4", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &via686a_in}, - {VIA686A_SYSCTL_FAN1, "fan1", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &via686a_fan}, - {VIA686A_SYSCTL_FAN2, "fan2", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &via686a_fan}, - {VIA686A_SYSCTL_TEMP, "temp1", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &via686a_temp}, - {VIA686A_SYSCTL_TEMP2, "temp2", NULL, 0, 0644, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &via686a_temp}, - {VIA686A_SYSCTL_TEMP3, "temp3", NULL, 0, 0644, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &via686a_temp}, - {VIA686A_SYSCTL_FAN_DIV, "fan_div", NULL, 0, 0644, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &via686a_fan_div}, - {VIA686A_SYSCTL_ALARMS, "alarms", NULL, 0, 0444, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &via686a_alarms}, - {0} -}; - -static inline int via686a_read_value(struct i2c_client *client, u8 reg) -{ - return (inb_p(client->addr + reg)); -} - -static inline void via686a_write_value(struct i2c_client *client, u8 reg, - u8 value) -{ - outb_p(value, client->addr + reg); -} - -/* This is called when the module is loaded */ -static int via686a_attach_adapter(struct i2c_adapter *adapter) -{ - return i2c_detect(adapter, &addr_data, via686a_detect); -} - -int via686a_detect(struct i2c_adapter *adapter, int address, - unsigned short flags, int kind) -{ - int i; - struct i2c_client *new_client; - struct via686a_data *data; - int err = 0; - const char *type_name = "via686a"; - u16 val; - - /* Make sure we are probing the ISA bus!! */ - if (!i2c_is_isa_adapter(adapter)) { - printk - ("via686a.o: via686a_detect called for an I2C bus adapter?!?\n"); - return 0; - } - - /* 8231 requires multiple of 256, we enforce that on 686 as well */ - if(force_addr) - address = force_addr & 0xFF00; - if (check_region(address, VIA686A_EXTENT)) { - printk("via686a.o: region 0x%x already in use!\n", - address); - return -ENODEV; - } - - if(force_addr) { - printk("via686a.o: forcing ISA address 0x%04X\n", address); - if (PCIBIOS_SUCCESSFUL != - pci_write_config_word(s_bridge, VIA686A_BASE_REG, address)) - return -ENODEV; - } - if (PCIBIOS_SUCCESSFUL != - pci_read_config_word(s_bridge, VIA686A_ENABLE_REG, &val)) - return -ENODEV; - if (!(val & 0x0001)) { - printk("via686a.o: enabling sensors\n"); - if (PCIBIOS_SUCCESSFUL != - pci_write_config_word(s_bridge, VIA686A_ENABLE_REG, - val | 0x0001)) - return -ENODEV; - } - - if (!(data = kmalloc(sizeof(struct via686a_data), GFP_KERNEL))) { - err = -ENOMEM; - goto ERROR0; - } - - new_client = &data->client; - new_client->addr = address; - init_MUTEX(&data->lock); - new_client->data = data; - new_client->adapter = adapter; - new_client->driver = &via686a_driver; - new_client->flags = 0; - - /* Reserve the ISA region */ - request_region(address, VIA686A_EXTENT, "via686a-sensors"); - - /* Fill in the remaining client fields and put into the global list */ - strcpy(new_client->name, "Via 686A Integrated Sensors"); - data->valid = 0; - init_MUTEX(&data->update_lock); - - /* Tell the I2C layer a new client has arrived */ - if ((err = i2c_attach_client(new_client))) - goto ERROR3; - - /* Register a new directory entry with module sensors */ - if ((i = i2c_register_entry((struct i2c_client *) new_client, - type_name, - via686a_dir_table_template, - THIS_MODULE)) < 0) { - err = i; - goto ERROR4; - } - data->sysctl_id = i; - - /* Initialize the VIA686A chip */ - via686a_init_client(new_client); - return 0; - - ERROR4: - i2c_detach_client(new_client); - ERROR3: - release_region(address, VIA686A_EXTENT); - kfree(data); - ERROR0: - return err; -} - -static int via686a_detach_client(struct i2c_client *client) -{ - int err; - - i2c_deregister_entry(((struct via686a_data *) - (client->data))->sysctl_id); - - if ((err = i2c_detach_client(client))) { - printk - ("via686a.o: Client deregistration failed, client not detached.\n"); - return err; - } - - release_region(client->addr, VIA686A_EXTENT); - kfree(client->data); - - return 0; -} - -/* Called when we have found a new VIA686A. */ -static void via686a_init_client(struct i2c_client *client) -{ - u8 reg; - - /* Start monitoring */ - reg = via686a_read_value(client, VIA686A_REG_CONFIG); - via686a_write_value(client, VIA686A_REG_CONFIG, (reg|0x01)&0x7F); - - /* Configure temp interrupt mode for continuous-interrupt operation */ - reg = via686a_read_value(client, VIA686A_REG_TEMP_MODE); - via686a_write_value(client, VIA686A_REG_TEMP_MODE, - (reg & ~VIA686A_TEMP_MODE_MASK) - | VIA686A_TEMP_MODE_CONTINUOUS); -} - -static void via686a_update_client(struct i2c_client *client) -{ - struct via686a_data *data = client->data; - int i; - - down(&data->update_lock); - - if (time_after(jiffies - data->last_updated, HZ + HZ / 2) || - time_before(jiffies, data->last_updated) || !data->valid) { - - for (i = 0; i <= 4; i++) { - data->in[i] = - via686a_read_value(client, VIA686A_REG_IN(i)); - data->in_min[i] = via686a_read_value(client, - VIA686A_REG_IN_MIN - (i)); - data->in_max[i] = - via686a_read_value(client, VIA686A_REG_IN_MAX(i)); - } - for (i = 1; i <= 2; i++) { - data->fan[i - 1] = - via686a_read_value(client, VIA686A_REG_FAN(i)); - data->fan_min[i - 1] = via686a_read_value(client, - VIA686A_REG_FAN_MIN(i)); - } - for (i = 1; i <= 3; i++) { - data->temp[i - 1] = via686a_read_value(client, - VIA686A_REG_TEMP(i)) << 2; - data->temp_over[i - 1] = - via686a_read_value(client, - VIA686A_REG_TEMP_OVER(i)); - data->temp_hyst[i - 1] = - via686a_read_value(client, - VIA686A_REG_TEMP_HYST(i)); - } - /* add in lower 2 bits - temp1 uses bits 7-6 of VIA686A_REG_TEMP_LOW1 - temp2 uses bits 5-4 of VIA686A_REG_TEMP_LOW23 - temp3 uses bits 7-6 of VIA686A_REG_TEMP_LOW23 - */ - data->temp[0] |= (via686a_read_value(client, - VIA686A_REG_TEMP_LOW1) - & 0xc0) >> 6; - data->temp[1] |= - (via686a_read_value(client, VIA686A_REG_TEMP_LOW23) & - 0x30) >> 4; - data->temp[2] |= - (via686a_read_value(client, VIA686A_REG_TEMP_LOW23) & - 0xc0) >> 6; - - i = via686a_read_value(client, VIA686A_REG_FANDIV); - data->fan_div[0] = (i >> 4) & 0x03; - data->fan_div[1] = i >> 6; - data->alarms = - via686a_read_value(client, - VIA686A_REG_ALARM1) | - (via686a_read_value(client, VIA686A_REG_ALARM2) << 8); - data->last_updated = jiffies; - data->valid = 1; - } - - up(&data->update_lock); -} - - -/* The next few functions are the call-back functions of the /proc/sys and - sysctl files. Which function is used is defined in the ctl_table in - the extra1 field. - Each function must return the magnitude (power of 10 to divide the date - with) if it is called with operation==SENSORS_PROC_REAL_INFO. It must - put a maximum of *nrels elements in results reflecting the data of this - file, and set *nrels to the number it actually put in it, if operation== - SENSORS_PROC_REAL_READ. Finally, it must get upto *nrels elements from - results and write them to the chip, if operations==SENSORS_PROC_REAL_WRITE. - Note that on SENSORS_PROC_REAL_READ, I do not check whether results is - large enough (by checking the incoming value of *nrels). This is not very - good practice, but as long as you put less than about 5 values in results, - you can assume it is large enough. */ -static void via686a_in(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct via686a_data *data = client->data; - int nr = ctl_name - VIA686A_SYSCTL_IN0; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 2; - else if (operation == SENSORS_PROC_REAL_READ) { - via686a_update_client(client); - results[0] = IN_FROM_REG(data->in_min[nr], nr); - results[1] = IN_FROM_REG(data->in_max[nr], nr); - results[2] = IN_FROM_REG(data->in[nr], nr); - *nrels_mag = 3; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag >= 1) { - data->in_min[nr] = IN_TO_REG(results[0], nr); - via686a_write_value(client, VIA686A_REG_IN_MIN(nr), - data->in_min[nr]); - } - if (*nrels_mag >= 2) { - data->in_max[nr] = IN_TO_REG(results[1], nr); - via686a_write_value(client, VIA686A_REG_IN_MAX(nr), - data->in_max[nr]); - } - } -} - -void via686a_fan(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct via686a_data *data = client->data; - int nr = ctl_name - VIA686A_SYSCTL_FAN1 + 1; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - via686a_update_client(client); - results[0] = FAN_FROM_REG(data->fan_min[nr - 1], - DIV_FROM_REG(data->fan_div - [nr - 1])); - results[1] = FAN_FROM_REG(data->fan[nr - 1], - DIV_FROM_REG(data->fan_div[nr - 1])); - *nrels_mag = 2; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag >= 1) { - data->fan_min[nr - 1] = FAN_TO_REG(results[0], - DIV_FROM_REG(data-> - fan_div[nr -1])); - via686a_write_value(client, - VIA686A_REG_FAN_MIN(nr), - data->fan_min[nr - 1]); - } - } -} - -void via686a_temp(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct via686a_data *data = client->data; - int nr = ctl_name - VIA686A_SYSCTL_TEMP; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 1; - else if (operation == SENSORS_PROC_REAL_READ) { - via686a_update_client(client); - results[0] = TEMP_FROM_REG(data->temp_over[nr]); - results[1] = TEMP_FROM_REG(data->temp_hyst[nr]); - results[2] = TEMP_FROM_REG10(data->temp[nr]); - *nrels_mag = 3; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag >= 1) { - data->temp_over[nr] = TEMP_TO_REG(results[0]); - via686a_write_value(client, - VIA686A_REG_TEMP_OVER(nr + 1), - data->temp_over[nr]); - } - if (*nrels_mag >= 2) { - data->temp_hyst[nr] = TEMP_TO_REG(results[1]); - via686a_write_value(client, - VIA686A_REG_TEMP_HYST(nr + 1), - data->temp_hyst[nr]); - } - } -} - -void via686a_alarms(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct via686a_data *data = client->data; - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - via686a_update_client(client); - results[0] = ALARMS_FROM_REG(data->alarms); - *nrels_mag = 1; - } -} - -void via686a_fan_div(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results) -{ - struct via686a_data *data = client->data; - int old; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - via686a_update_client(client); - results[0] = DIV_FROM_REG(data->fan_div[0]); - results[1] = DIV_FROM_REG(data->fan_div[1]); - *nrels_mag = 2; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - old = via686a_read_value(client, VIA686A_REG_FANDIV); - if (*nrels_mag >= 2) { - data->fan_div[1] = DIV_TO_REG(results[1]); - old = (old & 0x3f) | (data->fan_div[1] << 6); - } - if (*nrels_mag >= 1) { - data->fan_div[0] = DIV_TO_REG(results[0]); - old = (old & 0xcf) | (data->fan_div[0] << 4); - via686a_write_value(client, VIA686A_REG_FANDIV, - old); - } - } -} - - -static struct pci_device_id via686a_pci_ids[] __devinitdata = { - {PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C686_4, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, - { 0, } -}; - -static int __devinit via686a_pci_probe(struct pci_dev *dev, - const struct pci_device_id *id) -{ - u16 val; - int addr = 0; - - if (PCIBIOS_SUCCESSFUL != - pci_read_config_word(dev, VIA686A_BASE_REG, &val)) - return -ENODEV; - - addr = val & ~(VIA686A_EXTENT - 1); - if (addr == 0 && force_addr == 0) { - printk("via686a.o: base address not set - upgrade BIOS or use force_addr=0xaddr\n"); - return -ENODEV; - } - if (force_addr) - addr = force_addr; /* so detect will get called */ - - normal_isa[0] = addr; - s_bridge = dev; - return i2c_add_driver(&via686a_driver); -} - -static void __devexit via686a_pci_remove(struct pci_dev *dev) -{ - i2c_del_driver(&via686a_driver); -} - -static struct pci_driver via686a_pci_driver = { - .name = "via686a", - .id_table = via686a_pci_ids, - .probe = via686a_pci_probe, - .remove = __devexit_p(via686a_pci_remove), -}; - -static int __init sm_via686a_init(void) -{ - printk("via686a.o version %s (%s)\n", LM_VERSION, LM_DATE); - return pci_module_init(&via686a_pci_driver); -} - -static void __exit sm_via686a_exit(void) -{ - pci_unregister_driver(&via686a_pci_driver); -} - -MODULE_AUTHOR("Kyösti Mälkki , " - "Mark Studebaker " - "and Bob Dougherty "); -MODULE_DESCRIPTION("VIA 686A Sensor device"); -MODULE_LICENSE("GPL"); - -module_init(sm_via686a_init); -module_exit(sm_via686a_exit); diff --git a/kernel/chips/vt1211.c b/kernel/chips/vt1211.c deleted file mode 100644 index 37346f1c..00000000 --- a/kernel/chips/vt1211.c +++ /dev/null @@ -1,820 +0,0 @@ -/* - vt1211.c - Part of lm_sensors, Linux kernel modules - for hardware monitoring - - Copyright (c) 2002 Mark D. Studebaker - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -/* Supports VIA VT1211 Super I/O sensors via ISA (LPC) accesses only. */ - -#include -#include -#include -#include -#include -#include -#include -#include "version.h" -#include "sensors_vid.h" - -static int force_addr = 0; -MODULE_PARM(force_addr, "i"); -MODULE_PARM_DESC(force_addr, - "Initialize the base address of the sensors"); - -static unsigned short normal_i2c[] = { SENSORS_I2C_END }; -static unsigned short normal_i2c_range[] = { SENSORS_I2C_END }; -static unsigned int normal_isa[] = { 0x0000, SENSORS_ISA_END }; -static unsigned int normal_isa_range[] = { SENSORS_ISA_END }; - -SENSORS_INSMOD_1(vt1211); - -/* modified from kernel/include/traps.c */ -#define REG 0x2e /* The register to read/write */ -#define DEV 0x07 /* Register: Logical device select */ -#define VAL 0x2f /* The value to read/write */ -#define PME 0x0b /* The device with the hardware monitor */ -#define DEVID 0x20 /* Register: Device ID */ - -static inline void -superio_outb(int reg, int val) -{ - outb(reg, REG); - outb(val, VAL); -} - -static inline int -superio_inb(int reg) -{ - outb(reg, REG); - return inb(VAL); -} - -static inline void -superio_select(void) -{ - outb(DEV, REG); - outb(PME, VAL); -} - -static inline void -superio_enter(void) -{ - outb(0x87, REG); - outb(0x87, REG); -} - -static inline void -superio_exit(void) -{ - outb(0xAA, REG); -} - -#define VT1211_DEVID 0x3c -#define VT1211_ACT_REG 0x30 -#define VT1211_BASE_REG 0x60 - -#define VT1211_EXTENT 0x80 - -/* pwm numbered 1-2 */ -#define VT1211_REG_PWM(nr) (0x5f + (nr)) -#define VT1211_REG_PWM_CTL 0x51 - -/* The VT1211 registers */ -/* We define the sensors as follows. Somewhat convoluted to minimize - changes from via686a. - Sensor Voltage Mode Temp Mode - -------- ------------ --------- - Reading 1 temp1 Intel thermal diode - Reading 3 temp2 VT1211 internal thermal diode - UCH1/Reading2 in0 temp3 - UCH2 in1 temp4 - UCH3 in2 temp5 - UCH4 in3 temp6 - UCH5 in4 temp7 - 3.3V in5 -*/ - -/* ins numbered 0-5 */ -#define VT1211_REG_IN_MAX(nr) ((nr)==0 ? 0x3d : 0x29 + ((nr) * 2)) -#define VT1211_REG_IN_MIN(nr) ((nr)==0 ? 0x3e : 0x2a + ((nr) * 2)) -#define VT1211_REG_IN(nr) (0x21 + (nr)) - -/* fans numbered 1-2 */ -#define VT1211_REG_FAN_MIN(nr) (0x3a + (nr)) -#define VT1211_REG_FAN(nr) (0x28 + (nr)) - -static const u8 regtemp[] = { 0x1f, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25 }; -static const u8 regover[] = { 0x39, 0x1d, 0x3d, 0x2b, 0x2d, 0x2f, 0x31 }; -static const u8 reghyst[] = { 0x3a, 0x1e, 0x3e, 0x2c, 0x2e, 0x30, 0x32 }; - -/* temps numbered 1-7 */ -#define VT1211_REG_TEMP(nr) (regtemp[(nr) - 1]) -#define VT1211_REG_TEMP_OVER(nr) (regover[(nr) - 1]) -#define VT1211_REG_TEMP_HYST(nr) (reghyst[(nr) - 1]) -#define VT1211_REG_TEMP_LOW1 0x4b /* bits 7-6 */ -#define VT1211_REG_TEMP_LOW3 0x49 /* bits 5-4 */ -#define VT1211_REG_TEMP_LOW47 0x4d - -#define VT1211_REG_CONFIG 0x40 -#define VT1211_REG_ALARM1 0x41 -#define VT1211_REG_ALARM2 0x42 -#define VT1211_REG_VID 0x45 -#define VT1211_REG_FANDIV 0x47 -#define VT1211_REG_UCH_CONFIG 0x4a -#define VT1211_REG_TEMP1_CONFIG 0x4b -#define VT1211_REG_TEMP2_CONFIG 0x4c - -/* temps 1-7; voltages 0-5 */ -#define ISTEMP(i, ch_config) ((i) <= 2 ? 1 : \ - ((ch_config) >> ((i)-1)) & 1) -#define ISVOLT(i, ch_config) ((i) > 4 ? 1 : !(((ch_config) >> ((i)+2)) & 0x01)) - -#define DIV_FROM_REG(val) (1 << (val)) -#define DIV_TO_REG(val) ((val)==8?3:(val)==4?2:(val)==1?0:1) -#define PWM_FROM_REG(val) (val) -#define PWM_TO_REG(val) SENSORS_LIMIT((val), 0, 255) - -/* temp1 (i = 1) is an Intel thermal diode which is scaled in user space. - temp2 (i = 2) is the internal temp diode so it's scaled in the driver - according to some measurements taken on an EPIA M10000. - temp3-7 are thermistor based so the driver returns the voltage measured at - the pin (range 0V - 2.2V). */ -#define TEMP_FROM_REG(i, reg) ((i) == 1 ? (reg) * 10 : \ - (i) == 2 ? (reg) < 51 ? 0 : \ - ((reg) - 51) * 10 : \ - ((253 - (reg)) * 2200 + 105) / 210) -/* for 10-bit temp values */ -#define TEMP_FROM_REG10(i, reg) ((i) == 1 ? (reg) * 10 / 4 : \ - (i) == 2 ? (reg) < 204 ? 0 : \ - ((reg) - 204) * 10 / 4 : \ - ((1012 - (reg)) * 550 + 105) / 210) -#define TEMP_TO_REG(i, val) SENSORS_LIMIT( \ - ((i) == 1 ? ((val) + 5) / 10 : \ - (i) == 2 ? ((val) + 5) / 10 + 51 : \ - 253 - ((val) * 210 + 1100) / 2200), 0, 255) - -/* in5 (i = 5) is special. It's the internal 3.3V so it's scaled in the - driver according to the VT1211 BIOS porting guide */ -#define IN_FROM_REG(i, reg) ((reg) < 3 ? 0 : (i) == 5 ? \ - (((reg) - 3) * 15882 + 4790) / 9580 : \ - (((reg) - 3) * 10000 + 4790) / 9580) -#define IN_TO_REG(i, val) (SENSORS_LIMIT((i) == 5 ? \ - ((val) * 9580 + 7941) / 15882 + 3 : \ - ((val) * 9580 + 5000) / 10000 + 3, 0, 255)) - -/********* FAN RPM CONVERSIONS ********/ -/* But this chip saturates back at 0, not at 255 like all the other chips. - So, 0 means 0 RPM */ -static inline u8 FAN_TO_REG(long rpm, int div) -{ - if (rpm == 0) - return 0; - rpm = SENSORS_LIMIT(rpm, 1, 1000000); - return SENSORS_LIMIT((1310720 + rpm * div / 2) / (rpm * div), 1, 255); -} - -#define MIN_TO_REG(a,b) FAN_TO_REG(a,b) -#define FAN_FROM_REG(val,div) ((val)==0?0:(val)==255?0:1310720/((val)*(div))) - -struct vt1211_data { - struct i2c_client client; - struct semaphore lock; - int sysctl_id; - - struct semaphore update_lock; - char valid; /* !=0 if following fields are valid */ - unsigned long last_updated; /* In jiffies */ - - u8 in[6]; /* Register value */ - u8 in_max[6]; /* Register value */ - u8 in_min[6]; /* Register value */ - u16 temp[7]; /* Register value 10 bit */ - u8 temp_over[7]; /* Register value */ - u8 temp_hyst[7]; /* Register value */ - u8 fan[2]; /* Register value */ - u8 fan_min[2]; /* Register value */ - u8 fan_div[2]; /* Register encoding, shifted right */ - u16 alarms; /* Register encoding */ - u8 pwm[2]; /* Register value */ - u8 pwm_ctl; /* Register value */ - u8 vid; /* Register encoding */ - u8 vrm; - u8 uch_config; -}; - -static int vt1211_attach_adapter(struct i2c_adapter *adapter); -static int vt1211_detect(struct i2c_adapter *adapter, int address, - unsigned short flags, int kind); -static int vt1211_detach_client(struct i2c_client *client); - -static inline int vt_rdval(struct i2c_client *client, u8 register); -static inline void vt1211_write_value(struct i2c_client *client, u8 register, - u8 value); -static void vt1211_update_client(struct i2c_client *client); -static void vt1211_init_client(struct i2c_client *client); - - -static void vt1211_fan(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void vt1211_alarms(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void vt1211_fan_div(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void vt1211_in(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void vt1211_pwm(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void vt1211_vid(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void vt1211_vrm(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void vt1211_uch(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void vt1211_temp(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); - -static struct i2c_driver vt1211_driver = { - .name = "VT1211 sensors driver", - .id = I2C_DRIVERID_VT1211, - .flags = I2C_DF_NOTIFY, - .attach_adapter = vt1211_attach_adapter, - .detach_client = vt1211_detach_client, -}; - -/* -- SENSORS SYSCTL START -- */ -#define VT1211_SYSCTL_IN0 1000 -#define VT1211_SYSCTL_IN1 1001 -#define VT1211_SYSCTL_IN2 1002 -#define VT1211_SYSCTL_IN3 1003 -#define VT1211_SYSCTL_IN4 1004 -#define VT1211_SYSCTL_IN5 1005 -#define VT1211_SYSCTL_FAN1 1101 -#define VT1211_SYSCTL_FAN2 1102 -#define VT1211_SYSCTL_TEMP1 1200 -#define VT1211_SYSCTL_TEMP2 1201 -#define VT1211_SYSCTL_TEMP3 1202 -#define VT1211_SYSCTL_TEMP4 1203 -#define VT1211_SYSCTL_TEMP5 1204 -#define VT1211_SYSCTL_TEMP6 1205 -#define VT1211_SYSCTL_TEMP7 1206 -#define VT1211_SYSCTL_VID 1300 -#define VT1211_SYSCTL_PWM1 1401 -#define VT1211_SYSCTL_PWM2 1402 -#define VT1211_SYSCTL_VRM 1600 -#define VT1211_SYSCTL_UCH 1700 -#define VT1211_SYSCTL_FAN_DIV 2000 -#define VT1211_SYSCTL_ALARMS 2001 - -#define VT1211_ALARM_IN1 0x01 -#define VT1211_ALARM_IN2 0x02 -#define VT1211_ALARM_IN5 0x04 -#define VT1211_ALARM_IN3 0x08 -#define VT1211_ALARM_TEMP1 0x10 -#define VT1211_ALARM_FAN1 0x40 -#define VT1211_ALARM_FAN2 0x80 -#define VT1211_ALARM_IN4 0x100 -#define VT1211_ALARM_TEMP3 0x800 -#define VT1211_ALARM_CHAS 0x1000 -#define VT1211_ALARM_TEMP2 0x8000 -/* duplicates */ -#define VT1211_ALARM_IN0 VT1211_ALARM_TEMP3 -#define VT1211_ALARM_TEMP4 VT1211_ALARM_IN1 -#define VT1211_ALARM_TEMP5 VT1211_ALARM_IN2 -#define VT1211_ALARM_TEMP6 VT1211_ALARM_IN3 -#define VT1211_ALARM_TEMP7 VT1211_ALARM_IN4 - -/* -- SENSORS SYSCTL END -- */ - -static ctl_table vt1211_dir_table_template[] = { - {VT1211_SYSCTL_IN0, "in0", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &vt1211_in}, - {VT1211_SYSCTL_IN1, "in1", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &vt1211_in}, - {VT1211_SYSCTL_IN2, "in2", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &vt1211_in}, - {VT1211_SYSCTL_IN3, "in3", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &vt1211_in}, - {VT1211_SYSCTL_IN4, "in4", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &vt1211_in}, - {VT1211_SYSCTL_IN5, "in5", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &vt1211_in}, - {VT1211_SYSCTL_TEMP1, "temp1", NULL, 0, 0644, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &vt1211_temp}, - {VT1211_SYSCTL_TEMP2, "temp2", NULL, 0, 0644, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &vt1211_temp}, - {VT1211_SYSCTL_TEMP3, "temp3", NULL, 0, 0644, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &vt1211_temp}, - {VT1211_SYSCTL_TEMP4, "temp4", NULL, 0, 0644, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &vt1211_temp}, - {VT1211_SYSCTL_TEMP5, "temp5", NULL, 0, 0644, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &vt1211_temp}, - {VT1211_SYSCTL_TEMP6, "temp6", NULL, 0, 0644, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &vt1211_temp}, - {VT1211_SYSCTL_TEMP7, "temp7", NULL, 0, 0644, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &vt1211_temp}, - {VT1211_SYSCTL_FAN1, "fan1", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &vt1211_fan}, - {VT1211_SYSCTL_FAN2, "fan2", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &vt1211_fan}, - {VT1211_SYSCTL_FAN_DIV, "fan_div", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &vt1211_fan_div}, - {VT1211_SYSCTL_ALARMS, "alarms", NULL, 0, 0444, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &vt1211_alarms}, - {VT1211_SYSCTL_PWM1, "pwm1", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &vt1211_pwm}, - {VT1211_SYSCTL_PWM2, "pwm2", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &vt1211_pwm}, - {VT1211_SYSCTL_VID, "vid", NULL, 0, 0444, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &vt1211_vid}, - {VT1211_SYSCTL_VRM, "vrm", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &vt1211_vrm}, - {VT1211_SYSCTL_UCH, "uch_config", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &vt1211_uch}, - {0} -}; - -static int vt1211_attach_adapter(struct i2c_adapter *adapter) -{ - return i2c_detect(adapter, &addr_data, vt1211_detect); -} - -static int __init vt1211_find(int *address) -{ - u16 val; - - superio_enter(); - val= superio_inb(DEVID); - if(VT1211_DEVID != val) { - superio_exit(); - return -ENODEV; - } - - superio_select(); - val = (superio_inb(VT1211_BASE_REG) << 8) | - superio_inb(VT1211_BASE_REG + 1); - *address = val & ~(VT1211_EXTENT - 1); - if (*address == 0 && force_addr == 0) { - printk("vt1211.o: base address not set - use force_addr=0xaddr\n"); - superio_exit(); - return -ENODEV; - } - if (force_addr) - *address = force_addr; /* so detect will get called */ - - superio_exit(); - return 0; -} - -int vt1211_detect(struct i2c_adapter *adapter, int address, - unsigned short flags, int kind) -{ - int i; - struct i2c_client *new_client; - struct vt1211_data *data; - int err = 0; - u8 val; - const char *type_name = "vt1211"; - const char *client_name = "VT1211 chip"; - - if (!i2c_is_isa_adapter(adapter)) { - return 0; - } - - if(force_addr) - address = force_addr & ~(VT1211_EXTENT - 1); - if (check_region(address, VT1211_EXTENT)) { - printk("vt1211.o: region 0x%x already in use!\n", address); - return -ENODEV; - } - if(force_addr) { - printk("vt1211.o: forcing ISA address 0x%04X\n", address); - superio_enter(); - superio_select(); - superio_outb(VT1211_BASE_REG, address >> 8); - superio_outb(VT1211_BASE_REG+1, address & 0xff); - superio_exit(); - } - - superio_enter(); - superio_select(); - if((val = 0x01 & superio_inb(VT1211_ACT_REG)) == 0) - superio_outb(VT1211_ACT_REG, 1); - superio_exit(); - - if (!(data = kmalloc(sizeof(struct vt1211_data), GFP_KERNEL))) { - return -ENOMEM; - } - - new_client = &data->client; - new_client->addr = address; - init_MUTEX(&data->lock); - new_client->data = data; - new_client->adapter = adapter; - new_client->driver = &vt1211_driver; - new_client->flags = 0; - - request_region(address, VT1211_EXTENT, "vt1211-sensors"); - strcpy(new_client->name, client_name); - data->valid = 0; - init_MUTEX(&data->update_lock); - - if ((err = i2c_attach_client(new_client))) - goto ERROR3; - - if ((i = i2c_register_entry((struct i2c_client *) new_client, - type_name, - vt1211_dir_table_template, - THIS_MODULE)) < 0) { - err = i; - goto ERROR4; - } - data->sysctl_id = i; - - vt1211_init_client(new_client); - return 0; - - ERROR4: - i2c_detach_client(new_client); - ERROR3: - release_region(address, VT1211_EXTENT); - kfree(data); - return err; -} - -static int vt1211_detach_client(struct i2c_client *client) -{ - int err; - - i2c_deregister_entry(((struct vt1211_data *) (client->data))-> - sysctl_id); - - if ((err = i2c_detach_client(client))) { - printk - ("vt1211.o: Client deregistration failed, client not detached.\n"); - return err; - } - - release_region(client->addr, VT1211_EXTENT); - kfree(client->data); - - return 0; -} - -static inline int vt_rdval(struct i2c_client *client, u8 reg) -{ - return (inb_p(client->addr + reg)); -} - -static inline void vt1211_write_value(struct i2c_client *client, u8 reg, u8 value) -{ - outb_p(value, client->addr + reg); -} - -static void vt1211_init_client(struct i2c_client *client) -{ - struct vt1211_data *data = client->data; - - data->vrm = 91; - /* set "default" interrupt mode for alarms, which isn't the default */ - vt1211_write_value(client, VT1211_REG_TEMP1_CONFIG, 0); - vt1211_write_value(client, VT1211_REG_TEMP2_CONFIG, 0); -} - -static void vt1211_update_client(struct i2c_client *client) -{ - struct vt1211_data *data = client->data; - int i, j; - - down(&data->update_lock); - - if ((jiffies - data->last_updated > HZ + HZ / 2) || - (jiffies < data->last_updated) || !data->valid) { - data->uch_config = vt_rdval(client, VT1211_REG_UCH_CONFIG); - for (i = 0; i <= 5; i++) { - if(ISVOLT(i, data->uch_config)) { - data->in[i] = vt_rdval(client, VT1211_REG_IN(i)); - data->in_min[i] = vt_rdval(client, - VT1211_REG_IN_MIN(i)); - data->in_max[i] = vt_rdval(client, - VT1211_REG_IN_MAX(i)); - } else { - data->in[i] = 0; - data->in_min[i] = 0; - data->in_max[i] = 0; - } - } - for (i = 1; i <= 2; i++) { - data->fan[i - 1] = vt_rdval(client, VT1211_REG_FAN(i)); - data->fan_min[i - 1] = vt_rdval(client, - VT1211_REG_FAN_MIN(i)); - } - for (i = 1; i <= 7; i++) { - if(ISTEMP(i, data->uch_config)) { - data->temp[i - 1] = vt_rdval(client, - VT1211_REG_TEMP(i)) << 2; - switch(i) { - case 1: - j = (vt_rdval(client, - VT1211_REG_TEMP_LOW1) >> - 6) & 3; - break; - case 2: - j = 0; - break; - case 3: - j = (vt_rdval(client, - VT1211_REG_TEMP_LOW3) >> - 4) & 3; - break; - default: - j = (vt_rdval(client, - VT1211_REG_TEMP_LOW47) >> - ((i-4)*2)) & 0x03; - } - data->temp[i - 1] |= j; - data->temp_over[i - 1] = vt_rdval(client, - VT1211_REG_TEMP_OVER(i)); - data->temp_hyst[i - 1] = vt_rdval(client, - VT1211_REG_TEMP_HYST(i)); - } else { - data->temp[i - 1] = 0; - data->temp_over[i - 1] = 0; - data->temp_hyst[i - 1] = 0; - } - } - - for (i = 1; i <= 2; i++) { - data->fan[i - 1] = vt_rdval(client, VT1211_REG_FAN(i)); - data->fan_min[i - 1] = vt_rdval(client, - VT1211_REG_FAN_MIN(i)); - data->pwm[i - 1] = vt_rdval(client, VT1211_REG_PWM(i)); - } - - data->pwm_ctl = vt_rdval(client, VT1211_REG_PWM_CTL); - i = vt_rdval(client, VT1211_REG_FANDIV); - data->fan_div[0] = (i >> 4) & 0x03; - data->fan_div[1] = i >> 6; - data->alarms = vt_rdval(client, VT1211_REG_ALARM1) | - (vt_rdval(client, VT1211_REG_ALARM2) << 8); - data->vid= vt_rdval(client, VT1211_REG_VID) & 0x1f; - data->last_updated = jiffies; - data->valid = 1; - } - - up(&data->update_lock); -} - - -void vt1211_in(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct vt1211_data *data = client->data; - int nr = ctl_name - VT1211_SYSCTL_IN0; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 2; - else if (operation == SENSORS_PROC_REAL_READ) { - vt1211_update_client(client); - results[0] = IN_FROM_REG(nr, data->in_min[nr]); - results[1] = IN_FROM_REG(nr, data->in_max[nr]); - results[2] = IN_FROM_REG(nr, data->in[nr]); - *nrels_mag = 3; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag >= 1) { - data->in_min[nr] = IN_TO_REG(nr, results[0]); - vt1211_write_value(client, VT1211_REG_IN_MIN(nr), - data->in_min[nr]); - } - if (*nrels_mag >= 2) { - data->in_max[nr] = IN_TO_REG(nr, results[1]); - vt1211_write_value(client, VT1211_REG_IN_MAX(nr), - data->in_max[nr]); - } - } -} - -void vt1211_fan(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct vt1211_data *data = client->data; - int nr = ctl_name - VT1211_SYSCTL_FAN1 + 1; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - vt1211_update_client(client); - results[0] = FAN_FROM_REG(data->fan_min[nr - 1], - DIV_FROM_REG(data->fan_div - [nr - 1])); - results[1] = FAN_FROM_REG(data->fan[nr - 1], - DIV_FROM_REG(data->fan_div[nr - 1])); - *nrels_mag = 2; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag >= 1) { - data->fan_min[nr - 1] = MIN_TO_REG(results[0], - DIV_FROM_REG - (data-> - fan_div[nr-1])); - vt1211_write_value(client, VT1211_REG_FAN_MIN(nr), - data->fan_min[nr - 1]); - } - } -} - - -void vt1211_temp(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct vt1211_data *data = client->data; - int nr = ctl_name - VT1211_SYSCTL_TEMP1; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = nr < 2 ? 1 : 3; - else if (operation == SENSORS_PROC_REAL_READ) { - vt1211_update_client(client); - results[0] = TEMP_FROM_REG(nr + 1, data->temp_over[nr]); - results[1] = TEMP_FROM_REG(nr + 1, data->temp_hyst[nr]); - results[2] = TEMP_FROM_REG10(nr + 1, data->temp[nr]); - *nrels_mag = 3; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag >= 1) { - data->temp_over[nr] = TEMP_TO_REG(nr + 1, results[0]); - vt1211_write_value(client, - VT1211_REG_TEMP_OVER(nr + 1), - data->temp_over[nr]); - } - if (*nrels_mag >= 2) { - data->temp_hyst[nr] = TEMP_TO_REG(nr + 1, results[1]); - vt1211_write_value(client, - VT1211_REG_TEMP_HYST(nr + 1), - data->temp_hyst[nr]); - } - } -} - -void vt1211_alarms(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct vt1211_data *data = client->data; - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - vt1211_update_client(client); - results[0] = data->alarms; - *nrels_mag = 1; - } -} - -void vt1211_fan_div(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results) -{ - struct vt1211_data *data = client->data; - int old; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - vt1211_update_client(client); - results[0] = DIV_FROM_REG(data->fan_div[0]); - results[1] = DIV_FROM_REG(data->fan_div[1]); - *nrels_mag = 2; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - old = vt_rdval(client, VT1211_REG_FANDIV); - if (*nrels_mag >= 2) { - data->fan_div[1] = DIV_TO_REG(results[1]); - old = (old & 0x3f) | (data->fan_div[1] << 6); - } - if (*nrels_mag >= 1) { - data->fan_div[0] = DIV_TO_REG(results[0]); - old = (old & 0xcf) | (data->fan_div[0] << 4); - vt1211_write_value(client, VT1211_REG_FANDIV, old); - } - } -} - -void vt1211_pwm(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct vt1211_data *data = client->data; - int nr = 1 + ctl_name - VT1211_SYSCTL_PWM1; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - vt1211_update_client(client); - results[0] = PWM_FROM_REG(data->pwm[nr - 1]); - results[1] = (data->pwm_ctl >> (3 + (4 * (nr - 1)))) & 1; - *nrels_mag = 2; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag >= 1) { - data->pwm[nr - 1] = PWM_TO_REG(results[0]); - if (*nrels_mag >= 2) { - if(results[1]) { - data->pwm_ctl |= - (0x08 << (4 * (nr - 1))); - vt1211_write_value(client, - VT1211_REG_PWM_CTL, - data->pwm_ctl); - } else { - data->pwm_ctl &= - ~ (0x08 << (4 * (nr - 1))); - vt1211_write_value(client, - VT1211_REG_PWM_CTL, - data->pwm_ctl); - } - } - vt1211_write_value(client, VT1211_REG_PWM(nr), - data->pwm[nr - 1]); - } - } -} - -void vt1211_vid(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct vt1211_data *data = client->data; - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 3; - else if (operation == SENSORS_PROC_REAL_READ) { - vt1211_update_client(client); - results[0] = vid_from_reg(data->vid, data->vrm); - *nrels_mag = 1; - } -} - -void vt1211_vrm(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct vt1211_data *data = client->data; - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 1; - else if (operation == SENSORS_PROC_REAL_READ) { - results[0] = data->vrm; - *nrels_mag = 1; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag >= 1) - data->vrm = results[0]; - } -} - -void vt1211_uch(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct vt1211_data *data = client->data; - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - results[0] = data->uch_config & 0x7c; - *nrels_mag = 1; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag >= 1) { - data->uch_config = (data->uch_config & 0x83)|(results[0] & 0x7c); - vt1211_write_value(client, VT1211_REG_UCH_CONFIG, - data->uch_config); - } - } -} - -static int __init sm_vt1211_init(void) -{ - int addr; - - printk("vt1211.o version %s (%s)\n", LM_VERSION, LM_DATE); - - if (vt1211_find(&addr)) { - printk("vt1211.o: VT1211 not detected, module not inserted.\n"); - return -ENODEV; - } - normal_isa[0] = addr; - - return i2c_add_driver(&vt1211_driver); -} - -static void __exit sm_vt1211_exit(void) -{ - i2c_del_driver(&vt1211_driver); -} - - - -MODULE_AUTHOR("Mark D. Studebaker "); -MODULE_DESCRIPTION("VT1211 sensors"); -MODULE_LICENSE("GPL"); - -module_init(sm_vt1211_init); -module_exit(sm_vt1211_exit); diff --git a/kernel/chips/vt8231.c b/kernel/chips/vt8231.c deleted file mode 100644 index 24ab2e49..00000000 --- a/kernel/chips/vt8231.c +++ /dev/null @@ -1,836 +0,0 @@ -/* - vt8231.c - Part of lm_sensors, Linux kernel modules - for hardware monitoring - - Copyright (c) 2002 Mark D. Studebaker - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -/* Supports VIA VT8231 South Bridge embedded sensors */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include "version.h" -#include "sensors_vid.h" - - -static int force_addr = 0; -MODULE_PARM(force_addr, "i"); -MODULE_PARM_DESC(force_addr, - "Initialize the base address of the sensors"); - -static unsigned short normal_i2c[] = { SENSORS_I2C_END }; -static unsigned short normal_i2c_range[] = { SENSORS_I2C_END }; -static unsigned int normal_isa[] = { 0x0000, SENSORS_ISA_END }; -static unsigned int normal_isa_range[] = { SENSORS_ISA_END }; - -SENSORS_INSMOD_1(vt8231); - -#define VIA686A_EXTENT 0x80 -#define VIA686A_BASE_REG 0x70 -#define VIA686A_ENABLE_REG 0x74 - -/* pwm numbered 1-2 */ -#define VT8231_REG_PWM(nr) (0x5f + (nr)) -#define VT8231_REG_PWM_CTL 0x51 - -/* The VT8231 registers */ -/* We define the sensors as follows. - Sensor Voltage Mode Temp Mode - -------- ------------ --------- - Reading 1 temp1 - UCH1 in0 temp2 - UCH2 in1 temp3 - UCH3 in2 temp4 - UCH4 in3 temp5 - UCH5 in4 temp6 - 3.3V in5 -*/ - -/* ins numbered 0-5 */ -#define VT8231_REG_IN_MAX(nr) ((nr)==0 ? 0x3d : 0x29 + ((nr) * 2)) -#define VT8231_REG_IN_MIN(nr) ((nr)==0 ? 0x3e : 0x2a + ((nr) * 2)) -#define VT8231_REG_IN(nr) (0x21 + (nr)) - -/* fans numbered 1-2 */ -#define VT8231_REG_FAN_MIN(nr) (0x3a + (nr)) -#define VT8231_REG_FAN(nr) (0x28 + (nr)) - -static const u8 regtemp[] = { 0x1f, 0x21, 0x22, 0x23, 0x24, 0x25 }; -static const u8 regover[] = { 0x39, 0x3d, 0x2b, 0x2d, 0x2f, 0x31 }; -static const u8 reghyst[] = { 0x3a, 0x3e, 0x2c, 0x2e, 0x30, 0x32 }; - -/* temps numbered 1-6 */ -#define VT8231_REG_TEMP(nr) (regtemp[(nr) - 1]) -#define VT8231_REG_TEMP_OVER(nr) (regover[(nr) - 1]) -#define VT8231_REG_TEMP_HYST(nr) (reghyst[(nr) - 1]) -#define VT8231_REG_TEMP_LOW12 0x49 -#define VT8231_REG_TEMP_LOW36 0x4d - -#define VT8231_REG_CONFIG 0x40 -#define VT8231_REG_ALARM1 0x41 -#define VT8231_REG_ALARM2 0x42 -#define VT8231_REG_VID 0x45 -#define VT8231_REG_FANDIV 0x47 -#define VT8231_REG_UCH_CONFIG 0x4a -#define VT8231_REG_TEMP1_CONFIG 0x4b -#define VT8231_REG_TEMP2_CONFIG 0x4c - -/* temps 1-6; voltages 0-5 */ -#define ISTEMP(i, ch_config) ((i) == 1 ? 1 : \ - ((ch_config) >> (i)) & 0x01) -#define ISVOLT(i, ch_config) ((i) == 5 ? 1 : \ - !(((ch_config) >> ((i)+2)) & 0x01)) - -#define DIV_FROM_REG(val) (1 << (val)) -#define DIV_TO_REG(val) ((val)==8?3:(val)==4?2:(val)==1?0:1) -#define PWM_FROM_REG(val) (val) -#define PWM_TO_REG(val) SENSORS_LIMIT((val), 0, 255) - -/* Used for temp1 (diode) */ -#define TEMP_FROM_REG(val) ((val)*10) -#define TEMP_FROM_REG10(val) (((val)*10)/4) -#define TEMP_TO_REG(val) (SENSORS_LIMIT(((val)<0?(((val)-5)/10):\ - ((val)+5)/10),0,255)) - -/* Used for temp2-temp6 (thermistor) */ -#define THERM_FROM_REG(reg) (((253 * 4 - (reg)) * 55 + 105) / 210) -#define THERM_TO_REG(val) (253 - ((val) * 210 + 110) / 220) - -/* Used for in0-in4 */ -#define IN_FROM_REG(val) ((((val) - 3) * 1000 + 479) / 958) -#define IN_TO_REG(val) SENSORS_LIMIT(((val) * 958 + 500) \ - / 1000 + 3, 0, 255) -/* Used for in5 (scaled internally) */ -#define IN5_FROM_REG(val) ((((val) - 3) * 54000 + 16286) / 32572) -#define IN5_TO_REG(val) SENSORS_LIMIT(((val) * 32572 + 27000) \ - / 54000 + 3, 0, 255) - - -/********* FAN RPM CONVERSIONS ********/ -/* But this chip saturates back at 0, not at 255 like all the other chips. - So, 0 means 0 RPM */ -static inline u8 FAN_TO_REG(long rpm, int div) -{ - if (rpm == 0) - return 0; - rpm = SENSORS_LIMIT(rpm, 1, 1000000); - return SENSORS_LIMIT((1310720 + rpm * div / 2) / (rpm * div), 1, 255); -} - -#define MIN_TO_REG(a,b) FAN_TO_REG(a,b) -#define FAN_FROM_REG(val,div) ((val)==0?0:(val)==255?0:1310720/((val)*(div))) - -struct vt8231_data { - struct i2c_client client; - struct semaphore lock; - int sysctl_id; - - struct semaphore update_lock; - char valid; /* !=0 if following fields are valid */ - unsigned long last_updated; /* In jiffies */ - - u8 in[6]; /* Register value */ - u8 in_max[6]; /* Register value */ - u8 in_min[6]; /* Register value */ - u16 temp[6]; /* Register value 10 bit */ - u8 temp_over[6]; /* Register value */ - u8 temp_hyst[6]; /* Register value */ - u8 fan[2]; /* Register value */ - u8 fan_min[2]; /* Register value */ - u8 fan_div[2]; /* Register encoding, shifted right */ - u16 alarms; /* Register encoding */ - u8 pwm[2]; /* Register value */ - u8 pwm_ctl; /* Register value */ - u8 vid; /* Register encoding */ - u8 vrm; - u8 uch_config; -}; - -static int vt8231_attach_adapter(struct i2c_adapter *adapter); -static int vt8231_detect(struct i2c_adapter *adapter, int address, - unsigned short flags, int kind); -static int vt8231_detach_client(struct i2c_client *client); - -static inline int vt_rdval(struct i2c_client *client, u8 register); -static inline void vt8231_write_value(struct i2c_client *client, u8 register, - u8 value); -static void vt8231_update_client(struct i2c_client *client); -static void vt8231_init_client(struct i2c_client *client); - - -static void vt8231_fan(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void vt8231_alarms(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void vt8231_fan_div(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void vt8231_in(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void vt8231_in5(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void vt8231_pwm(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void vt8231_vid(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void vt8231_vrm(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void vt8231_uch(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void vt8231_temp(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void vt8231_therm(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); - -static struct i2c_driver vt8231_driver = { - .name = "VT8231 sensors driver", - .id = I2C_DRIVERID_VT8231, - .flags = I2C_DF_NOTIFY, - .attach_adapter = vt8231_attach_adapter, - .detach_client = vt8231_detach_client, -}; - -/* -- SENSORS SYSCTL START -- */ -#define VT8231_SYSCTL_IN0 1000 -#define VT8231_SYSCTL_IN1 1001 -#define VT8231_SYSCTL_IN2 1002 -#define VT8231_SYSCTL_IN3 1003 -#define VT8231_SYSCTL_IN4 1004 -#define VT8231_SYSCTL_IN5 1005 -#define VT8231_SYSCTL_FAN1 1101 -#define VT8231_SYSCTL_FAN2 1102 -#define VT8231_SYSCTL_TEMP 1200 -#define VT8231_SYSCTL_TEMP2 1201 -#define VT8231_SYSCTL_TEMP3 1202 -#define VT8231_SYSCTL_TEMP4 1203 -#define VT8231_SYSCTL_TEMP5 1204 -#define VT8231_SYSCTL_TEMP6 1205 -#define VT8231_SYSCTL_VID 1300 -#define VT8231_SYSCTL_PWM1 1401 -#define VT8231_SYSCTL_PWM2 1402 -#define VT8231_SYSCTL_VRM 1600 -#define VT8231_SYSCTL_UCH 1700 -#define VT8231_SYSCTL_FAN_DIV 2000 -#define VT8231_SYSCTL_ALARMS 2001 - -#define VT8231_ALARM_IN1 0x01 -#define VT8231_ALARM_IN2 0x02 -#define VT8231_ALARM_IN5 0x04 -#define VT8231_ALARM_IN3 0x08 -#define VT8231_ALARM_TEMP 0x10 -#define VT8231_ALARM_FAN1 0x40 -#define VT8231_ALARM_FAN2 0x80 -#define VT8231_ALARM_IN4 0x100 -#define VT8231_ALARM_TEMP2 0x800 -#define VT8231_ALARM_CHAS 0x1000 -/* duplicates */ -#define VT8231_ALARM_IN0 VT8231_ALARM_TEMP2 -#define VT8231_ALARM_TEMP3 VT8231_ALARM_IN1 -#define VT8231_ALARM_TEMP4 VT8231_ALARM_IN2 -#define VT8231_ALARM_TEMP5 VT8231_ALARM_IN3 -#define VT8231_ALARM_TEMP6 VT8231_ALARM_IN4 - -/* -- SENSORS SYSCTL END -- */ - -static ctl_table vt8231_dir_table_template[] = { - {VT8231_SYSCTL_IN0, "in0", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &vt8231_in}, - {VT8231_SYSCTL_IN1, "in1", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &vt8231_in}, - {VT8231_SYSCTL_IN2, "in2", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &vt8231_in}, - {VT8231_SYSCTL_IN3, "in3", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &vt8231_in}, - {VT8231_SYSCTL_IN4, "in4", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &vt8231_in}, - {VT8231_SYSCTL_IN5, "in5", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &vt8231_in5}, - {VT8231_SYSCTL_TEMP, "temp1", NULL, 0, 0644, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &vt8231_temp}, - {VT8231_SYSCTL_TEMP2, "temp2", NULL, 0, 0644, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &vt8231_therm}, - {VT8231_SYSCTL_TEMP3, "temp3", NULL, 0, 0644, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &vt8231_therm}, - {VT8231_SYSCTL_TEMP4, "temp4", NULL, 0, 0644, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &vt8231_therm}, - {VT8231_SYSCTL_TEMP5, "temp5", NULL, 0, 0644, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &vt8231_therm}, - {VT8231_SYSCTL_TEMP6, "temp6", NULL, 0, 0644, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &vt8231_therm}, - {VT8231_SYSCTL_FAN1, "fan1", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &vt8231_fan}, - {VT8231_SYSCTL_FAN2, "fan2", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &vt8231_fan}, - {VT8231_SYSCTL_FAN_DIV, "fan_div", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &vt8231_fan_div}, - {VT8231_SYSCTL_ALARMS, "alarms", NULL, 0, 0444, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &vt8231_alarms}, - {VT8231_SYSCTL_PWM1, "pwm1", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &vt8231_pwm}, - {VT8231_SYSCTL_PWM2, "pwm2", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &vt8231_pwm}, - {VT8231_SYSCTL_VID, "vid", NULL, 0, 0444, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &vt8231_vid}, - {VT8231_SYSCTL_VRM, "vrm", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &vt8231_vrm}, - {VT8231_SYSCTL_UCH, "uch_config", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &vt8231_uch}, - {0} -}; - -static struct pci_dev *s_bridge; - -static int vt8231_attach_adapter(struct i2c_adapter *adapter) -{ - return i2c_detect(adapter, &addr_data, vt8231_detect); -} - -/* Locate chip and get correct base address */ -static int __init vt8231_find(int *address) -{ - u16 val; - - if (!pci_present()) - return -ENODEV; - - if (!(s_bridge = pci_find_device(PCI_VENDOR_ID_VIA, - 0x8235, NULL))) - return -ENODEV; - - if (PCIBIOS_SUCCESSFUL != - pci_read_config_word(s_bridge, VIA686A_BASE_REG, &val)) - return -ENODEV; - *address = val & ~(VIA686A_EXTENT - 1); - if (*address == 0 && force_addr == 0) { - printk("vt8231.o: base address not set - upgrade BIOS or use force_addr=0xaddr\n"); - return -ENODEV; - } - if (force_addr) - *address = force_addr; /* so detect will get called */ - - return 0; -} - -int vt8231_detect(struct i2c_adapter *adapter, int address, - unsigned short flags, int kind) -{ - int i; - struct i2c_client *new_client; - struct vt8231_data *data; - int err = 0; - const char *type_name = "vt8231"; - u16 val; - - if (!i2c_is_isa_adapter(adapter)) { - return 0; - } - - /* 8231 requires multiple of 256 */ - if(force_addr) - address = force_addr & 0xFF00; - if (check_region(address, VIA686A_EXTENT)) { - printk("vt8231.o: region 0x%x already in use!\n", - address); - return -ENODEV; - } - - if(force_addr) { - printk("vt8231.o: forcing ISA address 0x%04X\n", address); - if (PCIBIOS_SUCCESSFUL != - pci_write_config_word(s_bridge, VIA686A_BASE_REG, address)) - return -ENODEV; - } - if (PCIBIOS_SUCCESSFUL != - pci_read_config_word(s_bridge, VIA686A_ENABLE_REG, &val)) - return -ENODEV; - if (!(val & 0x0001)) { - printk("vt8231.o: enabling sensors\n"); - if (PCIBIOS_SUCCESSFUL != - pci_write_config_word(s_bridge, VIA686A_ENABLE_REG, - val | 0x0001)) - return -ENODEV; - } - - if (!(data = kmalloc(sizeof(struct vt8231_data), GFP_KERNEL))) { - err = -ENOMEM; - goto ERROR0; - } - - new_client = &data->client; - new_client->addr = address; - init_MUTEX(&data->lock); - new_client->data = data; - new_client->adapter = adapter; - new_client->driver = &vt8231_driver; - new_client->flags = 0; - - /* Reserve the ISA region */ - request_region(address, VIA686A_EXTENT, "vt8231-sensors"); - - /* Fill in the remaining client fields and put into the global list */ - strcpy(new_client->name, "Via 8231 Integrated Sensors"); - data->valid = 0; - init_MUTEX(&data->update_lock); - - /* Tell the I2C layer a new client has arrived */ - if ((err = i2c_attach_client(new_client))) - goto ERROR3; - - /* Register a new directory entry with module sensors */ - if ((i = i2c_register_entry((struct i2c_client *) new_client, - type_name, - vt8231_dir_table_template, - THIS_MODULE)) < 0) { - err = i; - goto ERROR4; - } - data->sysctl_id = i; - - vt8231_init_client(new_client); - return 0; - - ERROR4: - i2c_detach_client(new_client); - ERROR3: - release_region(address, VIA686A_EXTENT); - kfree(data); - ERROR0: - return err; -} - -static int vt8231_detach_client(struct i2c_client *client) -{ - int err; - - i2c_deregister_entry(((struct vt8231_data *) (client->data))-> - sysctl_id); - - if ((err = i2c_detach_client(client))) { - printk - ("vt8231.o: Client deregistration failed, client not detached.\n"); - return err; - } - - release_region(client->addr, VIA686A_EXTENT); - kfree(client->data); - - return 0; -} - - -static inline int vt_rdval(struct i2c_client *client, u8 reg) -{ - return (inb_p(client->addr + reg)); -} - -static inline void vt8231_write_value(struct i2c_client *client, u8 reg, u8 value) -{ - outb_p(value, client->addr + reg); -} - -static void vt8231_init_client(struct i2c_client *client) -{ - struct vt8231_data *data = client->data; - - data->vrm = 91; - /* set "default" interrupt mode for alarms, which isn't the default */ - vt8231_write_value(client, VT8231_REG_TEMP1_CONFIG, 0); - vt8231_write_value(client, VT8231_REG_TEMP2_CONFIG, 0); -} - -static void vt8231_update_client(struct i2c_client *client) -{ - struct vt8231_data *data = client->data; - int i, j; - - down(&data->update_lock); - - if ((jiffies - data->last_updated > HZ + HZ / 2) || - (jiffies < data->last_updated) || !data->valid) { - data->uch_config = vt_rdval(client, VT8231_REG_UCH_CONFIG); - for (i = 0; i <= 5; i++) { - if(ISVOLT(i, data->uch_config)) { - data->in[i] = vt_rdval(client, VT8231_REG_IN(i)); - data->in_min[i] = vt_rdval(client, - VT8231_REG_IN_MIN(i)); - data->in_max[i] = vt_rdval(client, - VT8231_REG_IN_MAX(i)); - } else { - data->in[i] = 0; - data->in_min[i] = 0; - data->in_max[i] = 0; - } - } - for (i = 1; i <= 2; i++) { - data->fan[i - 1] = vt_rdval(client, VT8231_REG_FAN(i)); - data->fan_min[i - 1] = vt_rdval(client, - VT8231_REG_FAN_MIN(i)); - } - for (i = 1; i <= 6; i++) { - if(ISTEMP(i, data->uch_config)) { - data->temp[i - 1] = vt_rdval(client, - VT8231_REG_TEMP(i)) << 2; - switch(i) { - case 1: - j = (vt_rdval(client, - VT8231_REG_TEMP_LOW12) & - 0xc0) >> 6; - break; - case 2: - j = (vt_rdval(client, - VT8231_REG_TEMP_LOW12) & - 0x30) >> 4; - break; - default: - j = (vt_rdval(client, - VT8231_REG_TEMP_LOW36) >> - ((i-3)*2)) & 0x03; - break; - - } - data->temp[i - 1] |= j; - data->temp_over[i - 1] = vt_rdval(client, - VT8231_REG_TEMP_OVER(i)); - data->temp_hyst[i - 1] = vt_rdval(client, - VT8231_REG_TEMP_HYST(i)); - } else { - data->temp[i - 1] = 0; - data->temp_over[i - 1] = 0; - data->temp_hyst[i - 1] = 0; - } - } - - for (i = 1; i <= 2; i++) { - data->fan[i - 1] = vt_rdval(client, VT8231_REG_FAN(i)); - data->fan_min[i - 1] = vt_rdval(client, - VT8231_REG_FAN_MIN(i)); - data->pwm[i - 1] = vt_rdval(client, VT8231_REG_PWM(i)); - } - - data->pwm_ctl = vt_rdval(client, VT8231_REG_PWM_CTL); - i = vt_rdval(client, VT8231_REG_FANDIV); - data->fan_div[0] = (i >> 4) & 0x03; - data->fan_div[1] = i >> 6; - data->alarms = vt_rdval(client, VT8231_REG_ALARM1) | - (vt_rdval(client, VT8231_REG_ALARM2) << 8); - data->vid= vt_rdval(client, VT8231_REG_VID) & 0x1f; - data->last_updated = jiffies; - data->valid = 1; - } - - up(&data->update_lock); -} - - -void vt8231_in(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct vt8231_data *data = client->data; - int nr = ctl_name - VT8231_SYSCTL_IN0; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 2; - else if (operation == SENSORS_PROC_REAL_READ) { - vt8231_update_client(client); - results[0] = IN_FROM_REG(data->in_min[nr]); - results[1] = IN_FROM_REG(data->in_max[nr]); - results[2] = IN_FROM_REG(data->in[nr]); - *nrels_mag = 3; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag >= 1) { - data->in_min[nr] = IN_TO_REG(results[0]); - vt8231_write_value(client, VT8231_REG_IN_MIN(nr), - data->in_min[nr]); - } - if (*nrels_mag >= 2) { - data->in_max[nr] = IN_TO_REG(results[1]); - vt8231_write_value(client, VT8231_REG_IN_MAX(nr), - data->in_max[nr]); - } - } -} - -void vt8231_in5(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct vt8231_data *data = client->data; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 2; - else if (operation == SENSORS_PROC_REAL_READ) { - vt8231_update_client(client); - results[0] = IN5_FROM_REG(data->in_min[5]); - results[1] = IN5_FROM_REG(data->in_max[5]); - results[2] = IN5_FROM_REG(data->in[5]); - *nrels_mag = 3; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag >= 1) { - data->in_min[5] = IN5_TO_REG(results[0]); - vt8231_write_value(client, VT8231_REG_IN_MIN(5), - data->in_min[5]); - } - if (*nrels_mag >= 2) { - data->in_max[5] = IN5_TO_REG(results[1]); - vt8231_write_value(client, VT8231_REG_IN_MAX(5), - data->in_max[5]); - } - } -} - -void vt8231_fan(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct vt8231_data *data = client->data; - int nr = ctl_name - VT8231_SYSCTL_FAN1 + 1; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - vt8231_update_client(client); - results[0] = FAN_FROM_REG(data->fan_min[nr - 1], - DIV_FROM_REG(data->fan_div - [nr - 1])); - results[1] = FAN_FROM_REG(data->fan[nr - 1], - DIV_FROM_REG(data->fan_div[nr - 1])); - *nrels_mag = 2; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag >= 1) { - data->fan_min[nr - 1] = MIN_TO_REG(results[0], - DIV_FROM_REG - (data-> - fan_div[nr-1])); - vt8231_write_value(client, VT8231_REG_FAN_MIN(nr), - data->fan_min[nr - 1]); - } - } -} - - -void vt8231_temp(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct vt8231_data *data = client->data; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 1; - else if (operation == SENSORS_PROC_REAL_READ) { - vt8231_update_client(client); - results[0] = TEMP_FROM_REG(data->temp_over[0]); - results[1] = TEMP_FROM_REG(data->temp_hyst[0]); - results[2] = TEMP_FROM_REG10(data->temp[0]); - *nrels_mag = 3; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag >= 1) { - data->temp_over[0] = TEMP_TO_REG(results[0]); - vt8231_write_value(client, - VT8231_REG_TEMP_OVER(1), - data->temp_over[0]); - } - if (*nrels_mag >= 2) { - data->temp_hyst[0] = TEMP_TO_REG(results[1]); - vt8231_write_value(client, - VT8231_REG_TEMP_HYST(1), - data->temp_hyst[0]); - } - } -} - -void vt8231_therm(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct vt8231_data *data = client->data; - int nr = ctl_name - VT8231_SYSCTL_TEMP; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 2; - else if (operation == SENSORS_PROC_REAL_READ) { - vt8231_update_client(client); - results[0] = THERM_FROM_REG(data->temp_over[nr] * 4); - results[1] = THERM_FROM_REG(data->temp_hyst[nr] * 4); - results[2] = THERM_FROM_REG(data->temp[nr]); - *nrels_mag = 3; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag >= 1) { - data->temp_over[nr] = THERM_TO_REG(results[0]); - vt8231_write_value(client, - VT8231_REG_TEMP_OVER(nr + 1), - data->temp_over[nr]); - } - if (*nrels_mag >= 2) { - data->temp_hyst[nr] = THERM_TO_REG(results[1]); - vt8231_write_value(client, - VT8231_REG_TEMP_HYST(nr + 1), - data->temp_hyst[nr]); - } - } -} - -void vt8231_alarms(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct vt8231_data *data = client->data; - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - vt8231_update_client(client); - results[0] = data->alarms; - *nrels_mag = 1; - } -} - -void vt8231_fan_div(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results) -{ - struct vt8231_data *data = client->data; - int old; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - vt8231_update_client(client); - results[0] = DIV_FROM_REG(data->fan_div[0]); - results[1] = DIV_FROM_REG(data->fan_div[1]); - *nrels_mag = 2; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - old = vt_rdval(client, VT8231_REG_FANDIV); - if (*nrels_mag >= 2) { - data->fan_div[1] = DIV_TO_REG(results[1]); - old = (old & 0x3f) | (data->fan_div[1] << 6); - } - if (*nrels_mag >= 1) { - data->fan_div[0] = DIV_TO_REG(results[0]); - old = (old & 0xcf) | (data->fan_div[0] << 4); - vt8231_write_value(client, VT8231_REG_FANDIV, old); - } - } -} - -void vt8231_pwm(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct vt8231_data *data = client->data; - int nr = 1 + ctl_name - VT8231_SYSCTL_PWM1; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - vt8231_update_client(client); - results[0] = PWM_FROM_REG(data->pwm[nr - 1]); - results[1] = (data->pwm_ctl >> (3 + (4 * (nr - 1)))) & 1; - *nrels_mag = 2; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag >= 1) { - data->pwm[nr - 1] = PWM_TO_REG(results[0]); - if (*nrels_mag >= 2) { - if(results[1]) { - data->pwm_ctl |= - (0x08 << (4 * (nr - 1))); - vt8231_write_value(client, - VT8231_REG_PWM_CTL, - data->pwm_ctl); - } else { - data->pwm_ctl &= - ~ (0x08 << (4 * (nr - 1))); - vt8231_write_value(client, - VT8231_REG_PWM_CTL, - data->pwm_ctl); - } - } - vt8231_write_value(client, VT8231_REG_PWM(nr), - data->pwm[nr - 1]); - } - } -} - -void vt8231_vid(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct vt8231_data *data = client->data; - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 3; - else if (operation == SENSORS_PROC_REAL_READ) { - vt8231_update_client(client); - results[0] = vid_from_reg(data->vid, data->vrm); - *nrels_mag = 1; - } -} - -void vt8231_vrm(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct vt8231_data *data = client->data; - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 1; - else if (operation == SENSORS_PROC_REAL_READ) { - results[0] = data->vrm; - *nrels_mag = 1; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag >= 1) - data->vrm = results[0]; - } -} - -void vt8231_uch(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct vt8231_data *data = client->data; - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - results[0] = data->uch_config & 0x7c; - *nrels_mag = 1; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag >= 1) { - data->uch_config = (data->uch_config & 0x83)|(results[0] & 0x7c); - vt8231_write_value(client, VT8231_REG_UCH_CONFIG, - data->uch_config); - } - } -} - -static int __init sm_vt8231_init(void) -{ - int addr; - - printk("vt8231.o version %s (%s)\n", LM_VERSION, LM_DATE); - - if (vt8231_find(&addr)) { - printk("vt8231.o: VT8231 not detected, module not inserted.\n"); - return -ENODEV; - } - normal_isa[0] = addr; - - return i2c_add_driver(&vt8231_driver);} - -static void __exit sm_vt8231_exit(void) -{ - i2c_del_driver(&vt8231_driver); -} - - - -MODULE_AUTHOR("Mark D. Studebaker "); -MODULE_DESCRIPTION("VT8231 sensors"); -MODULE_LICENSE("GPL"); - -module_init(sm_vt8231_init); -module_exit(sm_vt8231_exit); diff --git a/kernel/chips/w83627ehf.c b/kernel/chips/w83627ehf.c deleted file mode 100644 index 51ebb565..00000000 --- a/kernel/chips/w83627ehf.c +++ /dev/null @@ -1,1138 +0,0 @@ -/* - w83627ehf - Driver for the hardware monitoring functionality of - the Winbond W83627EHF Super-I/O chip - Copyright (C) 2005, 2007 Jean Delvare - Copyright (C) 2006 Rudolf Marek - Backported to kernel 2.4 by Yuan Mu (Winbond). - - Shamelessly ripped from the w83627hf driver - Copyright (C) 2003 Mark Studebaker - - This driver also supports the W83627EHG, which is the lead-free - version of the W83627EHF. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - - Supports the following chips: - - Chip #vin #fan #pwm #temp - w83627ehf 10 5 4 3 -*/ - -#include -#include -#include -#include -#include -#include -#include -#include "version.h" -#include "sensors_vid.h" -#include "lm75.h" - -/* The actual ISA address is read from Super-I/O configuration space */ -static unsigned short normal_i2c[] = { SENSORS_I2C_END }; -static unsigned short normal_i2c_range[] = { SENSORS_I2C_END }; -static unsigned int normal_isa[] = { 0, SENSORS_ISA_END }; -static unsigned int normal_isa_range[] = { SENSORS_ISA_END }; - -/* Insmod parameters */ -SENSORS_INSMOD_1(w83627ehf); - -/* - * Super-I/O constants and functions - */ - -static int REG; /* The register to read/write */ -static int VAL; /* The value to read/write */ - -#define W83627EHF_LD_HWM 0x0b - -#define SIO_REG_LDSEL 0x07 /* Logical device select */ -#define SIO_REG_DEVID 0x20 /* Device ID (2 bytes) */ -#define SIO_REG_EN_VRM10 0x2C /* GPIO3, GPIO4 selection */ -#define SIO_REG_ENABLE 0x30 /* Logical device enable */ -#define SIO_REG_ADDR 0x60 /* Logical device address (2 bytes) */ -#define SIO_REG_VID_CTRL 0xF0 /* VID control */ -#define SIO_REG_VID_DATA 0xF1 /* VID data */ - -#define SIO_W83627EHF_ID 0x8850 -#define SIO_W83627EHG_ID 0x8860 -#define SIO_ID_MASK 0xFFF0 - -static inline void superio_outb(int reg, int val) -{ - outb(reg, REG); - outb(val, VAL); -} - -static inline int superio_inb(int reg) -{ - outb(reg, REG); - return inb(VAL); -} - -static inline void superio_select(int ld) -{ - outb(SIO_REG_LDSEL, REG); - outb(ld, VAL); -} - -static inline void superio_enter(void) -{ - outb(0x87, REG); - outb(0x87, REG); -} - -static inline void superio_exit(void) -{ - outb(0x02, REG); - outb(0x02, VAL); -} - -/* - * ISA constants - */ - -#define REGION_ALIGNMENT ~7 -#define REGION_OFFSET 5 -#define REGION_LENGTH 2 -#define ADDR_REG_OFFSET 5 -#define DATA_REG_OFFSET 6 - -#define W83627EHF_REG_BANK 0x4E -#define W83627EHF_REG_CONFIG 0x40 - -static const u16 W83627EHF_REG_FAN[] = { 0x28, 0x29, 0x2a, 0x3f, 0x553 }; -static const u16 W83627EHF_REG_FAN_MIN[] = { 0x3b, 0x3c, 0x3d, 0x3e, 0x55c }; - -/* The W83627EHF registers for nr=7,8,9 are in bank 5 */ -#define W83627EHF_REG_IN_MAX(nr) ((nr < 7) ? (0x2b + (nr) * 2) : \ - (0x554 + (((nr) - 7) * 2))) -#define W83627EHF_REG_IN_MIN(nr) ((nr < 7) ? (0x2c + (nr) * 2) : \ - (0x555 + (((nr) - 7) * 2))) -#define W83627EHF_REG_IN(nr) ((nr < 7) ? (0x20 + (nr)) : \ - (0x550 + (nr) - 7)) - -static const u16 W83627EHF_REG_TEMP[] = { 0x27, 0x150, 0x250 }; -static const u16 W83627EHF_REG_TEMP_HYST[] = { 0x3a, 0x153, 0x253 }; -static const u16 W83627EHF_REG_TEMP_OVER[] = { 0x39, 0x155, 0x255 }; -static const u16 W83627EHF_REG_TEMP_CONFIG[] = { 0x152, 0x252 }; - -/* Fan clock dividers are spread over the following five registers */ -#define W83627EHF_REG_FANDIV1 0x47 -#define W83627EHF_REG_FANDIV2 0x4B -#define W83627EHF_REG_VBAT 0x5D -#define W83627EHF_REG_DIODE 0x59 -#define W83627EHF_REG_SMI_OVT 0x4C - -#define W83627EHF_REG_ALARM1 0x459 -#define W83627EHF_REG_ALARM2 0x45A -#define W83627EHF_REG_ALARM3 0x45B - -/* SmartFan registers */ -/* DC or PWM output fan configuration */ -static const u8 W83627EHF_REG_PWM_ENABLE[] = { - 0x04, /* SYS FAN0 */ - 0x04, /* CPU FAN0 */ - 0x12, /* AUX FAN */ - 0x62, /* CPU FAN1 */ -}; - -#if 0 -static const u8 W83627EHF_PWM_MODE_SHIFT[4] = { 0, 1, 0, 6 }; -#endif -static const u8 W83627EHF_PWM_ENABLE_SHIFT[4] = { 2, 4, 1, 4 }; - -/* FAN Duty Cycle, be used to control */ -static const u8 W83627EHF_REG_PWM[] = { 0x01, 0x03, 0x11, 0x61 }; - -/* - * Conversions - */ - -static inline unsigned int fan_from_reg(u8 reg, unsigned int div) -{ - if (reg == 0 || reg == 255) - return 0; - return 1350000U / (reg * div); -} - -static inline unsigned int div_from_reg(u8 reg) -{ - return 1 << reg; -} - -/* Some of analog inputs have internal scaling (2x), 8mV is ADC LSB */ -static const u8 scale_in[10] = { 8, 8, 16, 16, 8, 8, 8, 16, 16, 8 }; - -static inline long in_from_reg(u8 reg, u8 nr) -{ - return reg * scale_in[nr]; -} - -static inline u8 in_to_reg(long val, u8 nr) -{ - return SENSORS_LIMIT((val + scale_in[nr] / 2) / scale_in[nr], 0, 255); -} - -/* - * Data structures and manipulation thereof - */ - -struct w83627ehf_data { - struct i2c_client client; - struct class_device *class_dev; - int sysctl_id; - struct semaphore lock; - struct semaphore update_lock; - char valid; /* !=0 if following fields are valid */ - unsigned long last_updated; /* In jiffies */ - - /* Register values */ - u8 in[10]; /* Register value */ - u8 in_max[10]; /* Register value */ - u8 in_min[10]; /* Register value */ - u8 fan[5]; - u8 fan_min[5]; - u8 fan_div[5]; - u8 has_fan; /* some fan inputs can be disabled */ - u8 sensor[3]; - u16 temp[3]; - u16 temp_max[3]; - u16 temp_hyst[3]; - u32 alarms; - - u8 pwm_enable[4]; /* 1 for manual, 2+ for auto */ - u8 pwm[4]; - - u8 vid; - u8 vrm; -}; - -/* The /proc/sys entries */ -/* -- SENSORS SYSCTL START -- */ - -#define W83627EHF_SYSCTL_IN0 1000 /* Volts * 1000 */ -#define W83627EHF_SYSCTL_IN1 1001 -#define W83627EHF_SYSCTL_IN2 1002 -#define W83627EHF_SYSCTL_IN3 1003 -#define W83627EHF_SYSCTL_IN4 1004 -#define W83627EHF_SYSCTL_IN5 1005 -#define W83627EHF_SYSCTL_IN6 1006 -#define W83627EHF_SYSCTL_IN7 1007 -#define W83627EHF_SYSCTL_IN8 1008 -#define W83627EHF_SYSCTL_IN9 1009 -#define W83627EHF_SYSCTL_FAN1 1101 /* Rotations/min */ -#define W83627EHF_SYSCTL_FAN2 1102 -#define W83627EHF_SYSCTL_FAN3 1103 -#define W83627EHF_SYSCTL_FAN4 1104 -#define W83627EHF_SYSCTL_FAN5 1105 -#define W83627EHF_SYSCTL_TEMP1 1201 /* Degrees Celsius * 10 */ -#define W83627EHF_SYSCTL_TEMP2 1202 -#define W83627EHF_SYSCTL_TEMP3 1203 -#define W83627EHF_SYSCTL_SENSOR1 1211 -#define W83627EHF_SYSCTL_SENSOR2 1212 -#define W83627EHF_SYSCTL_SENSOR3 1213 -#define W83627EHF_SYSCTL_VID 1300 /* Volts * 1000 */ -#define W83627EHF_SYSCTL_VRM 1301 -#define W83627EHF_SYSCTL_PWM1 1401 -#define W83627EHF_SYSCTL_PWM2 1402 -#define W83627EHF_SYSCTL_PWM3 1403 -#define W83627EHF_SYSCTL_PWM4 1404 -#define W83627EHF_SYSCTL_FAN_DIV 1506 -#define W83627EHF_SYSCTL_ALARMS 1507 /* bitvector */ - -#define W83627EHF_ALARM_IN0 (1 << 0) -#define W83627EHF_ALARM_IN1 (1 << 1) -#define W83627EHF_ALARM_IN2 (1 << 2) -#define W83627EHF_ALARM_IN3 (1 << 3) -#define W83627EHF_ALARM_IN4 (1 << 8) -#define W83627EHF_ALARM_IN5 (1 << 21) -#define W83627EHF_ALARM_IN6 (1 << 20) -#define W83627EHF_ALARM_IN7 (1 << 16) -#define W83627EHF_ALARM_IN8 (1 << 17) -#define W83627EHF_ALARM_IN9 (1 << 19) -#define W83627EHF_ALARM_TEMP1 (1 << 4) -#define W83627EHF_ALARM_TEMP2 (1 << 5) -#define W83627EHF_ALARM_TEMP3 (1 << 13) -#define W83627EHF_ALARM_FAN1 (1 << 6) -#define W83627EHF_ALARM_FAN2 (1 << 7) -#define W83627EHF_ALARM_FAN3 (1 << 11) -#define W83627EHF_ALARM_FAN4 (1 << 10) -#define W83627EHF_ALARM_FAN5 (1 << 23) - -/* -- SENSORS SYSCTL END -- */ - -static inline int is_word_sized(u16 reg) -{ - return (((reg & 0xff00) == 0x100 || (reg & 0xff00) == 0x200) - && ((reg & 0x00ff) == 0x50 || (reg & 0x00ff) == 0x53 || - (reg & 0x00ff) == 0x55)); -} - -/* We assume that the default bank is 0, thus the following two functions do - nothing for registers which live in bank 0. For others, they respectively - set the bank register to the correct value (before the register is - accessed), and back to 0 (afterwards). */ -static inline void w83627ehf_set_bank(struct i2c_client *client, u16 reg) -{ - if (reg & 0xff00) { - outb_p(W83627EHF_REG_BANK, client->addr + ADDR_REG_OFFSET); - outb_p(reg >> 8, client->addr + DATA_REG_OFFSET); - } -} - -static inline void w83627ehf_reset_bank(struct i2c_client *client, u16 reg) -{ - if (reg & 0xff00) { - outb_p(W83627EHF_REG_BANK, client->addr + ADDR_REG_OFFSET); - outb_p(0, client->addr + DATA_REG_OFFSET); - } -} - -static u16 w83627ehf_read_value(struct i2c_client *client, u16 reg) -{ - struct w83627ehf_data *data = client->data; - int res, word_sized = is_word_sized(reg); - - down(&data->lock); - - w83627ehf_set_bank(client, reg); - outb_p(reg & 0xff, client->addr + ADDR_REG_OFFSET); - res = inb_p(client->addr + DATA_REG_OFFSET); - if (word_sized) { - outb_p((reg & 0xff) + 1, client->addr + ADDR_REG_OFFSET); - res = (res << 8) + inb_p(client->addr + DATA_REG_OFFSET); - } - w83627ehf_reset_bank(client, reg); - - up(&data->lock); - return res; -} - -static int w83627ehf_write_value(struct i2c_client *client, u16 reg, u16 value) -{ - struct w83627ehf_data *data = client->data; - int word_sized = is_word_sized(reg); - - down(&data->lock); - - w83627ehf_set_bank(client, reg); - outb_p(reg & 0xff, client->addr + ADDR_REG_OFFSET); - if (word_sized) { - outb_p(value >> 8, client->addr + DATA_REG_OFFSET); - outb_p((reg & 0xff) + 1, client->addr + ADDR_REG_OFFSET); - } - outb_p(value & 0xff, client->addr + DATA_REG_OFFSET); - w83627ehf_reset_bank(client, reg); - - up(&data->lock); - return 0; -} - -/* This function assumes that the caller holds data->update_lock */ -static void w83627ehf_write_fan_div(struct i2c_client *client, int nr) -{ - struct w83627ehf_data *data = client->data; - u8 reg; - - switch (nr) { - case 0: - reg = w83627ehf_read_value(client, W83627EHF_REG_FANDIV1) - & 0xcf; - reg |= (data->fan_div[0] & 0x03) << 4; - /* fan5 input control bit is write only, compute the value */ - reg |= (data->has_fan & (1 << 4)) ? 1 : 0; - w83627ehf_write_value(client, W83627EHF_REG_FANDIV1, reg); - reg = w83627ehf_read_value(client, W83627EHF_REG_VBAT) - & 0xdf; - reg |= (data->fan_div[0] & 0x04) << 3; - w83627ehf_write_value(client, W83627EHF_REG_VBAT, reg); - break; - case 1: - reg = w83627ehf_read_value(client, W83627EHF_REG_FANDIV1) - & 0x3f; - reg |= (data->fan_div[1] & 0x03) << 6; - /* fan5 input control bit is write only, compute the value */ - reg |= (data->has_fan & (1 << 4)) ? 1 : 0; - w83627ehf_write_value(client, W83627EHF_REG_FANDIV1, reg); - reg = w83627ehf_read_value(client, W83627EHF_REG_VBAT) - & 0xbf; - reg |= (data->fan_div[1] & 0x04) << 4; - w83627ehf_write_value(client, W83627EHF_REG_VBAT, reg); - break; - case 2: - reg = w83627ehf_read_value(client, W83627EHF_REG_FANDIV2) - & 0x3f; - reg |= (data->fan_div[2] & 0x03) << 6; - w83627ehf_write_value(client, W83627EHF_REG_FANDIV2, reg); - reg = w83627ehf_read_value(client, W83627EHF_REG_VBAT) - & 0x7f; - reg |= (data->fan_div[2] & 0x04) << 5; - w83627ehf_write_value(client, W83627EHF_REG_VBAT, reg); - break; - case 3: - reg = w83627ehf_read_value(client, W83627EHF_REG_DIODE) - & 0xfc; - reg |= data->fan_div[3] & 0x03; - w83627ehf_write_value(client, W83627EHF_REG_DIODE, reg); - reg = w83627ehf_read_value(client, W83627EHF_REG_SMI_OVT) - & 0x7f; - reg |= (data->fan_div[3] & 0x04) << 5; - w83627ehf_write_value(client, W83627EHF_REG_SMI_OVT, reg); - break; - case 4: - reg = w83627ehf_read_value(client, W83627EHF_REG_DIODE) - & 0x73; - reg |= (data->fan_div[4] & 0x03) << 2; - reg |= (data->fan_div[4] & 0x04) << 5; - w83627ehf_write_value(client, W83627EHF_REG_DIODE, reg); - break; - } -} - -static void w83627ehf_update_client(struct i2c_client *client) -{ - struct w83627ehf_data *data = client->data; - int pwmcfg = 0; /* shut up the compiler */ - int i; - - down(&data->update_lock); - if (time_after(jiffies, data->last_updated + HZ) - || !data->valid) { - /* Fan clock dividers */ - i = w83627ehf_read_value(client, W83627EHF_REG_FANDIV1); - data->fan_div[0] = (i >> 4) & 0x03; - data->fan_div[1] = (i >> 6) & 0x03; - i = w83627ehf_read_value(client, W83627EHF_REG_FANDIV2); - data->fan_div[2] = (i >> 6) & 0x03; - i = w83627ehf_read_value(client, W83627EHF_REG_VBAT); - data->fan_div[0] |= (i >> 3) & 0x04; - data->fan_div[1] |= (i >> 4) & 0x04; - data->fan_div[2] |= (i >> 5) & 0x04; - if (data->has_fan & ((1 << 3) | (1 << 4))) { - i = w83627ehf_read_value(client, W83627EHF_REG_DIODE); - data->fan_div[3] = i & 0x03; - data->fan_div[4] = ((i >> 2) & 0x03) - | ((i >> 5) & 0x04); - } - if (data->has_fan & (1 << 3)) { - i = w83627ehf_read_value(client, W83627EHF_REG_SMI_OVT); - data->fan_div[3] |= (i >> 5) & 0x04; - } - - /* Measured voltages and limits */ - for (i = 0; i < 10; i++) { - data->in[i] = w83627ehf_read_value(client, - W83627EHF_REG_IN(i)); - data->in_min[i] = w83627ehf_read_value(client, - W83627EHF_REG_IN_MIN(i)); - data->in_max[i] = w83627ehf_read_value(client, - W83627EHF_REG_IN_MAX(i)); - } - - /* Measured fan speeds and limits */ - for (i = 0; i < 5; i++) { - if (!(data->has_fan & (1 << i))) - continue; - - data->fan[i] = w83627ehf_read_value(client, - W83627EHF_REG_FAN[i]); - data->fan_min[i] = w83627ehf_read_value(client, - W83627EHF_REG_FAN_MIN[i]); - - /* If we failed to measure the fan speed and clock - divider can be increased, let's try that for next - time */ - if (data->fan[i] == 0xff - && data->fan_div[i] < 0x07) { -#ifdef DEBUG - printk(KERN_DEBUG "w83627ehf: Increasing " - "fan%d clock divider from %u to %u\n", - i + 1, div_from_reg(data->fan_div[i]), - div_from_reg(data->fan_div[i] + 1)); -#endif - data->fan_div[i]++; - w83627ehf_write_fan_div(client, i); - /* Preserve min limit if possible */ - if (data->fan_min[i] >= 2 - && data->fan_min[i] != 255) { - w83627ehf_write_value(client, - W83627EHF_REG_FAN_MIN[i], - (data->fan_min[i] /= 2)); - } - } - } - - for (i = 0; i < 4; i++) { - /* pwmcfg mapped for i=0, i=1 to same reg */ - if (i != 1) - pwmcfg = w83627ehf_read_value(client, - W83627EHF_REG_PWM_ENABLE[i]); - - data->pwm_enable[i] = 1 + - ((pwmcfg >> W83627EHF_PWM_ENABLE_SHIFT[i]) & 3); - data->pwm[i] = w83627ehf_read_value(client, - W83627EHF_REG_PWM[i]); - } - - /* Measured temperatures and limits */ - for (i = 0; i < 3; i++) { - data->temp[i] = w83627ehf_read_value(client, - W83627EHF_REG_TEMP[i]); - data->temp_max[i] = w83627ehf_read_value(client, - W83627EHF_REG_TEMP_OVER[i]); - data->temp_hyst[i] = w83627ehf_read_value(client, - W83627EHF_REG_TEMP_HYST[i]); - } - /* temp1 is 8-bit, align it */ - data->temp[0] <<= 8; - data->temp_max[0] <<= 8; - data->temp_hyst[0] <<= 8; - - data->alarms = w83627ehf_read_value(client, - W83627EHF_REG_ALARM1) | - (w83627ehf_read_value(client, - W83627EHF_REG_ALARM2) << 8) | - (w83627ehf_read_value(client, W83627EHF_REG_ALARM3) << 16); - - data->last_updated = jiffies; - data->valid = 1; - } - - up(&data->update_lock); -} - -static void w83627ehf_in(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct w83627ehf_data *data = client->data; - int nr = ctl_name - W83627EHF_SYSCTL_IN0; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 3; - else if (operation == SENSORS_PROC_REAL_READ) { - w83627ehf_update_client(client); - results[0] = in_from_reg(data->in_min[nr], nr); - results[1] = in_from_reg(data->in_max[nr], nr); - results[2] = in_from_reg(data->in[nr], nr); - *nrels_mag = 3; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - down(&data->update_lock); - if (*nrels_mag >= 1) { - /* Write low limit into register */ - data->in_min[nr] = in_to_reg(results[0], nr); - w83627ehf_write_value(client, W83627EHF_REG_IN_MIN(nr), - data->in_min[nr]); - } - if (*nrels_mag >= 2) { - /* Write high limit into register */ - data->in_max[nr] = in_to_reg(results[1], nr); - w83627ehf_write_value(client, W83627EHF_REG_IN_MAX(nr), - data->in_max[nr]); - } - up(&data->update_lock); - } -} - -static void store_fan_min(struct i2c_client *client, long val, int nr) -{ - struct w83627ehf_data *data = client->data; - unsigned int reg; - u8 new_div; - - down(&data->update_lock); - if (val <= 0) { - /* No min limit, alarm disabled */ - data->fan_min[nr] = 255; - new_div = data->fan_div[nr]; /* No change */ - printk(KERN_INFO "w83627ehf: fan%u low limit and alarm " - "disabled\n", nr + 1); - } else if ((reg = 1350000U / val) >= 128 * 255) { - /* Speed below this value cannot possibly be represented, - even with the highest divider (128) */ - data->fan_min[nr] = 254; - new_div = 7; /* 128 == (1 << 7) */ - printk(KERN_WARNING "w83627ehf: fan%u low limit %lu below " - "minimum %u, set to minimum\n", nr + 1, val, - fan_from_reg(254, 128)); - } else if (!reg) { - /* Speed above this value cannot possibly be represented, - even with the lowest divider (1) */ - data->fan_min[nr] = 1; - new_div = 0; /* 1 == (1 << 0) */ - printk(KERN_WARNING "w83627ehf: fan%u low limit %lu above " - "maximum %u, set to maximum\n", nr + 1, val, - fan_from_reg(1, 1)); - } else { - /* Automatically pick the best divider, i.e. the one such - that the min limit will correspond to a register value - in the 96..192 range */ - new_div = 0; - while (reg > 192 && new_div < 7) { - reg >>= 1; - new_div++; - } - data->fan_min[nr] = reg; - } - - /* Write both the fan clock divider (if it changed) and the new - fan min (unconditionally) */ - if (new_div != data->fan_div[nr]) { - /* Preserve the fan speed reading */ - if (data->fan[nr] != 0xff) { - if (new_div > data->fan_div[nr]) - data->fan[nr] >>= new_div - data->fan_div[nr]; - else if (data->fan[nr] & 0x80) - data->fan[nr] = 0xff; - else - data->fan[nr] <<= data->fan_div[nr] - new_div; - } - -#ifdef DEBUG - printk(KERN_DEBUG "w83627ehf: fan%u clock divider changed " - "from %u to %u\n", nr + 1, - div_from_reg(data->fan_div[nr]), - div_from_reg(new_div)); -#endif - data->fan_div[nr] = new_div; - w83627ehf_write_fan_div(client, nr); - } - w83627ehf_write_value(client, W83627EHF_REG_FAN_MIN[nr], - data->fan_min[nr]); - up(&data->update_lock); -} - -static void w83627ehf_fan(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results) -{ - struct w83627ehf_data *data = client->data; - int nr = ctl_name - W83627EHF_SYSCTL_FAN1; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - if (data->has_fan & (1 << nr)) { - w83627ehf_update_client(client); - results[0] = fan_from_reg(data->fan_min[nr], - div_from_reg(data->fan_div[nr])); - results[1] = fan_from_reg(data->fan[nr], - div_from_reg(data->fan_div[nr])); - } else { - results[0] = 0; - results[1] = 0; - } - *nrels_mag = 2; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if ((data->has_fan & (1 << nr)) - && (*nrels_mag >= 1)) { - store_fan_min(client, results[0], nr); - } - } -} - -static void w83627ehf_temp(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results) -{ - struct w83627ehf_data *data = client->data; - int nr = ctl_name - W83627EHF_SYSCTL_TEMP1; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 1; - else if (operation == SENSORS_PROC_REAL_READ) { - w83627ehf_update_client(client); - results[0] = LM75_TEMP_FROM_REG(data->temp_max[nr]); - results[1] = LM75_TEMP_FROM_REG(data->temp_hyst[nr]); - results[2] = LM75_TEMP_FROM_REG(data->temp[nr]); - *nrels_mag = 3; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - down(&data->update_lock); - if (*nrels_mag >= 1) { - data->temp_max[nr] = LM75_TEMP_TO_REG(results[0]); - w83627ehf_write_value(client, - W83627EHF_REG_TEMP_OVER[nr], - nr ? data->temp_max[nr] : - data->temp_max[nr] >> 8); - } - if (*nrels_mag >= 2) { - data->temp_hyst[nr] = LM75_TEMP_TO_REG(results[1]); - w83627ehf_write_value(client, - W83627EHF_REG_TEMP_HYST[nr], - nr ? data->temp_hyst[nr] : - data->temp_hyst[nr] >> 8); - } - up(&data->update_lock); - } -} - -static void w83627ehf_alarms(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results) -{ - struct w83627ehf_data *data = client->data; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - w83627ehf_update_client(client); - results[0] = data->alarms; - *nrels_mag = 1; - } -} - -static void w83627ehf_fan_div(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results) -{ - struct w83627ehf_data *data = client->data; - int i; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - w83627ehf_update_client(client); - for (i = 0; i < 5; i++) - results[i] = div_from_reg(data->fan_div[i]); - *nrels_mag = 5; - } -} - -/* This function assumes that the caller holds data->update_lock */ -static void store_pwm_enable(struct i2c_client *client, long val, int nr) -{ - struct w83627ehf_data *data = client->data; - u16 reg; - long modemax; - - /* Only pwm2 and pwm4 support Smart Fan III */ - modemax = (nr == 1 || nr == 3) ? 4 : 3; - if (val < 1 || val > modemax) - return; - - data->pwm_enable[nr] = val; - reg = w83627ehf_read_value(client, W83627EHF_REG_PWM_ENABLE[nr]); - reg &= ~(0x03 << W83627EHF_PWM_ENABLE_SHIFT[nr]); - reg |= (val - 1) << W83627EHF_PWM_ENABLE_SHIFT[nr]; - w83627ehf_write_value(client, W83627EHF_REG_PWM_ENABLE[nr], reg); -} - -static void w83627ehf_pwm(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results) -{ - struct w83627ehf_data *data = client->data; - int nr = ctl_name - W83627EHF_SYSCTL_PWM1; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - w83627ehf_update_client(client); - results[0] = data->pwm[nr]; - results[1] = data->pwm_enable[nr]; - *nrels_mag = 2; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - down(&data->update_lock); - if (*nrels_mag >= 1) { - data->pwm[nr] = SENSORS_LIMIT(results[0], 0, 255); - w83627ehf_write_value(client, W83627EHF_REG_PWM[nr], - data->pwm[nr]); - } - if (*nrels_mag >= 2) { - store_pwm_enable(client, results[1], nr); - } - up(&data->update_lock); - } -} - -static void w83627ehf_vid(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results) -{ - struct w83627ehf_data *data = client->data; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 3; - else if (operation == SENSORS_PROC_REAL_READ) { - results[0] = vid_from_reg(data->vid, data->vrm); - *nrels_mag = 1; - } -} - -/* Change the VID input level, and read VID value again - This function assumes that the caller holds data->update_lock */ -static void w83627ehf_en_vrm10(struct w83627ehf_data *data, int enable) -{ - u8 reg; - - superio_enter(); - reg = superio_inb(SIO_REG_EN_VRM10) & ~0x08; - if (enable) - reg |= 0x08; - superio_outb(SIO_REG_EN_VRM10, reg); - - superio_select(W83627EHF_LD_HWM); - if (superio_inb(SIO_REG_VID_CTRL) & 0x80) /* VID input mode */ - data->vid = superio_inb(SIO_REG_VID_DATA) & 0x3f; - superio_exit(); -} - -static void w83627ehf_vrm(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results) -{ - struct w83627ehf_data *data = client->data; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 1; - else if (operation == SENSORS_PROC_REAL_READ) { - results[0] = data->vrm; - *nrels_mag = 1; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag >= 1) { - down(&data->update_lock); - /* We may have to change the VID input level */ - if (data->vrm/10 != 10 && results[0]/10 == 10) - w83627ehf_en_vrm10(data, 1); - else if (data->vrm/10 == 10 && results[0]/10 != 10) - w83627ehf_en_vrm10(data, 0); - data->vrm = results[0]; - up(&data->update_lock); - } - } -} - -static void w83627ehf_sensor(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results) -{ - struct w83627ehf_data *data = client->data; - int nr = ctl_name - W83627EHF_SYSCTL_SENSOR1; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - w83627ehf_update_client(client); - results[0] = data->sensor[nr]; - *nrels_mag = 1; - } -} - -static ctl_table w83627ehf_dir_table_template[] = { - {W83627EHF_SYSCTL_IN0, "in0", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83627ehf_in}, - {W83627EHF_SYSCTL_IN1, "in1", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83627ehf_in}, - {W83627EHF_SYSCTL_IN2, "in2", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83627ehf_in}, - {W83627EHF_SYSCTL_IN3, "in3", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83627ehf_in}, - {W83627EHF_SYSCTL_IN4, "in4", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83627ehf_in}, - {W83627EHF_SYSCTL_IN5, "in5", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83627ehf_in}, - {W83627EHF_SYSCTL_IN6, "in6", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83627ehf_in}, - {W83627EHF_SYSCTL_IN7, "in7", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83627ehf_in}, - {W83627EHF_SYSCTL_IN8, "in8", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83627ehf_in}, - {W83627EHF_SYSCTL_IN9, "in9", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83627ehf_in}, - - {W83627EHF_SYSCTL_FAN1, "fan1", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83627ehf_fan}, - {W83627EHF_SYSCTL_FAN2, "fan2", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83627ehf_fan}, - {W83627EHF_SYSCTL_FAN3, "fan3", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83627ehf_fan}, - {W83627EHF_SYSCTL_FAN4, "fan4", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83627ehf_fan}, - {W83627EHF_SYSCTL_FAN5, "fan5", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83627ehf_fan}, - - {W83627EHF_SYSCTL_TEMP1, "temp1", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83627ehf_temp}, - {W83627EHF_SYSCTL_TEMP2, "temp2", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83627ehf_temp}, - {W83627EHF_SYSCTL_TEMP3, "temp3", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83627ehf_temp}, - - /* manual adjust fan divisor not allowed */ - {W83627EHF_SYSCTL_FAN_DIV, "fan_div", NULL, 0, 0444, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &w83627ehf_fan_div}, - {W83627EHF_SYSCTL_ALARMS, "alarms", NULL, 0, 0444, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83627ehf_alarms}, - - {W83627EHF_SYSCTL_PWM1, "pwm1", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83627ehf_pwm}, - {W83627EHF_SYSCTL_PWM2, "pwm2", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83627ehf_pwm}, - {W83627EHF_SYSCTL_PWM3, "pwm3", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83627ehf_pwm}, - {W83627EHF_SYSCTL_PWM4, "pwm4", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83627ehf_pwm}, - - {W83627EHF_SYSCTL_VID, "vid", NULL, 0, 0444, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83627ehf_vid}, - {W83627EHF_SYSCTL_VRM, "vrm", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83627ehf_vrm}, - - {W83627EHF_SYSCTL_SENSOR1, "sensor1", NULL, 0, 0444, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83627ehf_sensor}, - {W83627EHF_SYSCTL_SENSOR2, "sensor2", NULL, 0, 0444, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83627ehf_sensor}, - {W83627EHF_SYSCTL_SENSOR3, "sensor3", NULL, 0, 0444, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83627ehf_sensor}, - {0} -}; - -/* - * Driver and client management - */ - -static struct i2c_driver w83627ehf_driver; - -static void w83627ehf_init_client(struct i2c_client *client) -{ - struct w83627ehf_data *data = client->data; - int i; - u8 tmp, diode; - - /* Start monitoring if needed */ - tmp = w83627ehf_read_value(client, W83627EHF_REG_CONFIG); - if (!(tmp & 0x01)) - w83627ehf_write_value(client, W83627EHF_REG_CONFIG, - tmp | 0x01); - - /* Enable temp2 and temp3 if needed */ - for (i = 0; i < 2; i++) { - tmp = w83627ehf_read_value(client, - W83627EHF_REG_TEMP_CONFIG[i]); - if (tmp & 0x01) - w83627ehf_write_value(client, - W83627EHF_REG_TEMP_CONFIG[i], - tmp & 0xfe); - } - - /* Enable VBAT monitoring if needed */ - tmp = w83627ehf_read_value(client, W83627EHF_REG_VBAT); - if (!(tmp & 0x01)) { - printk(KERN_INFO "w83627ehf: Enabling VBAT monitoring\n"); - w83627ehf_write_value(client, W83627EHF_REG_VBAT, tmp | 0x01); - } - - /* Get thermal sensor types */ - diode = w83627ehf_read_value(client, W83627EHF_REG_DIODE); - for (i = 0; i < 3; i++) { - if ((tmp & (0x02 << i))) - data->sensor[i] = (diode & (0x10 << i)) ? 1 : 2; - else - data->sensor[i] = 4; /* thermistor */ - } -} - -static int w83627ehf_detect(struct i2c_adapter *adapter, int address, - unsigned short flags, int kind) -{ - struct i2c_client *client; - struct w83627ehf_data *data; - u8 fan4pin, fan5pin; - int i, err; - - if (!i2c_is_isa_adapter(adapter)) - return -ENODEV; - - if (!request_region(address + REGION_OFFSET, REGION_LENGTH, - "w83627ehf")) { - printk(KERN_ERR "w83627ehf: Region 0x%x-0x%x already in " - "use!\n", address + REGION_OFFSET, - address + REGION_OFFSET + REGION_LENGTH - 1); - err = -EBUSY; - goto exit; - } - - if (!(data = kmalloc(sizeof(struct w83627ehf_data), GFP_KERNEL))) { - err = -ENOMEM; - goto exit_release; - } - memset(data, 0, sizeof(struct w83627ehf_data)); - - client = &data->client; - client->addr = address; - client->data = data; - client->adapter = adapter; - client->driver = &w83627ehf_driver; - strcpy(client->name, "W83627EHF chip"); - init_MUTEX(&data->lock); - init_MUTEX(&data->update_lock); - - /* Tell the i2c layer a new client has arrived */ - if ((err = i2c_attach_client(client))) - goto exit_free; - - w83627ehf_init_client(client); - - /* Read VID value */ - superio_enter(); - superio_select(W83627EHF_LD_HWM); - if (superio_inb(SIO_REG_VID_CTRL) & 0x80) /* VID input mode */ - data->vid = superio_inb(SIO_REG_VID_DATA) & 0x3f; - else { - printk(KERN_NOTICE "w83627ehf: VID pins in output mode, CPU " - "VID not available\n"); - data->vid = 0x3f; - } - - /* Wild guess, might not be correct */ - if (superio_inb(SIO_REG_EN_VRM10) & 0x08) - data->vrm = 100; - else - data->vrm = 91; - - /* fan4 and fan5 share some pins with the GPIO and serial flash */ - fan5pin = superio_inb(0x24) & 0x2; - fan4pin = superio_inb(0x29) & 0x6; - superio_exit(); - - /* It looks like fan4 and fan5 pins can be alternatively used - as fan on/off switches, but fan5 control is write only :/ - We assume that if the serial interface is disabled, designers - connected fan5 as input unless they are emitting log 1, which - is not the default. */ - - data->has_fan = 0x07; /* fan1, fan2 and fan3 */ - i = w83627ehf_read_value(client, W83627EHF_REG_FANDIV1); - if ((i & (1 << 2)) && (!fan4pin)) - data->has_fan |= (1 << 3); - if (!(i & (1 << 1)) && (!fan5pin)) - data->has_fan |= (1 << 4); - - /* Register a new directory entry with module sensors */ - if ((i = i2c_register_entry(client, - "w83627ehf", - w83627ehf_dir_table_template, - THIS_MODULE)) < 0) { - err = i; - goto exit_detach; - } - data->sysctl_id = i; - - return 0; - - exit_detach: - i2c_detach_client(client); - exit_free: - kfree(data); - exit_release: - release_region(address + REGION_OFFSET, REGION_LENGTH); - exit: - return err; - -} - -static int w83627ehf_attach_adapter(struct i2c_adapter *adapter) -{ - return i2c_detect(adapter, &addr_data, w83627ehf_detect); -} - -static int w83627ehf_detach_client(struct i2c_client *client) -{ - struct w83627ehf_data *data = client->data; - int err; - - i2c_deregister_entry(data->sysctl_id); - - if ((err = i2c_detach_client(client))) { - printk(KERN_ERR "w83627ehf: Client deregistration failed\n"); - return err; - } - - release_region(client->addr + REGION_OFFSET, REGION_LENGTH); - kfree(client->data); - - return 0; -} - -static struct i2c_driver w83627ehf_driver = { - .name = "w83627ehf", - .flags = I2C_DF_NOTIFY, - .attach_adapter = w83627ehf_attach_adapter, - .detach_client = w83627ehf_detach_client, -}; - -static int __init w83627ehf_find(int sioaddr, unsigned int *addr) -{ - u16 val; - const char *devname; - - REG = sioaddr; - VAL = sioaddr + 1; - superio_enter(); - - val = (superio_inb(SIO_REG_DEVID) << 8) - | superio_inb(SIO_REG_DEVID + 1); - switch (val & SIO_ID_MASK) { - case SIO_W83627EHF_ID: - devname = "W83627EHF"; - break; - case SIO_W83627EHG_ID: - devname = "W83627EHG"; - break; - default: - superio_exit(); - return -ENODEV; - } - - superio_select(W83627EHF_LD_HWM); - val = (superio_inb(SIO_REG_ADDR) << 8) - | superio_inb(SIO_REG_ADDR + 1); - *addr = val & REGION_ALIGNMENT; - if (*addr == 0) { - printk(KERN_ERR "w83627ehf: HWM I/O area not set\n"); - superio_exit(); - return -ENODEV; - } - - printk(KERN_INFO "w83627ehf: Found %s device at 0x%x\n", - devname, *addr); - - /* Activate logical device if needed */ - val = superio_inb(SIO_REG_ENABLE); - if (!(val & 0x01)) { - printk(KERN_WARNING "w83627ehf: HWM disabled, enabling\n"); - superio_outb(SIO_REG_ENABLE, val | 0x01); - } - - superio_exit(); - return 0; -} - -static int __init sensors_w83627ehf_init(void) -{ - printk(KERN_INFO "w83627ehf: Driver version %s (%s)\n", - LM_VERSION, LM_DATE); - if (w83627ehf_find(0x2e, &normal_isa[0]) - && w83627ehf_find(0x4e, &normal_isa[0])) - return -ENODEV; - - return i2c_add_driver(&w83627ehf_driver); -} - -static void __exit sensors_w83627ehf_exit(void) -{ - i2c_del_driver(&w83627ehf_driver); -} - -MODULE_AUTHOR("Yuan Mu (Winbond), Jean Delvare "); -MODULE_DESCRIPTION("W83627EHF harware monitoring driver"); -MODULE_LICENSE("GPL"); - -module_init(sensors_w83627ehf_init); -module_exit(sensors_w83627ehf_exit); diff --git a/kernel/chips/w83627hf.c b/kernel/chips/w83627hf.c deleted file mode 100644 index 688dd376..00000000 --- a/kernel/chips/w83627hf.c +++ /dev/null @@ -1,1506 +0,0 @@ -/* - w83627hf.c - Part of lm_sensors, Linux kernel modules for hardware - monitoring - Copyright (c) 1998 - 2003 Frodo Looijaard , - Philip Edelbrock , - and Mark Studebaker - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -/* - Supports following chips: - - Chip #vin #fanin #pwm #temp wchipid vendid i2c ISA - w83627hf 9 3 2 3 0x20 0x5ca3 no yes(LPC) - w83627thf 7 3 3 3 0x90 0x5ca3 no yes(LPC) - w83637hf 7 3 3 3 0x80 0x5ca3 no yes(LPC) - w83687thf 7 3 3 3 0x90 0x5ca3 no yes(LPC) - w83697hf 8 2 2 2 0x60 0x5ca3 no yes(LPC) - - For other winbond chips, and for i2c support in the above chips, - use w83781d.c. - - Note: automatic ("cruise") fan control for 697, 637 & 627thf not - supported yet. -*/ - -#include -#include -#include -#include -#include -#include -#include -#include "version.h" -#include "sensors_vid.h" -#include "lm75.h" - -static int force_addr; -MODULE_PARM(force_addr, "i"); -MODULE_PARM_DESC(force_addr, - "Initialize the base address of the sensors"); -static int force_i2c = 0x1f; -MODULE_PARM(force_i2c, "i"); -MODULE_PARM_DESC(force_i2c, - "Initialize the i2c address of the sensors"); - -/* Addresses to scan */ -static unsigned short normal_i2c[] = { SENSORS_I2C_END }; -static unsigned short normal_i2c_range[] = { SENSORS_I2C_END }; -static unsigned int normal_isa[] = { 0, SENSORS_ISA_END }; -static unsigned int normal_isa_range[] = { SENSORS_ISA_END }; - -/* Insmod parameters */ -SENSORS_INSMOD_5(w83627hf, w83627thf, w83697hf, w83637hf, w83687thf); - -static int init = 1; -MODULE_PARM(init, "i"); -MODULE_PARM_DESC(init, "Set to zero to bypass chip initialization"); - -/* modified from kernel/include/traps.c */ -static int REG; /* The register to read/write */ -#define DEV 0x07 /* Register: Logical device select */ -static int VAL; /* The value to read/write */ - -/* logical device numbers for superio_select (below) */ -#define W83627HF_LD_FDC 0x00 -#define W83627HF_LD_PRT 0x01 -#define W83627HF_LD_UART1 0x02 -#define W83627HF_LD_UART2 0x03 -#define W83627HF_LD_KBC 0x05 -#define W83627HF_LD_CIR 0x06 /* w83627hf only */ -#define W83627HF_LD_GAME 0x07 -#define W83627HF_LD_MIDI 0x07 -#define W83627HF_LD_GPIO1 0x07 -#define W83627HF_LD_GPIO5 0x07 /* w83627thf only */ -#define W83627HF_LD_GPIO2 0x08 -#define W83627HF_LD_GPIO3 0x09 -#define W83627HF_LD_GPIO4 0x09 /* w83627thf only */ -#define W83627HF_LD_ACPI 0x0a -#define W83627HF_LD_HWM 0x0b - -#define DEVID 0x20 /* Register: Device ID */ - -#define W83627THF_GPIO5_EN 0x30 /* w83627thf only */ -#define W83627THF_GPIO5_IOSR 0xf3 /* w83627thf only */ -#define W83627THF_GPIO5_DR 0xf4 /* w83627thf only */ - -#define W83687THF_VID_EN 0x29 /* w83687thf only */ -#define W83687THF_VID_CFG 0xF0 /* w83687thf only */ -#define W83687THF_VID_DATA 0xF1 /* w83687thf only */ - -static inline void -superio_outb(int reg, int val) -{ - outb(reg, REG); - outb(val, VAL); -} - -static inline int -superio_inb(int reg) -{ - outb(reg, REG); - return inb(VAL); -} - -static inline void -superio_select(int ld) -{ - outb(DEV, REG); - outb(ld, VAL); -} - -static inline void -superio_enter(void) -{ - outb(0x87, REG); - outb(0x87, REG); -} - -static inline void -superio_exit(void) -{ - outb(0xAA, REG); -} - -#define W627_DEVID 0x52 -#define W627THF_DEVID 0x82 -#define W697_DEVID 0x60 -#define W637_DEVID 0x70 -#define W687THF_DEVID 0x85 -#define WINB_ACT_REG 0x30 -#define WINB_BASE_REG 0x60 -/* Constants specified below */ - -/* Length of ISA address segment */ -#define WINB_EXTENT 8 - -/* Where are the ISA address/data registers relative to the base address */ -#define W83781D_ADDR_REG_OFFSET 5 -#define W83781D_DATA_REG_OFFSET 6 - -/* The W83781D registers */ -/* The W83782D registers for nr=7,8 are in bank 5 */ -#define W83781D_REG_IN_MAX(nr) ((nr < 7) ? (0x2b + (nr) * 2) : \ - (0x554 + (((nr) - 7) * 2))) -#define W83781D_REG_IN_MIN(nr) ((nr < 7) ? (0x2c + (nr) * 2) : \ - (0x555 + (((nr) - 7) * 2))) -#define W83781D_REG_IN(nr) ((nr < 7) ? (0x20 + (nr)) : \ - (0x550 + (nr) - 7)) - -#define W83781D_REG_FAN_MIN(nr) (0x3a + (nr)) -#define W83781D_REG_FAN(nr) (0x27 + (nr)) - -#define W83781D_REG_TEMP2 0x0150 -#define W83781D_REG_TEMP3 0x0250 -#define W83781D_REG_TEMP2_HYST 0x153 -#define W83781D_REG_TEMP3_HYST 0x253 -#define W83781D_REG_TEMP2_CONFIG 0x152 -#define W83781D_REG_TEMP3_CONFIG 0x252 -#define W83781D_REG_TEMP2_OVER 0x155 -#define W83781D_REG_TEMP3_OVER 0x255 - -#define W83781D_REG_TEMP 0x27 -#define W83781D_REG_TEMP_OVER 0x39 -#define W83781D_REG_TEMP_HYST 0x3A -#define W83781D_REG_BANK 0x4E - -#define W83781D_REG_CONFIG 0x40 -#define W83781D_REG_ALARM1 0x459 -#define W83781D_REG_ALARM2 0x45A -#define W83781D_REG_ALARM3 0x45B - -#define W83781D_REG_BEEP_CONFIG 0x4D -#define W83781D_REG_BEEP_INTS1 0x56 -#define W83781D_REG_BEEP_INTS2 0x57 -#define W83781D_REG_BEEP_INTS3 0x453 - -#define W83781D_REG_VID_FANDIV 0x47 - -#define W83781D_REG_CHIPID 0x49 -#define W83781D_REG_WCHIPID 0x58 -#define W83781D_REG_CHIPMAN 0x4F -#define W83781D_REG_PIN 0x4B - -#define W83781D_REG_VBAT 0x5D - -#define W83627HF_REG_PWM1 0x5A -#define W83627HF_REG_PWM2 0x5B - -#define W83627THF_REG_PWM1 0x01 /* 697HF/637HF/687THF too */ -#define W83627THF_REG_PWM2 0x03 /* 697HF/637HF/687THF too */ -#define W83627THF_REG_PWM3 0x11 /* 637HF/687THF too */ - -#define W83627THF_REG_VRM_OVT_CFG 0x18 /* 637HF/687THF too */ - -static const u8 regpwm_627hf[] = { W83627HF_REG_PWM1, W83627HF_REG_PWM2 }; -static const u8 regpwm[] = { W83627THF_REG_PWM1, W83627THF_REG_PWM2, - W83627THF_REG_PWM3 }; -#define W836X7HF_REG_PWM(type, nr) (((type) == w83627hf) ? \ - regpwm_627hf[(nr) - 1] : regpwm[(nr) - 1]) - -#define W83781D_REG_I2C_ADDR 0x48 -#define W83781D_REG_I2C_SUBADDR 0x4A - -/* Sensor selection */ -#define W83781D_REG_SCFG1 0x5D -static const u8 BIT_SCFG1[] = { 0x02, 0x04, 0x08 }; -#define W83781D_REG_SCFG2 0x59 -static const u8 BIT_SCFG2[] = { 0x10, 0x20, 0x40 }; -#define W83781D_DEFAULT_BETA 3435 - -/* Conversions. Limit checking is only done on the TO_REG - variants. Note that you should be a bit careful with which arguments - these macros are called: arguments may be evaluated more than once. - Fixing this is just not worth it. */ -#define IN_TO_REG(val) (SENSORS_LIMIT((((val) * 10 + 8)/16),0,255)) -#define IN_FROM_REG(val) (((val) * 16 + 5) / 10) - -#define IN_TO_REG_VRM9(val) \ - (SENSORS_LIMIT((((val) * 1000 - 70000 + 244) / 488), 0, 255)) -#define IN_FROM_REG_VRM9(reg) (((reg) * 488 + 70000 + 500) / 1000) - -static inline u8 FAN_TO_REG(long rpm, int div) -{ - if (rpm == 0) - return 255; - rpm = SENSORS_LIMIT(rpm, 1, 1000000); - return SENSORS_LIMIT((1350000 + rpm * div / 2) / (rpm * div), 1, - 254); -} - -#define TEMP_MIN (-1280) -#define TEMP_MAX ( 1270) - -/* TEMP: 1/10 degrees C (-128C to +127C) - REG: 1C/bit, two's complement */ -static u8 TEMP_TO_REG(int temp) -{ - int ntemp = SENSORS_LIMIT(temp, TEMP_MIN, TEMP_MAX); - ntemp += (ntemp<0 ? -5 : 5); - return (u8)(ntemp / 10); -} - -static int TEMP_FROM_REG(u8 reg) -{ - return (s8)reg * 10; -} - -#define FAN_FROM_REG(val,div) ((val)==0?-1:(val)==255?0:1350000/((val)*(div))) - -#define PWM_TO_REG(val) (SENSORS_LIMIT((val),0,255)) -#define BEEPS_TO_REG(val) ((val) & 0xffffff) - -#define BEEP_ENABLE_TO_REG(val) ((val)?1:0) -#define BEEP_ENABLE_FROM_REG(val) ((val)?1:0) - -#define DIV_FROM_REG(val) (1 << (val)) - -static inline u8 DIV_TO_REG(long val) -{ - int i; - val = SENSORS_LIMIT(val, 1, 128) >> 1; - for (i = 0; i < 7; i++) { - if (val == 0) - break; - val >>= 1; - } - return ((u8) i); -} - -/* For each registered chip, we need to keep some data in memory. It is - dynamically allocated, at the same time when a new client is allocated. */ -struct w83627hf_data { - struct i2c_client client; - struct semaphore lock; - int sysctl_id; - enum chips type; - - struct semaphore update_lock; - char valid; /* !=0 if following fields are valid */ - unsigned long last_updated; /* In jiffies */ - - u8 in[9]; /* Register value */ - u8 in_max[9]; /* Register value */ - u8 in_min[9]; /* Register value */ - u8 fan[3]; /* Register value */ - u8 fan_min[3]; /* Register value */ - u8 temp; - u8 temp_over; /* Register value */ - u8 temp_hyst; /* Register value */ - u16 temp_add[2]; /* Register value */ - u16 temp_add_over[2]; /* Register value */ - u16 temp_add_hyst[2]; /* Register value */ - u8 fan_div[3]; /* Register encoding, shifted right */ - u8 vid; /* Register encoding, combined */ - u32 alarms; /* Register encoding, combined */ - u32 beeps; /* Register encoding, combined */ - u8 beep_enable; /* Boolean */ - u8 pwm[3]; /* Register value */ - u16 sens[3]; /* 782D/783S only. - 1 = pentium diode; 2 = 3904 diode; - 3000-5000 = thermistor beta. - Default = 3435. - Other Betas unimplemented */ - u8 vrm; - u8 vrm_ovt; /* Register value, 627THF/637HF/687THF only */ -}; - - -static int w83627hf_attach_adapter(struct i2c_adapter *adapter); -static int w83627hf_detect(struct i2c_adapter *adapter, int address, - unsigned short flags, int kind); -static int w83627hf_detach_client(struct i2c_client *client); - -static int w83627hf_read_value(struct i2c_client *client, u16 register); -static int w83627hf_write_value(struct i2c_client *client, u16 register, - u16 value); -static void w83627hf_update_client(struct i2c_client *client); -static void w83627hf_init_client(struct i2c_client *client); - - -static void w83627hf_in(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void w83627hf_fan(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void w83627hf_temp(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void w83627hf_temp_add(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void w83627hf_vid(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void w83627hf_vrm(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void w83627hf_alarms(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void w83627hf_beep(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void w83627hf_fan_div(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void w83627hf_pwm(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void w83627hf_sens(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); - -static struct i2c_driver w83627hf_driver = { - .name = "W83627HF sensor driver", - .id = I2C_DRIVERID_W83627HF, - .flags = I2C_DF_NOTIFY, - .attach_adapter = w83627hf_attach_adapter, - .detach_client = w83627hf_detach_client, -}; - -/* The /proc/sys entries */ -/* WARNING these are copied from w83781d.c and have not been renamed. - Note that the 627hf is supported by both drivers. - Do not make incompatible changes here or we will have errors - in the generated file ../include/sensors.h !!! -*/ -/* -- SENSORS SYSCTL START -- */ - -#define W83781D_SYSCTL_IN0 1000 /* Volts * 100 */ -#define W83781D_SYSCTL_IN1 1001 -#define W83781D_SYSCTL_IN2 1002 -#define W83781D_SYSCTL_IN3 1003 -#define W83781D_SYSCTL_IN4 1004 -#define W83781D_SYSCTL_IN5 1005 -#define W83781D_SYSCTL_IN6 1006 -#define W83781D_SYSCTL_IN7 1007 -#define W83781D_SYSCTL_IN8 1008 -#define W83781D_SYSCTL_FAN1 1101 /* Rotations/min */ -#define W83781D_SYSCTL_FAN2 1102 -#define W83781D_SYSCTL_FAN3 1103 -#define W83781D_SYSCTL_TEMP1 1200 /* Degrees Celsius * 10 */ -#define W83781D_SYSCTL_TEMP2 1201 /* Degrees Celsius * 10 */ -#define W83781D_SYSCTL_TEMP3 1202 /* Degrees Celsius * 10 */ -#define W83781D_SYSCTL_VID 1300 /* Volts * 1000 */ -#define W83781D_SYSCTL_VRM 1301 -#define W83781D_SYSCTL_PWM1 1401 -#define W83781D_SYSCTL_PWM2 1402 -#define W83781D_SYSCTL_PWM3 1403 -#define W83781D_SYSCTL_SENS1 1501 /* 1, 2, or Beta (3000-5000) */ -#define W83781D_SYSCTL_SENS2 1502 -#define W83781D_SYSCTL_SENS3 1503 -#define W83781D_SYSCTL_FAN_DIV 2000 /* 1, 2, 4 or 8 */ -#define W83781D_SYSCTL_ALARMS 2001 /* bitvector */ -#define W83781D_SYSCTL_BEEP 2002 /* bitvector */ - -#define W83781D_ALARM_IN0 0x0001 -#define W83781D_ALARM_IN1 0x0002 -#define W83781D_ALARM_IN2 0x0004 -#define W83781D_ALARM_IN3 0x0008 -#define W83781D_ALARM_IN4 0x0100 -#define W83781D_ALARM_IN5 0x0200 -#define W83781D_ALARM_IN6 0x0400 -#define W83782D_ALARM_IN7 0x10000 -#define W83782D_ALARM_IN8 0x20000 -#define W83781D_ALARM_FAN1 0x0040 -#define W83781D_ALARM_FAN2 0x0080 -#define W83781D_ALARM_FAN3 0x0800 -#define W83781D_ALARM_TEMP1 0x0010 -#define W83781D_ALARM_TEMP23 0x0020 /* 781D only */ -#define W83781D_ALARM_TEMP2 0x0020 /* 782D/783S */ -#define W83781D_ALARM_TEMP3 0x2000 /* 782D only */ -#define W83781D_ALARM_CHAS 0x1000 - -/* -- SENSORS SYSCTL END -- */ - -/* These files are created for each detected chip. This is just a template; - though at first sight, you might think we could use a statically - allocated list, we need some way to get back to the parent - which - is done through one of the 'extra' fields which are initialized - when a new copy is allocated. */ - -/* without pwm3-4 */ -static ctl_table w83627hf_dir_table_template[] = { - {W83781D_SYSCTL_IN0, "in0", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83627hf_in}, - {W83781D_SYSCTL_IN1, "in1", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83627hf_in}, - {W83781D_SYSCTL_IN2, "in2", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83627hf_in}, - {W83781D_SYSCTL_IN3, "in3", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83627hf_in}, - {W83781D_SYSCTL_IN4, "in4", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83627hf_in}, - {W83781D_SYSCTL_IN5, "in5", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83627hf_in}, - {W83781D_SYSCTL_IN6, "in6", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83627hf_in}, - {W83781D_SYSCTL_IN7, "in7", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83627hf_in}, - {W83781D_SYSCTL_IN8, "in8", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83627hf_in}, - {W83781D_SYSCTL_FAN1, "fan1", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83627hf_fan}, - {W83781D_SYSCTL_FAN2, "fan2", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83627hf_fan}, - {W83781D_SYSCTL_FAN3, "fan3", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83627hf_fan}, - {W83781D_SYSCTL_TEMP1, "temp1", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83627hf_temp}, - {W83781D_SYSCTL_TEMP2, "temp2", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83627hf_temp_add}, - {W83781D_SYSCTL_TEMP3, "temp3", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83627hf_temp_add}, - {W83781D_SYSCTL_VID, "vid", NULL, 0, 0444, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83627hf_vid}, - {W83781D_SYSCTL_VRM, "vrm", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83627hf_vrm}, - {W83781D_SYSCTL_FAN_DIV, "fan_div", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83627hf_fan_div}, - {W83781D_SYSCTL_ALARMS, "alarms", NULL, 0, 0444, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83627hf_alarms}, - {W83781D_SYSCTL_BEEP, "beep", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83627hf_beep}, - {W83781D_SYSCTL_PWM1, "pwm1", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83627hf_pwm}, - {W83781D_SYSCTL_PWM2, "pwm2", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83627hf_pwm}, - {W83781D_SYSCTL_SENS1, "sensor1", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83627hf_sens}, - {W83781D_SYSCTL_SENS2, "sensor2", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83627hf_sens}, - {W83781D_SYSCTL_SENS3, "sensor3", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83627hf_sens}, - {0} -}; - -/* similar to w83782d but no fan3, no vid */ -static ctl_table w83697hf_dir_table_template[] = { - {W83781D_SYSCTL_IN0, "in0", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83627hf_in}, - /* no in1 to maintain compatibility with 781d and 782d. */ - {W83781D_SYSCTL_IN2, "in2", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83627hf_in}, - {W83781D_SYSCTL_IN3, "in3", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83627hf_in}, - {W83781D_SYSCTL_IN4, "in4", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83627hf_in}, - {W83781D_SYSCTL_IN5, "in5", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83627hf_in}, - {W83781D_SYSCTL_IN6, "in6", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83627hf_in}, - {W83781D_SYSCTL_IN7, "in7", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83627hf_in}, - {W83781D_SYSCTL_IN8, "in8", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83627hf_in}, - {W83781D_SYSCTL_FAN1, "fan1", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83627hf_fan}, - {W83781D_SYSCTL_FAN2, "fan2", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83627hf_fan}, - {W83781D_SYSCTL_TEMP1, "temp1", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83627hf_temp}, - {W83781D_SYSCTL_TEMP2, "temp2", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83627hf_temp_add}, - {W83781D_SYSCTL_FAN_DIV, "fan_div", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83627hf_fan_div}, - {W83781D_SYSCTL_ALARMS, "alarms", NULL, 0, 0444, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83627hf_alarms}, - {W83781D_SYSCTL_BEEP, "beep", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83627hf_beep}, - {W83781D_SYSCTL_PWM1, "pwm1", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83627hf_pwm}, - {W83781D_SYSCTL_PWM2, "pwm2", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83627hf_pwm}, - {W83781D_SYSCTL_SENS1, "sensor1", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83627hf_sens}, - {W83781D_SYSCTL_SENS2, "sensor2", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83627hf_sens}, - {0} -}; - -/* no in5 and in6 */ -/* We use this one for W83637HF and W83687THF too */ -static ctl_table w83627thf_dir_table_template[] = { - {W83781D_SYSCTL_IN0, "in0", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83627hf_in}, - {W83781D_SYSCTL_IN1, "in1", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83627hf_in}, - {W83781D_SYSCTL_IN2, "in2", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83627hf_in}, - {W83781D_SYSCTL_IN3, "in3", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83627hf_in}, - {W83781D_SYSCTL_IN4, "in4", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83627hf_in}, - {W83781D_SYSCTL_IN7, "in7", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83627hf_in}, - {W83781D_SYSCTL_IN8, "in8", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83627hf_in}, - {W83781D_SYSCTL_FAN1, "fan1", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83627hf_fan}, - {W83781D_SYSCTL_FAN2, "fan2", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83627hf_fan}, - {W83781D_SYSCTL_FAN3, "fan3", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83627hf_fan}, - {W83781D_SYSCTL_TEMP1, "temp1", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83627hf_temp}, - {W83781D_SYSCTL_TEMP2, "temp2", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83627hf_temp_add}, - {W83781D_SYSCTL_TEMP3, "temp3", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83627hf_temp_add}, - {W83781D_SYSCTL_VID, "vid", NULL, 0, 0444, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83627hf_vid}, - {W83781D_SYSCTL_VRM, "vrm", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83627hf_vrm}, - {W83781D_SYSCTL_FAN_DIV, "fan_div", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83627hf_fan_div}, - {W83781D_SYSCTL_ALARMS, "alarms", NULL, 0, 0444, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83627hf_alarms}, - {W83781D_SYSCTL_BEEP, "beep", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83627hf_beep}, - {W83781D_SYSCTL_PWM1, "pwm1", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83627hf_pwm}, - {W83781D_SYSCTL_PWM2, "pwm2", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83627hf_pwm}, - {W83781D_SYSCTL_PWM3, "pwm3", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83627hf_pwm}, - {W83781D_SYSCTL_SENS1, "sensor1", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83627hf_sens}, - {W83781D_SYSCTL_SENS2, "sensor2", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83627hf_sens}, - {W83781D_SYSCTL_SENS3, "sensor3", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83627hf_sens}, - {0} -}; - - -/* This function is called when: - * w83627hf_driver is inserted (when this module is loaded), for each - available adapter - * when a new adapter is inserted (and w83627hf_driver is still present) */ -static int w83627hf_attach_adapter(struct i2c_adapter *adapter) -{ - return i2c_detect(adapter, &addr_data, w83627hf_detect); -} - -static int __init w83627hf_find(int sioaddr, int *address) -{ - u16 val; - - REG = sioaddr; - VAL = sioaddr + 1; - - superio_enter(); - val= superio_inb(DEVID); - if (val != W627_DEVID && val != W627THF_DEVID && val != W697_DEVID - && val != W637_DEVID && val != W687THF_DEVID) { - superio_exit(); - return -ENODEV; - } - - superio_select(W83627HF_LD_HWM); - val = (superio_inb(WINB_BASE_REG) << 8) | - superio_inb(WINB_BASE_REG + 1); - *address = val & ~(WINB_EXTENT - 1); - if (*address == 0 && force_addr == 0) { - printk("w83627hf.o: base address not set - use force_addr=0xaddr\n"); - superio_exit(); - return -ENODEV; - } - if (force_addr) - *address = force_addr; /* so detect will get called */ - - superio_exit(); - return 0; -} - -int w83627hf_detect(struct i2c_adapter *adapter, int address, - unsigned short flags, int kind) -{ - int i, val; - struct i2c_client *new_client; - struct w83627hf_data *data; - int err = 0; - const char *type_name = ""; - const char *client_name = ""; - - if (!i2c_is_isa_adapter(adapter)) - return 0; - - if(force_addr) - address = force_addr & ~(WINB_EXTENT - 1); - if (check_region(address, WINB_EXTENT)) { - printk("w83627hf.o: region 0x%x already in use!\n", address); - return -ENODEV; - } - if(force_addr) { - printk("w83627hf.o: forcing ISA address 0x%04X\n", address); - superio_enter(); - superio_select(W83627HF_LD_HWM); - superio_outb(WINB_BASE_REG, address >> 8); - superio_outb(WINB_BASE_REG+1, address & 0xff); - superio_exit(); - } - - superio_enter(); - val= superio_inb(DEVID); - if(val == W627_DEVID) - kind = w83627hf; - else if(val == W697_DEVID) - kind = w83697hf; - else if(val == W627THF_DEVID) - kind = w83627thf; - else if(val == W637_DEVID) - kind = w83637hf; - else if (val == W687THF_DEVID) - kind = w83687thf; - - superio_select(W83627HF_LD_HWM); - if((val = 0x01 & superio_inb(WINB_ACT_REG)) == 0) - superio_outb(WINB_ACT_REG, 1); - superio_exit(); - - /* OK. For now, we presume we have a valid client. We now create the - client structure, even though we cannot fill it completely yet. - But it allows us to access w83627hf_{read,write}_value. */ - - if (!(data = kmalloc(sizeof(struct w83627hf_data), GFP_KERNEL))) { - err = -ENOMEM; - goto ERROR0; - } - - new_client = &data->client; - new_client->addr = address; - init_MUTEX(&data->lock); - new_client->data = data; - new_client->adapter = adapter; - new_client->driver = &w83627hf_driver; - new_client->flags = 0; - - - if (kind == w83627hf) { - type_name = "w83627hf"; - client_name = "W83627HF chip"; - } else if (kind == w83627thf) { - type_name = "w83627thf"; - client_name = "W83627THF chip"; - } else if (kind == w83697hf) { - type_name = "w83697hf"; - client_name = "W83697HF chip"; - } else if (kind == w83637hf) { - type_name = "w83637hf"; - client_name = "W83637HF chip"; - } else if (kind == w83687thf) { - type_name = "w83687thf"; - client_name = "W83687THF chip"; - } else { - goto ERROR1; - } - - request_region(address, WINB_EXTENT, type_name); - - /* Fill in the remaining client fields and put it into the global list */ - strcpy(new_client->name, client_name); - data->type = kind; - data->valid = 0; - init_MUTEX(&data->update_lock); - - /* Tell the I2C layer a new client has arrived */ - if ((err = i2c_attach_client(new_client))) - goto ERROR3; - - /* Register a new directory entry with module sensors */ - if ((i = i2c_register_entry(new_client, - type_name, - (kind == w83697hf) ? - w83697hf_dir_table_template : - (kind == w83627hf) ? - w83627hf_dir_table_template : - /* w83627thf table also used for 637HF - and 687THF */ - w83627thf_dir_table_template, - THIS_MODULE)) < 0) { - err = i; - goto ERROR7; - } - data->sysctl_id = i; - - /* Initialize the chip */ - w83627hf_init_client(new_client); - return 0; - -/* OK, this is not exactly good programming practice, usually. But it is - very code-efficient in this case. */ - -ERROR7: - i2c_detach_client(new_client); -ERROR3: - release_region(address, WINB_EXTENT); -ERROR1: - kfree(data); -ERROR0: - return err; -} - -static int w83627hf_detach_client(struct i2c_client *client) -{ - int err; - - i2c_deregister_entry(((struct w83627hf_data *) (client->data))-> - sysctl_id); - - if ((err = i2c_detach_client(client))) { - printk - (KERN_ERR "w83627hf.o: Client deregistration failed, client not detached.\n"); - return err; - } - - release_region(client->addr, WINB_EXTENT); - kfree(client->data); - - return 0; -} - - -/* - ISA access must always be locked explicitly! - We ignore the W83781D BUSY flag at this moment - it could lead to deadlocks, - would slow down the W83781D access and should not be necessary. - There are some ugly typecasts here, but the good news is - they should - nowhere else be necessary! */ -static int w83627hf_read_value(struct i2c_client *client, u16 reg) -{ - int res, word_sized; - - down(&(((struct w83627hf_data *) (client->data))->lock)); - word_sized = (((reg & 0xff00) == 0x100) - || ((reg & 0xff00) == 0x200)) - && (((reg & 0x00ff) == 0x50) - || ((reg & 0x00ff) == 0x53) - || ((reg & 0x00ff) == 0x55)); - if (reg & 0xff00) { - outb_p(W83781D_REG_BANK, - client->addr + W83781D_ADDR_REG_OFFSET); - outb_p(reg >> 8, - client->addr + W83781D_DATA_REG_OFFSET); - } - outb_p(reg & 0xff, client->addr + W83781D_ADDR_REG_OFFSET); - res = inb_p(client->addr + W83781D_DATA_REG_OFFSET); - if (word_sized) { - outb_p((reg & 0xff) + 1, - client->addr + W83781D_ADDR_REG_OFFSET); - res = - (res << 8) + inb_p(client->addr + - W83781D_DATA_REG_OFFSET); - } - if (reg & 0xff00) { - outb_p(W83781D_REG_BANK, - client->addr + W83781D_ADDR_REG_OFFSET); - outb_p(0, client->addr + W83781D_DATA_REG_OFFSET); - } - up(&(((struct w83627hf_data *) (client->data))->lock)); - return res; -} - -static int w83627thf_read_gpio5(struct i2c_client *client) -{ - int res = 0xff, sel; - - superio_enter(); - superio_select(W83627HF_LD_GPIO5); - - /* Make sure these GPIO pins are enabled */ - if (!(superio_inb(W83627THF_GPIO5_EN) & (1<<3))) { -#ifdef DEBUG - printk(KERN_DEBUG "w83627hf: GPIO5 disabled, no VID " - "function\n"); -#endif - goto exit; - } - - /* Make sure the pins are configured for input - There must be at least five (VRM 9), and possibly 6 (VRM 10) */ - sel = superio_inb(W83627THF_GPIO5_IOSR) & 0x3f; - if ((sel & 0x1f) != 0x1f) { -#ifdef DEBUG - printk(KERN_DEBUG "w83627hf: GPIO5 not configured for " - "VID function\n"); -#endif - goto exit; - } - - printk(KERN_INFO "w83627hf: Reading VID from GPIO5\n"); - res = superio_inb(W83627THF_GPIO5_DR) & sel; - -exit: - superio_exit(); - return res; -} - -static int w83687thf_read_vid(struct i2c_client *client) -{ - int res = 0xff; - - superio_enter(); - superio_select(W83627HF_LD_HWM); - - /* Make sure these GPIO pins are enabled */ - if (!(superio_inb(W83687THF_VID_EN) & (1 << 2))) { -#ifdef DEBUG - printk(KERN_DEBUG "w83627hf: VID disabled, no VID " - "function\n"); -#endif - goto exit; - } - - /* Make sure the pins are configured for input */ - if (!(superio_inb(W83687THF_VID_CFG) & (1 << 4))) { -#ifdef DEBUG - printk(KERN_DEBUG "w83627hf: VID configured as output, " - "no VID function\n"); -#endif - goto exit; - } - - res = superio_inb(W83687THF_VID_DATA) & 0x3f; - -exit: - superio_exit(); - return res; -} - -static int w83627hf_write_value(struct i2c_client *client, u16 reg, u16 value) -{ - int word_sized; - - down(&(((struct w83627hf_data *) (client->data))->lock)); - word_sized = (((reg & 0xff00) == 0x100) - || ((reg & 0xff00) == 0x200)) - && (((reg & 0x00ff) == 0x53) - || ((reg & 0x00ff) == 0x55)); - if (reg & 0xff00) { - outb_p(W83781D_REG_BANK, - client->addr + W83781D_ADDR_REG_OFFSET); - outb_p(reg >> 8, - client->addr + W83781D_DATA_REG_OFFSET); - } - outb_p(reg & 0xff, client->addr + W83781D_ADDR_REG_OFFSET); - if (word_sized) { - outb_p(value >> 8, - client->addr + W83781D_DATA_REG_OFFSET); - outb_p((reg & 0xff) + 1, - client->addr + W83781D_ADDR_REG_OFFSET); - } - outb_p(value & 0xff, - client->addr + W83781D_DATA_REG_OFFSET); - if (reg & 0xff00) { - outb_p(W83781D_REG_BANK, - client->addr + W83781D_ADDR_REG_OFFSET); - outb_p(0, client->addr + W83781D_DATA_REG_OFFSET); - } - up(&(((struct w83627hf_data *) (client->data))->lock)); - return 0; -} - -/* Called when we have found a new W83781D. */ -static void w83627hf_init_client(struct i2c_client *client) -{ - struct w83627hf_data *data = client->data; - int i; - int type = data->type; - u8 tmp; - - /* Minimize conflicts with other winbond i2c-only clients... */ - /* disable i2c subclients... how to disable main i2c client?? */ - /* force i2c address to relatively uncommon address */ - w83627hf_write_value(client, W83781D_REG_I2C_SUBADDR, 0x89); - w83627hf_write_value(client, W83781D_REG_I2C_ADDR, force_i2c); - - /* Read VID only once */ - if (w83627hf == data->type || w83637hf == data->type) { - int lo = w83627hf_read_value(client, W83781D_REG_VID_FANDIV); - int hi = w83627hf_read_value(client, W83781D_REG_CHIPID); - data->vid = (lo & 0x0f) | ((hi & 0x01) << 4); - } else if (w83627thf == data->type) { - data->vid = w83627thf_read_gpio5(client); - } else if (w83687thf == data->type) { - data->vid = w83687thf_read_vid(client); - } - - /* Read VRM & OVT Config only once */ - if (w83627thf == data->type || w83637hf == data->type - || w83687thf == data->type) - data->vrm_ovt = - w83627hf_read_value(client, W83627THF_REG_VRM_OVT_CFG); - else - data->vrm_ovt = 0; - - /* Choose VRM based on "VRM & OVT" register */ - data->vrm = (data->vrm_ovt & 0x01) ? 90 : 82; - - tmp = w83627hf_read_value(client, W83781D_REG_SCFG1); - for (i = 1; i <= 3; i++) { - if (!(tmp & BIT_SCFG1[i - 1])) { - data->sens[i - 1] = W83781D_DEFAULT_BETA; - } else { - if (w83627hf_read_value - (client, - W83781D_REG_SCFG2) & BIT_SCFG2[i - 1]) - data->sens[i - 1] = 1; - else - data->sens[i - 1] = 2; - } - if ((type == w83697hf) && (i == 2)) - break; - } - - if(init) { - /* Enable temp2 */ - tmp = w83627hf_read_value(client, W83781D_REG_TEMP2_CONFIG); - if (tmp & 0x01) { - printk(KERN_WARNING "w83627hf: temp2 was disabled, " - "readings might not make sense\n"); - w83627hf_write_value(client, W83781D_REG_TEMP2_CONFIG, - tmp & 0xfe); - } - - /* Enable temp3 */ - if (type != w83697hf) { - tmp = w83627hf_read_value(client, - W83781D_REG_TEMP3_CONFIG); - if (tmp & 0x01) { - printk(KERN_WARNING "w83627hf: temp3 was " - "disabled, readings might not make " - "sense\n"); - w83627hf_write_value(client, - W83781D_REG_TEMP3_CONFIG, tmp & 0xfe); - } - } - } - - /* Start monitoring */ - w83627hf_write_value(client, W83781D_REG_CONFIG, - (w83627hf_read_value(client, - W83781D_REG_CONFIG) & 0xf7) - | 0x01); - - /* Enable VBAT monitoring if needed */ - tmp = w83627hf_read_value(client, W83781D_REG_VBAT); - if (!(tmp & 0x01)) - w83627hf_write_value(client, W83781D_REG_VBAT, tmp | 0x01); -} - -static void w83627hf_update_client(struct i2c_client *client) -{ - struct w83627hf_data *data = client->data; - int i; - - down(&data->update_lock); - - if ((jiffies - data->last_updated > HZ + HZ / 2) || - (jiffies < data->last_updated) || !data->valid) { - for (i = 0; i <= 8; i++) { - /* skip missing sensors */ - if (((data->type == w83697hf) && (i == 1)) || - ((data->type == w83627thf || data->type == w83637hf - || data->type == w83687thf) && (i == 5 || i == 6))) - continue; - data->in[i] = - w83627hf_read_value(client, W83781D_REG_IN(i)); - data->in_min[i] = - w83627hf_read_value(client, - W83781D_REG_IN_MIN(i)); - data->in_max[i] = - w83627hf_read_value(client, - W83781D_REG_IN_MAX(i)); - } - for (i = 1; i <= 3; i++) { - data->fan[i - 1] = - w83627hf_read_value(client, W83781D_REG_FAN(i)); - data->fan_min[i - 1] = - w83627hf_read_value(client, - W83781D_REG_FAN_MIN(i)); - } - for (i = 1; i <= 3; i++) { - u8 tmp = w83627hf_read_value(client, - W836X7HF_REG_PWM(data->type, i)); - if (data->type == w83627thf) - tmp &= 0xf0; /* bits 0-3 are reserved in 627THF */ - data->pwm[i - 1] = tmp; - if(i == 2 && (data->type == w83627hf || data->type == w83697hf)) - break; - } - - data->temp = w83627hf_read_value(client, W83781D_REG_TEMP); - data->temp_over = - w83627hf_read_value(client, W83781D_REG_TEMP_OVER); - data->temp_hyst = - w83627hf_read_value(client, W83781D_REG_TEMP_HYST); - data->temp_add[0] = - w83627hf_read_value(client, W83781D_REG_TEMP2); - data->temp_add_over[0] = - w83627hf_read_value(client, W83781D_REG_TEMP2_OVER); - data->temp_add_hyst[0] = - w83627hf_read_value(client, W83781D_REG_TEMP2_HYST); - if (data->type != w83697hf) { - data->temp_add[1] = - w83627hf_read_value(client, W83781D_REG_TEMP3); - data->temp_add_over[1] = - w83627hf_read_value(client, W83781D_REG_TEMP3_OVER); - data->temp_add_hyst[1] = - w83627hf_read_value(client, W83781D_REG_TEMP3_HYST); - } - - i = w83627hf_read_value(client, W83781D_REG_VID_FANDIV); - data->fan_div[0] = (i >> 4) & 0x03; - data->fan_div[1] = (i >> 6) & 0x03; - if (data->type != w83697hf) { - data->fan_div[2] = (w83627hf_read_value(client, - W83781D_REG_PIN) >> 6) & 0x03; - } - i = w83627hf_read_value(client, W83781D_REG_VBAT); - data->fan_div[0] |= (i >> 3) & 0x04; - data->fan_div[1] |= (i >> 4) & 0x04; - if (data->type != w83697hf) - data->fan_div[2] |= (i >> 5) & 0x04; - data->alarms = - w83627hf_read_value(client, W83781D_REG_ALARM1) | - (w83627hf_read_value(client, W83781D_REG_ALARM2) << 8) | - (w83627hf_read_value(client, W83781D_REG_ALARM3) << 16); - i = w83627hf_read_value(client, W83781D_REG_BEEP_INTS2); - data->beep_enable = i >> 7; - data->beeps = ((i & 0x7f) << 8) | - w83627hf_read_value(client, W83781D_REG_BEEP_INTS1) | - w83627hf_read_value(client, W83781D_REG_BEEP_INTS3) << 16; - data->last_updated = jiffies; - data->valid = 1; - } - - up(&data->update_lock); -} - -void w83627hf_in(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct w83627hf_data *data = client->data; - int nr = ctl_name - W83781D_SYSCTL_IN0; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 2; - else if (operation == SENSORS_PROC_REAL_READ) { - w83627hf_update_client(client); - - if (nr == 0 && (data->vrm_ovt & 0x01)) { - /* use VRM9 calculation */ - results[0] = IN_FROM_REG_VRM9(data->in_min[0]); - results[1] = IN_FROM_REG_VRM9(data->in_max[0]); - results[2] = IN_FROM_REG_VRM9(data->in[0]); - - } else { - /* use VRM8 (standard) calculation */ - results[0] = IN_FROM_REG(data->in_min[nr]); - results[1] = IN_FROM_REG(data->in_max[nr]); - results[2] = IN_FROM_REG(data->in[nr]); - } - - *nrels_mag = 3; - - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag >= 1) { - if (nr == 0 && (data->vrm_ovt & 0x01)) - /* use VRM9 calculation */ - data->in_min[0] = IN_TO_REG_VRM9(results[0]); - else - /* use VRM8 (standard) calculation */ - data->in_min[nr] = IN_TO_REG(results[0]); - - w83627hf_write_value(client, W83781D_REG_IN_MIN(nr), - data->in_min[nr]); - } - if (*nrels_mag >= 2) { - if (nr == 0 && (data->vrm_ovt & 0x01)) - /* use VRM9 calculation */ - data->in_max[0] = IN_TO_REG_VRM9(results[1]); - else - /* use VRM8 (standard) calculation */ - data->in_max[nr] = IN_TO_REG(results[1]); - - w83627hf_write_value(client, W83781D_REG_IN_MAX(nr), - data->in_max[nr]); - } - } -} - -void w83627hf_fan(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct w83627hf_data *data = client->data; - int nr = ctl_name - W83781D_SYSCTL_FAN1 + 1; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - w83627hf_update_client(client); - results[0] = FAN_FROM_REG(data->fan_min[nr - 1], - DIV_FROM_REG(data->fan_div[nr - 1])); - results[1] = FAN_FROM_REG(data->fan[nr - 1], - DIV_FROM_REG(data->fan_div[nr - 1])); - *nrels_mag = 2; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag >= 1) { - data->fan_min[nr - 1] = - FAN_TO_REG(results[0], - DIV_FROM_REG(data->fan_div[nr-1])); - w83627hf_write_value(client, - W83781D_REG_FAN_MIN(nr), - data->fan_min[nr - 1]); - } - } -} - -void w83627hf_temp(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct w83627hf_data *data = client->data; - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 1; - else if (operation == SENSORS_PROC_REAL_READ) { - w83627hf_update_client(client); - results[0] = TEMP_FROM_REG(data->temp_over); - results[1] = TEMP_FROM_REG(data->temp_hyst); - results[2] = TEMP_FROM_REG(data->temp); - *nrels_mag = 3; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag >= 1) { - data->temp_over = TEMP_TO_REG(results[0]); - w83627hf_write_value(client, W83781D_REG_TEMP_OVER, - data->temp_over); - } - if (*nrels_mag >= 2) { - data->temp_hyst = TEMP_TO_REG(results[1]); - w83627hf_write_value(client, W83781D_REG_TEMP_HYST, - data->temp_hyst); - } - } -} - -void w83627hf_temp_add(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results) -{ - struct w83627hf_data *data = client->data; - int nr = ctl_name - W83781D_SYSCTL_TEMP2; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 1; - else if (operation == SENSORS_PROC_REAL_READ) { - w83627hf_update_client(client); - results[0] = - LM75_TEMP_FROM_REG(data->temp_add_over[nr]); - results[1] = - LM75_TEMP_FROM_REG(data->temp_add_hyst[nr]); - results[2] = LM75_TEMP_FROM_REG(data->temp_add[nr]); - *nrels_mag = 3; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag >= 1) { - data->temp_add_over[nr] = - LM75_TEMP_TO_REG(results[0]); - w83627hf_write_value(client, - nr ? W83781D_REG_TEMP3_OVER : - W83781D_REG_TEMP2_OVER, - data->temp_add_over[nr]); - } - if (*nrels_mag >= 2) { - data->temp_add_hyst[nr] = - LM75_TEMP_TO_REG(results[1]); - w83627hf_write_value(client, - nr ? W83781D_REG_TEMP3_HYST : - W83781D_REG_TEMP2_HYST, - data->temp_add_hyst[nr]); - } - } -} - -void w83627hf_vid(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct w83627hf_data *data = client->data; - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 3; - else if (operation == SENSORS_PROC_REAL_READ) { - if (data->vid == 0xff) - results[0] = 0; - else - results[0] = vid_from_reg(data->vid, data->vrm); - *nrels_mag = 1; - } -} - -void w83627hf_vrm(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct w83627hf_data *data = client->data; - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 1; - else if (operation == SENSORS_PROC_REAL_READ) { - results[0] = data->vrm; - *nrels_mag = 1; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag >= 1) - data->vrm = results[0]; - } -} - -void w83627hf_alarms(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct w83627hf_data *data = client->data; - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - w83627hf_update_client(client); - results[0] = data->alarms; - *nrels_mag = 1; - } -} - -void w83627hf_beep(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct w83627hf_data *data = client->data; - int val; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - w83627hf_update_client(client); - results[0] = BEEP_ENABLE_FROM_REG(data->beep_enable); - results[1] = data->beeps; - *nrels_mag = 2; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag >= 2) { - data->beeps = BEEPS_TO_REG(results[1]); - w83627hf_write_value(client, W83781D_REG_BEEP_INTS1, - data->beeps & 0xff); - w83627hf_write_value(client, - W83781D_REG_BEEP_INTS3, - ((data-> beeps) >> 16) & - 0xff); - val = (data->beeps >> 8) & 0x7f; - } else if (*nrels_mag >= 1) - val = - w83627hf_read_value(client, - W83781D_REG_BEEP_INTS2) & - 0x7f; - if (*nrels_mag >= 1) { - data->beep_enable = BEEP_ENABLE_TO_REG(results[0]); - w83627hf_write_value(client, W83781D_REG_BEEP_INTS2, - val | data->beep_enable << 7); - } - } -} - -/* w83697hf only has two fans */ -void w83627hf_fan_div(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results) -{ - struct w83627hf_data *data = client->data; - int old, old2, old3 = 0; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - w83627hf_update_client(client); - results[0] = DIV_FROM_REG(data->fan_div[0]); - results[1] = DIV_FROM_REG(data->fan_div[1]); - if (data->type == w83697hf) { - *nrels_mag = 2; - } else { - results[2] = DIV_FROM_REG(data->fan_div[2]); - *nrels_mag = 3; - } - } else if (operation == SENSORS_PROC_REAL_WRITE) { - unsigned long min = 0; - - old = w83627hf_read_value(client, W83781D_REG_VID_FANDIV); - /* w83627hf doesn't have extended divisor bits */ - old3 = w83627hf_read_value(client, W83781D_REG_VBAT); - if (*nrels_mag >= 3 && data->type != w83697hf) { - min = FAN_FROM_REG(data->fan_min[2], - DIV_FROM_REG(data->fan_div[2])); - data->fan_div[2] = DIV_TO_REG(results[2]); - old2 = w83627hf_read_value(client, W83781D_REG_PIN); - old2 = (old2 & 0x3f) - | ((data->fan_div[2] & 0x03) << 6); - w83627hf_write_value(client, W83781D_REG_PIN, old2); - old3 = (old3 & 0x7f) - | ((data->fan_div[2] & 0x04) << 5); - data->fan_min[2] = FAN_TO_REG(min, - DIV_FROM_REG(data->fan_div[2])); - w83627hf_write_value(client, W83781D_REG_FAN_MIN(3), - data->fan_min[2]); - } - if (*nrels_mag >= 2) { - min = FAN_FROM_REG(data->fan_min[1], - DIV_FROM_REG(data->fan_div[1])); - data->fan_div[1] = DIV_TO_REG(results[1]); - old = (old & 0x3f) - | ((data->fan_div[1] & 0x03) << 6); - old3 = (old3 & 0xbf) - | ((data->fan_div[1] & 0x04) << 4); - data->fan_min[1] = FAN_TO_REG(min, - DIV_FROM_REG(data->fan_div[1])); - w83627hf_write_value(client, W83781D_REG_FAN_MIN(2), - data->fan_min[1]); - } - if (*nrels_mag >= 1) { - min = FAN_FROM_REG(data->fan_min[0], - DIV_FROM_REG(data->fan_div[0])); - data->fan_div[0] = DIV_TO_REG(results[0]); - old = (old & 0xcf) - | ((data->fan_div[0] & 0x03) << 4); - w83627hf_write_value(client, W83781D_REG_VID_FANDIV, - old); - old3 = (old3 & 0xdf) - | ((data->fan_div[0] & 0x04) << 3); - w83627hf_write_value(client, W83781D_REG_VBAT, - old3); - data->fan_min[0] = FAN_TO_REG(min, - DIV_FROM_REG(data->fan_div[0])); - w83627hf_write_value(client, W83781D_REG_FAN_MIN(1), - data->fan_min[0]); - } - } -} - -/* we do not currently support disabling PWM with 2nd argument; - set first argument to 255 to disable */ -void w83627hf_pwm(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct w83627hf_data *data = client->data; - int nr = 1 + ctl_name - W83781D_SYSCTL_PWM1; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - w83627hf_update_client(client); - results[0] = data->pwm[nr - 1]; - *nrels_mag = 1; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag >= 1) { - if (data->type == w83627thf) { - /* bits 0-3 are reserved in 627THF */ - data->pwm[nr - 1] = PWM_TO_REG(results[0]) & 0xf0; - w83627hf_write_value(client, - W836X7HF_REG_PWM(data->type, nr), - data->pwm[nr - 1] | - (w83627hf_read_value(client, - W836X7HF_REG_PWM(data->type, nr)) & 0x0f)); - } else { - data->pwm[nr - 1] = PWM_TO_REG(results[0]); - w83627hf_write_value(client, - W836X7HF_REG_PWM(data->type, nr), - data->pwm[nr - 1]); - } - } - } -} - -void w83627hf_sens(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct w83627hf_data *data = client->data; - int nr = 1 + ctl_name - W83781D_SYSCTL_SENS1; - u8 tmp; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - results[0] = data->sens[nr - 1]; - *nrels_mag = 1; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag >= 1) { - switch (results[0]) { - case 1: /* PII/Celeron diode */ - tmp = w83627hf_read_value(client, - W83781D_REG_SCFG1); - w83627hf_write_value(client, - W83781D_REG_SCFG1, - tmp | BIT_SCFG1[nr - - 1]); - tmp = w83627hf_read_value(client, - W83781D_REG_SCFG2); - w83627hf_write_value(client, - W83781D_REG_SCFG2, - tmp | BIT_SCFG2[nr - - 1]); - data->sens[nr - 1] = results[0]; - break; - case 2: /* 3904 */ - tmp = w83627hf_read_value(client, - W83781D_REG_SCFG1); - w83627hf_write_value(client, - W83781D_REG_SCFG1, - tmp | BIT_SCFG1[nr - - 1]); - tmp = w83627hf_read_value(client, - W83781D_REG_SCFG2); - w83627hf_write_value(client, - W83781D_REG_SCFG2, - tmp & ~BIT_SCFG2[nr - - 1]); - data->sens[nr - 1] = results[0]; - break; - case W83781D_DEFAULT_BETA: /* thermistor */ - tmp = w83627hf_read_value(client, - W83781D_REG_SCFG1); - w83627hf_write_value(client, - W83781D_REG_SCFG1, - tmp & ~BIT_SCFG1[nr - - 1]); - data->sens[nr - 1] = results[0]; - break; - default: - printk - (KERN_ERR "w83627hf.o: Invalid sensor type %ld; must be 1, 2, or %d\n", - results[0], W83781D_DEFAULT_BETA); - break; - } - } - } -} - -static int __init sm_w83627hf_init(void) -{ - int addr; - - printk(KERN_INFO "w83627hf.o version %s (%s)\n", LM_VERSION, LM_DATE); - if (w83627hf_find(0x2e, &addr) - && w83627hf_find(0x4e, &addr)) { - printk("w83627hf.o: W83627/697 not detected, module not inserted.\n"); - return -ENODEV; - } - normal_isa[0] = addr; - - return i2c_add_driver(&w83627hf_driver); -} - -static void __exit sm_w83627hf_exit(void) -{ - i2c_del_driver(&w83627hf_driver); -} - - - -MODULE_AUTHOR("Frodo Looijaard , " - "Philip Edelbrock , " - "and Mark Studebaker "); -MODULE_DESCRIPTION("W83627HF driver"); -MODULE_LICENSE("GPL"); - -module_init(sm_w83627hf_init); -module_exit(sm_w83627hf_exit); diff --git a/kernel/chips/w83781d.c b/kernel/chips/w83781d.c deleted file mode 100644 index 5b7f6401..00000000 --- a/kernel/chips/w83781d.c +++ /dev/null @@ -1,1883 +0,0 @@ -/* - w83781d.c - Part of lm_sensors, Linux kernel modules for hardware - monitoring - Copyright (c) 1998 - 2003 Frodo Looijaard , - Philip Edelbrock , - and Mark Studebaker - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -/* - Supports following chips: - - Chip #vin #fanin #pwm #temp wchipid vendid i2c ISA - as99127f 7 3 0 3 0x31 0x12c3 yes no - as99127f rev.2 (type name = as99127f) 0x31 0x5ca3 yes no - w83627hf 9 3 2 3 0x21 0x5ca3 yes yes(LPC) - w83781d 7 3 0 3 0x10-1 0x5ca3 yes yes - w83782d 9 3 2-4 3 0x30 0x5ca3 yes yes - w83783s 5-6 3 2 1-2 0x40 0x5ca3 yes no - w83791d 10 5 5 3 0x71 0x5ca3 yes no - -*/ - -#include -#include -#include -#include -#include -#include -#include -#include "version.h" -#include "sensors_vid.h" -#include "lm75.h" - -/* RT Table support #defined so we can take it out if it gets bothersome */ -#define W83781D_RT 1 - -/* Addresses to scan */ -static unsigned short normal_i2c[] = { SENSORS_I2C_END }; -static unsigned short normal_i2c_range[] = { 0x20, 0x2f, SENSORS_I2C_END }; -static unsigned int normal_isa[] = { 0x0290, SENSORS_ISA_END }; -static unsigned int normal_isa_range[] = { SENSORS_ISA_END }; - -/* Insmod parameters */ -SENSORS_INSMOD_6(w83781d, w83782d, w83783s, w83627hf, as99127f, w83791d); -SENSORS_MODULE_PARM(force_subclients, "List of subclient addresses: " \ - "{bus, clientaddr, subclientaddr1, subclientaddr2}"); - -static int init = 1; -MODULE_PARM(init, "i"); -MODULE_PARM_DESC(init, "Set to zero to bypass chip initialization"); - -/* Constants specified below */ - -/* Length of ISA address segment */ -#define W83781D_EXTENT 8 - -/* Where are the ISA address/data registers relative to the base address */ -#define W83781D_ADDR_REG_OFFSET 5 -#define W83781D_DATA_REG_OFFSET 6 - -/* The W83781D registers */ -/* The W83782D registers for nr=7,8 are in bank 5 */ -#define W83781D_REG_IN_MAX(nr) ((nr < 7) ? (0x2b + (nr) * 2) : \ - (0x554 + (((nr) - 7) * 2))) -#define W83781D_REG_IN_MIN(nr) ((nr < 7) ? (0x2c + (nr) * 2) : \ - (0x555 + (((nr) - 7) * 2))) -#define W83781D_REG_IN(nr) ((nr < 7) ? (0x20 + (nr)) : \ - (0x550 + (nr) - 7)) - -#define W83791D_REG_IN_MAX(nr) ((nr < 7) ? (0x2b + (nr) * 2) : \ - (0xb4 + (((nr) - 7) * 2))) -#define W83791D_REG_IN_MIN(nr) ((nr < 7) ? (0x2c + (nr) * 2) : \ - (0xb5 + (((nr) - 7) * 2))) -#define W83791D_REG_IN(nr) ((nr < 7) ? (0x20 + (nr)) : \ - (0xb0 + (nr) - 7)) - -#define W83781D_REG_FAN_MIN(nr) ((nr < 4) ? (0x3a + (nr)) : \ - (0xba + (nr) - 4)) -#define W83781D_REG_FAN(nr) ((nr < 4) ? (0x27 + (nr)) : \ - (0xbc + (nr) - 4)) - -#define W83781D_REG_TEMP2 0x0150 -#define W83781D_REG_TEMP3 0x0250 -#define W83781D_REG_TEMP2_HYST 0x153 -#define W83781D_REG_TEMP3_HYST 0x253 -#define W83781D_REG_TEMP2_CONFIG 0x152 -#define W83781D_REG_TEMP3_CONFIG 0x252 -#define W83781D_REG_TEMP2_OVER 0x155 -#define W83781D_REG_TEMP3_OVER 0x255 - -#define W83781D_REG_TEMP 0x27 -#define W83781D_REG_TEMP_OVER 0x39 -#define W83781D_REG_TEMP_HYST 0x3A -#define W83781D_REG_BANK 0x4E - -#define W83781D_REG_CONFIG 0x40 - -/* Interrupt status (W83781D, AS99127F) */ -#define W83781D_REG_ALARM1 0x41 -#define W83781D_REG_ALARM2 0x42 - -/* Real-time status (W83782D, W83783S, W83627HF) */ -#define W83782D_REG_ALARM1 0x459 -#define W83782D_REG_ALARM2 0x45A -#define W83782D_REG_ALARM3 0x45B - -/* Real-time status (W83791D) */ -#define W83791D_REG_ALARM1 0xA9 -#define W83791D_REG_ALARM2 0xAA -#define W83791D_REG_ALARM3 0xAB - -#define W83781D_REG_BEEP_CONFIG 0x4D -#define W83781D_REG_BEEP_INTS1 0x56 -#define W83781D_REG_BEEP_INTS2 0x57 -#define W83781D_REG_BEEP_INTS3 0x453 /* not on W83781D */ - -#define W83781D_REG_VID_FANDIV 0x47 - -#define W83781D_REG_CHIPID 0x49 -#define W83781D_REG_WCHIPID 0x58 -#define W83781D_REG_CHIPMAN 0x4F -#define W83781D_REG_PIN 0x4B - -/* 782D/783S/791D only */ -#define W83781D_REG_VBAT 0x5D - -/* PWM 782D (1-4) and 783S (1-2) only */ -#define W83781D_REG_PWM1 0x5B /* 782d and 783s/627hf datasheets disagree */ - /* on which is which; */ -#define W83781D_REG_PWM2 0x5A /* We follow the 782d convention here, */ - /* However 782d is probably wrong. */ -#define W83781D_REG_PWM3 0x5E -#define W83781D_REG_PWM4 0x5F -#define W83781D_REG_PWMCLK12 0x5C -#define W83781D_REG_PWMCLK34 0x45C - -#define W83791D_REG_PWM1 0x81 -#define W83791D_REG_PWM2 0x83 -#define W83791D_REG_PWM3 0x94 - -#define W83627HF_REG_PWM1 0x01 -#define W83627HF_REG_PWM2 0x03 -#define W83627HF_REG_PWMCLK1 0x00 -#define W83627HF_REG_PWMCLK2 0x02 - -static const u8 regpwm[] = { W83781D_REG_PWM1, W83781D_REG_PWM2, - W83781D_REG_PWM3, W83781D_REG_PWM4 -}; - -static const u8 regpwm_w83791d[] = { W83791D_REG_PWM1, W83791D_REG_PWM2, - W83791D_REG_PWM3 -}; - -#define W83781D_REG_PWM(type, nr) (((type) == w83791d) ? \ - regpwm_w83791d[(nr) - 1] : \ - regpwm[(nr) - 1]) - -#define W83781D_REG_I2C_ADDR 0x48 -#define W83781D_REG_I2C_SUBADDR 0x4A - -/* The following are undocumented in the data sheets however we - received the information in an email from Winbond tech support */ -/* Sensor selection - not on 781d */ -#define W83781D_REG_SCFG1 0x5D -static const u8 BIT_SCFG1[] = { 0x02, 0x04, 0x08 }; -#define W83781D_REG_SCFG2 0x59 -static const u8 BIT_SCFG2[] = { 0x10, 0x20, 0x40 }; -#define W83781D_DEFAULT_BETA 3435 - -/* RT Table registers */ -#define W83781D_REG_RT_IDX 0x50 -#define W83781D_REG_RT_VAL 0x51 - -/* Conversions. Rounding and limit checking is only done on the TO_REG - variants. Note that you should be a bit careful with which arguments - these macros are called: arguments may be evaluated more than once. - Fixing this is just not worth it. */ -#define IN_TO_REG(val) (SENSORS_LIMIT((((val) * 10 + 8)/16),0,255)) -#define IN_FROM_REG(val) (((val) * 16 + 5) / 10) - -static inline u8 FAN_TO_REG(long rpm, int div) -{ - if (rpm == 0) - return 255; - rpm = SENSORS_LIMIT(rpm, 1, 1000000); - return SENSORS_LIMIT((1350000 + rpm * div / 2) / (rpm * div), 1, - 254); -} - -#define FAN_FROM_REG(val,div) ((val)==0?-1:(val)==255?0:1350000/((val)*(div))) - -#define TEMP_TO_REG(val) (SENSORS_LIMIT(((val)<0?(((val)-5)/10):\ - ((val)+5)/10),0,255)) -#define TEMP_FROM_REG(val) (((val)>0x80?(val)-0x100:(val))*10) - -#define ALARMS_FROM_REG(val) (val) -#define PWM_FROM_REG(val) (val) -#define PWM_TO_REG(val) (SENSORS_LIMIT((val),0,255)) -#define BEEPS_FROM_REG(val,type) ((type)==as99127f?(val)^0x7FFF:(val)) -#define BEEPS_TO_REG(val,type) ((type)==as99127f?(~(val))&0x7FFF:(val)&0xffffff) - -#define BEEP_ENABLE_TO_REG(val) ((val)?1:0) -#define BEEP_ENABLE_FROM_REG(val) ((val)?1:0) - -#define DIV_FROM_REG(val) (1 << (val)) - -static inline u8 DIV_TO_REG(long val, enum chips type) -{ - int i; - val = SENSORS_LIMIT(val, 1, - ((type == w83781d || type == as99127f) ? 8 : 128)) >> 1; - for (i = 0; i < 7; i++) { - if (val == 0) - break; - val >>= 1; - } - return ((u8) i); -} - -/* There are some complications in a module like this. First off, W83781D chips - may be both present on the SMBus and the ISA bus, and we have to handle - those cases separately at some places. Second, there might be several - W83781D chips available (well, actually, that is probably never done; but - it is a clean illustration of how to handle a case like that). Finally, - a specific chip may be attached to *both* ISA and SMBus, and we would - not like to detect it double. Fortunately, in the case of the W83781D at - least, a register tells us what SMBus address we are on, so that helps - a bit - except if there could be more than one SMBus. Groan. No solution - for this yet. */ - -/* This module may seem overly long and complicated. In fact, it is not so - bad. Quite a lot of bookkeeping is done. A real driver can often cut - some corners. */ - -/* For each registered W83781D, we need to keep some data in memory. It is - dynamically allocated, at the same time when a new w83781d client is - allocated. */ -struct w83781d_data { - struct i2c_client client; - struct semaphore lock; - int sysctl_id; - enum chips type; - - struct semaphore update_lock; - char valid; /* !=0 if following fields are valid */ - unsigned long last_updated; /* In jiffies */ - - struct i2c_client *lm75; /* for secondary I2C addresses */ - /* pointer to array of 2 subclients */ - - u8 in[10]; /* Register value - 8 & 9 for 782D and 791D only 10 for 791D */ - u8 in_max[10]; /* Register value - 8 & 9 for 782D and 791D only 10 for 791D */ - u8 in_min[10]; /* Register value - 8 & 9 for 782D and 791D only 10 for 791D */ - u8 fan[5]; /* Register value - 4 & 5 for 791D only */ - u8 fan_min[5]; /* Register value - 4 & 5 for 791D only */ - u8 temp; - u8 temp_over; /* Register value */ - u8 temp_hyst; /* Register value */ - u16 temp_add[2]; /* Register value */ - u16 temp_add_over[2]; /* Register value */ - u16 temp_add_hyst[2]; /* Register value */ - u8 fan_div[3]; /* Register encoding, shifted right */ - u8 vid; /* Register encoding, combined */ - u32 alarms; /* Register encoding, combined */ - u32 beeps; /* Register encoding, combined */ - u8 beep_enable; /* Boolean */ - u8 pwm[4]; /* Register value */ - u8 pwmenable[4]; /* bool */ - u16 sens[3]; /* 782D/783S only. - 1 = pentium diode; 2 = 3904 diode; - 3000-5000 = thermistor beta. - Default = 3435. - Other Betas unimplemented */ -#ifdef W83781D_RT - u8 rt[3][32]; /* Register value */ -#endif - u8 vrm; -}; - - -static int w83781d_attach_adapter(struct i2c_adapter *adapter); -static int w83781d_detect(struct i2c_adapter *adapter, int address, - unsigned short flags, int kind); -static int w83781d_detach_client(struct i2c_client *client); - -static int w83781d_read_value(struct i2c_client *client, u16 register); -static int w83781d_write_value(struct i2c_client *client, u16 register, - u16 value); -static void w83781d_update_client(struct i2c_client *client); -static void w83781d_init_client(struct i2c_client *client); - - -static void w83781d_in(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void w83781d_fan(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void w83781d_temp(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void w83781d_temp_add(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void w83781d_vid(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void w83781d_vrm(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void w83781d_alarms(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void w83781d_beep(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void w83781d_fan_div(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void w83781d_pwm(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void w83781d_sens(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -#ifdef W83781D_RT -static void w83781d_rt(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -#endif - -static struct i2c_driver w83781d_driver = { - .name = "W83781D sensor driver", - .id = I2C_DRIVERID_W83781D, - .flags = I2C_DF_NOTIFY, - .attach_adapter = w83781d_attach_adapter, - .detach_client = w83781d_detach_client, -}; - -/* The /proc/sys entries */ -/* -- SENSORS SYSCTL START -- */ - -#define W83781D_SYSCTL_IN0 1000 /* Volts * 100 */ -#define W83781D_SYSCTL_IN1 1001 -#define W83781D_SYSCTL_IN2 1002 -#define W83781D_SYSCTL_IN3 1003 -#define W83781D_SYSCTL_IN4 1004 -#define W83781D_SYSCTL_IN5 1005 -#define W83781D_SYSCTL_IN6 1006 -#define W83781D_SYSCTL_IN7 1007 -#define W83781D_SYSCTL_IN8 1008 -#define W83781D_SYSCTL_IN9 1009 -#define W83781D_SYSCTL_FAN1 1101 /* Rotations/min */ -#define W83781D_SYSCTL_FAN2 1102 -#define W83781D_SYSCTL_FAN3 1103 -#define W83781D_SYSCTL_FAN4 1104 -#define W83781D_SYSCTL_FAN5 1105 - -#define W83781D_SYSCTL_TEMP1 1200 /* Degrees Celsius * 10 */ -#define W83781D_SYSCTL_TEMP2 1201 /* Degrees Celsius * 10 */ -#define W83781D_SYSCTL_TEMP3 1202 /* Degrees Celsius * 10 */ -#define W83781D_SYSCTL_VID 1300 /* Volts * 1000 */ -#define W83781D_SYSCTL_VRM 1301 -#define W83781D_SYSCTL_PWM1 1401 -#define W83781D_SYSCTL_PWM2 1402 -#define W83781D_SYSCTL_PWM3 1403 -#define W83781D_SYSCTL_PWM4 1404 -#define W83781D_SYSCTL_SENS1 1501 /* 1, 2, or Beta (3000-5000) */ -#define W83781D_SYSCTL_SENS2 1502 -#define W83781D_SYSCTL_SENS3 1503 -#define W83781D_SYSCTL_RT1 1601 /* 32-entry table */ -#define W83781D_SYSCTL_RT2 1602 /* 32-entry table */ -#define W83781D_SYSCTL_RT3 1603 /* 32-entry table */ -#define W83781D_SYSCTL_FAN_DIV 2000 /* 1, 2, 4 or 8 */ -#define W83781D_SYSCTL_ALARMS 2001 /* bitvector */ -#define W83781D_SYSCTL_BEEP 2002 /* bitvector */ - -#define W83781D_ALARM_IN0 0x0001 -#define W83781D_ALARM_IN1 0x0002 -#define W83781D_ALARM_IN2 0x0004 -#define W83781D_ALARM_IN3 0x0008 -#define W83781D_ALARM_IN4 0x0100 -#define W83781D_ALARM_IN5 0x0200 -#define W83781D_ALARM_IN6 0x0400 -#define W83782D_ALARM_IN7 0x10000 -#define W83782D_ALARM_IN8 0x20000 -#define W83791D_ALARM_IN7 0x080000 /* 791D only */ -#define W83791D_ALARM_IN8 0x100000 /* 791D only */ -#define W83791D_ALARM_IN9 0x004000 /* 791D only */ -#define W83781D_ALARM_FAN1 0x0040 -#define W83781D_ALARM_FAN2 0x0080 -#define W83781D_ALARM_FAN3 0x0800 -#define W83791D_ALARM_FAN4 0x200000 /* 791D only */ -#define W83791D_ALARM_FAN5 0x400000 /* 791D only */ -#define W83781D_ALARM_TEMP1 0x0010 -#define W83781D_ALARM_TEMP23 0x0020 /* 781D only */ -#define W83781D_ALARM_TEMP2 0x0020 /* 782D/783S/791D */ -#define W83781D_ALARM_TEMP3 0x2000 /* 782D/791D */ -#define W83781D_ALARM_CHAS 0x1000 /* 782D/791D */ - -#define W83791D_BEEP_IN1 0x002000 /* 791D only */ -#define W83791D_BEEP_IN7 0x010000 /* 791D only */ -#define W83791D_BEEP_IN8 0x020000 /* 791D only */ -#define W83791D_BEEP_TEMP3 0x000002 /* 791D only */ - -/* -- SENSORS SYSCTL END -- */ - -/* These files are created for each detected chip. This is just a template; - though at first sight, you might think we could use a statically - allocated list, we need some way to get back to the parent - which - is done through one of the 'extra' fields which are initialized - when a new copy is allocated. */ - -/* just a guess - no datasheet */ -static ctl_table as99127f_dir_table_template[] = { - {W83781D_SYSCTL_IN0, "in0", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83781d_in}, - {W83781D_SYSCTL_IN1, "in1", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83781d_in}, - {W83781D_SYSCTL_IN2, "in2", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83781d_in}, - {W83781D_SYSCTL_IN3, "in3", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83781d_in}, - {W83781D_SYSCTL_IN4, "in4", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83781d_in}, - {W83781D_SYSCTL_IN5, "in5", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83781d_in}, - {W83781D_SYSCTL_IN6, "in6", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83781d_in}, - {W83781D_SYSCTL_FAN1, "fan1", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83781d_fan}, - {W83781D_SYSCTL_FAN2, "fan2", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83781d_fan}, - {W83781D_SYSCTL_FAN3, "fan3", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83781d_fan}, - {W83781D_SYSCTL_TEMP1, "temp1", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83781d_temp}, - {W83781D_SYSCTL_TEMP2, "temp2", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83781d_temp_add}, - {W83781D_SYSCTL_TEMP3, "temp3", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83781d_temp_add}, - {W83781D_SYSCTL_VID, "vid", NULL, 0, 0444, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83781d_vid}, - {W83781D_SYSCTL_VRM, "vrm", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83781d_vrm}, - {W83781D_SYSCTL_FAN_DIV, "fan_div", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83781d_fan_div}, - {W83781D_SYSCTL_ALARMS, "alarms", NULL, 0, 0444, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83781d_alarms}, - {W83781D_SYSCTL_BEEP, "beep", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83781d_beep}, - {0} -}; - -static ctl_table w83781d_dir_table_template[] = { - {W83781D_SYSCTL_IN0, "in0", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83781d_in}, - {W83781D_SYSCTL_IN1, "in1", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83781d_in}, - {W83781D_SYSCTL_IN2, "in2", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83781d_in}, - {W83781D_SYSCTL_IN3, "in3", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83781d_in}, - {W83781D_SYSCTL_IN4, "in4", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83781d_in}, - {W83781D_SYSCTL_IN5, "in5", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83781d_in}, - {W83781D_SYSCTL_IN6, "in6", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83781d_in}, - {W83781D_SYSCTL_FAN1, "fan1", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83781d_fan}, - {W83781D_SYSCTL_FAN2, "fan2", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83781d_fan}, - {W83781D_SYSCTL_FAN3, "fan3", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83781d_fan}, - {W83781D_SYSCTL_TEMP1, "temp1", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83781d_temp}, - {W83781D_SYSCTL_TEMP2, "temp2", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83781d_temp_add}, - {W83781D_SYSCTL_TEMP3, "temp3", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83781d_temp_add}, - {W83781D_SYSCTL_VID, "vid", NULL, 0, 0444, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83781d_vid}, - {W83781D_SYSCTL_VRM, "vrm", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83781d_vrm}, - {W83781D_SYSCTL_FAN_DIV, "fan_div", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83781d_fan_div}, - {W83781D_SYSCTL_ALARMS, "alarms", NULL, 0, 0444, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83781d_alarms}, - {W83781D_SYSCTL_BEEP, "beep", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83781d_beep}, -#ifdef W83781D_RT - {W83781D_SYSCTL_RT1, "rt1", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83781d_rt}, - {W83781D_SYSCTL_RT2, "rt2", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83781d_rt}, - {W83781D_SYSCTL_RT3, "rt3", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83781d_rt}, -#endif - {0} -}; - -/* without pwm3-4 */ -static ctl_table w83782d_isa_dir_table_template[] = { - {W83781D_SYSCTL_IN0, "in0", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83781d_in}, - {W83781D_SYSCTL_IN1, "in1", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83781d_in}, - {W83781D_SYSCTL_IN2, "in2", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83781d_in}, - {W83781D_SYSCTL_IN3, "in3", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83781d_in}, - {W83781D_SYSCTL_IN4, "in4", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83781d_in}, - {W83781D_SYSCTL_IN5, "in5", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83781d_in}, - {W83781D_SYSCTL_IN6, "in6", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83781d_in}, - {W83781D_SYSCTL_IN7, "in7", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83781d_in}, - {W83781D_SYSCTL_IN8, "in8", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83781d_in}, - {W83781D_SYSCTL_FAN1, "fan1", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83781d_fan}, - {W83781D_SYSCTL_FAN2, "fan2", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83781d_fan}, - {W83781D_SYSCTL_FAN3, "fan3", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83781d_fan}, - {W83781D_SYSCTL_TEMP1, "temp1", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83781d_temp}, - {W83781D_SYSCTL_TEMP2, "temp2", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83781d_temp_add}, - {W83781D_SYSCTL_TEMP3, "temp3", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83781d_temp_add}, - {W83781D_SYSCTL_VID, "vid", NULL, 0, 0444, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83781d_vid}, - {W83781D_SYSCTL_VRM, "vrm", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83781d_vrm}, - {W83781D_SYSCTL_FAN_DIV, "fan_div", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83781d_fan_div}, - {W83781D_SYSCTL_ALARMS, "alarms", NULL, 0, 0444, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83781d_alarms}, - {W83781D_SYSCTL_BEEP, "beep", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83781d_beep}, - {W83781D_SYSCTL_PWM1, "pwm1", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83781d_pwm}, - {W83781D_SYSCTL_PWM2, "pwm2", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83781d_pwm}, - {W83781D_SYSCTL_SENS1, "sensor1", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83781d_sens}, - {W83781D_SYSCTL_SENS2, "sensor2", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83781d_sens}, - {W83781D_SYSCTL_SENS3, "sensor3", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83781d_sens}, - {0} -}; - -/* with pwm3-4 */ -static ctl_table w83782d_i2c_dir_table_template[] = { - {W83781D_SYSCTL_IN0, "in0", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83781d_in}, - {W83781D_SYSCTL_IN1, "in1", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83781d_in}, - {W83781D_SYSCTL_IN2, "in2", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83781d_in}, - {W83781D_SYSCTL_IN3, "in3", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83781d_in}, - {W83781D_SYSCTL_IN4, "in4", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83781d_in}, - {W83781D_SYSCTL_IN5, "in5", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83781d_in}, - {W83781D_SYSCTL_IN6, "in6", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83781d_in}, - {W83781D_SYSCTL_IN7, "in7", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83781d_in}, - {W83781D_SYSCTL_IN8, "in8", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83781d_in}, - {W83781D_SYSCTL_FAN1, "fan1", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83781d_fan}, - {W83781D_SYSCTL_FAN2, "fan2", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83781d_fan}, - {W83781D_SYSCTL_FAN3, "fan3", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83781d_fan}, - {W83781D_SYSCTL_TEMP1, "temp1", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83781d_temp}, - {W83781D_SYSCTL_TEMP2, "temp2", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83781d_temp_add}, - {W83781D_SYSCTL_TEMP3, "temp3", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83781d_temp_add}, - {W83781D_SYSCTL_VID, "vid", NULL, 0, 0444, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83781d_vid}, - {W83781D_SYSCTL_VRM, "vrm", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83781d_vrm}, - {W83781D_SYSCTL_FAN_DIV, "fan_div", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83781d_fan_div}, - {W83781D_SYSCTL_ALARMS, "alarms", NULL, 0, 0444, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83781d_alarms}, - {W83781D_SYSCTL_BEEP, "beep", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83781d_beep}, - {W83781D_SYSCTL_PWM1, "pwm1", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83781d_pwm}, - {W83781D_SYSCTL_PWM2, "pwm2", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83781d_pwm}, - {W83781D_SYSCTL_PWM3, "pwm3", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83781d_pwm}, - {W83781D_SYSCTL_PWM4, "pwm4", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83781d_pwm}, - {W83781D_SYSCTL_SENS1, "sensor1", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83781d_sens}, - {W83781D_SYSCTL_SENS2, "sensor2", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83781d_sens}, - {W83781D_SYSCTL_SENS3, "sensor3", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83781d_sens}, - {0} -}; - -/* w83791D has 10 voltages 5 fans and 3 temps. 2 of the temps are on other - devices. */ -static ctl_table w83791d_dir_table_template[] = { - {W83781D_SYSCTL_IN0, "in0", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83781d_in}, - {W83781D_SYSCTL_IN1, "in1", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83781d_in}, - {W83781D_SYSCTL_IN2, "in2", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83781d_in}, - {W83781D_SYSCTL_IN3, "in3", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83781d_in}, - {W83781D_SYSCTL_IN4, "in4", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83781d_in}, - {W83781D_SYSCTL_IN5, "in5", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83781d_in}, - {W83781D_SYSCTL_IN6, "in6", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83781d_in}, - {W83781D_SYSCTL_IN7, "in7", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83781d_in}, - {W83781D_SYSCTL_IN8, "in8", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83781d_in}, - {W83781D_SYSCTL_IN9, "in9", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83781d_in}, - {W83781D_SYSCTL_FAN1, "fan1", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83781d_fan}, - {W83781D_SYSCTL_FAN2, "fan2", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83781d_fan}, - {W83781D_SYSCTL_FAN3, "fan3", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83781d_fan}, - {W83781D_SYSCTL_FAN4, "fan4", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83781d_fan}, - {W83781D_SYSCTL_FAN5, "fan5", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83781d_fan}, - {W83781D_SYSCTL_TEMP1, "temp1", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83781d_temp}, - {W83781D_SYSCTL_TEMP2, "temp2", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83781d_temp_add}, - {W83781D_SYSCTL_TEMP3, "temp3", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83781d_temp_add}, - {W83781D_SYSCTL_VID, "vid", NULL, 0, 0444, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83781d_vid}, - {W83781D_SYSCTL_FAN_DIV, "fan_div", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83781d_fan_div}, - {W83781D_SYSCTL_ALARMS, "alarms", NULL, 0, 0444, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83781d_alarms}, - {W83781D_SYSCTL_BEEP, "beep", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83781d_beep}, - {W83781D_SYSCTL_PWM1, "pwm1", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83781d_pwm}, - {W83781D_SYSCTL_PWM2, "pwm2", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83781d_pwm}, - {W83781D_SYSCTL_PWM3, "pwm3", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83781d_pwm}, - {W83781D_SYSCTL_PWM4, "pwm4", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83781d_pwm}, - {W83781D_SYSCTL_VRM, "vrm", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83781d_vrm}, - {0} -}; - -static ctl_table w83783s_dir_table_template[] = { - {W83781D_SYSCTL_IN0, "in0", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83781d_in}, - /* no in1 to maintain compatibility with 781d and 782d. */ - {W83781D_SYSCTL_IN2, "in2", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83781d_in}, - {W83781D_SYSCTL_IN3, "in3", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83781d_in}, - {W83781D_SYSCTL_IN4, "in4", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83781d_in}, - {W83781D_SYSCTL_IN5, "in5", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83781d_in}, - {W83781D_SYSCTL_IN6, "in6", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83781d_in}, - {W83781D_SYSCTL_FAN1, "fan1", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83781d_fan}, - {W83781D_SYSCTL_FAN2, "fan2", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83781d_fan}, - {W83781D_SYSCTL_FAN3, "fan3", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83781d_fan}, - {W83781D_SYSCTL_TEMP1, "temp1", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83781d_temp}, - {W83781D_SYSCTL_TEMP2, "temp2", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83781d_temp_add}, - {W83781D_SYSCTL_VID, "vid", NULL, 0, 0444, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83781d_vid}, - {W83781D_SYSCTL_VRM, "vrm", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83781d_vrm}, - {W83781D_SYSCTL_FAN_DIV, "fan_div", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83781d_fan_div}, - {W83781D_SYSCTL_ALARMS, "alarms", NULL, 0, 0444, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83781d_alarms}, - {W83781D_SYSCTL_BEEP, "beep", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83781d_beep}, - {W83781D_SYSCTL_PWM1, "pwm1", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83781d_pwm}, - {W83781D_SYSCTL_PWM2, "pwm2", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83781d_pwm}, - {W83781D_SYSCTL_SENS1, "sensor1", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83781d_sens}, - {W83781D_SYSCTL_SENS2, "sensor2", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83781d_sens}, - {0} -}; - - -/* This function is called when: - * w83781d_driver is inserted (when this module is loaded), for each - available adapter - * when a new adapter is inserted (and w83781d_driver is still present) */ -static int w83781d_attach_adapter(struct i2c_adapter *adapter) -{ - return i2c_detect(adapter, &addr_data, w83781d_detect); -} - -static int w83781d_detect(struct i2c_adapter *adapter, int address, - unsigned short flags, int kind) -{ - int i, val1 = 0, val2, id; - struct i2c_client *new_client; - struct w83781d_data *data; - int err = 0; - const char *type_name = ""; - const char *client_name = ""; - int is_isa = i2c_is_isa_adapter(adapter); - enum vendor { winbond, asus } vendid; - - if (!is_isa - && !i2c_check_functionality(adapter, - I2C_FUNC_SMBUS_BYTE_DATA)) goto - ERROR0; - - if (is_isa) { - if (!request_region(address, W83781D_EXTENT, "w83781d")) - goto ERROR0; - release_region(address, W83781D_EXTENT); - } - - /* Probe whether there is anything available on this address. Already - done for SMBus clients */ - if (kind < 0) { - if (is_isa) { - -#define REALLY_SLOW_IO - /* We need the timeouts for at least some LM78-like chips. But only - if we read 'undefined' registers. */ - i = inb_p(address + 1); - if (inb_p(address + 2) != i) - goto ERROR0; - if (inb_p(address + 3) != i) - goto ERROR0; - if (inb_p(address + 7) != i) - goto ERROR0; -#undef REALLY_SLOW_IO - - /* Let's just hope nothing breaks here */ - i = inb_p(address + 5) & 0x7f; - outb_p(~i & 0x7f, address + 5); - if ((inb_p(address + 5) & 0x7f) != (~i & 0x7f)) { - outb_p(i, address + 5); - return 0; - } - } - } - - /* OK. For now, we presume we have a valid client. We now create the - client structure, even though we cannot fill it completely yet. - But it allows us to access w83781d_{read,write}_value. */ - - if (!(data = kmalloc(sizeof(struct w83781d_data), GFP_KERNEL))) { - err = -ENOMEM; - goto ERROR0; - } - - new_client = &data->client; - new_client->addr = address; - init_MUTEX(&data->lock); - new_client->data = data; - new_client->adapter = adapter; - new_client->driver = &w83781d_driver; - new_client->flags = 0; - - /* Now, we do the remaining detection. */ - - /* The w8378?d may be stuck in some other bank than bank 0. This may - make reading other information impossible. Specify a force=... or - force_*=... parameter, and the Winbond will be reset to the right - bank. */ - if (kind < 0) { - if (w83781d_read_value(new_client, W83781D_REG_CONFIG) & - 0x80) - goto ERROR1; - - val1 = w83781d_read_value(new_client, W83781D_REG_BANK); - val2 = w83781d_read_value(new_client, W83781D_REG_CHIPMAN); - /* Check for Winbond or Asus ID if in bank 0 */ - if ((!(val1 & 0x07)) && - (((!(val1 & 0x80)) && (val2 != 0xa3) && (val2 != 0xc3)) - || ((val1 & 0x80) && (val2 != 0x5c) && (val2 != 0x12)))) - goto ERROR1; - - /* If Winbond SMBus, check address at 0x48. - Asus doesn't support, except for the as99127f rev.2 */ - if ((!is_isa) && (((!(val1 & 0x80)) && (val2 == 0xa3)) || - ((val1 & 0x80) && (val2 == 0x5c)))) { - if (w83781d_read_value - (new_client, W83781D_REG_I2C_ADDR) != address) - goto ERROR1; - } - } - - /* We have either had a force parameter, or we have already detected the - Winbond. Put it now into bank 0 and Vendor ID High Byte */ - w83781d_write_value(new_client, W83781D_REG_BANK, - (w83781d_read_value(new_client, - W83781D_REG_BANK) & 0x78) | - 0x80); - - /* Determine the chip type. */ - if (kind <= 0) { - /* get vendor ID */ - val2 = w83781d_read_value(new_client, W83781D_REG_CHIPMAN); - if (val2 == 0x5c) - vendid = winbond; - else if (val2 == 0x12) - vendid = asus; - else - goto ERROR1; - - val1 = - w83781d_read_value(new_client, W83781D_REG_WCHIPID); - if ((val1 == 0x10 || val1 == 0x11) && vendid == winbond) - kind = w83781d; - else if (val1 == 0x30 && vendid == winbond) - kind = w83782d; - else if (val1 == 0x40 && vendid == winbond && !is_isa && address == 0x2d) - kind = w83783s; - else if (val1 == 0x21 && vendid == winbond) - kind = w83627hf; - else if (val1 == 0x71 && vendid == winbond && address >= 0x2c) - kind = w83791d; - else if (val1 == 0x31 && !is_isa && address >= 0x28) - kind = as99127f; - else { - if (kind == 0) - printk(KERN_WARNING "w83781d.o: Ignoring " - "'force' parameter for unknown chip " - "at adapter %d, address 0x%02x\n", - i2c_adapter_id(adapter), address); - goto ERROR1; - } - } - - if (kind == w83781d) { - type_name = "w83781d"; - client_name = "W83781D chip"; - } else if (kind == w83782d) { - type_name = "w83782d"; - client_name = "W83782D chip"; - } else if (kind == w83783s) { - type_name = "w83783s"; - client_name = "W83783S chip"; - } else if (kind == w83627hf) { - type_name = "w83627hf"; - client_name = "W83627HF chip"; - } else if (kind == as99127f) { - type_name = "as99127f"; - client_name = "AS99127F chip"; - } else if (kind == w83791d) { - type_name = "w83791d"; - client_name = "W83791D chip"; - } else { -#ifdef DEBUG - printk(KERN_ERR "w83781d.o: Internal error: unknown kind (%d)\n", - kind); -#endif - err = -ENODEV; - goto ERROR1; - } - - /* Reserve the ISA region */ - if (is_isa) - request_region(address, W83781D_EXTENT, type_name); - - /* Fill in the remaining client fields and put it into the global list */ - strcpy(new_client->name, client_name); - data->type = kind; - data->valid = 0; - init_MUTEX(&data->update_lock); - - /* Tell the I2C layer a new client has arrived */ - if ((err = i2c_attach_client(new_client))) - goto ERROR3; - - /* attach secondary i2c lm75-like clients */ - if (!is_isa) { - if (!(data->lm75 = kmalloc(2 * sizeof(struct i2c_client), - GFP_KERNEL))) { - err = -ENOMEM; - goto ERROR4; - } - id = i2c_adapter_id(adapter); - if(force_subclients[0] == id && force_subclients[1] == address) { - for(i = 2; i <= 3; i++) { - if(force_subclients[i] < 0x48 || - force_subclients[i] > 0x4f) { - printk(KERN_ERR "w83781d.o: Invalid subclient address %d; must be 0x48-0x4f\n", - force_subclients[i]); - goto ERROR5; - } - } - w83781d_write_value(new_client, - W83781D_REG_I2C_SUBADDR, - (force_subclients[2] & 0x07) | - ((force_subclients[3] & 0x07) <<4)); - data->lm75[0].addr = force_subclients[2]; - } else { - val1 = w83781d_read_value(new_client, - W83781D_REG_I2C_SUBADDR); - data->lm75[0].addr = 0x48 + (val1 & 0x07); - } - if (kind != w83783s) { - if(force_subclients[0] == id && - force_subclients[1] == address) { - data->lm75[1].addr = force_subclients[3]; - } else { - data->lm75[1].addr = 0x48 + ((val1 >> 4) & 0x07); - } - if(data->lm75[0].addr == data->lm75[1].addr) { - printk(KERN_ERR "w83781d.o: Duplicate addresses 0x%x for subclients.\n", - data->lm75[0].addr); - goto ERROR5; - } - } - if (kind == w83781d) - client_name = "W83781D subclient"; - else if (kind == w83782d) - client_name = "W83782D subclient"; - else if (kind == w83783s) - client_name = "W83783S subclient"; - else if (kind == w83627hf) - client_name = "W83627HF subclient"; - else if (kind == as99127f) - client_name = "AS99127F subclient"; - else if (kind == w83791d) - client_name = "W83791D subclient"; - - - for (i = 0; i <= 1; i++) { - data->lm75[i].data = NULL; /* store all data in w83781d */ - data->lm75[i].adapter = adapter; - data->lm75[i].driver = &w83781d_driver; - data->lm75[i].flags = 0; - strcpy(data->lm75[i].name, client_name); - if ((err = i2c_attach_client(&(data->lm75[i])))) { - printk(KERN_ERR "w83781d.o: Subclient %d registration at address 0x%x failed.\n", - i, data->lm75[i].addr); - if (i == 1) - goto ERROR6; - goto ERROR5; - } - if (kind == w83783s) - break; - } - } else { - data->lm75 = NULL; - } - - /* Register a new directory entry with module sensors */ - if ((i = i2c_register_entry(new_client, - type_name, - (kind == as99127f) ? - as99127f_dir_table_template : - (kind == w83781d) ? - w83781d_dir_table_template : - (kind == w83783s) ? - w83783s_dir_table_template : - (kind == w83791d ) ? - w83791d_dir_table_template : - (is_isa || kind == w83627hf) ? - w83782d_isa_dir_table_template : - w83782d_i2c_dir_table_template, - THIS_MODULE)) < 0) { - err = i; - goto ERROR7; - } - data->sysctl_id = i; - - /* Only PWM2 can be disabled */ - for(i = 0; i < 4; i++) - data->pwmenable[i] = 1; - - /* Initialize the chip */ - w83781d_init_client(new_client); - return 0; - -/* OK, this is not exactly good programming practice, usually. But it is - very code-efficient in this case. */ - - ERROR7: - if (!is_isa) - i2c_detach_client(& - (((struct - w83781d_data *) (new_client->data))-> - lm75[1])); - ERROR6: - if (!is_isa) - i2c_detach_client(& - (((struct - w83781d_data *) (new_client->data))-> - lm75[0])); - ERROR5: - if (!is_isa) - kfree(((struct w83781d_data *) (new_client->data))->lm75); - ERROR4: - i2c_detach_client(new_client); - ERROR3: - if (is_isa) - release_region(address, W83781D_EXTENT); - ERROR1: - kfree(data); - ERROR0: - return err; -} - -static int w83781d_detach_client(struct i2c_client *client) -{ - int err; - struct w83781d_data *data = client->data; - - i2c_deregister_entry(data->sysctl_id); - - if ((err = i2c_detach_client(client))) { - printk - (KERN_ERR "w83781d.o: Client deregistration failed, client not detached.\n"); - return err; - } - - if(i2c_is_isa_client(client)) { - release_region(client->addr, W83781D_EXTENT); - } else { - i2c_detach_client(&(data->lm75[0])); - if (data->type != w83783s) - i2c_detach_client(&(data->lm75[1])); - kfree(data->lm75); - } - kfree(data); - - return 0; -} - -/* The SMBus locks itself, usually, but nothing may access the Winbond between - bank switches. ISA access must always be locked explicitly! - We ignore the W83781D BUSY flag at this moment - it could lead to deadlocks, - would slow down the W83781D access and should not be necessary. - There are some ugly typecasts here, but the good news is - they should - nowhere else be necessary! */ -static int w83781d_read_value(struct i2c_client *client, u16 reg) -{ - int res, word_sized, bank; - struct i2c_client *cl; - - down(&(((struct w83781d_data *) (client->data))->lock)); - if (i2c_is_isa_client(client)) { - word_sized = (((reg & 0xff00) == 0x100) - || ((reg & 0xff00) == 0x200)) - && (((reg & 0x00ff) == 0x50) - || ((reg & 0x00ff) == 0x53) - || ((reg & 0x00ff) == 0x55)); - if (reg & 0xff00) { - outb_p(W83781D_REG_BANK, - client->addr + W83781D_ADDR_REG_OFFSET); - outb_p(reg >> 8, - client->addr + W83781D_DATA_REG_OFFSET); - } - outb_p(reg & 0xff, client->addr + W83781D_ADDR_REG_OFFSET); - res = inb_p(client->addr + W83781D_DATA_REG_OFFSET); - if (word_sized) { - outb_p((reg & 0xff) + 1, - client->addr + W83781D_ADDR_REG_OFFSET); - res = - (res << 8) + inb_p(client->addr + - W83781D_DATA_REG_OFFSET); - } - if (reg & 0xff00) { - outb_p(W83781D_REG_BANK, - client->addr + W83781D_ADDR_REG_OFFSET); - outb_p(0, client->addr + W83781D_DATA_REG_OFFSET); - } - } else { - bank = (reg >> 8) & 0x0f; - if (bank > 2) - /* switch banks */ - i2c_smbus_write_byte_data(client, W83781D_REG_BANK, - bank); - if (bank == 0 || bank > 2) { - res = i2c_smbus_read_byte_data(client, reg & 0xff); - } else { - /* switch to subclient */ - cl = - &(((struct w83781d_data *) (client->data))-> - lm75[bank - 1]); - /* convert from ISA to LM75 I2C addresses */ - switch (reg & 0xff) { - case 0x50: /* TEMP */ - res = swab16(i2c_smbus_read_word_data(cl, 0)); - break; - case 0x52: /* CONFIG */ - res = i2c_smbus_read_byte_data(cl, 1); - break; - case 0x53: /* HYST */ - res = swab16(i2c_smbus_read_word_data(cl, 2)); - break; - case 0x55: /* OVER */ - default: - res = swab16(i2c_smbus_read_word_data(cl, 3)); - break; - } - } - if (bank > 2) - i2c_smbus_write_byte_data(client, W83781D_REG_BANK, - 0); - } - up(&(((struct w83781d_data *) (client->data))->lock)); - return res; -} - -static int w83781d_write_value(struct i2c_client *client, u16 reg, u16 value) -{ - int word_sized, bank; - struct i2c_client *cl; - - down(&(((struct w83781d_data *) (client->data))->lock)); - if (i2c_is_isa_client(client)) { - word_sized = (((reg & 0xff00) == 0x100) - || ((reg & 0xff00) == 0x200)) - && (((reg & 0x00ff) == 0x53) - || ((reg & 0x00ff) == 0x55)); - if (reg & 0xff00) { - outb_p(W83781D_REG_BANK, - client->addr + W83781D_ADDR_REG_OFFSET); - outb_p(reg >> 8, - client->addr + W83781D_DATA_REG_OFFSET); - } - outb_p(reg & 0xff, client->addr + W83781D_ADDR_REG_OFFSET); - if (word_sized) { - outb_p(value >> 8, - client->addr + W83781D_DATA_REG_OFFSET); - outb_p((reg & 0xff) + 1, - client->addr + W83781D_ADDR_REG_OFFSET); - } - outb_p(value & 0xff, - client->addr + W83781D_DATA_REG_OFFSET); - if (reg & 0xff00) { - outb_p(W83781D_REG_BANK, - client->addr + W83781D_ADDR_REG_OFFSET); - outb_p(0, client->addr + W83781D_DATA_REG_OFFSET); - } - } else { - bank = (reg >> 8) & 0x0f; - if (bank > 2) - /* switch banks */ - i2c_smbus_write_byte_data(client, W83781D_REG_BANK, - bank); - if (bank == 0 || bank > 2) { - i2c_smbus_write_byte_data(client, reg & 0xff, - value & 0xff); - } else { - /* switch to subclient */ - cl = &(((struct w83781d_data *) (client->data))-> - lm75[bank - 1]); - /* convert from ISA to LM75 I2C addresses */ - switch (reg & 0xff) { - case 0x52: /* CONFIG */ - i2c_smbus_write_byte_data(cl, 1, value & 0xff); - break; - case 0x53: /* HYST */ - i2c_smbus_write_word_data(cl, 2, swab16(value)); - break; - case 0x55: /* OVER */ - i2c_smbus_write_word_data(cl, 3, swab16(value)); - break; - } - } - if (bank > 2) - i2c_smbus_write_byte_data(client, W83781D_REG_BANK, - 0); - } - up(&(((struct w83781d_data *) (client->data))->lock)); - return 0; -} - -/* Called when we have found a new W83781D. */ -static void w83781d_init_client(struct i2c_client *client) -{ - struct w83781d_data *data = client->data; - int i, p; - int type = data->type; - u8 tmp; - - if(init && type != as99127f) { /* this resets registers we don't have - documentation for on the as99127f */ - /* save these registers */ - i = w83781d_read_value(client, W83781D_REG_BEEP_CONFIG); - p = w83781d_read_value(client, W83781D_REG_PWMCLK12); - /* Reset all except Watchdog values and last conversion values - This sets fan-divs to 2, among others */ - w83781d_write_value(client, W83781D_REG_CONFIG, 0x80); - /* Restore the registers and disable power-on abnormal beep. - This saves FAN 1/2/3 input/output values set by BIOS. */ - w83781d_write_value(client, W83781D_REG_BEEP_CONFIG, i | 0x80); - w83781d_write_value(client, W83781D_REG_PWMCLK12, p); - /* Disable master beep-enable (reset turns it on). - Individual beeps should be reset to off but for some reason - disabling this bit helps some people not get beeped */ - w83781d_write_value(client, W83781D_REG_BEEP_INTS2, 0); - } - - data->vrm = (type == w83791d) ? 90 : 82; - - if ((type != w83781d) && (type != as99127f)) { - tmp = w83781d_read_value(client, W83781D_REG_SCFG1); - for (i = 1; i <= 3; i++) { - if (!(tmp & BIT_SCFG1[i - 1])) { - data->sens[i - 1] = W83781D_DEFAULT_BETA; - } else { - if (w83781d_read_value - (client, - W83781D_REG_SCFG2) & BIT_SCFG2[i - 1]) - data->sens[i - 1] = 1; - else - data->sens[i - 1] = 2; - } - if (type == w83783s && i == 2) - break; - } - } -#ifdef W83781D_RT -/* - Fill up the RT Tables. - We assume that they are 32 bytes long, in order for temp 1-3. - Data sheet documentation is sparse. - We also assume that it is only for the 781D although I suspect - that the others support it as well.... -*/ - - if (init && type == w83781d) { - u16 k = 0; -/* - Auto-indexing doesn't seem to work... - w83781d_write_value(client,W83781D_REG_RT_IDX,0); -*/ - for (i = 0; i < 3; i++) { - int j; - for (j = 0; j < 32; j++) { - w83781d_write_value(client, - W83781D_REG_RT_IDX, - k++); - data->rt[i][j] = - w83781d_read_value(client, - W83781D_REG_RT_VAL); - } - } - } -#endif /* W83781D_RT */ - - if (init && type != as99127f) { - w83781d_write_value(client, W83781D_REG_TEMP2_CONFIG, 0x00); - if (type != w83783s) { - w83781d_write_value(client, W83781D_REG_TEMP3_CONFIG, - 0x00); - } - } - - /* Start monitoring */ - w83781d_write_value(client, W83781D_REG_CONFIG, - (w83781d_read_value(client, - W83781D_REG_CONFIG) & 0xf7) - | 0x01); -} - -static void w83781d_update_client(struct i2c_client *client) -{ - struct w83781d_data *data = client->data; - int i; - - down(&data->update_lock); - - if (time_after(jiffies - data->last_updated, HZ + HZ / 2) || - time_before(jiffies, data->last_updated) || !data->valid) { - pr_debug(KERN_DEBUG "Starting device update\n"); - - for (i = 0; i <= 9; i++) { - if ((data->type == w83783s) - && (i == 1)) - continue; /* 783S has no in1 */ - if (data->type == w83791d) { - data->in[i] = - w83781d_read_value(client, W83791D_REG_IN(i)); - data->in_min[i] = - w83781d_read_value(client, - W83791D_REG_IN_MIN(i)); - data->in_max[i] = - w83781d_read_value(client, - W83791D_REG_IN_MAX(i)); - } else { - data->in[i] = - w83781d_read_value(client, W83781D_REG_IN(i)); - data->in_min[i] = - w83781d_read_value(client, - W83781D_REG_IN_MIN(i)); - data->in_max[i] = - w83781d_read_value(client, - W83781D_REG_IN_MAX(i)); - } - if ((data->type != w83782d) - && (data->type != w83627hf) && (i == 6) - && (data->type != w83791d)) - break; - - if (data->type != w83791d && i == 8) - break; - } - for (i = 1; i <= 5; i++) { - data->fan[i - 1] = - w83781d_read_value(client, W83781D_REG_FAN(i)); - data->fan_min[i - 1] = - w83781d_read_value(client, - W83781D_REG_FAN_MIN(i)); - if (data->type != w83791d && i == 3) break; - } - if (data->type != w83781d && data->type != as99127f) { - for (i = 1; i <= 4; i++) { - data->pwm[i - 1] = - w83781d_read_value(client, - W83781D_REG_PWM(data->type, i)); - if (((data->type == w83783s) - || (data->type == w83627hf) - || ((data->type == w83782d) - && i2c_is_isa_client(client))) - && i == 2) - break; - } - /* Only PWM2 can be disabled */ - data->pwmenable[1] = (w83781d_read_value(client, - W83781D_REG_PWMCLK12) & 0x08) >> 3; - } - - data->temp = w83781d_read_value(client, W83781D_REG_TEMP); - data->temp_over = - w83781d_read_value(client, W83781D_REG_TEMP_OVER); - data->temp_hyst = - w83781d_read_value(client, W83781D_REG_TEMP_HYST); - data->temp_add[0] = - w83781d_read_value(client, W83781D_REG_TEMP2); - data->temp_add_over[0] = - w83781d_read_value(client, W83781D_REG_TEMP2_OVER); - data->temp_add_hyst[0] = - w83781d_read_value(client, W83781D_REG_TEMP2_HYST); - if (data->type != w83783s) { - data->temp_add[1] = - w83781d_read_value(client, W83781D_REG_TEMP3); - data->temp_add_over[1] = - w83781d_read_value(client, W83781D_REG_TEMP3_OVER); - data->temp_add_hyst[1] = - w83781d_read_value(client, W83781D_REG_TEMP3_HYST); - } - i = w83781d_read_value(client, W83781D_REG_VID_FANDIV); - data->vid = i & 0x0f; - data->vid |= (w83781d_read_value(client, - W83781D_REG_CHIPID) & 0x01) << 4; - data->fan_div[0] = (i >> 4) & 0x03; - data->fan_div[1] = (i >> 6) & 0x03; - data->fan_div[2] = (w83781d_read_value(client, - W83781D_REG_PIN) >> 6) & 0x03; - if ((data->type != w83781d) && (data->type != as99127f)) { - i = w83781d_read_value(client, W83781D_REG_VBAT); - data->fan_div[0] |= (i >> 3) & 0x04; - data->fan_div[1] |= (i >> 4) & 0x04; - data->fan_div[2] |= (i >> 5) & 0x04; - } - - if ((data->type == w83782d) || (data->type == w83627hf)) { - data->alarms = w83781d_read_value(client, - W83782D_REG_ALARM1) - | (w83781d_read_value(client, - W83782D_REG_ALARM2) << 8) - | (w83781d_read_value(client, - W83782D_REG_ALARM3) << 16); - } else if (data->type == w83783s) { - /* Only two real-time status registers */ - data->alarms = w83781d_read_value(client, - W83782D_REG_ALARM1) - | (w83781d_read_value(client, - W83782D_REG_ALARM2) << 8); - } else if (data->type == w83791d) { - data->alarms = w83781d_read_value(client, - W83791D_REG_ALARM1) - | (w83781d_read_value(client, - W83791D_REG_ALARM2) << 8) - | (w83781d_read_value(client, - W83791D_REG_ALARM3) << 16); - } else { - /* No real-time status registers, fall back to - interrupt status registers */ - data->alarms = w83781d_read_value(client, - W83781D_REG_ALARM1) - | (w83781d_read_value(client, - W83781D_REG_ALARM2) << 8); - } - - i = w83781d_read_value(client, W83781D_REG_BEEP_INTS2); - data->beep_enable = i >> 7; - data->beeps = ((i & 0x7f) << 8) + - w83781d_read_value(client, W83781D_REG_BEEP_INTS1); - if ((data->type != w83781d) && (data->type != as99127f) - && (data->type != w83791d)) { - data->beeps |= - w83781d_read_value(client, - W83781D_REG_BEEP_INTS3) << 16; - } - data->last_updated = jiffies; - data->valid = 1; - } - - up(&data->update_lock); -} - - -/* The next few functions are the call-back functions of the /proc/sys and - sysctl files. Which function is used is defined in the ctl_table in - the extra1 field. - Each function must return the magnitude (power of 10 to divide the date - with) if it is called with operation==SENSORS_PROC_REAL_INFO. It must - put a maximum of *nrels elements in results reflecting the data of this - file, and set *nrels to the number it actually put in it, if operation== - SENSORS_PROC_REAL_READ. Finally, it must get upto *nrels elements from - results and write them to the chip, if operations==SENSORS_PROC_REAL_WRITE. - Note that on SENSORS_PROC_REAL_READ, I do not check whether results is - large enough (by checking the incoming value of *nrels). This is not very - good practice, but as long as you put less than about 5 values in results, - you can assume it is large enough. */ -static void w83781d_in(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct w83781d_data *data = client->data; - int nr = ctl_name - W83781D_SYSCTL_IN0; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 2; - else if (operation == SENSORS_PROC_REAL_READ) { - w83781d_update_client(client); - results[0] = IN_FROM_REG(data->in_min[nr]); - results[1] = IN_FROM_REG(data->in_max[nr]); - results[2] = IN_FROM_REG(data->in[nr]); - *nrels_mag = 3; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag >= 1) { - data->in_min[nr] = IN_TO_REG(results[0]); - w83781d_write_value(client, W83781D_REG_IN_MIN(nr), - data->in_min[nr]); - } - if (*nrels_mag >= 2) { - data->in_max[nr] = IN_TO_REG(results[1]); - w83781d_write_value(client, W83781D_REG_IN_MAX(nr), - data->in_max[nr]); - } - } -} - -void w83781d_fan(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct w83781d_data *data = client->data; - int nr = ctl_name - W83781D_SYSCTL_FAN1 + 1; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - w83781d_update_client(client); - results[0] = FAN_FROM_REG(data->fan_min[nr - 1], - DIV_FROM_REG(data->fan_div[nr - 1])); - results[1] = FAN_FROM_REG(data->fan[nr - 1], - DIV_FROM_REG(data->fan_div[nr - 1])); - *nrels_mag = 2; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag >= 1) { - data->fan_min[nr - 1] = - FAN_TO_REG(results[0], - DIV_FROM_REG(data->fan_div[nr-1])); - w83781d_write_value(client, - W83781D_REG_FAN_MIN(nr), - data->fan_min[nr - 1]); - } - } -} - -void w83781d_temp(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct w83781d_data *data = client->data; - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 1; - else if (operation == SENSORS_PROC_REAL_READ) { - w83781d_update_client(client); - results[0] = TEMP_FROM_REG(data->temp_over); - results[1] = TEMP_FROM_REG(data->temp_hyst); - results[2] = TEMP_FROM_REG(data->temp); - *nrels_mag = 3; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag >= 1) { - data->temp_over = TEMP_TO_REG(results[0]); - w83781d_write_value(client, W83781D_REG_TEMP_OVER, - data->temp_over); - } - if (*nrels_mag >= 2) { - data->temp_hyst = TEMP_TO_REG(results[1]); - w83781d_write_value(client, W83781D_REG_TEMP_HYST, - data->temp_hyst); - } - } -} - -void w83781d_temp_add(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results) -{ - struct w83781d_data *data = client->data; - int nr = ctl_name - W83781D_SYSCTL_TEMP2; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 1; - else if (operation == SENSORS_PROC_REAL_READ) { - w83781d_update_client(client); - results[0] = LM75_TEMP_FROM_REG(data->temp_add_over[nr]); - results[1] = LM75_TEMP_FROM_REG(data->temp_add_hyst[nr]); - results[2] = LM75_TEMP_FROM_REG(data->temp_add[nr]); - *nrels_mag = 3; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag >= 1) { - data->temp_add_over[nr] = - LM75_TEMP_TO_REG(results[0]); - w83781d_write_value(client, - nr ? W83781D_REG_TEMP3_OVER : - W83781D_REG_TEMP2_OVER, - data->temp_add_over[nr]); - } - if (*nrels_mag >= 2) { - data->temp_add_hyst[nr] = - LM75_TEMP_TO_REG(results[1]); - w83781d_write_value(client, - nr ? W83781D_REG_TEMP3_HYST : - W83781D_REG_TEMP2_HYST, - data->temp_add_hyst[nr]); - } - } -} - - -void w83781d_vid(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct w83781d_data *data = client->data; - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 3; - else if (operation == SENSORS_PROC_REAL_READ) { - w83781d_update_client(client); - results[0] = vid_from_reg(data->vid, data->vrm); - *nrels_mag = 1; - } -} - -void w83781d_vrm(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct w83781d_data *data = client->data; - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 1; - else if (operation == SENSORS_PROC_REAL_READ) { - results[0] = data->vrm; - *nrels_mag = 1; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag >= 1) - data->vrm = results[0]; - } -} - -void w83781d_alarms(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct w83781d_data *data = client->data; - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - w83781d_update_client(client); - results[0] = ALARMS_FROM_REG(data->alarms); - *nrels_mag = 1; - } -} - -void w83781d_beep(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct w83781d_data *data = client->data; - int val; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - w83781d_update_client(client); - results[0] = BEEP_ENABLE_FROM_REG(data->beep_enable); - results[1] = BEEPS_FROM_REG(data->beeps, data->type); - *nrels_mag = 2; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag >= 2) { - data->beeps = BEEPS_TO_REG(results[1], data->type); - w83781d_write_value(client, W83781D_REG_BEEP_INTS1, - data->beeps & 0xff); - if ((data->type != w83781d) && - (data->type != as99127f)) { - w83781d_write_value(client, - W83781D_REG_BEEP_INTS3, - ((data-> beeps) >> 16) & - 0xff); - } - val = (data->beeps >> 8) & 0x7f; - } else if (*nrels_mag >= 1) - val = - w83781d_read_value(client, - W83781D_REG_BEEP_INTS2) & - 0x7f; - if (*nrels_mag >= 1) { - data->beep_enable = BEEP_ENABLE_TO_REG(results[0]); - w83781d_write_value(client, W83781D_REG_BEEP_INTS2, - val | data->beep_enable << 7); - } - } -} - -void w83781d_fan_div(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results) -{ - struct w83781d_data *data = client->data; - int old, old2, old3 = 0; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - w83781d_update_client(client); - results[0] = DIV_FROM_REG(data->fan_div[0]); - results[1] = DIV_FROM_REG(data->fan_div[1]); - results[2] = DIV_FROM_REG(data->fan_div[2]); - *nrels_mag = 3; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - old = w83781d_read_value(client, W83781D_REG_VID_FANDIV); - /* w83781d and as99127f don't have extended divisor bits */ - if ((data->type != w83781d) && data->type != as99127f) { - old3 = - w83781d_read_value(client, W83781D_REG_VBAT); - } - if (*nrels_mag >= 3) { - data->fan_div[2] = - DIV_TO_REG(results[2], data->type); - old2 = w83781d_read_value(client, W83781D_REG_PIN); - old2 = - (old2 & 0x3f) | ((data->fan_div[2] & 0x03) << 6); - w83781d_write_value(client, W83781D_REG_PIN, old2); - if ((data->type != w83781d) && - (data->type != as99127f)) { - old3 = - (old3 & 0x7f) | - ((data->fan_div[2] & 0x04) << 5); - } - } - if (*nrels_mag >= 2) { - data->fan_div[1] = - DIV_TO_REG(results[1], data->type); - old = - (old & 0x3f) | ((data->fan_div[1] & 0x03) << 6); - if ((data->type != w83781d) && - (data->type != as99127f)) { - old3 = - (old3 & 0xbf) | - ((data->fan_div[1] & 0x04) << 4); - } - } - if (*nrels_mag >= 1) { - data->fan_div[0] = - DIV_TO_REG(results[0], data->type); - old = - (old & 0xcf) | ((data->fan_div[0] & 0x03) << 4); - w83781d_write_value(client, W83781D_REG_VID_FANDIV, - old); - if ((data->type != w83781d) && - (data->type != as99127f)) { - old3 = - (old3 & 0xdf) | - ((data->fan_div[0] & 0x04) << 3); - w83781d_write_value(client, - W83781D_REG_VBAT, - old3); - } - } - } -} - -void w83781d_pwm(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct w83781d_data *data = client->data; - int nr = 1 + ctl_name - W83781D_SYSCTL_PWM1; - int j, k; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - w83781d_update_client(client); - results[0] = PWM_FROM_REG(data->pwm[nr - 1]); - results[1] = data->pwmenable[nr - 1]; - *nrels_mag = 2; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag >= 1) { - data->pwm[nr - 1] = PWM_TO_REG(results[0]); - w83781d_write_value(client, - W83781D_REG_PWM(data->type, nr), - data->pwm[nr - 1]); - } - /* only PWM2 can be enabled/disabled */ - if (*nrels_mag >= 2 && nr == 2) { - j = w83781d_read_value(client, W83781D_REG_PWMCLK12); - k = w83781d_read_value(client, W83781D_REG_BEEP_CONFIG); - if(results[1]) { - if(!(j & 0x08)) - w83781d_write_value(client, - W83781D_REG_PWMCLK12, j | 0x08); - if(k & 0x10) - w83781d_write_value(client, - W83781D_REG_BEEP_CONFIG, k & 0xef); - data->pwmenable[1] = 1; - } else { - if(j & 0x08) - w83781d_write_value(client, - W83781D_REG_PWMCLK12, j & 0xf7); - if(!(k & 0x10)) - w83781d_write_value(client, - W83781D_REG_BEEP_CONFIG, j | 0x10); - data->pwmenable[1] = 0; - } - } - } -} - -void w83781d_sens(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct w83781d_data *data = client->data; - int nr = 1 + ctl_name - W83781D_SYSCTL_SENS1; - u8 tmp; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - results[0] = data->sens[nr - 1]; - *nrels_mag = 1; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag >= 1) { - switch (results[0]) { - case 1: /* PII/Celeron diode */ - tmp = w83781d_read_value(client, - W83781D_REG_SCFG1); - w83781d_write_value(client, - W83781D_REG_SCFG1, - tmp | BIT_SCFG1[nr - - 1]); - tmp = w83781d_read_value(client, - W83781D_REG_SCFG2); - w83781d_write_value(client, - W83781D_REG_SCFG2, - tmp | BIT_SCFG2[nr - - 1]); - data->sens[nr - 1] = results[0]; - break; - case 2: /* 3904 */ - tmp = w83781d_read_value(client, - W83781D_REG_SCFG1); - w83781d_write_value(client, - W83781D_REG_SCFG1, - tmp | BIT_SCFG1[nr - - 1]); - tmp = w83781d_read_value(client, - W83781D_REG_SCFG2); - w83781d_write_value(client, - W83781D_REG_SCFG2, - tmp & ~BIT_SCFG2[nr - - 1]); - data->sens[nr - 1] = results[0]; - break; - case W83781D_DEFAULT_BETA: /* thermistor */ - tmp = w83781d_read_value(client, - W83781D_REG_SCFG1); - w83781d_write_value(client, - W83781D_REG_SCFG1, - tmp & ~BIT_SCFG1[nr - - 1]); - data->sens[nr - 1] = results[0]; - break; - default: - printk - (KERN_ERR "w83781d.o: Invalid sensor type %ld; must be 1, 2, or %d\n", - results[0], W83781D_DEFAULT_BETA); - break; - } - } - } -} - -#ifdef W83781D_RT -static void w83781d_rt(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct w83781d_data *data = client->data; - int nr = 1 + ctl_name - W83781D_SYSCTL_RT1; - int i; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - for (i = 0; i < 32; i++) { - results[i] = data->rt[nr - 1][i]; - } - *nrels_mag = 32; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag > 32) - *nrels_mag = 32; - for (i = 0; i < *nrels_mag; i++) { - /* fixme: no bounds checking 0-255 */ - data->rt[nr - 1][i] = results[i]; - w83781d_write_value(client, W83781D_REG_RT_IDX, i); - w83781d_write_value(client, W83781D_REG_RT_VAL, - data->rt[nr - 1][i]); - } - } -} -#endif - -static int __init sm_w83781d_init(void) -{ - printk(KERN_INFO "w83781d.o version %s (%s)\n", LM_VERSION, LM_DATE); - return i2c_add_driver(&w83781d_driver); -} - -static void __exit sm_w83781d_exit(void) -{ - i2c_del_driver(&w83781d_driver); -} - - - -MODULE_AUTHOR("Frodo Looijaard , " - "Philip Edelbrock , " - "and Mark Studebaker "); -MODULE_DESCRIPTION("W83781D driver"); -MODULE_LICENSE("GPL"); - -module_init(sm_w83781d_init); -module_exit(sm_w83781d_exit); diff --git a/kernel/chips/w83792d.c b/kernel/chips/w83792d.c deleted file mode 100644 index 09998c5a..00000000 --- a/kernel/chips/w83792d.c +++ /dev/null @@ -1,1532 +0,0 @@ -/* - w83792d.c - Part of lm_sensors, Linux kernel modules for hardware - monitoring - Copyright (c) 2004, 2005 Winbond Electronics Corp. - Chunhao Huang - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - - Note: - 1. This driver is only for 2.4 kernel(2.4.10 or later), 2.6 kernel - need a different driver. - 2. This driver is only for Winbond W83792D C version device, there - are also some motherboards with B version W83792D device. The - calculation method to in6-in7(measured value, limits) is a little - different between C and B version. C or B version can be identified - by CR[0x49h]. - 3. The function of chassis open detection need further test. - 4. The function of vid and vrm has not been finished, because I'm NOT - very familiar with them. If someone can finish it, that's good, - then please delete this note 4. -*/ - -/* - Supports following chips: - - Chip #vin #fanin #pwm #temp wchipid vendid i2c ISA - w83792d 9 7 3 3 0x7a 0x5ca3 yes no -*/ - -#include -#include -#include -#include -#include -#include "version.h" -#include "sensors_vid.h" - -/* Addresses to scan */ -static unsigned short normal_i2c[] = { SENSORS_I2C_END }; -static unsigned short normal_i2c_range[] = { 0x2c, 0x2f, SENSORS_I2C_END }; -static unsigned int normal_isa[] = { SENSORS_ISA_END }; -static unsigned int normal_isa_range[] = { SENSORS_ISA_END }; - -/* Insmod parameters */ -SENSORS_INSMOD_1(w83792d); -SENSORS_MODULE_PARM(force_subclients, "List of subclient addresses: " \ - "{bus, clientaddr, subclientaddr1, subclientaddr2}"); - -static int init; -MODULE_PARM(init, "i"); -MODULE_PARM_DESC(init, "Set to one for chip initialization"); - -/* Enable/Disable w83792d debugging output */ -/* #define W83792D_DEBUG 1 */ - -/* Constants specified below */ -#define W83792D_REG_GPIO_EN 0x1A -#define W83792D_REG_CONFIG 0x40 -#define W83792D_REG_I2C_ADDR 0x48 -#define W83792D_REG_CHIPID 0x49 /* contains version ID: A/B/C */ -#define W83792D_REG_I2C_SUBADDR 0x4A -#define W83792D_REG_PIN 0x4B -#define W83792D_REG_IRQ 0x4C -#define W83792D_REG_BANK 0x4E -#define W83792D_REG_CHIPMAN 0x4F /* contains the vendor ID */ -#define W83792D_REG_WCHIPID 0x58 /* contains the chip ID */ -#define W83792D_REG_VID_IN_B 0x17 /* ctroll in0/in1 's limit modifiability */ - -static const u8 W83792D_REG_IN[9] = { - 0x20, /* Vcore A in DataSheet */ - 0x21, /* Vcore B in DataSheet */ - 0x22, /* VIN0 in DataSheet */ - 0x23, /* VIN1 in DataSheet */ - 0x24, /* VIN2 in DataSheet */ - 0x25, /* VIN3 in DataSheet */ - 0x26, /* 5VCC in DataSheet */ - 0xB0, /* 5VSB in DataSheet */ - 0xB1 /* VBAT in DataSheet */ -}; -#define W83792D_REG_LOW_BITS1 0x3E /* Low Bits I in DataSheet */ -#define W83792D_REG_LOW_BITS2 0x3F /* Low Bits II in DataSheet */ -static const u8 W83792D_REG_IN_MAX[9] = { - 0x2B, /* Vcore A High Limit in DataSheet */ - 0x2D, /* Vcore B High Limit in DataSheet */ - 0x2F, /* VIN0 High Limit in DataSheet */ - 0x31, /* VIN1 High Limit in DataSheet */ - 0x33, /* VIN2 High Limit in DataSheet */ - 0x35, /* VIN3 High Limit in DataSheet */ - 0x37, /* 5VCC High Limit in DataSheet */ - 0xB4, /* 5VSB High Limit in DataSheet */ - 0xB6 /* VBAT High Limit in DataSheet */ -}; -static const u8 W83792D_REG_IN_MIN[9] = { - 0x2C, /* Vcore A Low Limit in DataSheet */ - 0x2E, /* Vcore B Low Limit in DataSheet */ - 0x30, /* VIN0 Low Limit in DataSheet */ - 0x32, /* VIN1 Low Limit in DataSheet */ - 0x34, /* VIN2 Low Limit in DataSheet */ - 0x36, /* VIN3 Low Limit in DataSheet */ - 0x38, /* 5VCC Low Limit in DataSheet */ - 0xB5, /* 5VSB Low Limit in DataSheet */ - 0xB7 /* VBAT Low Limit in DataSheet */ -}; - -static const u8 W83792D_REG_FAN[7] = { - 0x28, /* FAN 1 Count in DataSheet */ - 0x29, /* FAN 2 Count in DataSheet */ - 0x2A, /* FAN 3 Count in DataSheet */ - 0xB8, /* FAN 4 Count in DataSheet */ - 0xB9, /* FAN 5 Count in DataSheet */ - 0xBA, /* FAN 6 Count in DataSheet */ - 0xBE /* FAN 7 Count in DataSheet */ -}; -static const u8 W83792D_REG_FAN_MIN[7] = { - 0x3B, /* FAN 1 Count Low Limit in DataSheet */ - 0x3C, /* FAN 2 Count Low Limit in DataSheet */ - 0x3D, /* FAN 3 Count Low Limit in DataSheet */ - 0xBB, /* FAN 4 Count Low Limit in DataSheet */ - 0xBC, /* FAN 5 Count Low Limit in DataSheet */ - 0xBD, /* FAN 6 Count Low Limit in DataSheet */ - 0xBF /* FAN 7 Count Low Limit in DataSheet */ -}; -#define W83792D_REG_FAN_CFG 0x84 /* FAN Configuration in DataSheet */ -static const u8 W83792D_REG_PWM[7] = { - 0x81, /* FAN 1 Duty Cycle, be used to control */ - 0x83, /* FAN 2 Duty Cycle, be used to control */ - 0x94, /* FAN 3 Duty Cycle, be used to control */ - 0xA3, /* FAN 4 Duty Cycle, be used to control */ - 0xA4, /* FAN 5 Duty Cycle, be used to control */ - 0xA5, /* FAN 6 Duty Cycle, be used to control */ - 0xA6 /* FAN 7 Duty Cycle, be used to control */ -}; - -#define W83792D_REG_TEMP1 0x27 /* TEMP 1 in DataSheet */ -#define W83792D_REG_TEMP1_OVER 0x39 /* TEMP 1 High Limit in DataSheet */ -#define W83792D_REG_TEMP1_HYST 0x3A /* TEMP 1 Low Limit in DataSheet */ -static const u8 W83792D_REG_TEMP_ADD[2][7] = { - { 0xC0, /* TEMP 2 in DataSheet */ - 0xC1, /* TEMP 2(0.5 deg) in DataSheet */ - 0xC5, /* TEMP 2 Over High part in DataSheet */ - 0xC6, /* TEMP 2 Over Low part in DataSheet */ - 0xC3, /* TEMP 2 Thyst High part in DataSheet */ - 0xC4, /* TEMP 2 Thyst Low part in DataSheet */ - 0xC2 }, /* TEMP 2 Config in DataSheet */ - { 0xC8, /* TEMP 3 in DataSheet */ - 0xC9, /* TEMP 3(0.5 deg) in DataSheet */ - 0xCD, /* TEMP 3 Over High part in DataSheet */ - 0xCE, /* TEMP 3 Over Low part in DataSheet */ - 0xCB, /* TEMP 3 Thyst High part in DataSheet */ - 0xCC, /* TEMP 3 Thyst Low part in DataSheet */ - 0xCA } /* TEMP 3 Config in DataSheet */ -}; - -static const u8 W83792D_REG_FAN_DIV[4] = { - 0x47, /* contains FAN2 and FAN1 Divisor */ - 0x5B, /* contains FAN4 and FAN3 Divisor */ - 0x5C, /* contains FAN6 and FAN5 Divisor */ - 0x9E /* contains FAN7 Divisor. */ -}; - -#define W83792D_REG_ALARM1 0xA9 /* realtime status register1 */ -#define W83792D_REG_ALARM2 0xAA /* realtime status register2 */ -#define W83792D_REG_ALARM3 0xAB /* realtime status register3 */ -#define W83792D_REG_CASE_OPEN 0x42 /* Bit 5: Case Open status bit */ -#define W83792D_REG_CASE_OPEN_CLR 0x44 /* Bit 7: Case Open CLR_CHS/Reset bit */ - -static const u8 W83792D_REG_THERMAL[3] = { - 0x85, /* SmartFanI: Fan1 target value */ - 0x86, /* SmartFanI: Fan2 target value */ - 0x96 /* SmartFanI: Fan3 target value */ -}; - -static const u8 W83792D_REG_FAN_TOL[3] = { - 0x87, /* (bit3-0)SmartFan Fan1 tolerance */ - 0x87, /* (bit7-4)SmartFan Fan2 tolerance */ - 0x97 /* (bit3-0)SmartFan Fan3 tolerance */ -}; - -static const u8 W83792D_REG_POINTS[3][4] = { - { 0x85, /* SmartFanII: Fan1 temp point 1 */ - 0xE3, /* SmartFanII: Fan1 temp point 2 */ - 0xE4, /* SmartFanII: Fan1 temp point 3 */ - 0xE5 }, /* SmartFanII: Fan1 temp point 4 */ - { 0x86, /* SmartFanII: Fan2 temp point 1 */ - 0xE6, /* SmartFanII: Fan2 temp point 2 */ - 0xE7, /* SmartFanII: Fan2 temp point 3 */ - 0xE8 }, /* SmartFanII: Fan2 temp point 4 */ - { 0x96, /* SmartFanII: Fan3 temp point 1 */ - 0xE9, /* SmartFanII: Fan3 temp point 2 */ - 0xEA, /* SmartFanII: Fan3 temp point 3 */ - 0xEB } /* SmartFanII: Fan3 temp point 4 */ -}; - -static const u8 W83792D_REG_LEVELS[3][4] = { - { 0x88, /* (bit3-0) SmartFanII: Fan1 Non-Stop */ - 0x88, /* (bit7-4) SmartFanII: Fan1 Level 1 */ - 0xE0, /* (bit7-4) SmartFanII: Fan1 Level 2 */ - 0xE0 }, /* (bit3-0) SmartFanII: Fan1 Level 3 */ - { 0x89, /* (bit3-0) SmartFanII: Fan2 Non-Stop */ - 0x89, /* (bit7-4) SmartFanII: Fan2 Level 1 */ - 0xE1, /* (bit7-4) SmartFanII: Fan2 Level 2 */ - 0xE1 }, /* (bit3-0) SmartFanII: Fan2 Level 3 */ - { 0x98, /* (bit3-0) SmartFanII: Fan3 Non-Stop */ - 0x98, /* (bit7-4) SmartFanII: Fan3 Level 1 */ - 0xE2, /* (bit7-4) SmartFanII: Fan3 Level 2 */ - 0xE2 } /* (bit3-0) SmartFanII: Fan3 Level 3 */ -}; - -static inline u8 FAN_TO_REG(long rpm, int div) -{ - if (rpm == 0) - return 255; - rpm = SENSORS_LIMIT(rpm, 1, 1000000); - return SENSORS_LIMIT(1350000/(rpm * div), 1, 254); -} - -#define IN_FROM_REG(nr,val) (((nr)<=1)?(val*2): \ - ((((nr)==6)||((nr)==7))?(val*6):(val*4))) -#define IN_TO_REG(nr,val) (((nr)<=1)?(val/2): \ - ((((nr)==6)||((nr)==7))?(val/6):(val/4))) -#define TEMP_FROM_REG(val) (((val)>0x80?(val)-0x100:(val))*10) -#define TEMP_TO_REG(val) (SENSORS_LIMIT((val>=0)?((val)/10):((val)/10+256), 0, 255)) -#define FAN_FROM_REG(val,div) ((val)==0?-1:(val)==255?0:1350000/((val)*(div))) -#define DIV_FROM_REG(val) (1 << (val)) - -#ifdef W83792D_DEBUG -#define ENTER() printk(KERN_DEBUG "w83792d: ENTERING %s, line: %d\n", __FUNCTION__, __LINE__); -#define LEAVE() printk(KERN_DEBUG "w83792d: LEAVING %s, line: %d\n", __FUNCTION__, __LINE__); -#else -#define ENTER() -#define LEAVE() -#endif - -struct w83792d_data { - struct i2c_client client; - int sysctl_id; - enum chips type; - - struct semaphore update_lock; - char valid; /* !=0 if following fields are valid */ - unsigned long last_updated; /* In jiffies */ - - struct i2c_client *lm75[2]; /* for secondary I2C addresses */ - - u8 in[9]; /* Register value */ - u8 in_max[9]; /* Register value */ - u8 in_min[9]; /* Register value */ - u16 low_bits; /* Register value */ - u8 has_fan; /* Bit vector */ - u8 fan[7]; /* Register value */ - u8 fan_min[7]; /* Register value */ - u8 fan_cfg; /* Configure Fan Mode */ - u8 temp1[3]; /* Register value */ - u8 temp_add[2][7]; /* Register value */ - u8 fan_div[7]; /* Fan Divisor */ - /*u8 vid; Register encoding, combined */ - u8 pwm[7]; /* We only consider the first 3 set of pwm, - although 792 chip has 7 set of pwm. */ - u8 pwm_flag[7]; /* indicates PWM or DC mode: 1->PWM; 0->DC */ - /* u8 vrm; VRM version */ - u32 alarms; /* realtime status register encoding,combined */ - u8 chassis[2]; /* [0]->Chassis status, [1]->CLR_CHS */ - u8 thermal_cruise[3]; /* Smart FanI: Fan1,2,3 target value */ - u8 fan_tolerance[3]; /* Fan1,2,3 tolerance(Smart Fan I/II) */ - u8 sf2_points[3][4]; /* Smart FanII: Fan1,2,3 temperature points */ - u8 sf2_levels[3][4]; /* Smart FanII: Fan1,2,3 duty cycle levels */ -}; - -/* Read the w83792d register value, only use bank 0 of the 792 chip */ -static inline int -w83792d_read_value(struct i2c_client *client, u8 reg) -{ - return i2c_smbus_read_byte_data(client, reg); -} - -/* Write value into the w83792d registers, only use bank 0 of the 792 chip */ -static inline int -w83792d_write_value(struct i2c_client *client, u8 reg, u8 value) -{ - return i2c_smbus_write_byte_data(client, reg, value); -} - -static int w83792d_attach_adapter(struct i2c_adapter *adapter); -static int w83792d_detect(struct i2c_adapter *adapter, int address, - unsigned short flags, int kind); -static int w83792d_detach_client(struct i2c_client *client); - -static void w83792d_init_client(struct i2c_client *client); -static void w83792d_update_client(struct i2c_client *client); -#ifdef W83792D_DEBUG -static void w83792d_print_debug(struct w83792d_data *data); -#endif -static void w83792d_in(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void w83792d_fan(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void w83792d_temp(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void w83792d_temp_add(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -/*static void w83792d_vid(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void w83792d_vrm(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); */ -static void w83792d_set_fan_div(struct i2c_client *client, - int nr, u8 newdiv); -static void w83792d_fan_div(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void w83792d_alarms(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void w83792d_chassis(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void w83792d_pwm(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void w83792d_pwm_flag(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void w83792d_fan_cfg(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void w83792d_thermal_cruise(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void w83792d_fan_tolerance(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void w83792d_sf2_points(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void w83792d_sf2_levels(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); - -static struct i2c_driver w83792d_driver = { - .name = "W83792D sensor driver", - .flags = I2C_DF_NOTIFY, - .attach_adapter = w83792d_attach_adapter, - .detach_client = w83792d_detach_client, -}; - -/* The /proc/sys entries */ -/* -- SENSORS SYSCTL START -- */ - -#define W83792D_SYSCTL_IN0 1000 -#define W83792D_SYSCTL_IN1 1001 -#define W83792D_SYSCTL_IN2 1002 -#define W83792D_SYSCTL_IN3 1003 -#define W83792D_SYSCTL_IN4 1004 -#define W83792D_SYSCTL_IN5 1005 -#define W83792D_SYSCTL_IN6 1006 -#define W83792D_SYSCTL_IN7 1007 -#define W83792D_SYSCTL_IN8 1008 -#define W83792D_SYSCTL_FAN1 1101 -#define W83792D_SYSCTL_FAN2 1102 -#define W83792D_SYSCTL_FAN3 1103 -#define W83792D_SYSCTL_FAN4 1104 -#define W83792D_SYSCTL_FAN5 1105 -#define W83792D_SYSCTL_FAN6 1106 -#define W83792D_SYSCTL_FAN7 1107 - -#define W83792D_SYSCTL_TEMP1 1200 -#define W83792D_SYSCTL_TEMP2 1201 -#define W83792D_SYSCTL_TEMP3 1202 -/*#define W83792D_SYSCTL_VID 1300 -#define W83792D_SYSCTL_VRM 1301*/ -#define W83792D_SYSCTL_PWM_FLAG 1400 -#define W83792D_SYSCTL_PWM1 1401 -#define W83792D_SYSCTL_PWM2 1402 -#define W83792D_SYSCTL_PWM3 1403 -#define W83792D_SYSCTL_FAN_CFG 1500 /* control Fan Mode */ -#define W83792D_SYSCTL_FAN_DIV 1501 -#define W83792D_SYSCTL_CHASSIS 1502 /* control Case Open */ -#define W83792D_SYSCTL_ALARMS 1503 - -#define W83792D_SYSCTL_THERMAL_CRUISE 1600 /* Smart Fan I: target value */ -#define W83792D_SYSCTL_FAN_TOLERANCE 1601 /* Smart Fan I/II: tolerance */ -#define W83792D_SYSCTL_SF2_POINTS_FAN1 1602 /* Smart Fan II: Fan1 points */ -#define W83792D_SYSCTL_SF2_POINTS_FAN2 1603 /* Smart Fan II: Fan2 points */ -#define W83792D_SYSCTL_SF2_POINTS_FAN3 1604 /* Smart Fan II: Fan3 points */ -#define W83792D_SYSCTL_SF2_LEVELS_FAN1 1605 /* Smart Fan II: Fan1 levels */ -#define W83792D_SYSCTL_SF2_LEVELS_FAN2 1606 /* Smart Fan II: Fan2 levels */ -#define W83792D_SYSCTL_SF2_LEVELS_FAN3 1607 /* Smart Fan II: Fan3 levels */ - -#define W83792D_ALARM_IN0 0x0001 -#define W83792D_ALARM_IN1 0x0002 -#define W83792D_ALARM_IN2 0x0100 -#define W83792D_ALARM_IN3 0x0200 -#define W83792D_ALARM_IN4 0x0400 -#define W83792D_ALARM_IN5 0x0800 -#define W83792D_ALARM_IN6 0x1000 -#define W83792D_ALARM_IN7 0x80000 -#define W83792D_ALARM_IN8 0x100000 -#define W83792D_ALARM_TEMP1 0x0004 -#define W83792D_ALARM_TEMP2 0x0008 -#define W83792D_ALARM_TEMP3 0x0010 -#define W83792D_ALARM_FAN1 0x0020 -#define W83792D_ALARM_FAN2 0x0040 -#define W83792D_ALARM_FAN3 0x0080 -#define W83792D_ALARM_FAN4 0x200000 -#define W83792D_ALARM_FAN5 0x400000 -#define W83792D_ALARM_FAN6 0x800000 -#define W83792D_ALARM_FAN7 0x8000 - -/* -- SENSORS SYSCTL END -- */ - -/* These files are created for detected chip, - W83792D has 9 voltages 7 fans and 3 temperatures. */ -static ctl_table w83792d_dir_table_template[] = -{ - {W83792D_SYSCTL_IN0, "in0", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83792d_in}, - {W83792D_SYSCTL_IN1, "in1", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83792d_in}, - {W83792D_SYSCTL_IN2, "in2", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83792d_in}, - {W83792D_SYSCTL_IN3, "in3", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83792d_in}, - {W83792D_SYSCTL_IN4, "in4", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83792d_in}, - {W83792D_SYSCTL_IN5, "in5", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83792d_in}, - {W83792D_SYSCTL_IN6, "in6", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83792d_in}, - {W83792D_SYSCTL_IN7, "in7", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83792d_in}, - {W83792D_SYSCTL_IN8, "in8", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83792d_in}, - {W83792D_SYSCTL_FAN1, "fan1", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83792d_fan}, - {W83792D_SYSCTL_FAN2, "fan2", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83792d_fan}, - {W83792D_SYSCTL_FAN3, "fan3", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83792d_fan}, - {W83792D_SYSCTL_FAN4, "fan4", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83792d_fan}, - {W83792D_SYSCTL_FAN5, "fan5", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83792d_fan}, - {W83792D_SYSCTL_FAN6, "fan6", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83792d_fan}, - {W83792D_SYSCTL_FAN7, "fan7", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83792d_fan}, - {W83792D_SYSCTL_TEMP1, "temp1", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83792d_temp}, - {W83792D_SYSCTL_TEMP2, "temp2", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83792d_temp_add}, - {W83792D_SYSCTL_TEMP3, "temp3", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83792d_temp_add}, - /*{W83792D_SYSCTL_VID, "vid", NULL, 0, 0444, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83792d_vid}, */ - {W83792D_SYSCTL_FAN_DIV, "fan_div", NULL, 0, 0444, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83792d_fan_div}, - {W83792D_SYSCTL_ALARMS, "alarms", NULL, 0, 0644, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &w83792d_alarms}, - {W83792D_SYSCTL_CHASSIS, "chassis", NULL, 0, 0644, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &w83792d_chassis}, - {W83792D_SYSCTL_PWM1, "pwm1", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83792d_pwm}, - {W83792D_SYSCTL_PWM2, "pwm2", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83792d_pwm}, - {W83792D_SYSCTL_PWM3, "pwm3", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83792d_pwm}, - {W83792D_SYSCTL_PWM_FLAG, "pwm_flag", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83792d_pwm_flag}, - {W83792D_SYSCTL_FAN_CFG, "fan_cfg", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83792d_fan_cfg}, - /*{W83792D_SYSCTL_VRM, "vrm", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83792d_vrm}, */ - {W83792D_SYSCTL_THERMAL_CRUISE, "thermal_cruise", NULL, 0, 0644, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &w83792d_thermal_cruise}, - {W83792D_SYSCTL_FAN_TOLERANCE, "fan_tolerance", NULL, 0, 0644, - NULL, &i2c_proc_real, &i2c_sysctl_real, NULL, &w83792d_fan_tolerance}, - {W83792D_SYSCTL_SF2_POINTS_FAN1, "sf2_points_fan1", NULL, 0, 0644, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &w83792d_sf2_points}, - {W83792D_SYSCTL_SF2_POINTS_FAN2, "sf2_points_fan2", NULL, 0, 0644, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &w83792d_sf2_points}, - {W83792D_SYSCTL_SF2_POINTS_FAN3, "sf2_points_fan3", NULL, 0, 0644, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &w83792d_sf2_points}, - {W83792D_SYSCTL_SF2_LEVELS_FAN1, "sf2_levels_fan1", NULL, 0, 0644, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &w83792d_sf2_levels}, - {W83792D_SYSCTL_SF2_LEVELS_FAN2, "sf2_levels_fan2", NULL, 0, 0644, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &w83792d_sf2_levels}, - {W83792D_SYSCTL_SF2_LEVELS_FAN3, "sf2_levels_fan3", NULL, 0, 0644, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &w83792d_sf2_levels}, - {0} -}; - -/* This function is called when: - * w83792d_driver is inserted (when this module is loaded), for each - available adapter - * when a new adapter is inserted (and w83792d_driver is still present) */ -static int w83792d_attach_adapter(struct i2c_adapter *adapter) -{ - int i_tmp; - ENTER() - i_tmp = i2c_detect(adapter, &addr_data, w83792d_detect); - LEAVE() - return i_tmp; -} - -static int -w83792d_create_subclient(struct i2c_adapter *adapter, - struct i2c_client *new_client, int addr, - struct i2c_client **sub_cli) -{ - int err; - struct i2c_client *sub_client; - - (*sub_cli) = sub_client = kmalloc(sizeof(struct i2c_client), GFP_KERNEL); - if (!(sub_client)) { - return -ENOMEM; - } - memset(sub_client, 0x00, sizeof(struct i2c_client)); - sub_client->addr = 0x48 + addr; - sub_client->data = NULL; - sub_client->adapter = adapter; - sub_client->driver = &w83792d_driver; - sub_client->flags = 0; - strcpy(sub_client->name, "w83792d subclient"); - if ((err = i2c_attach_client(sub_client))) { - printk(KERN_ERR "w83792: subclient registration " - "at address 0x%x failed\n", sub_client->addr); - kfree(sub_client); - return err; - } - return 0; -} - -static int -w83792d_detect_subclients(struct i2c_adapter *adapter, int address, int kind, - struct i2c_client *new_client) -{ - int i, id, err; - u8 val; - struct w83792d_data *data = new_client->data; - - data->lm75[0] = NULL; - data->lm75[1] = NULL; - - id = i2c_adapter_id(adapter); - if (force_subclients[0] == id && force_subclients[1] == address) { - for (i = 2; i <= 3; i++) { - if (force_subclients[i] < 0x48 || - force_subclients[i] > 0x4f) { - printk(KERN_ERR "w83792d: invalid subclient " - "address %d; must be 0x48-0x4f\n", - force_subclients[i]); - err = -ENODEV; - goto ERROR_SC_0; - } - } - w83792d_write_value(new_client, W83792D_REG_I2C_SUBADDR, - (force_subclients[2] & 0x07) | - ((force_subclients[3] & 0x07) << 4)); - } - - val = w83792d_read_value(new_client, W83792D_REG_I2C_SUBADDR); - if (!(val & 0x08)) { - err = w83792d_create_subclient(adapter, new_client, val & 0x7, - &data->lm75[0]); - if (err < 0) - goto ERROR_SC_0; - } - if (!(val & 0x80)) { - if ((data->lm75[0] != NULL) && - ((val & 0x7) == ((val >> 4) & 0x7))) { - printk(KERN_ERR "w83792d: duplicate addresses 0x%x, " - "use force_subclient\n", data->lm75[0]->addr); - err = -ENODEV; - goto ERROR_SC_1; - } - err = w83792d_create_subclient(adapter, new_client, - (val >> 4) & 0x7, &data->lm75[1]); - if (err < 0) - goto ERROR_SC_1; - } - - return 0; - -/* Undo inits in case of errors */ - -ERROR_SC_1: - if (data->lm75[0] != NULL) { - i2c_detach_client(data->lm75[0]); - kfree(data->lm75[0]); - } -ERROR_SC_0: - return err; -} - - -static int w83792d_detect(struct i2c_adapter *adapter, int address, - unsigned short flags, int kind) -{ - int i, val1 = 0, val2 = 0; - struct i2c_client *new_client; - struct w83792d_data *data; - int err = 0; - const char *type_name = ""; - const char *client_name = ""; - - ENTER() - - if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) { - LEAVE() - goto ERROR0; - } - - /* OK. For now, we presume we have a valid client. We now create the - client structure, even though we cannot fill it completely yet. - But it allows us to access w83792d_{read,write}_value. */ - - if (!(data = kmalloc(sizeof(struct w83792d_data), GFP_KERNEL))) { - printk(KERN_ERR "w83792d: Out of memory in w83792d_detect (new_client).\n"); - err = -ENOMEM; - LEAVE() - goto ERROR0; - } - - new_client = &data->client; - new_client->addr = address; - new_client->data = data; - new_client->adapter = adapter; - new_client->driver = &w83792d_driver; - new_client->flags = 0; - - /* Now, we do the remaining detection. */ - if (kind < 0) { - if (w83792d_read_value(new_client, W83792D_REG_CONFIG)&0x80) { - LEAVE() - goto ERROR1; - } - val1 = w83792d_read_value(new_client, W83792D_REG_BANK); - val2 = w83792d_read_value(new_client, W83792D_REG_CHIPMAN); -#ifdef W83792D_DEBUG - printk(KERN_DEBUG "w83792d: val1 is: %d, val2 is: %d\n", - val1, val2); -#endif - /* Check for Winbond ID if in bank 0 */ - if (!(val1 & 0x07)) { /* is Bank0 */ - if (((!(val1 & 0x80)) && (val2 != 0xa3)) || - ((val1 & 0x80) && (val2 != 0x5c))) { - LEAVE() - goto ERROR1; - } - } - /* check address at 0x48. */ - if (w83792d_read_value(new_client, W83792D_REG_I2C_ADDR) - != address) { - LEAVE() - goto ERROR1; - } - } - - /* We have either had a force parameter, or we have already detected - the Winbond. Put it now into bank 0 and Vendor ID High Byte */ - w83792d_write_value(new_client, W83792D_REG_BANK, - (w83792d_read_value(new_client, - W83792D_REG_BANK) & 0x78) | - 0x80); - - /* Determine the chip type. */ - if (kind <= 0) { - /* get vendor ID */ - val2 = w83792d_read_value(new_client, W83792D_REG_CHIPMAN); - if (val2 != 0x5c) { /* the vendor is NOT Winbond */ - LEAVE() - goto ERROR1; - } - val1 = w83792d_read_value(new_client, W83792D_REG_WCHIPID); - if (val1 == 0x7a) { - kind = w83792d; - } else { - if (kind == 0) - printk(KERN_WARNING "w83792d: Ignoring " - "'force' parameter for unknown chip " - "at adapter %d, address 0x%02x\n", - i2c_adapter_id(adapter), address); - LEAVE() - goto ERROR1; - } - } - - if (kind == w83792d) { - type_name = "w83792d"; - client_name = "W83792D chip"; - } else { - printk(KERN_ERR "w83792d: Internal error: unknown kind (%d)\n", - kind); - LEAVE() - goto ERROR1; - } - - /* Fill in the remaining client fields and put it into the global list */ - strcpy(new_client->name, client_name); - data->type = kind; - data->valid = 0; - data->has_fan = 0x07; /* at least 3 fan inputs */ - init_MUTEX(&data->update_lock); - - /* Tell the I2C layer a new client has arrived */ - if ((err = i2c_attach_client(new_client))) { - LEAVE() - goto ERROR1; - } - - if ((err = w83792d_detect_subclients(adapter, address, - kind, new_client))) - goto ERROR2; - - /* Read GPIO enable register to check if pins for fan 4,5 are used as - GPIO */ - val1 = w83792d_read_value(new_client, W83792D_REG_GPIO_EN); - if (!(val1 & 0x40)) - data->has_fan |= 0x08; /* fan 4 */ - if (!(val1 & 0x20)) - data->has_fan |= 0x10; /* fan 5 */ - - val1 = w83792d_read_value(new_client, W83792D_REG_PIN); - if (val1 & 0x40) - data->has_fan |= 0x20; /* fan 6 */ - if (val1 & 0x04) - data->has_fan |= 0x40; /* fan 7 */ - - /* Register a new directory entry with module sensors */ - if ((i = i2c_register_entry(new_client, type_name, - w83792d_dir_table_template, THIS_MODULE)) < 0) { - err = i; - goto ERROR3; - } - data->sysctl_id = i; - - /* Initialize the chip */ - w83792d_init_client(new_client); - LEAVE() - return 0; - -ERROR3: - if (data->lm75[0] != NULL) { - i2c_detach_client(data->lm75[0]); - kfree(data->lm75[0]); - } - if (data->lm75[1] != NULL) { - i2c_detach_client(data->lm75[1]); - kfree(data->lm75[1]); - } -ERROR2: - i2c_detach_client(new_client); -ERROR1: - kfree(data); -ERROR0: - - LEAVE() - return err; -} - -static int w83792d_detach_client(struct i2c_client *client) -{ - int err; - struct w83792d_data *data = client->data; - ENTER() - - /* remove sysctl table (primary client only) */ - if ((data)) - i2c_deregister_entry(data->sysctl_id); - - if ((err = i2c_detach_client(client))) { - printk(KERN_ERR "w83792d: Client deregistration failed, client not detached.\n"); - LEAVE() - return err; - } - - if (data) { - /* primary client */ - kfree(data); - } else { - /* subclients */ - kfree(client); - } - - return 0; -} - -/* Called when we have found a new W83792D. */ -static void w83792d_init_client(struct i2c_client *client) -{ - int temp2_cfg, temp3_cfg; - u8 vid_in_b; - - ENTER() - - if (init) { - w83792d_write_value(client, W83792D_REG_CONFIG, 0x80); - } - /* data->vrm = 90; */ /* maybe need to be modified! */ - - /* Clear the bit6 of W83792D_REG_VID_IN_B(set it into 0): - W83792D_REG_VID_IN_B bit6 = 0: the high/low limit of - vin0/vin1 can be modified by user; - W83792D_REG_VID_IN_B bit6 = 1: the high/low limit of - vin0/vin1 auto-updated, can NOT be modified by user. */ - vid_in_b = w83792d_read_value(client, W83792D_REG_VID_IN_B); - w83792d_write_value(client, W83792D_REG_VID_IN_B, - vid_in_b & 0xbf); - - temp2_cfg = w83792d_read_value(client, W83792D_REG_TEMP_ADD[0][6]); - temp3_cfg = w83792d_read_value(client, W83792D_REG_TEMP_ADD[1][6]); - w83792d_write_value(client, W83792D_REG_TEMP_ADD[0][6], - temp2_cfg & 0xe6); - w83792d_write_value(client, W83792D_REG_TEMP_ADD[1][6], - temp3_cfg & 0xe6); - - /* Start monitoring */ - w83792d_write_value(client, W83792D_REG_CONFIG, (w83792d_read_value( - client, W83792D_REG_CONFIG) & 0xf7) | 0x01); - LEAVE() -} - -static void w83792d_update_client(struct i2c_client *client) -{ - struct w83792d_data *data = client->data; - int i, j; - u8 reg_array_tmp[4], pwm_array_tmp[7], reg_tmp; - - down(&data->update_lock); - - if (time_after(jiffies - data->last_updated, HZ * 3) || - time_before(jiffies, data->last_updated) || !data->valid) { - pr_debug(KERN_DEBUG "Starting device update\n"); - - /* Update the voltages measured value and limits */ - for (i = 0; i < 9; i++) { - data->in[i] = w83792d_read_value(client, - W83792D_REG_IN[i]); - data->in_max[i] = w83792d_read_value(client, - W83792D_REG_IN_MAX[i]); - data->in_min[i] = w83792d_read_value(client, - W83792D_REG_IN_MIN[i]); - } - data->low_bits = w83792d_read_value(client, - W83792D_REG_LOW_BITS1) + - (w83792d_read_value(client, - W83792D_REG_LOW_BITS2) << 8); - - for (i = 0; i < 7; i++) { - /* Update the Fan measured value and limits */ - data->fan[i] = w83792d_read_value(client, - W83792D_REG_FAN[i]); - data->fan_min[i] = w83792d_read_value(client, - W83792D_REG_FAN_MIN[i]); - /* Update the PWM/DC Value and PWM/DC flag */ - pwm_array_tmp[i] = w83792d_read_value(client, - W83792D_REG_PWM[i]); - data->pwm[i] = pwm_array_tmp[i] & 0x0f; - data->pwm_flag[i] = pwm_array_tmp[i] >> 7; - } - data->fan_cfg = w83792d_read_value(client, W83792D_REG_FAN_CFG); - - /* Update the Fan Divisor */ - for (i = 0; i < 4; i++) { - reg_array_tmp[i] = w83792d_read_value(client, W83792D_REG_FAN_DIV[i]); - } - data->fan_div[0] = reg_array_tmp[0] & 0x07; - data->fan_div[1] = (reg_array_tmp[0] >> 4) & 0x07; - data->fan_div[2] = reg_array_tmp[1] & 0x07; - data->fan_div[3] = (reg_array_tmp[1] >> 4) & 0x07; - data->fan_div[4] = reg_array_tmp[2] & 0x07; - data->fan_div[5] = (reg_array_tmp[2] >> 4) & 0x07; - data->fan_div[6] = reg_array_tmp[3] & 0x07; - - for (i = 0; i < 7; i++) { - if (!(data->has_fan & (1 << i))) - continue; - if (data->fan[i] == 0xff && data->fan_div[i] < 7) - w83792d_set_fan_div(client, i, 7); - else if (data->fan[i] < 0x70 && data->fan_div[i] > 0) { - w83792d_set_fan_div(client, i, - data->fan_div[i] - 1); - } else if (data->fan[i] > 0xf8 && - data->fan_div[i] < 7) { - w83792d_set_fan_div(client, i, - data->fan_div[i] + 1); - } - } - - /* Update the Temperature1 measured value and limits */ - data->temp1[0] = w83792d_read_value(client, W83792D_REG_TEMP1); - data->temp1[1] = w83792d_read_value(client, W83792D_REG_TEMP1_OVER); - data->temp1[2] = w83792d_read_value(client, W83792D_REG_TEMP1_HYST); - - /* Update the Temperature2/3 measured value and limits */ - for (i = 0; i < 7; i++) { - data->temp_add[0][i] = w83792d_read_value(client, - W83792D_REG_TEMP_ADD[0][i]); - data->temp_add[1][i] = w83792d_read_value(client, - W83792D_REG_TEMP_ADD[1][i]); - } - - /* Update the VID */ - /* i = w83792d_read_value(client, W83792D_REG_FAN_DIV[0]); - data->vid = i & 0x0f; - data->vid |= - (w83792d_read_value(client, W83792D_REG_CHIPID) & 0x01) - << 4; */ - - /* Update the realtime status */ - data->alarms = w83792d_read_value(client, W83792D_REG_ALARM1) + - (w83792d_read_value(client, W83792D_REG_ALARM2) << 8) + - (w83792d_read_value(client, W83792D_REG_ALARM3) << 16); - - /* Update CaseOpen status and it's CLR_CHS. */ - data->chassis[0] = (w83792d_read_value(client, - W83792D_REG_CASE_OPEN) - >> 5) & 0x01; - data->chassis[1] = (w83792d_read_value(client, - W83792D_REG_CASE_OPEN_CLR) - >> 7) & 0x01; - - /* Update Thermal Cruise/Smart Fan I target value */ - for (i = 0; i < 3; i++) { - data->thermal_cruise[i] = - w83792d_read_value(client, - W83792D_REG_THERMAL[i]) & 0x7f; - } - - /* Update Smart Fan I/II tolerance */ - reg_tmp = w83792d_read_value(client, W83792D_REG_FAN_TOL[0]); - data->fan_tolerance[0] = reg_tmp & 0x0f; - data->fan_tolerance[1] = (reg_tmp >> 4) & 0x0f; - data->fan_tolerance[2] = - w83792d_read_value(client, W83792D_REG_FAN_TOL[2]) & 0x0f; - - /* Update Smart Fan II temperature points */ - for (i = 0; i < 3; i++) { - for (j = 0; j < 4; j++) { - data->sf2_points[i][j] = w83792d_read_value( - client,W83792D_REG_POINTS[i][j]) & 0x7f; - } - } - - /* Update Smart Fan II duty cycle levels */ - for (i = 0; i < 3; i++) { - reg_tmp = w83792d_read_value(client, - W83792D_REG_LEVELS[i][0]); - data->sf2_levels[i][0] = reg_tmp & 0x0f; - data->sf2_levels[i][1] = (reg_tmp >> 4) & 0x0f; - reg_tmp = w83792d_read_value(client, - W83792D_REG_LEVELS[i][2]); - data->sf2_levels[i][2] = (reg_tmp >> 4) & 0x0f; - data->sf2_levels[i][3] = reg_tmp & 0x0f; - } - data->last_updated = jiffies; - data->valid = 1; -#ifdef W83792D_DEBUG - w83792d_print_debug(data); -#endif - } - up(&data->update_lock); -} - -/* This is a function used to debug the message. */ -#ifdef W83792D_DEBUG -static void w83792d_print_debug(struct w83792d_data *data) -{ - int i=0, j=0; - printk(KERN_DEBUG "==========The following is the debug message...========\n"); - printk(KERN_DEBUG "9 set of Voltages: =====>\n"); - for (i=0; i<=8; i++) { - printk(KERN_DEBUG "vin[%d] is: 0x%x\n", i, data->in[i]); - printk(KERN_DEBUG "vin[%d] max is: 0x%x\n", i, data->in_max[i]); - printk(KERN_DEBUG "vin[%d] min is: 0x%x\n", i, data->in_min[i]); - } - printk(KERN_DEBUG "Low Bit1 is: 0x%x\n", data->low_bits & 0xff); - printk(KERN_DEBUG "Low Bit2 is: 0x%x\n", data->low_bits >> 8); - printk(KERN_DEBUG "7 set of Fan Counts and 3 set of Duty Cycles: =====>\n"); - printk(KERN_DEBUG "fan_cfg is: 0x%x\n", data->fan_cfg); - for (i=0; i<=6; i++) { - printk(KERN_DEBUG "fan[%d] is: 0x%x\n", i, data->fan[i]); - printk(KERN_DEBUG "fan[%d] min is: 0x%x\n", i, data->fan_min[i]); - if (i<3) { - printk(KERN_DEBUG "pwm[%d] is: 0x%x\n", i, data->pwm[i]); - printk(KERN_DEBUG "pwm_flag[%d] is: 0x%x\n", i, data->pwm_flag[i]); - } - } - printk(KERN_DEBUG "3 set of Temperatures: =====>\n"); - printk(KERN_DEBUG "temp1 is: 0x%x\n", data->temp1[0]); - printk(KERN_DEBUG "temp1 high limit is: 0x%x\n", data->temp1[1]); - printk(KERN_DEBUG "temp1 low limit is: 0x%x\n", data->temp1[2]); - for (i=0; i<2; i++) { - for (j=0; j<7; j++) { - printk(KERN_DEBUG "temp_add[%d][%d] is: 0x%x\n", i, j, - data->temp_add[i][j]); - } - } - for (i=0; i<=6; i++) { - printk(KERN_DEBUG "fan_div[%d] is: 0x%x\n", i, data->fan_div[i]); - } - printk(KERN_DEBUG "==========End of the debug message...==================\n\n"); -} -#endif - -/* The next few functions are the call-back functions of the /proc/sys and - sysctl files. Which function is used is defined in the ctl_table in - the extra1 field. - Each function must return the magnitude (power of 10 to divide the date - with) if it is called with operation==SENSORS_PROC_REAL_INFO. It must - put a maximum of *nrels elements in results reflecting the data of this - file, and set *nrels to the number it actually put in it, if operation== - SENSORS_PROC_REAL_READ. Finally, it must get upto *nrels elements from - results and write them to the chip, if operations==SENSORS_PROC_REAL_WRITE. - Note that on SENSORS_PROC_REAL_READ, I do not check whether results is - large enough (by checking the incoming value of *nrels). This is not very - good practice, but as long as you put less than about 5 values in results, - you can assume it is large enough. */ - -/* read/write voltage meaured value and limits */ -static void w83792d_in(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct w83792d_data *data = client->data; - int nr = ctl_name - W83792D_SYSCTL_IN0; - - /* result[0]: low limit, result[1]: high limit, - result[2]: measured value */ - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 3; - else if (operation == SENSORS_PROC_REAL_READ) { - w83792d_update_client(client); - results[0] = IN_FROM_REG(nr, data->in_min[nr]*4); - results[1] = IN_FROM_REG(nr, data->in_max[nr]*4); - /* in7 and in8 do not have low bits, but the formula still - works */ - results[2] = IN_FROM_REG(nr, ((data->in[nr] << 2) | - ((data->low_bits >> (2 * nr)) - & 0x03))); - *nrels_mag = 3; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag >= 1) { - /* Write Low limit into register. */ - data->in_min[nr] = SENSORS_LIMIT(IN_TO_REG(nr,results[0])/4, - 0, 255); - w83792d_write_value(client, W83792D_REG_IN_MIN[nr], - data->in_min[nr]); - } - if (*nrels_mag >= 2) { - /* Write High limit into register. */ - data->in_max[nr] = SENSORS_LIMIT(IN_TO_REG(nr,results[1])/4, - 0, 255); - w83792d_write_value(client, W83792D_REG_IN_MAX[nr], - data->in_max[nr]); - } - } -} - -static void w83792d_set_fan_div(struct i2c_client *client, int nr, u8 newdiv) -{ - struct w83792d_data *data = client->data; - int min, old; - u8 tmp; - - min = FAN_FROM_REG(data->fan_min[nr], DIV_FROM_REG(data->fan_div[nr])); - old = FAN_FROM_REG(data->fan[nr], DIV_FROM_REG(data->fan_div[nr])); - data->fan_div[nr] = newdiv; - tmp = w83792d_read_value(client, W83792D_REG_FAN_DIV[nr >> 1]); - tmp &= (nr & 1) ? 0x8f : 0xf8; - tmp |= (nr & 1) ? ((newdiv << 4) & 0x70) : (newdiv & 0x07); - w83792d_write_value(client, W83792D_REG_FAN_DIV[nr >> 1], tmp); - data->fan_min[nr] = FAN_TO_REG(min, DIV_FROM_REG(data->fan_div[nr])); - data->fan[nr] = FAN_TO_REG(old, DIV_FROM_REG(data->fan_div[nr])); - w83792d_write_value(client, W83792D_REG_FAN_MIN[nr], - data->fan_min[nr]); -} - -/* read/write fan meaured value and limits */ -static void w83792d_fan(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct w83792d_data *data = client->data; - int nr = ctl_name - W83792D_SYSCTL_FAN1; - - /* result[0]: low limit, result[1]: measured value */ - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - w83792d_update_client(client); - if (data->has_fan & (1 << nr)) { - results[0] = FAN_FROM_REG(data->fan_min[nr], - DIV_FROM_REG(data->fan_div[nr])); - results[1] = FAN_FROM_REG(data->fan[nr], - DIV_FROM_REG(data->fan_div[nr])); - } else { - results[0] = 0; - results[1] = 0; - } - *nrels_mag = 2; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag >= 1 && (data->has_fan & (1 << nr))) { - data->fan_min[nr] = FAN_TO_REG(results[0], - DIV_FROM_REG(data->fan_div[nr])); - w83792d_write_value(client, - W83792D_REG_FAN_MIN[nr], - data->fan_min[nr]); - } - } -} - -/* read/write temperature1 meaured value and limits */ -static void w83792d_temp(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct w83792d_data *data = client->data; - - /* result[0]: high limit, result[1]: low limit - result[2]: measured value, the order is different with voltage(in) */ - if (operation == SENSORS_PROC_REAL_INFO) { - *nrels_mag = 1; - } else if (operation == SENSORS_PROC_REAL_READ) { - w83792d_update_client(client); - results[0] = TEMP_FROM_REG(data->temp1[1]); - results[1] = TEMP_FROM_REG(data->temp1[2]); - results[2] = TEMP_FROM_REG(data->temp1[0]); - *nrels_mag = 3; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag >= 1) { - data->temp1[1] = TEMP_TO_REG(results[0]); - w83792d_write_value(client, W83792D_REG_TEMP1_OVER, - data->temp1[1]); - } - if (*nrels_mag >= 2) { - data->temp1[2] = TEMP_TO_REG(results[1]); - w83792d_write_value(client, W83792D_REG_TEMP1_HYST, - data->temp1[2]); - } - } -} - -/* read/write temperature2,3 meaured value and limits */ -static void w83792d_temp_add(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results) -{ - struct w83792d_data *data = client->data; - int nr = ctl_name - W83792D_SYSCTL_TEMP2; - int i=0, j=0; - - /* result[0]: high limit, result[1]: low limit - result[2]: measured value, the order is different with voltage(in) */ - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 1; - else if (operation == SENSORS_PROC_REAL_READ) { - w83792d_update_client(client); - for (i=0; i<3; i++) { - j = (i==0) ? 2 : ((i==1)?0:1); - if ((data->temp_add[nr][i*2+1]) & 0x80) { - results[j] = TEMP_FROM_REG(data->temp_add[nr][i*2]) + 5; - } else { - results[j] = TEMP_FROM_REG(data->temp_add[nr][i*2]); - } - } - *nrels_mag = 3; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag >= 1) { - data->temp_add[nr][2] = TEMP_TO_REG(results[0]); - w83792d_write_value(client, - W83792D_REG_TEMP_ADD[nr][2], - data->temp_add[nr][2]); - if ((results[0]%10) == 0) { - w83792d_write_value(client, - W83792D_REG_TEMP_ADD[nr][3], 0x00); - } else { /* consider the 0.5 degree */ - w83792d_write_value(client, - W83792D_REG_TEMP_ADD[nr][3], 0x80); - } - } - if (*nrels_mag >= 2) { - data->temp_add[nr][4] = TEMP_TO_REG(results[1]); - w83792d_write_value(client, - W83792D_REG_TEMP_ADD[nr][4], - data->temp_add[nr][4]); - if ((results[1]%10) == 0) { - w83792d_write_value(client, - W83792D_REG_TEMP_ADD[nr][5], 0x00); - } else { /* consider the 0.5 degree */ - w83792d_write_value(client, - W83792D_REG_TEMP_ADD[nr][5], 0x80); - } - } - } -} - -/* -void w83792d_vid(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct w83792d_data *data = client->data; - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 3; - else if (operation == SENSORS_PROC_REAL_READ) { - w83792d_update_client(client); - results[0] = vid_from_reg(data->vid, data->vrm); - *nrels_mag = 1; - } -} - -void w83792d_vrm(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct w83792d_data *data = client->data; - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 1; - else if (operation == SENSORS_PROC_REAL_READ) { - results[0] = data->vrm; - *nrels_mag = 1; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag >= 1) { - data->vrm = results[0]; - } - } -} */ - -/* Read/Write Fan Divisor */ -static void w83792d_fan_div(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results) -{ - struct w83792d_data *data = client->data; - int i = 0; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - w83792d_update_client(client); - for (i=0; i<7; i++) { - results[i] = DIV_FROM_REG(data->fan_div[i]); - } - *nrels_mag = 7; - } -} - - -/* Under Smart Fan I mode: read/write the Fan1/2/3 target temperature */ -static void w83792d_thermal_cruise(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results) -{ - struct w83792d_data *data = client->data; - int i=0; - u8 target_tmp=0, target_mask=0; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - w83792d_update_client(client); - for (i=0; i<3; i++) { - results[i] = data->thermal_cruise[i]; - } - *nrels_mag = 3; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - for (i=0; i<3; i++) { - if (*nrels_mag < (i+1)) { - return; - } - target_tmp = results[i]; - target_tmp = target_tmp & 0x7f; - target_mask = w83792d_read_value(client, - W83792D_REG_THERMAL[i]) & 0x80; - data->thermal_cruise[i] = SENSORS_LIMIT(target_tmp, 0, 255); - w83792d_write_value(client, W83792D_REG_THERMAL[i], - (data->thermal_cruise[i])|target_mask); - } - } -} - -/* The tolerance of fan1/fan2/fan3, when using Thermal Cruise(Smart Fan I) - or Smart Fan II mode. */ -static void w83792d_fan_tolerance(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results) -{ - struct w83792d_data *data = client->data; - int i=0; - u8 tol_tmp, tol_mask; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - w83792d_update_client(client); - for (i=0; i<3; i++) { - results[i] = data->fan_tolerance[i]; - } - *nrels_mag = 3; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - for (i=0; i<3; i++) { - if (*nrels_mag < (i+1)) { - return; - } - tol_mask = w83792d_read_value(client, - W83792D_REG_FAN_TOL[i]) & ((i==1)?0x0f:0xf0); - tol_tmp = SENSORS_LIMIT(results[i], 0, 15); - tol_tmp &= 0x0f; - data->fan_tolerance[i] = tol_tmp; - if (i==1) { - tol_tmp <<= 4; - } - w83792d_write_value(client, W83792D_REG_FAN_TOL[i], - tol_mask|tol_tmp); - } - } -} - -/* Under Smart Fan II mode: read/write the Fan1/2/3 temperature points */ -static void w83792d_sf2_points(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results) -{ - struct w83792d_data *data = client->data; - int nr = ctl_name - W83792D_SYSCTL_SF2_POINTS_FAN1; - int j=0; - u8 mask_tmp = 0; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - w83792d_update_client(client); - for (j=0; j<4; j++) { - results[j] = data->sf2_points[nr][j]; - } - *nrels_mag = 4; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - for (j=0; j<4; j++) { - if (*nrels_mag < (j+1)) { - return; - } - data->sf2_points[nr][j] = SENSORS_LIMIT(results[j], - 0, 127); - mask_tmp = w83792d_read_value(client, - W83792D_REG_POINTS[nr][j]) & 0x80; - w83792d_write_value(client, W83792D_REG_POINTS[nr][j], - mask_tmp|data->sf2_points[nr][j]); - } - } -} - -/* Smart Fan II Duty Cycle1/2/3 of Fan1/2/3. - Notice that: The Non-Stop can NOT be modified by user, - because it is related with some physical characters, - usually set by BIOS. User's modification to it may lead to - Fan's stop, then bring danger. */ -static void w83792d_sf2_levels(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results) -{ - struct w83792d_data *data = client->data; - int nr = ctl_name - W83792D_SYSCTL_SF2_LEVELS_FAN1; - int j = 0; - u8 mask_tmp = 0, level_tmp = 0; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - w83792d_update_client(client); - for (j=0; j<4; j++) { - results[j] = (data->sf2_levels[nr][j] * 100) / 15; - } - *nrels_mag = 4; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - for (j=1; j<4; j++) { /* start with 1: need ignore Non-Stop */ - if (*nrels_mag < j) { - return; - } - data->sf2_levels[nr][j] = - SENSORS_LIMIT((results[j]*15)/100, 0, 15); - mask_tmp = w83792d_read_value(client, W83792D_REG_LEVELS[nr][j]) - & ((j==3) ? 0xf0 : 0x0f); - if (j==3) { - level_tmp = data->sf2_levels[nr][j]; - } else { - level_tmp = data->sf2_levels[nr][j] << 4; - } - w83792d_write_value(client, W83792D_REG_LEVELS[nr][j], - level_tmp | mask_tmp); - } - } -} - -/* get reatime status of all sensors items: voltage, temp, fan */ -static void w83792d_alarms(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct w83792d_data *data = client->data; - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - w83792d_update_client(client); - results[0] = data->alarms; - *nrels_mag = 1; - } -} - -/* Read/Write Chassis status and Reset Chassis. */ -static void w83792d_chassis(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results) -{ - struct w83792d_data *data = client->data; - u8 temp1 = 0, temp2 = 0; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - w83792d_update_client(client); - results[0] = data->chassis[0]; - results[1] = data->chassis[1]; - *nrels_mag = 2; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - data->chassis[1] = SENSORS_LIMIT(results[1], 0 ,1); - temp1 = ((data->chassis[1]) << 7) & 0x80; - temp2 = w83792d_read_value(client, - W83792D_REG_CASE_OPEN_CLR) & 0x7f; - w83792d_write_value(client, - W83792D_REG_CASE_OPEN_CLR, - temp1|temp2); - } -} - -/* Read/Write PWM/DC value of Fan1,Fan2,Fan3, which controls the - Fan Duty Cycle */ -static void w83792d_pwm(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct w83792d_data *data = client->data; - int nr = ctl_name - W83792D_SYSCTL_PWM1; - u8 pwm_mask; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - w83792d_update_client(client); - results[0] = data->pwm[nr] << 4; - *nrels_mag = 1; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - data->pwm[nr] = SENSORS_LIMIT(results[0], 0, 255) >> 4; - pwm_mask = w83792d_read_value(client,W83792D_REG_PWM[nr]) & 0xf0; - w83792d_write_value(client,W83792D_REG_PWM[nr],pwm_mask|data->pwm[nr]); - } -} - -/* Read/Write PWM/DC mode for Fan1,Fan2,Fan3: - 1->PWM mode, 0->DC mode */ -static void w83792d_pwm_flag(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct w83792d_data *data = client->data; - int i = 0; - u8 pwm_flag_mask; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - w83792d_update_client(client); - for (i=0; i<3; i++) { - results[i] = data->pwm_flag[i]; - } - *nrels_mag = 3; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - for (i=0; i<3; i++) { - if (*nrels_mag < (i+1)) { - return; - } - data->pwm_flag[i] = SENSORS_LIMIT(results[i], 0, 1); - pwm_flag_mask = w83792d_read_value(client, - W83792D_REG_PWM[i]) & 0x7f; - w83792d_write_value(client, W83792D_REG_PWM[i], - ((data->pwm_flag[i])<<7)|pwm_flag_mask); - } - } -} - -/* Read/Write Fan mode into:PWM/DC, Thermal Cruise(SmartFanI), SmartFanII - 0->PWM/DC mode, 1->Thermal Cruise mode, 2/3->SmartFanII mode */ -static void w83792d_fan_cfg(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results) -{ - struct w83792d_data *data = client->data; - u8 temp_cfg1, temp_cfg2, temp_cfg3, temp_cfg4; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - w83792d_update_client(client); - results[0] = (data->fan_cfg) & 0x03; /* Fan1's Mode */ - results[1] = ((data->fan_cfg)>>2) & 0x03; /* Fan2's Mode */ - results[2] = ((data->fan_cfg)>>4) & 0x03; /* Fan3's Mode */ - *nrels_mag = 3; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag < 3) { - return; - } - temp_cfg1 = SENSORS_LIMIT(results[0], 0, 3); - temp_cfg2 = SENSORS_LIMIT(results[1], 0, 3) << 2; - temp_cfg3 = SENSORS_LIMIT(results[2], 0, 3) << 4; - temp_cfg4 = w83792d_read_value(client,W83792D_REG_FAN_CFG) & 0xc0; - data->fan_cfg = ((temp_cfg4|temp_cfg3)|temp_cfg2)|temp_cfg1; - w83792d_write_value(client,W83792D_REG_FAN_CFG,data->fan_cfg); - } -} - -static int __init sm_w83792d_init(void) -{ - ENTER() - - printk(KERN_INFO "w83792d version %s (%s)\n", LM_VERSION, LM_DATE); - - LEAVE() - return i2c_add_driver(&w83792d_driver); -} - -static void __exit sm_w83792d_exit(void) -{ - ENTER() - - i2c_del_driver(&w83792d_driver); - - LEAVE() -} - - -MODULE_AUTHOR("Chunhao Huang @ Winbond"); -MODULE_DESCRIPTION("W83792AD/D driver for linux-2.4"); -MODULE_LICENSE("GPL"); - -module_init(sm_w83792d_init); -module_exit(sm_w83792d_exit); - diff --git a/kernel/chips/w83l785ts.c b/kernel/chips/w83l785ts.c deleted file mode 100644 index 07726c7d..00000000 --- a/kernel/chips/w83l785ts.c +++ /dev/null @@ -1,378 +0,0 @@ -/* - * w83l785ts.c - Part of lm_sensors, Linux kernel modules for hardware - * monitoring - * Copyright (C) 2003-2004 Jean Delvare - * - * Inspired from the lm83 driver. The W83L785TS-S is a sensor chip made - * by Winbond. It reports a single external temperature with a 1 deg - * resolution and a 3 deg accuracy. Data sheet can be obtained from - * Winbond's website at: - * http://www.winbond-usa.com/products/winbond_products/pdfs/PCIC/W83L785TS-S.pdf - * - * Thanks to James Bolt for benchmarking the read - * error handling mechanism. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include -#include -#include -#include -#include -#include -#include "version.h" - -#ifndef I2C_DRIVERID_W83L785TS -#define I2C_DRIVERID_W83L785TS 1047 -#endif - -/* How many retries on register read error */ -#define MAX_RETRIES 5 - -/* - * Address to scan - * Address is fully defined internally and cannot be changed. - */ - -static unsigned short normal_i2c[] = { 0x2e, SENSORS_I2C_END }; -static unsigned short normal_i2c_range[] = { SENSORS_I2C_END }; -static unsigned int normal_isa[] = { SENSORS_ISA_END }; -static unsigned int normal_isa_range[] = { SENSORS_ISA_END }; - -/* - * Insmod parameters - */ - -SENSORS_INSMOD_1(w83l785ts); - -/* - * The W83L785TS-S registers - * Manufacturer ID is 0x5CA3 for Winbond. - */ - -#define W83L785TS_REG_MAN_ID1 0x4D -#define W83L785TS_REG_MAN_ID2 0x4C -#define W83L785TS_REG_CHIP_ID 0x4E -#define W83L785TS_REG_CONFIG 0x40 -#define W83L785TS_REG_TYPE 0x52 -#define W83L785TS_REG_TEMP 0x27 -#define W83L785TS_REG_TEMP_OVER 0x53 /* not sure about this one */ - -/* - * Conversions - * The W83L785TS-S uses signed 8-bit values. - */ - -#define TEMP_FROM_REG(val) (val) - -/* - * Functions declaration - */ - -static int w83l785ts_attach_adapter(struct i2c_adapter *adapter); -static int w83l785ts_detect(struct i2c_adapter *adapter, int address, unsigned - short flags, int kind); -static int w83l785ts_detach_client(struct i2c_client *client); -static u8 w83l785ts_read_value(struct i2c_client *client, u8 reg, u8 defval); -static void w83l785ts_update_client(struct i2c_client *client); -static void w83l785ts_temp(struct i2c_client *client, int operation, int - ctl_name, int *nrels_mag, long *results); - -/* - * Driver data (common to all clients) - */ - -static struct i2c_driver w83l785ts_driver = { - .name = "W83L785S-S sensor driver", - .id = I2C_DRIVERID_W83L785TS, - .flags = I2C_DF_NOTIFY, - .attach_adapter = w83l785ts_attach_adapter, - .detach_client = w83l785ts_detach_client, -}; - -/* - * Client data (each client gets its own) - */ - -struct w83l785ts_data { - struct i2c_client client; - int sysctl_id; - - struct semaphore update_lock; - char valid; /* zero until following fields are valid */ - unsigned long last_updated; /* in jiffies */ - - /* registers values */ - s8 temp, temp_over; -}; - -/* - * Proc entries - * These files are created for each detected W83L785TS-S. - */ - -/* -- SENSORS SYSCTL START -- */ - -#define W83L785TS_SYSCTL_TEMP 1200 - -/* -- SENSORS SYSCTL END -- */ - - -static ctl_table w83l785ts_dir_table_template[] = -{ - {W83L785TS_SYSCTL_TEMP, "temp", NULL, 0, 0444, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &w83l785ts_temp}, - {0} -}; - -/* - * Real code - */ - -static int w83l785ts_attach_adapter(struct i2c_adapter *adapter) -{ - return i2c_detect(adapter, &addr_data, w83l785ts_detect); -} - -/* - * The following function does more than just detection. If detection - * succeeds, it also registers the new chip. - */ -static int w83l785ts_detect(struct i2c_adapter *adapter, int address, - unsigned short flags, int kind) -{ - struct i2c_client *new_client; - struct w83l785ts_data *data; - int err = 0; - const char *type_name = ""; - const char *client_name = ""; - - if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) { -#ifdef DEBUG - printk(KERN_DEBUG "w83l785ts.o: I2C bus doesn't support " - "byte read mode, skipping.\n"); -#endif - return 0; - } - - if (!(data = kmalloc(sizeof(struct w83l785ts_data), GFP_KERNEL))) { - printk(KERN_ERR "w83l785ts.o: Out of memory in w83l785ts_detect " - "(new_client).\n"); - return -ENOMEM; - } - - /* - * The common I2C client data is placed right after the - * W83L785TS-specific. The W83L785TS-specific data is pointed to by the - * data field from the I2C client data. - */ - - new_client = &data->client; - new_client->addr = address; - new_client->data = data; - new_client->adapter = adapter; - new_client->driver = &w83l785ts_driver; - new_client->flags = 0; - - /* - * Now we do the remaining detection. A negative kind means that - * the driver was loaded with no force parameter (default), so we - * must both detect and identify the chip (actually there is only - * one possible kind of chip for now, W83L785TS-S). A zero kind means - * that the driver was loaded with the force parameter, the detection - * step shall be skipped. A positive kind means that the driver - * was loaded with the force parameter and a given kind of chip is - * requested, so both the detection and the identification steps - * are skipped. - */ - - if (kind < 0) { /* detection */ - if (((w83l785ts_read_value(new_client, W83L785TS_REG_CONFIG, 0) - & 0x80) != 0x00) - || ((w83l785ts_read_value(new_client, W83L785TS_REG_TYPE, 0) - & 0xFC) != 0x00)) { -#ifdef DEBUG - printk(KERN_DEBUG "w83l785ts.o: Detection failed at " - "0x%02x.\n", address); -#endif - goto ERROR1; - } - } - - if (kind <= 0) { /* identification */ - u16 man_id; - u8 chip_id; - - man_id = (w83l785ts_read_value(new_client, W83L785TS_REG_MAN_ID1, 0) << 8) - + w83l785ts_read_value(new_client, W83L785TS_REG_MAN_ID2, 0); - chip_id = w83l785ts_read_value(new_client, W83L785TS_REG_CHIP_ID, 0); - if (man_id == 0x5CA3) { /* Winbond */ - if (chip_id == 0x70) - kind = w83l785ts; - } - } - - if (kind <= 0) { /* identification failed */ - printk(KERN_INFO "w83l785ts.o: Unsupported chip.\n"); - goto ERROR1; - } - - if (kind == w83l785ts) { - type_name = "w83l785ts"; - client_name = "W83L785TS-S chip"; - } else { - printk(KERN_ERR "w83l785ts.o: Unknown kind %d.\n", kind); - goto ERROR1; - } - - /* - * OK, we got a valid chip so we can fill in the remaining client - * fields. - */ - - strcpy(new_client->name, client_name); - data->valid = 0; - init_MUTEX(&data->update_lock); - - /* - * Tell the I2C layer a new client has arrived. - */ - - if ((err = i2c_attach_client(new_client))) { -#ifdef DEBUG - printk(KERN_ERR "w83l785ts.o: Failed attaching client.\n"); -#endif - goto ERROR1; - } - - /* - * Register a new directory entry. - */ - - if ((err = i2c_register_entry(new_client, type_name, - w83l785ts_dir_table_template, THIS_MODULE)) < 0) { -#ifdef DEBUG - printk(KERN_ERR "w83l785ts.o: Failed registering directory " - "entry.\n"); -#endif - goto ERROR2; - } - data->sysctl_id = err; - - /* - * Initialize the W83L785TS chip - * Nothing yet, assume it is already started. - */ - - return 0; - - ERROR2: - i2c_detach_client(new_client); - ERROR1: - kfree(data); - return err; -} - -static int w83l785ts_detach_client(struct i2c_client *client) -{ - int err; - - i2c_deregister_entry(((struct w83l785ts_data *) (client->data))->sysctl_id); - if ((err = i2c_detach_client(client))) { - printk(KERN_ERR "w83l785ts.o: Client deregistration failed, " - "client not detached.\n"); - return err; - } - - kfree(client->data); - return 0; -} - -static u8 w83l785ts_read_value(struct i2c_client *client, u8 reg, u8 defval) -{ - int value, i; - - /* Frequent read errors have been reported on Asus boards, so we - * retry on read errors. If it still fails (unlikely), return the - * default value requested by the caller. */ - for (i = 1; i <= MAX_RETRIES; i++) { - value = i2c_smbus_read_byte_data(client, reg); - if (value >= 0) - return value; - printk(KERN_WARNING "w83l785ts.o: Read failed, will retry " - "in %d.\n", i); - mdelay(i); - } - - printk(KERN_ERR "w83l785ts.o: Couldn't read value from register.\n"); - return defval; -} - -static void w83l785ts_update_client(struct i2c_client *client) -{ - struct w83l785ts_data *data = client->data; - - down(&data->update_lock); - - if ((jiffies - data->last_updated > HZ * 2) - || (jiffies < data->last_updated) - || !data->valid) { -#ifdef DEBUG - printk(KERN_DEBUG "w83l785ts.o: Updating data.\n"); -#endif - data->temp = w83l785ts_read_value(client, W83L785TS_REG_TEMP, - data->temp); - data->temp_over = w83l785ts_read_value(client, - W83L785TS_REG_TEMP_OVER, data->temp_over); - data->last_updated = jiffies; - data->valid = 1; - } - - up(&data->update_lock); -} - -static void w83l785ts_temp(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results) -{ - struct w83l785ts_data *data = client->data; - - if (operation == SENSORS_PROC_REAL_INFO) { - *nrels_mag = 0; /* magnitude */ - } else if (operation == SENSORS_PROC_REAL_READ) { - w83l785ts_update_client(client); - results[0] = TEMP_FROM_REG(data->temp_over); - results[1] = TEMP_FROM_REG(data->temp); - *nrels_mag = 2; - } -} - -static int __init sm_w83l785ts_init(void) -{ - printk(KERN_INFO "w83l785ts.o version %s (%s)\n", LM_VERSION, LM_DATE); - return i2c_add_driver(&w83l785ts_driver); -} - -static void __exit sm_w83l785ts_exit(void) -{ - i2c_del_driver(&w83l785ts_driver); -} - -MODULE_AUTHOR("Jean Delvare "); -MODULE_DESCRIPTION("W83L785TS-S sensor driver"); -MODULE_LICENSE("GPL"); - -module_init(sm_w83l785ts_init); -module_exit(sm_w83l785ts_exit); diff --git a/kernel/chips/xeontemp.c b/kernel/chips/xeontemp.c deleted file mode 100644 index df97c887..00000000 --- a/kernel/chips/xeontemp.c +++ /dev/null @@ -1,383 +0,0 @@ -/* - xeontemp.c - Part of lm_sensors, Linux kernel modules for hardware - monitoring - Copyright (c) 1998, 1999,2003 Frodo Looijaard , - Philip Edelbrock , and - Mark D. Studebaker - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -/* The Xeon temperature sensor looks just like an ADM1021 with the remote - sensor only. There is are no ID registers so detection is difficult. */ - -#include -#include -#include -#include -#include -#include "version.h" - -#ifndef I2C_DRIVERID_XEONTEMP -#define I2C_DRIVERID_XEONTEMP 1045 -#endif - -/* Addresses to scan */ -static unsigned short normal_i2c[] = { 0x18, 0x1a, 0x29, 0x2b, - 0x4c, 0x4e, SENSORS_I2C_END -}; -static unsigned short normal_i2c_range[] = { SENSORS_I2C_END }; -static unsigned int normal_isa[] = { SENSORS_ISA_END }; -static unsigned int normal_isa_range[] = { SENSORS_ISA_END }; - -/* Insmod parameters */ -SENSORS_INSMOD_1(xeontemp); - -/* xeontemp constants specified below */ - -/* The registers */ -/* Read-only */ -#define XEONTEMP_REG_REMOTE_TEMP 0x01 -#define XEONTEMP_REG_STATUS 0x02 -/* These use different addresses for reading/writing */ -#define XEONTEMP_REG_CONFIG_R 0x03 -#define XEONTEMP_REG_CONFIG_W 0x09 -#define XEONTEMP_REG_CONV_RATE_R 0x04 -#define XEONTEMP_REG_CONV_RATE_W 0x0A -/* limits */ -#define XEONTEMP_REG_REMOTE_TOS_R 0x07 -#define XEONTEMP_REG_REMOTE_TOS_W 0x0D -#define XEONTEMP_REG_REMOTE_THYST_R 0x08 -#define XEONTEMP_REG_REMOTE_THYST_W 0x0E -/* write-only */ -#define XEONTEMP_REG_ONESHOT 0x0F - -#define XEONTEMP_ALARM_RTEMP (XEONTEMP_ALARM_RTEMP_HIGH | XEONTEMP_ALARM_RTEMP_LOW\ - | XEONTEMP_ALARM_RTEMP_NA) -#define XEONTEMP_ALARM_ALL XEONTEMP_ALARM_RTEMP - -/* Conversions. Rounding and limit checking is only done on the TO_REG - variants. Note that you should be a bit careful with which arguments - these macros are called: arguments may be evaluated more than once. - Fixing this is just not worth it. */ -/* Conversions note: 1021 uses normal integer signed-byte format*/ -#define TEMP_FROM_REG(val) (val > 127 ? val-256 : val) -#define TEMP_TO_REG(val) (SENSORS_LIMIT((val < 0 ? val+256 : val),0,255)) - -/* Each client has this additional data */ -struct xeontemp_data { - struct i2c_client client; - int sysctl_id; - enum chips type; - - struct semaphore update_lock; - char valid; /* !=0 if following fields are valid */ - unsigned long last_updated; /* In jiffies */ - - u8 remote_temp, remote_temp_os, remote_temp_hyst, alarms; - u8 fail; -}; - -static int xeontemp_attach_adapter(struct i2c_adapter *adapter); -static int xeontemp_detect(struct i2c_adapter *adapter, int address, - unsigned short flags, int kind); -static void xeontemp_init_client(struct i2c_client *client); -static int xeontemp_detach_client(struct i2c_client *client); -static int xeontemp_read_value(struct i2c_client *client, u8 reg); -static int xeontemp_rd_good(u8 *val, struct i2c_client *client, u8 reg, u8 mask); -static int xeontemp_write_value(struct i2c_client *client, u8 reg, - u16 value); -static void xeontemp_remote_temp(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, - long *results); -static void xeontemp_alarms(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void xeontemp_update_client(struct i2c_client *client); - -/* (amalysh) read only mode, otherwise any limit's writing confuse BIOS */ -static int read_only = 0; - - -/* This is the driver that will be inserted */ -static struct i2c_driver xeontemp_driver = { - .name = "Xeon temp sensor driver", - .id = I2C_DRIVERID_XEONTEMP, - .flags = I2C_DF_NOTIFY, - .attach_adapter = xeontemp_attach_adapter, - .detach_client = xeontemp_detach_client, -}; - -/* -- SENSORS SYSCTL START -- */ - -#define XEONTEMP_SYSCTL_REMOTE_TEMP 1201 -#define XEONTEMP_SYSCTL_ALARMS 1203 - -#define XEONTEMP_ALARM_RTEMP_HIGH 0x10 -#define XEONTEMP_ALARM_RTEMP_LOW 0x08 -#define XEONTEMP_ALARM_RTEMP_NA 0x04 - -/* -- SENSORS SYSCTL END -- */ - -/* These files are created for each detected xeontemp. This is just a template; - though at first sight, you might think we could use a statically - allocated list, we need some way to get back to the parent - which - is done through one of the 'extra' fields which are initialized - when a new copy is allocated. */ -static ctl_table xeontemp_dir_table_template[] = { - {XEONTEMP_SYSCTL_REMOTE_TEMP, "temp", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &xeontemp_remote_temp}, - {XEONTEMP_SYSCTL_ALARMS, "alarms", NULL, 0, 0444, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &xeontemp_alarms}, - {0} -}; - -static int xeontemp_attach_adapter(struct i2c_adapter *adapter) -{ - return i2c_detect(adapter, &addr_data, xeontemp_detect); -} - -static int xeontemp_detect(struct i2c_adapter *adapter, int address, - unsigned short flags, int kind) -{ - int i; - struct i2c_client *new_client; - struct xeontemp_data *data; - int err = 0; - const char *type_name = ""; - const char *client_name = ""; - - if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) - goto error0; - - /* OK. For now, we presume we have a valid client. We now create the - client structure, even though we cannot fill it completely yet. - But it allows us to access xeontemp_{read,write}_value. */ - - if (!(data = kmalloc(sizeof(struct xeontemp_data), GFP_KERNEL))) { - err = -ENOMEM; - goto error0; - } - - new_client = &data->client; - new_client->addr = address; - new_client->data = data; - new_client->adapter = adapter; - new_client->driver = &xeontemp_driver; - new_client->flags = 0; - - /* Now, we do the remaining detection. */ - - if (kind < 0) { - if ( - (xeontemp_read_value(new_client, XEONTEMP_REG_STATUS) & - 0x03) != 0x00) - goto error1; - } - - /* Determine the chip type. */ - - if (kind <= 0) { - kind = xeontemp; - } - - type_name = "xeontemp"; - client_name = "xeon sensors"; - - /* Fill in the remaining client fields and put it into the global list */ - strcpy(new_client->name, client_name); - data->type = kind; - data->valid = 0; - init_MUTEX(&data->update_lock); - - /* Tell the I2C layer a new client has arrived */ - if ((err = i2c_attach_client(new_client))) - goto error3; - - /* Register a new directory entry with module sensors */ - if ((i = i2c_register_entry(new_client, type_name, - xeontemp_dir_table_template, - THIS_MODULE)) < 0) { - err = i; - goto error4; - } - data->sysctl_id = i; - - xeontemp_init_client(new_client); - return 0; - - error4: - i2c_detach_client(new_client); - error3: - error1: - kfree(data); - error0: - return err; -} - -static void xeontemp_init_client(struct i2c_client *client) -{ - /* Enable ADC and disable suspend mode */ - xeontemp_write_value(client, XEONTEMP_REG_CONFIG_W, 0); - /* Set Conversion rate to 1/sec (this can be tinkered with) */ - xeontemp_write_value(client, XEONTEMP_REG_CONV_RATE_W, 0x04); -} - -static int xeontemp_detach_client(struct i2c_client *client) -{ - - int err; - - i2c_deregister_entry(((struct xeontemp_data *) (client->data))-> - sysctl_id); - - if ((err = i2c_detach_client(client))) { - printk - ("xeontemp.o: Client deregistration failed, client not detached.\n"); - return err; - } - - kfree(client->data); - - return 0; - -} - - -/* All registers are byte-sized */ -static int xeontemp_read_value(struct i2c_client *client, u8 reg) -{ - return i2c_smbus_read_byte_data(client, reg); -} - -/* only update value if read succeeded; set fail bit if failed */ -static int xeontemp_rd_good(u8 *val, struct i2c_client *client, u8 reg, u8 mask) -{ - int i; - struct xeontemp_data *data = client->data; - - i = i2c_smbus_read_byte_data(client, reg); - if (i < 0) { - data->fail |= mask; - return i; - } - *val = i; - return 0; -} - -static int xeontemp_write_value(struct i2c_client *client, u8 reg, u16 value) -{ - if (read_only > 0) - return 0; - - return i2c_smbus_write_byte_data(client, reg, value); -} - -static void xeontemp_update_client(struct i2c_client *client) -{ - struct xeontemp_data *data = client->data; - - down(&data->update_lock); - - if ((jiffies - data->last_updated > HZ + HZ / 2) || - (jiffies < data->last_updated) || !data->valid) { - -#ifdef DEBUG - printk("Starting xeontemp update\n"); -#endif - - data->fail = 0; - xeontemp_rd_good(&(data->remote_temp), client, - XEONTEMP_REG_REMOTE_TEMP, XEONTEMP_ALARM_RTEMP); - xeontemp_rd_good(&(data->remote_temp_os), client, - XEONTEMP_REG_REMOTE_TOS_R, XEONTEMP_ALARM_RTEMP); - xeontemp_rd_good(&(data->remote_temp_hyst), client, - XEONTEMP_REG_REMOTE_THYST_R, - XEONTEMP_ALARM_RTEMP); - data->alarms = XEONTEMP_ALARM_ALL; - if (!xeontemp_rd_good(&(data->alarms), client, - XEONTEMP_REG_STATUS, 0)) - data->alarms &= XEONTEMP_ALARM_ALL; - data->last_updated = jiffies; - data->valid = 1; - } - - up(&data->update_lock); -} - -void xeontemp_remote_temp(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results) -{ - struct xeontemp_data *data = client->data; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - xeontemp_update_client(client); - results[0] = TEMP_FROM_REG(data->remote_temp_os); - results[1] = TEMP_FROM_REG(data->remote_temp_hyst); - results[2] = TEMP_FROM_REG(data->remote_temp); - *nrels_mag = 3; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag >= 1) { - data->remote_temp_os = TEMP_TO_REG(results[0]); - xeontemp_write_value(client, - XEONTEMP_REG_REMOTE_TOS_W, - data->remote_temp_os); - } - if (*nrels_mag >= 2) { - data->remote_temp_hyst = TEMP_TO_REG(results[1]); - xeontemp_write_value(client, - XEONTEMP_REG_REMOTE_THYST_W, - data->remote_temp_hyst); - } - } -} - -void xeontemp_alarms(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct xeontemp_data *data = client->data; - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - xeontemp_update_client(client); - results[0] = data->alarms | data->fail; - *nrels_mag = 1; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - /* Can't write to it */ - } -} - -static int __init sm_xeontemp_init(void) -{ - printk(KERN_INFO "xeontemp.o version %s (%s)\n", LM_VERSION, LM_DATE); - return i2c_add_driver(&xeontemp_driver); -} - -static void __exit sm_xeontemp_exit(void) -{ - i2c_del_driver(&xeontemp_driver); -} - -MODULE_AUTHOR - ("Frodo Looijaard and Philip Edelbrock "); -MODULE_DESCRIPTION("xeontemp driver"); -MODULE_LICENSE("GPL"); - -MODULE_PARM(read_only, "i"); -MODULE_PARM_DESC(read_only, "Don't set any values, read only mode"); - -module_init(sm_xeontemp_init) -module_exit(sm_xeontemp_exit) diff --git a/kernel/include/Module.mk b/kernel/include/Module.mk deleted file mode 100644 index f9815487..00000000 --- a/kernel/include/Module.mk +++ /dev/null @@ -1,57 +0,0 @@ -# Module.mk - Makefile for a Linux module for reading sensor data. -# Copyright (c) 1998, 1999 Frodo Looijaard -# -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - -# Note that MODULE_DIR (the directory in which this file resides) is a -# 'simply expanded variable'. That means that its value is substituted -# verbatim in the rules, until it is redefined. -MODULE_DIR := kernel/include -KERNELINCLUDEDIR := $(MODULE_DIR) -KERNELCHIPSDIR := kernel/chips - -KERNELINCLUDEFILES := $(MODULE_DIR)/i2c-dev.h $(MODULE_DIR)/sensors.h - -$(KERNELINCLUDEDIR)/sensors.h: $(KERNELINCLUDEDIR)/sensors.h.template - cat $@.template > $@ - $(AWK) '/SENSORS SYSCTL START/,/SENSORS SYSCTL END/' $(KERNELCHIPSDIR)/*.c >> $@ - echo '#endif' >> $@ - -$(KERNELINCLUDEDIR)/sensors.hd: - ( $(GREP) 'SENSORS SYSCTL START' /dev/null $(KERNELCHIPSDIR)/*.c | \ - $(SED) -e 's/:.*//' -e 's#^#$(KERNELINCLUDEDIR)/sensors.h: #' ) > $@ - -# Get dependencies of sensors.h -INCLUDEFILES += $(MODULE_DIR)/sensors.hd - -REMOVEKERNELINC := $(patsubst $(MODULE_DIR)/%,$(DESTDIR)$(SYSINCLUDEDIR)/%,$(KERNELINCLUDEFILES)) - -install-all-kernel-include: - if [ -n "$(KERNELINCLUDEFILES)" ] ; then \ - $(MKDIR) $(DESTDIR)$(SYSINCLUDEDIR) ; \ - $(INSTALL) -m 644 $(KERNELINCLUDEFILES) $(DESTDIR)$(SYSINCLUDEDIR) ; \ - fi - -user_install :: install-all-kernel-include - -user_uninstall:: - $(RM) $(REMOVEKERNELINC) -# Remove directory if empty, ignore failure - $(RMDIR) $(DESTDIR)$(SYSINCLUDEDIR) 2> /dev/null || true - -clean-all-kernel-include: - $(RM) $(KERNELINCLUDEDIR)/sensors.h $(KERNELINCLUDEDIR)/sensors.hd - -clean :: clean-all-kernel-include diff --git a/kernel/include/ds1307.h b/kernel/include/ds1307.h deleted file mode 100644 index add9b123..00000000 --- a/kernel/include/ds1307.h +++ /dev/null @@ -1,59 +0,0 @@ -#ifndef DS1307_H -#define DS1307_H - -/* - * linux/include/linux/ds1307.h - * - * Author: Abraham van der Merwe - * - * Linux support for the Dallas Semiconductor DS1307 Serial Real-Time - * Clock. - * - * Based on code from the lm-sensors project which is available - * at http://www.lm-sensors.org/ and Russell King's PCF8583 Real-Time - * Clock driver (linux/drivers/acorn/char/pcf8583.c). - * - * This source code is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * version 2 as published by the Free Software Foundation. - */ - -#include - -/* practically the same as struct rtc_time, but without tm_yday and tm_isdst */ -struct ds1307_date { - int tm_sec; - int tm_min; - int tm_hour; - int tm_mday; - int tm_mon; - int tm_year; - int tm_wday; -}; - -struct ds1307_memory { - u8 offset; /* 0 - 55 */ - u8 buf[56]; /* data */ - u8 length; /* offset + length <= 50 */ -}; - -/* size of the rtc non-volatile ram */ -#define DS1307_SIZE 56 - -/* the following frequencies are supported */ -#define DS1307_FREQ_1HZ 1 -#define DS1307_FREQ_4KHZ 4096 -#define DS1307_FREQ_8KHZ 8192 -#define DS1307_FREQ_32KHZ 32768 - -#define DS1307_GET_DATE _IOR ('d',0,struct ds1307_date *) -#define DS1307_SET_DATE _IOW ('d',1,struct ds1307_date *) -#define DS1307_IRQ_ON _IO ('d',2) -#define DS1307_IRQ_OFF _IO ('d',3) -#define DS1307_GET_FREQ _IOR ('d',4,u16 *) -#define DS1307_SET_FREQ _IOW ('d',5,u16 *) -#define DS1307_READ _IOR ('d',6,struct ds1307_memory *) -#define DS1307_WRITE _IOW ('d',7,struct ds1307_memory *) -#define DS1307_ENABLE _IO ('d',8) - -#endif /* #ifdef DS1307_H */ diff --git a/kernel/include/i2c-dev.h b/kernel/include/i2c-dev.h deleted file mode 100644 index 6151980a..00000000 --- a/kernel/include/i2c-dev.h +++ /dev/null @@ -1,333 +0,0 @@ -/* - i2c-dev.h - i2c-bus driver, char device interface - - Copyright (C) 1995-97 Simon G. Vogl - Copyright (C) 1998-99 Frodo Looijaard - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -/* $Id$ */ - -#ifndef LIB_I2CDEV_H -#define LIB_I2CDEV_H - -#include -#include - - -/* -- i2c.h -- */ - - -/* - * I2C Message - used for pure i2c transaction, also from /dev interface - */ -struct i2c_msg { - __u16 addr; /* slave address */ - unsigned short flags; -#define I2C_M_TEN 0x10 /* we have a ten bit chip address */ -#define I2C_M_RD 0x01 -#define I2C_M_NOSTART 0x4000 -#define I2C_M_REV_DIR_ADDR 0x2000 -#define I2C_M_IGNORE_NAK 0x1000 -#define I2C_M_NO_RD_ACK 0x0800 - short len; /* msg length */ - char *buf; /* pointer to msg data */ -}; - -/* To determine what functionality is present */ - -#define I2C_FUNC_I2C 0x00000001 -#define I2C_FUNC_10BIT_ADDR 0x00000002 -#define I2C_FUNC_PROTOCOL_MANGLING 0x00000004 /* I2C_M_{REV_DIR_ADDR,NOSTART,..} */ -#define I2C_FUNC_SMBUS_PEC 0x00000008 -#define I2C_FUNC_SMBUS_BLOCK_PROC_CALL 0x00008000 /* SMBus 2.0 */ -#define I2C_FUNC_SMBUS_QUICK 0x00010000 -#define I2C_FUNC_SMBUS_READ_BYTE 0x00020000 -#define I2C_FUNC_SMBUS_WRITE_BYTE 0x00040000 -#define I2C_FUNC_SMBUS_READ_BYTE_DATA 0x00080000 -#define I2C_FUNC_SMBUS_WRITE_BYTE_DATA 0x00100000 -#define I2C_FUNC_SMBUS_READ_WORD_DATA 0x00200000 -#define I2C_FUNC_SMBUS_WRITE_WORD_DATA 0x00400000 -#define I2C_FUNC_SMBUS_PROC_CALL 0x00800000 -#define I2C_FUNC_SMBUS_READ_BLOCK_DATA 0x01000000 -#define I2C_FUNC_SMBUS_WRITE_BLOCK_DATA 0x02000000 -#define I2C_FUNC_SMBUS_READ_I2C_BLOCK 0x04000000 /* I2C-like block xfer */ -#define I2C_FUNC_SMBUS_WRITE_I2C_BLOCK 0x08000000 /* w/ 1-byte reg. addr. */ - -#define I2C_FUNC_SMBUS_BYTE (I2C_FUNC_SMBUS_READ_BYTE | \ - I2C_FUNC_SMBUS_WRITE_BYTE) -#define I2C_FUNC_SMBUS_BYTE_DATA (I2C_FUNC_SMBUS_READ_BYTE_DATA | \ - I2C_FUNC_SMBUS_WRITE_BYTE_DATA) -#define I2C_FUNC_SMBUS_WORD_DATA (I2C_FUNC_SMBUS_READ_WORD_DATA | \ - I2C_FUNC_SMBUS_WRITE_WORD_DATA) -#define I2C_FUNC_SMBUS_BLOCK_DATA (I2C_FUNC_SMBUS_READ_BLOCK_DATA | \ - I2C_FUNC_SMBUS_WRITE_BLOCK_DATA) -#define I2C_FUNC_SMBUS_I2C_BLOCK (I2C_FUNC_SMBUS_READ_I2C_BLOCK | \ - I2C_FUNC_SMBUS_WRITE_I2C_BLOCK) - -/* Old name, for compatibility */ -#define I2C_FUNC_SMBUS_HWPEC_CALC I2C_FUNC_SMBUS_PEC - -/* - * Data for SMBus Messages - */ -#define I2C_SMBUS_BLOCK_MAX 32 /* As specified in SMBus standard */ -#define I2C_SMBUS_I2C_BLOCK_MAX 32 /* Not specified but we use same structure */ -union i2c_smbus_data { - __u8 byte; - __u16 word; - __u8 block[I2C_SMBUS_BLOCK_MAX + 2]; /* block[0] is used for length */ - /* and one more for PEC */ -}; - -/* smbus_access read or write markers */ -#define I2C_SMBUS_READ 1 -#define I2C_SMBUS_WRITE 0 - -/* SMBus transaction types (size parameter in the above functions) - Note: these no longer correspond to the (arbitrary) PIIX4 internal codes! */ -#define I2C_SMBUS_QUICK 0 -#define I2C_SMBUS_BYTE 1 -#define I2C_SMBUS_BYTE_DATA 2 -#define I2C_SMBUS_WORD_DATA 3 -#define I2C_SMBUS_PROC_CALL 4 -#define I2C_SMBUS_BLOCK_DATA 5 -#define I2C_SMBUS_I2C_BLOCK_BROKEN 6 -#define I2C_SMBUS_BLOCK_PROC_CALL 7 /* SMBus 2.0 */ -#define I2C_SMBUS_I2C_BLOCK_DATA 8 - - -/* ----- commands for the ioctl like i2c_command call: - * note that additional calls are defined in the algorithm and hw - * dependent layers - these can be listed here, or see the - * corresponding header files. - */ - /* -> bit-adapter specific ioctls */ -#define I2C_RETRIES 0x0701 /* number of times a device address */ - /* should be polled when not */ - /* acknowledging */ -#define I2C_TIMEOUT 0x0702 /* set timeout - call with int */ - - -/* this is for i2c-dev.c */ -#define I2C_SLAVE 0x0703 /* Change slave address */ - /* Attn.: Slave address is 7 or 10 bits */ -#define I2C_SLAVE_FORCE 0x0706 /* Change slave address */ - /* Attn.: Slave address is 7 or 10 bits */ - /* This changes the address, even if it */ - /* is already taken! */ -#define I2C_TENBIT 0x0704 /* 0 for 7 bit addrs, != 0 for 10 bit */ - -#define I2C_FUNCS 0x0705 /* Get the adapter functionality */ -#define I2C_RDWR 0x0707 /* Combined R/W transfer (one stop only)*/ -#define I2C_PEC 0x0708 /* != 0 for SMBus PEC */ - -#define I2C_SMBUS 0x0720 /* SMBus-level access */ - -/* -- i2c.h -- */ - - -/* Note: 10-bit addresses are NOT supported! */ - -/* This is the structure as used in the I2C_SMBUS ioctl call */ -struct i2c_smbus_ioctl_data { - char read_write; - __u8 command; - int size; - union i2c_smbus_data *data; -}; - -/* This is the structure as used in the I2C_RDWR ioctl call */ -struct i2c_rdwr_ioctl_data { - struct i2c_msg *msgs; /* pointers to i2c_msgs */ - int nmsgs; /* number of i2c_msgs */ -}; - - -static inline __s32 i2c_smbus_access(int file, char read_write, __u8 command, - int size, union i2c_smbus_data *data) -{ - struct i2c_smbus_ioctl_data args; - - args.read_write = read_write; - args.command = command; - args.size = size; - args.data = data; - return ioctl(file,I2C_SMBUS,&args); -} - - -static inline __s32 i2c_smbus_write_quick(int file, __u8 value) -{ - return i2c_smbus_access(file,value,0,I2C_SMBUS_QUICK,NULL); -} - -static inline __s32 i2c_smbus_read_byte(int file) -{ - union i2c_smbus_data data; - if (i2c_smbus_access(file,I2C_SMBUS_READ,0,I2C_SMBUS_BYTE,&data)) - return -1; - else - return 0x0FF & data.byte; -} - -static inline __s32 i2c_smbus_write_byte(int file, __u8 value) -{ - return i2c_smbus_access(file,I2C_SMBUS_WRITE,value, - I2C_SMBUS_BYTE,NULL); -} - -static inline __s32 i2c_smbus_read_byte_data(int file, __u8 command) -{ - union i2c_smbus_data data; - if (i2c_smbus_access(file,I2C_SMBUS_READ,command, - I2C_SMBUS_BYTE_DATA,&data)) - return -1; - else - return 0x0FF & data.byte; -} - -static inline __s32 i2c_smbus_write_byte_data(int file, __u8 command, - __u8 value) -{ - union i2c_smbus_data data; - data.byte = value; - return i2c_smbus_access(file,I2C_SMBUS_WRITE,command, - I2C_SMBUS_BYTE_DATA, &data); -} - -static inline __s32 i2c_smbus_read_word_data(int file, __u8 command) -{ - union i2c_smbus_data data; - if (i2c_smbus_access(file,I2C_SMBUS_READ,command, - I2C_SMBUS_WORD_DATA,&data)) - return -1; - else - return 0x0FFFF & data.word; -} - -static inline __s32 i2c_smbus_write_word_data(int file, __u8 command, - __u16 value) -{ - union i2c_smbus_data data; - data.word = value; - return i2c_smbus_access(file,I2C_SMBUS_WRITE,command, - I2C_SMBUS_WORD_DATA, &data); -} - -static inline __s32 i2c_smbus_process_call(int file, __u8 command, __u16 value) -{ - union i2c_smbus_data data; - data.word = value; - if (i2c_smbus_access(file,I2C_SMBUS_WRITE,command, - I2C_SMBUS_PROC_CALL,&data)) - return -1; - else - return 0x0FFFF & data.word; -} - - -/* Returns the number of read bytes */ -static inline __s32 i2c_smbus_read_block_data(int file, __u8 command, - __u8 *values) -{ - union i2c_smbus_data data; - int i; - if (i2c_smbus_access(file,I2C_SMBUS_READ,command, - I2C_SMBUS_BLOCK_DATA,&data)) - return -1; - else { - for (i = 1; i <= data.block[0]; i++) - values[i-1] = data.block[i]; - return data.block[0]; - } -} - -static inline __s32 i2c_smbus_write_block_data(int file, __u8 command, - __u8 length, __u8 *values) -{ - union i2c_smbus_data data; - int i; - if (length > 32) - length = 32; - for (i = 1; i <= length; i++) - data.block[i] = values[i-1]; - data.block[0] = length; - return i2c_smbus_access(file,I2C_SMBUS_WRITE,command, - I2C_SMBUS_BLOCK_DATA, &data); -} - -/* Returns the number of read bytes */ -/* Until kernel 2.6.22, the length is hardcoded to 32 bytes. If you - ask for less than 32 bytes, your code will only work with kernels - 2.6.23 and later. */ -static inline __s32 i2c_smbus_read_i2c_block_data(int file, __u8 command, - __u8 length, __u8 *values) -{ - union i2c_smbus_data data; - int i; - - if (length > 32) - length = 32; - data.block[0] = length; - if (i2c_smbus_access(file,I2C_SMBUS_READ,command, - length == 32 ? I2C_SMBUS_I2C_BLOCK_BROKEN : - I2C_SMBUS_I2C_BLOCK_DATA,&data)) - return -1; - else { - for (i = 1; i <= data.block[0]; i++) - values[i-1] = data.block[i]; - return data.block[0]; - } -} - -static inline __s32 i2c_smbus_write_i2c_block_data(int file, __u8 command, - __u8 length, __u8 *values) -{ - union i2c_smbus_data data; - int i; - if (length > 32) - length = 32; - for (i = 1; i <= length; i++) - data.block[i] = values[i-1]; - data.block[0] = length; - return i2c_smbus_access(file,I2C_SMBUS_WRITE,command, - I2C_SMBUS_I2C_BLOCK_BROKEN, &data); -} - -/* Returns the number of read bytes */ -static inline __s32 i2c_smbus_block_process_call(int file, __u8 command, - __u8 length, __u8 *values) -{ - union i2c_smbus_data data; - int i; - if (length > 32) - length = 32; - for (i = 1; i <= length; i++) - data.block[i] = values[i-1]; - data.block[0] = length; - if (i2c_smbus_access(file,I2C_SMBUS_WRITE,command, - I2C_SMBUS_BLOCK_PROC_CALL,&data)) - return -1; - else { - for (i = 1; i <= data.block[0]; i++) - values[i-1] = data.block[i]; - return data.block[0]; - } -} - - -#endif /* LIB_I2CDEV_H */ diff --git a/kernel/include/i2c-virtual.h b/kernel/include/i2c-virtual.h deleted file mode 100644 index 4bca2f1a..00000000 --- a/kernel/include/i2c-virtual.h +++ /dev/null @@ -1,71 +0,0 @@ -/* - * i2c-virtual.h - Header file for the 'virtual i2c' adapter driver. - * - * Copyright (c) 2004 Google, Inc. - * - * Based on: - * i2c-virtual.h from Brian Kuschak - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ -#ifndef __I2C_VIRTUAL_H -#define __I2C_VIRTUAL_H - -#include - -struct i2c_mux_ctrl { - struct i2c_client *client; /* The mux chip/device */ - - unsigned long addr; - unsigned long value; /* Channel # */ - - /* fn which enables the mux */ - int (*select)(struct i2c_adapter *adap, struct i2c_mux_ctrl *mux); - - /* fn which disables the mux */ - int (*deselect)(struct i2c_adapter *adap, struct i2c_mux_ctrl *mux); -}; - -/* This has to be exposed, since the code which assigns the callbacks must - use it. - */ -struct i2c_virt_priv { - struct i2c_adapter *parent_adap; /* pointer to parent adapter */ - struct i2c_mux_ctrl mux; /* MUX settings for this adapter */ -}; - - -static inline struct i2c_adapter *i2c_virt_parent(struct i2c_adapter *adap) -{ - if (adap->algo && (adap->algo->id == I2C_ALGO_VIRT)) { - return ((struct i2c_virt_priv *)(adap->data))->parent_adap; - } - return NULL; -} - -/* - * Called to create a 'virtual' i2c bus which represents a multiplexed bus - * segment. The client and mux_val are passed to the select and deselect - * callback functions to perform hardware-specific mux control. - */ -struct i2c_adapter *i2c_virt_create_adapter(struct i2c_adapter *parent_adap, - struct i2c_client *client, - unsigned long mux_val, - void *select_cb, - void *deselect_cb); -int i2c_virt_remove_adapter(struct i2c_adapter *adap); - - -#endif /* __I2C_VIRTUAL_H */ diff --git a/kernel/include/sensors.h.template b/kernel/include/sensors.h.template deleted file mode 100644 index 8a60a74b..00000000 --- a/kernel/include/sensors.h.template +++ /dev/null @@ -1,55 +0,0 @@ -/* - sensors.h - Part of lm_sensors, Linux kernel modules for hardware - monitoring - Copyright (c) 1998, 1999 Frodo Looijaard - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - - --- THIS FILE IS AUTOGENERATED DO NOT EDIT -- -*/ - -#ifndef LIB_SENSORS_H -#define LIB_SENSORS_H - -/* This file is intended to be included from userland utilities only. - * - * Individual drivers define their own SYSCTL and ALARM values in - * the driver itself surrounded by the following 'trigger' lines: - * - * -- SENSORS SYSCTL START -- - * -- SENSORS SYSCTL END -- - */ - - -/* From linux/i2c-proc.h */ - -/* Sysctl IDs */ -#ifdef DEV_HWMON -#define DEV_SENSORS DEV_HWMON -#else /* ndef DEV_HWMOM */ -#define DEV_SENSORS 2 /* The id of the lm_sensors directory within the - dev table */ -#endif /* def DEV_HWMON */ - -/* The maximum length of the prefix */ -#define SENSORS_PREFIX_MAX 20 - -#define SENSORS_CHIPS 1 -struct i2c_chips_data { - int sysctl_id; - char name[SENSORS_PREFIX_MAX + 13]; -}; - - diff --git a/kernel/include/sensors_compat.h b/kernel/include/sensors_compat.h deleted file mode 100644 index ccde2b82..00000000 --- a/kernel/include/sensors_compat.h +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Stolen from kernel 2.5.69 - * device.h - generic, centralized driver model - * To make it easier to backport from 2.5 - * - * Copyright (c) 2001-2003 Patrick Mochel - * - */ - -#ifndef _SENSORS_COMPAT_H_ -#define _SENSORS_COMPAT_H_ - -#include - -/* debugging and troubleshooting/diagnostic helpers. */ -#define dev_printk(level, dev, format, arg...) \ - printk(level "%s: " format , (dev)->name , ## arg) - -#ifdef DEBUG -#define dev_dbg(dev, format, arg...) \ - dev_printk(KERN_DEBUG , dev , format , ## arg) -#else -#define dev_dbg(dev, format, arg...) do {} while (0) -#endif - -#define dev_err(dev, format, arg...) \ - dev_printk(KERN_ERR , dev , format , ## arg) -#define dev_info(dev, format, arg...) \ - dev_printk(KERN_INFO , dev , format , ## arg) -#define dev_warn(dev, format, arg...) \ - dev_printk(KERN_WARNING , dev , format , ## arg) - - -/* The part below, taken from linux/init.h, is required for compatibility with - kernels 2.4.16 and older, which don't know about __devexit_p. */ - -/* Functions marked as __devexit may be discarded at kernel link time, depending - on config options. Newer versions of binutils detect references from - retained sections to discarded sections and flag an error. Pointers to - __devexit functions must use __devexit_p(function_name), the wrapper will - insert either the function_name or NULL, depending on the config options. - */ -#ifndef __devexit_p -#if defined(MODULE) || defined(CONFIG_HOTPLUG) -#define __devexit_p(x) x -#else -#define __devexit_p(x) NULL -#endif -#endif /* __devexit_p */ - -#endif /* _SENSORS_COMPAT_H_ */ diff --git a/kernel/include/sensors_vid.h b/kernel/include/sensors_vid.h deleted file mode 100644 index 81b36b66..00000000 --- a/kernel/include/sensors_vid.h +++ /dev/null @@ -1,98 +0,0 @@ -/* - sensors_vid.h - Part of lm_sensors, Linux kernel modules for hardware - monitoring - Copyright (c) 2002-2004 Mark D. Studebaker - With assistance from Trent Piepho - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -/* - This file contains common code for decoding VID pins. - This file is #included in various sensor chip drivers. - As the user is unlikely to load more than one driver which - includes this code we don't worry about the wasted space. - References: VRM x.y DC-DC Converter Design Guidelines, - VRD 10.0 Design Guide, - available at http://developer.intel.com -*/ - -/* - AMD Opteron processors don't follow the Intel VRM spec. - I'm going to "make up" 2.4 as the VRM spec for the Opterons. - No good reason just a mnemonic for the 24x Opteron processor - series - - Opteron VID encoding is: - - 00000 = 1.550 V - 00001 = 1.525 V - . . . . - 11110 = 0.800 V - 11111 = 0.000 V (off) - */ - -/* - Legal val values 00 - 1F except for VRD 10.0, 0x00-0x3f. - vrm is the Intel VRM document version. - Note: vrm version is scaled by 10 and the return value is scaled by 1000 - to avoid floating point in the kernel. -*/ - -static inline int vid_from_reg(int val, int vrm) -{ - int vid; - - switch(vrm) { - - case 100: /* VRD 10.0 */ - val &= 0x3f; - if((val & 0x1f) == 0x1f) - return 0; - if((val & 0x1f) <= 0x09 || val == 0x0a) - vid = 10875 - (val & 0x1f) * 250; - else - vid = 18625 - (val & 0x1f) * 250; - if(val & 0x20) - vid -= 125; - vid /= 10; /* only return 3 dec. places for now */ - return vid; - - case 24: /* Opteron processor */ - val &= 0x1f; - return(val == 0x1f ? 0 : 1550 - val * 25); - - case 91: /* VRM 9.1 */ - case 90: /* VRM 9.0 */ - val &= 0x1f; - return(val == 0x1f ? 0 : - 1850 - val * 25); - - case 85: /* VRM 8.5 */ - val &= 0x1f; - return((val & 0x10 ? 25 : 0) + - ((val & 0x0f) > 0x04 ? 2050 : 1250) - - ((val & 0x0f) * 50)); - - case 84: /* VRM 8.4 */ - val &= 0x0f; - /* fall through */ - default: /* VRM 8.2 */ - val &= 0x1f; - return(val == 0x1f ? 0 : - val & 0x10 ? 5100 - (val) * 100 : - 2050 - (val) * 50); - } -} diff --git a/lib/Module.mk b/lib/Module.mk index 7e98f4e2..1bbe124f 100644 --- a/lib/Module.mk +++ b/lib/Module.mk @@ -13,7 +13,8 @@ # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software -# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, +# MA 02110-1301 USA. # Note that MODULE_DIR (the directory in which this file resides) is a # 'simply expanded variable'. That means that its value is substituted @@ -30,10 +31,9 @@ LIBMAN5FILES := $(MODULE_DIR)/sensors.conf.5 # The main and minor version of the library # The library soname (major number) must be changed if and only if the interface is # changed in a backward incompatible way. The interface is defined by -# the public header files - in this case they are error.h, sensors.h, -# chips.h. -LIBMAINVER := 3 -LIBMINORVER := 1.7 +# the public header files - in this case they are error.h and sensors.h. +LIBMAINVER := 4 +LIBMINORVER := 0.2 LIBVER := $(LIBMAINVER).$(LIBMINORVER) # The static lib name, the shared lib name, and the internal ('so') name of @@ -47,12 +47,8 @@ LIBTARGETS := $(MODULE_DIR)/$(LIBSTLIBNAME) $(MODULE_DIR)/$(LIBSHLIBNAME) \ $(MODULE_DIR)/$(LIBSHSONAME) $(MODULE_DIR)/$(LIBSHBASENAME) LIBCSOURCES := $(MODULE_DIR)/data.c $(MODULE_DIR)/general.c \ - $(MODULE_DIR)/error.c $(MODULE_DIR)/chips.c \ - $(MODULE_DIR)/proc.c $(MODULE_DIR)/access.c \ - $(MODULE_DIR)/init.c -ifdef SYSFS_SUPPORT - LIBCSOURCES := $(LIBCSOURCES) $(MODULE_DIR)/sysfs.c -endif + $(MODULE_DIR)/error.c $(MODULE_DIR)/access.c \ + $(MODULE_DIR)/init.c $(MODULE_DIR)/sysfs.c LIBOTHEROBJECTS := $(MODULE_DIR)/conf-parse.o $(MODULE_DIR)/conf-lex.o LIBSHOBJECTS := $(LIBCSOURCES:.c=.lo) $(LIBOTHEROBJECTS:.o=.lo) @@ -60,17 +56,11 @@ LIBSTOBJECTS := $(LIBCSOURCES:.c=.ao) $(LIBOTHEROBJECTS:.o=.ao) LIBEXTRACLEAN := $(MODULE_DIR)/conf-parse.h $(MODULE_DIR)/conf-parse.c \ $(MODULE_DIR)/conf-lex.c -LIBHEADERFILES := $(MODULE_DIR)/error.h $(MODULE_DIR)/sensors.h \ - $(MODULE_DIR)/chips.h +LIBHEADERFILES := $(MODULE_DIR)/error.h $(MODULE_DIR)/sensors.h # How to create the shared library -ifdef SYSFS_SUPPORT -$(MODULE_DIR)/$(LIBSHLIBNAME): $(LIBSHOBJECTS) - $(CC) -shared -Wl,-soname,$(LIBSHSONAME) -o $@ $^ -lc -lm -lsysfs -else $(MODULE_DIR)/$(LIBSHLIBNAME): $(LIBSHOBJECTS) $(CC) -shared -Wl,-soname,$(LIBSHSONAME) -o $@ $^ -lc -lm -endif $(MODULE_DIR)/$(LIBSHSONAME): $(MODULE_DIR)/$(LIBSHLIBNAME) $(RM) $@ @@ -96,10 +86,18 @@ $(MODULE_DIR)/conf-parse.h: $(MODULE_DIR)/conf-parse.c INCLUDEFILES += $(LIBCSOURCES:.c=.ld) $(LIBCSOURCES:.c=.ad) # Special warning prevention for flex-generated files +FLEXNOWARN:=-Wno-shadow -Wno-undef -Wno-unused -Wno-missing-prototypes -Wno-sign-compare $(MODULE_DIR)/conf-lex.ao: $(MODULE_DIR)/conf-lex.c - $(CC) $(ARCPPFLAGS) $(ARCFLAGS) -Wno-unused -c $< -o $@ + $(CC) $(ARCPPFLAGS) $(ARCFLAGS) $(FLEXNOWARN) -c $< -o $@ $(MODULE_DIR)/conf-lex.lo: $(MODULE_DIR)/conf-lex.c - $(CC) $(LIBCPPFLAGS) $(LIBCFLAGS) -Wno-unused -c $< -o $@ + $(CC) $(LIBCPPFLAGS) $(LIBCFLAGS) $(FLEXNOWARN) -c $< -o $@ + +# Special warning prevention for bison-generated files +YACCNOWARN:=-Wno-undef +$(MODULE_DIR)/conf-parse.ao: $(MODULE_DIR)/conf-parse.c + $(CC) $(ARCPPFLAGS) $(ARCFLAGS) $(YACCNOWARN) -c $< -o $@ +$(MODULE_DIR)/conf-parse.lo: $(MODULE_DIR)/conf-parse.c + $(CC) $(LIBCPPFLAGS) $(LIBCFLAGS) $(YACCNOWARN) -c $< -o $@ REMOVELIBST := $(patsubst $(MODULE_DIR)/%,$(DESTDIR)$(LIBDIR)/%,$(LIB_DIR)/$(LIBSTLIBNAME)) REMOVELIBSH := $(patsubst $(MODULE_DIR)/%,$(DESTDIR)$(LIBDIR)/%,$(LIB_DIR)/$(LIBSHLIBNAME)) @@ -118,35 +116,35 @@ user :: all-lib # so we can't make any assumptions. install-lib: all-lib $(MKDIR) $(DESTDIR)$(LIBDIR) $(DESTDIR)$(LIBINCLUDEDIR) $(DESTDIR)$(LIBMAN3DIR) $(DESTDIR)$(LIBMAN5DIR) - @if [ ! -e "$(DESTDIR)$(LIBDIR)/$(LIBSHSONAME)" ] ; then \ + @if [ -z "$(DESTDIR)" -a ! -e "$(LIBDIR)/$(LIBSHSONAME)" ] ; then \ echo '******************************************************************************' ; \ echo 'Warning: This is the first installation of the $(LIBSHSONAME)*' ; \ - echo ' library files in $(DESTDIR)$(LIBDIR)!' ; \ + echo ' library files in $(LIBDIR)!' ; \ echo ' You must update the library cache or the userspace tools may fail' ; \ echo ' or have unpredictable results!' ; \ - echo ' Run the following command: /sbin/ldconfig' ; \ + echo ' Run the following command: /sbin/ldconfig' ; \ echo '******************************************************************************' ; \ fi $(INSTALL) -m 644 $(LIB_DIR)/$(LIBSTLIBNAME) $(DESTDIR)$(LIBDIR) $(INSTALL) -m 755 $(LIB_DIR)/$(LIBSHLIBNAME) $(DESTDIR)$(LIBDIR) $(LN) $(LIBSHLIBNAME) $(DESTDIR)$(LIBDIR)/$(LIBSHSONAME) $(LN) $(LIBSHSONAME) $(DESTDIR)$(LIBDIR)/$(LIBSHBASENAME) - @if [ "$(DESTDIR)$(LIBDIR)" != "/usr/lib" -a "$(DESTDIR)$(LIBDIR)" != "/lib" ] ; then \ + @if [ -z "$(DESTDIR)" -a "$(LIBDIR)" != "/usr/lib" -a "$(LIBDIR)" != "/lib" ] ; then \ if [ -e "/usr/lib/$(LIBSHSONAME)" -o -e "/usr/lib/$(LIBSHBASENAME)" ] ; then \ echo '******************************************************************************' ; \ echo 'Warning: You have at least one $(LIBSHBASENAME) library file in /usr/lib' ; \ - echo ' and the new library files are in $(DESTDIR)$(LIBDIR)!' ; \ + echo ' and the new library files are in $(LIBDIR)!' ; \ echo ' These old files must be removed or the userspace tools may fail' ; \ echo ' or have unpredictable results!' ; \ echo ' Run the following command: rm /usr/lib/$(LIBSHBASENAME)*' ; \ echo '******************************************************************************' ; \ fi ; \ - grep -q '^$(DESTDIR)$(LIBDIR)$$' /etc/ld.so.conf || \ - grep -q '^$(DESTDIR)$(LIBDIR)[[:space:]:,=]' /etc/ld.so.conf || \ - grep -q '[[:space:]:,]$(DESTDIR)$(LIBDIR)$$' /etc/ld.so.conf || \ - grep -q '[[:space:]:,]$(DESTDIR)$(LIBDIR)[[:space:]:,=]' /etc/ld.so.conf || \ + grep -q '^$(LIBDIR)$$' /etc/ld.so.conf || \ + grep -q '^$(LIBDIR)[[:space:]:,=]' /etc/ld.so.conf || \ + grep -q '[[:space:]:,]$(LIBDIR)$$' /etc/ld.so.conf || \ + grep -q '[[:space:]:,]$(LIBDIR)[[:space:]:,=]' /etc/ld.so.conf || \ ( echo '******************************************************************************' ; \ - echo 'Warning: Library directory $(DESTDIR)$(LIBDIR) is not in /etc/ld.so.conf!' ; \ + echo 'Warning: Library directory $(LIBDIR) is not in /etc/ld.so.conf!' ; \ echo ' Add it and run /sbin/ldconfig for the userspace tools to work.' ; \ echo '******************************************************************************' ) ; \ fi diff --git a/lib/access.c b/lib/access.c index ab517557..78503360 100644 --- a/lib/access.c +++ b/lib/access.c @@ -1,6 +1,7 @@ /* access.c - Part of libsensors, a Linux library for reading sensor data. Copyright (c) 1998, 1999 Frodo Looijaard + Copyright (C) 2007, 2008 Jean Delvare This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -14,56 +15,51 @@ You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + MA 02110-1301 USA. */ #include #include #include -#include #include "access.h" #include "sensors.h" #include "data.h" #include "error.h" -#include "proc.h" -#include "general.h" #include "sysfs.h" +#include "general.h" -static int sensors_eval_expr(sensors_chip_name chipname, - const sensors_expr *expr, - double val, double *result); +/* We watch the recursion depth for variables only, as an easy way to + detect cycles. */ +#define DEPTH_MAX 8 -static int sensors_do_this_chip_sets(sensors_chip_name name); +static int sensors_eval_expr(const sensors_chip_features *chip_features, + const sensors_expr *expr, + double val, int depth, double *result); /* Compare two chips name descriptions, to see whether they could match. Return 0 if it does not match, return 1 if it does match. */ -int sensors_match_chip(sensors_chip_name chip1, sensors_chip_name chip2) +static int sensors_match_chip(const sensors_chip_name *chip1, + const sensors_chip_name *chip2) { - if ((chip1.prefix != SENSORS_CHIP_NAME_PREFIX_ANY) && - (chip2.prefix != SENSORS_CHIP_NAME_PREFIX_ANY) && - strcasecmp(chip1.prefix, chip2.prefix)) + if ((chip1->prefix != SENSORS_CHIP_NAME_PREFIX_ANY) && + (chip2->prefix != SENSORS_CHIP_NAME_PREFIX_ANY) && + strcmp(chip1->prefix, chip2->prefix)) return 0; - if ((chip1.bus != SENSORS_CHIP_NAME_BUS_ANY) && - (chip2.bus != SENSORS_CHIP_NAME_BUS_ANY) && - (chip1.bus != chip2.bus)) { + if ((chip1->bus.type != SENSORS_BUS_TYPE_ANY) && + (chip2->bus.type != SENSORS_BUS_TYPE_ANY) && + (chip1->bus.type != chip2->bus.type)) + return 0; - if ((chip1.bus == SENSORS_CHIP_NAME_BUS_ISA) || - (chip2.bus == SENSORS_CHIP_NAME_BUS_ISA)) - return 0; + if ((chip1->bus.nr != SENSORS_BUS_NR_ANY) && + (chip2->bus.nr != SENSORS_BUS_NR_ANY) && + (chip1->bus.nr != chip2->bus.nr)) + return 0; - if ((chip1.bus == SENSORS_CHIP_NAME_BUS_PCI) || - (chip2.bus == SENSORS_CHIP_NAME_BUS_PCI)) - return 0; - - if ((chip1.bus != SENSORS_CHIP_NAME_BUS_ANY_I2C) && - (chip2.bus != SENSORS_CHIP_NAME_BUS_ANY_I2C)) - return 0; - } - - if ((chip1.addr != chip2.addr) && - (chip1.addr != SENSORS_CHIP_NAME_ADDR_ANY) && - (chip2.addr != SENSORS_CHIP_NAME_ADDR_ANY)) + if ((chip1->addr != chip2->addr) && + (chip1->addr != SENSORS_CHIP_NAME_ADDR_ANY) && + (chip2->addr != SENSORS_CHIP_NAME_ADDR_ANY)) return 0; return 1; @@ -76,8 +72,9 @@ int sensors_match_chip(sensors_chip_name chip1, sensors_chip_name chip2) the struct the return value points to! Note that this visits the list of chips from last to first. Usually, you want the match that was latest in the config file. */ -sensors_chip *sensors_for_all_config_chips(sensors_chip_name chip_name, - const sensors_chip * last) +static sensors_chip * +sensors_for_all_config_chips(const sensors_chip_name *name, + const sensors_chip *last) { int nr, i; sensors_chip_name_list chips; @@ -87,303 +84,361 @@ sensors_chip *sensors_for_all_config_chips(sensors_chip_name chip_name, chips = sensors_config_chips[nr].chips; for (i = 0; i < chips.fits_count; i++) { - if (sensors_match_chip(chips.fits[i], chip_name)) + if (sensors_match_chip(&chips.fits[i], name)) return sensors_config_chips + nr; } } return NULL; } -/* Look up a resource in the intern chip list, and return a pointer to it. - Do not modify the struct the return value points to! Returns NULL if +/* Look up a chip in the intern chip list, and return a pointer to it. + Do not modify the struct the return value points to! Returns NULL if not found.*/ -const sensors_chip_feature *sensors_lookup_feature_nr(const char *prefix, - int feature) +static const sensors_chip_features * +sensors_lookup_chip(const sensors_chip_name *name) { - int i, j; - const sensors_chip_feature *features; + int i; + + for (i = 0; i < sensors_proc_chips_count; i++) + if (sensors_match_chip(&sensors_proc_chips[i].chip, name)) + return &sensors_proc_chips[i]; - for (i = 0; sensors_chip_features_list[i].prefix; i++) - if (!strcasecmp(sensors_chip_features_list[i].prefix, prefix)) { - features = sensors_chip_features_list[i].feature; - for (j = 0; features[j].data.name; j++) - if (features[j].data.number == feature) - return features + j; - } return NULL; } -/* Look up a resource in the intern chip list, and return a pointer to it. +/* Look up a subfeature of the given chip, and return a pointer to it. + Do not modify the struct the return value points to! Returns NULL if + not found.*/ +static const sensors_subfeature * +sensors_lookup_subfeature_nr(const sensors_chip_features *chip, + int subfeat_nr) +{ + if (subfeat_nr < 0 || + subfeat_nr >= chip->subfeature_count) + return NULL; + return chip->subfeature + subfeat_nr; +} + +/* Look up a feature of the given chip, and return a pointer to it. + Do not modify the struct the return value points to! Returns NULL if + not found.*/ +static const sensors_feature * +sensors_lookup_feature_nr(const sensors_chip_features *chip, int feat_nr) +{ + if (feat_nr < 0 || + feat_nr >= chip->feature_count) + return NULL; + return chip->feature + feat_nr; +} + +/* Look up a subfeature by name, and return a pointer to it. Do not modify the struct the return value points to! Returns NULL if not found.*/ -const sensors_chip_feature *sensors_lookup_feature_name(const char *prefix, - const char *feature) +static const sensors_subfeature * +sensors_lookup_subfeature_name(const sensors_chip_features *chip, + const char *name) { - int i, j; - const sensors_chip_feature *features; + int j; - for (i = 0; sensors_chip_features_list[i].prefix; i++) - if (!strcasecmp(sensors_chip_features_list[i].prefix, prefix)) { - features = sensors_chip_features_list[i].feature; - for (j = 0; features[j].data.name; j++) - if (!strcasecmp(features[j].data.name, feature)) - return features + j; - } + for (j = 0; j < chip->subfeature_count; j++) + if (!strcmp(chip->subfeature[j].name, name)) + return chip->subfeature + j; return NULL; } /* Check whether the chip name is an 'absolute' name, which can only match one chip, or whether it has wildcards. Returns 0 if it is absolute, 1 if there are wildcards. */ -int sensors_chip_name_has_wildcards(sensors_chip_name chip) +int sensors_chip_name_has_wildcards(const sensors_chip_name *chip) { - if ((chip.prefix == SENSORS_CHIP_NAME_PREFIX_ANY) || - (chip.bus == SENSORS_CHIP_NAME_BUS_ANY) || - (chip.bus == SENSORS_CHIP_NAME_BUS_ANY_I2C) || - (chip.addr == SENSORS_CHIP_NAME_ADDR_ANY)) + if ((chip->prefix == SENSORS_CHIP_NAME_PREFIX_ANY) || + (chip->bus.type == SENSORS_BUS_TYPE_ANY) || + (chip->bus.nr == SENSORS_BUS_NR_ANY) || + (chip->addr == SENSORS_CHIP_NAME_ADDR_ANY)) return 1; else return 0; } -/* Look up the label which belongs to this chip. Note that chip should not - contain wildcard values! *result is newly allocated (free it yourself). - This function will return 0 on success, and <0 on failure. +/* Look up the label for a given feature. Note that chip should not + contain wildcard values! The returned string is newly allocated (free it + yourself). On failure, NULL is returned. If no label exists for this feature, its name is returned itself. */ -int sensors_get_label(sensors_chip_name name, int feature, char **result) +char *sensors_get_label(const sensors_chip_name *name, + const sensors_feature *feature) { + char *label; const sensors_chip *chip; - const sensors_chip_feature *featureptr; + char buf[128], path[PATH_MAX]; + FILE *f; int i; - *result = NULL; if (sensors_chip_name_has_wildcards(name)) - return -SENSORS_ERR_WILDCARDS; - if (!(featureptr = sensors_lookup_feature_nr(name.prefix, feature))) - return -SENSORS_ERR_NO_ENTRY; + return NULL; for (chip = NULL; (chip = sensors_for_all_config_chips(name, chip));) for (i = 0; i < chip->labels_count; i++) - if (!strcasecmp(featureptr->data.name,chip->labels[i].name)){ - *result = strdup(chip->labels[i].value); + if (!strcmp(feature->name, chip->labels[i].name)) { + label = strdup(chip->labels[i].value); goto sensors_get_label_exit; } - if (sensors_found_sysfs) { - char buf[128], path[PATH_MAX]; - FILE *f; - - /* No user specified label, check for a _label sysfs file */ - snprintf(path, PATH_MAX, "%s/%s_label", name.busname, - featureptr->data.name); - - if ((f = fopen(path, "r"))) { - i = fread(buf, 1, sizeof(buf) - 1, f); - fclose(f); - if (i > 0) { - /* i - 1 to strip the '\n' at the end */ - buf[i - 1] = 0; - *result = strdup(buf); - goto sensors_get_label_exit; - } + /* No user specified label, check for a _label sysfs file */ + snprintf(path, PATH_MAX, "%s/%s_label", name->path, feature->name); + + if ((f = fopen(path, "r"))) { + i = fread(buf, 1, sizeof(buf) - 1, f); + fclose(f); + if (i > 0) { + /* i - 1 to strip the '\n' at the end */ + buf[i - 1] = 0; + label = strdup(buf); + goto sensors_get_label_exit; } } /* No label, return the feature name instead */ - *result = strdup(featureptr->data.name); + label = strdup(feature->name); sensors_get_label_exit: - if (*result == NULL) + if (!label) sensors_fatal_error("sensors_get_label", "Allocating label text"); + return label; +} + +/* Looks up whether a feature should be ignored. Returns + 1 if it should be ignored, 0 if not. */ +static int sensors_get_ignored(const sensors_chip_name *name, + const sensors_feature *feature) +{ + const sensors_chip *chip; + int i; + + for (chip = NULL; (chip = sensors_for_all_config_chips(name, chip));) + for (i = 0; i < chip->ignores_count; i++) + if (!strcmp(feature->name, chip->ignores[i].name)) + return 1; return 0; } -int sensors_get_ignored(sensors_chip_name name, int feature) -{ - const sensors_chip *chip; - const sensors_chip_feature *featureptr; - const sensors_chip_feature *alt_featureptr; - int i; - - if (sensors_chip_name_has_wildcards(name)) - return -SENSORS_ERR_WILDCARDS; - if (!(featureptr = sensors_lookup_feature_nr(name.prefix, feature))) - return -SENSORS_ERR_NO_ENTRY; - if (featureptr->data.mapping == SENSORS_NO_MAPPING) - alt_featureptr = NULL; - else if (!(alt_featureptr = - sensors_lookup_feature_nr(name.prefix, - featureptr->data.mapping))) - return -SENSORS_ERR_NO_ENTRY; - for (chip = NULL; (chip = sensors_for_all_config_chips(name, chip));) - for (i = 0; i < chip->ignores_count; i++) - if (!strcasecmp(featureptr->data.name, chip->ignores[i].name) || - (alt_featureptr && - !strcasecmp(alt_featureptr->data.name, chip->ignores[i].name))) - return 0; - /* valid */ - return 1; -} - -/* Read the value of a feature of a certain chip. Note that chip should not +/* Read the value of a subfeature of a certain chip. Note that chip should not contain wildcard values! This function will return 0 on success, and <0 on failure. */ -int sensors_get_feature(sensors_chip_name name, int feature, double *result) +static int __sensors_get_value(const sensors_chip_name *name, int subfeat_nr, + int depth, double *result) { - const sensors_chip_feature *main_feature; - const sensors_chip_feature *alt_feature; - const sensors_chip *chip; + const sensors_chip_features *chip_features; + const sensors_subfeature *subfeature; const sensors_expr *expr = NULL; double val; int res, i; - int final_expr = 0; + if (depth >= DEPTH_MAX) + return -SENSORS_ERR_RECURSION; if (sensors_chip_name_has_wildcards(name)) return -SENSORS_ERR_WILDCARDS; - if (!(main_feature = sensors_lookup_feature_nr(name.prefix, feature))) + if (!(chip_features = sensors_lookup_chip(name))) return -SENSORS_ERR_NO_ENTRY; - if (main_feature->data.compute_mapping == SENSORS_NO_MAPPING) - alt_feature = NULL; - else if (!(alt_feature = sensors_lookup_feature_nr(name.prefix, - main_feature->data.compute_mapping))) + if (!(subfeature = sensors_lookup_subfeature_nr(chip_features, + subfeat_nr))) return -SENSORS_ERR_NO_ENTRY; - if (!(main_feature->data.mode & SENSORS_MODE_R)) + if (!(subfeature->flags & SENSORS_MODE_R)) return -SENSORS_ERR_ACCESS_R; - for (chip = NULL; - !expr && (chip = sensors_for_all_config_chips(name, chip));) - for (i = 0; !final_expr && (i < chip->computes_count); i++) { - if (!strcasecmp(main_feature->data.name, chip->computes[i].name)) { - expr = chip->computes[i].from_proc; - final_expr = 1; - } else if (alt_feature && !strcasecmp(alt_feature->data.name, - chip->computes[i].name)) { - expr = chip->computes[i].from_proc; + + /* Apply compute statement if it exists */ + if (subfeature->flags & SENSORS_COMPUTE_MAPPING) { + const sensors_feature *feature; + const sensors_chip *chip; + + feature = sensors_lookup_feature_nr(chip_features, + subfeature->mapping); + + chip = NULL; + while (!expr && + (chip = sensors_for_all_config_chips(name, chip))) + for (i = 0; i < chip->computes_count; i++) { + if (!strcmp(feature->name, + chip->computes[i].name)) { + expr = chip->computes[i].from_proc; + break; + } } - } - if (sensors_read_proc(name, feature, &val)) - return -SENSORS_ERR_PROC; + } + + res = sensors_read_sysfs_attr(name, subfeature, &val); + if (res) + return res; if (!expr) *result = val; - else if ((res = sensors_eval_expr(name, expr, val, result))) + else if ((res = sensors_eval_expr(chip_features, expr, val, depth, + result))) return res; return 0; } -/* Set the value of a feature of a certain chip. Note that chip should not +int sensors_get_value(const sensors_chip_name *name, int subfeat_nr, + double *result) +{ + return __sensors_get_value(name, subfeat_nr, 0, result); +} + +/* Set the value of a subfeature of a certain chip. Note that chip should not contain wildcard values! This function will return 0 on success, and <0 on failure. */ -int sensors_set_feature(sensors_chip_name name, int feature, double value) +int sensors_set_value(const sensors_chip_name *name, int subfeat_nr, + double value) { - const sensors_chip_feature *main_feature; - const sensors_chip_feature *alt_feature; - const sensors_chip *chip; + const sensors_chip_features *chip_features; + const sensors_subfeature *subfeature; const sensors_expr *expr = NULL; int i, res; - int final_expr = 0; double to_write; if (sensors_chip_name_has_wildcards(name)) return -SENSORS_ERR_WILDCARDS; - if (!(main_feature = sensors_lookup_feature_nr(name.prefix, feature))) + if (!(chip_features = sensors_lookup_chip(name))) return -SENSORS_ERR_NO_ENTRY; - if (main_feature->data.compute_mapping == SENSORS_NO_MAPPING) - alt_feature = NULL; - else if (!(alt_feature = sensors_lookup_feature_nr(name.prefix, - main_feature->data.compute_mapping))) + if (!(subfeature = sensors_lookup_subfeature_nr(chip_features, + subfeat_nr))) return -SENSORS_ERR_NO_ENTRY; - if (!(main_feature->data.mode & SENSORS_MODE_W)) + if (!(subfeature->flags & SENSORS_MODE_W)) return -SENSORS_ERR_ACCESS_W; - for (chip = NULL; - !expr && (chip = sensors_for_all_config_chips(name, chip));) - for (i = 0; !final_expr && (i < chip->computes_count); i++) - if (!strcasecmp(main_feature->data.name, chip->computes[i].name)) { - expr = chip->computes->to_proc; - final_expr = 1; - } else if (alt_feature && !strcasecmp(alt_feature->data.name, - chip->computes[i].name)) { - expr = chip->computes[i].to_proc; + + /* Apply compute statement if it exists */ + if (subfeature->flags & SENSORS_COMPUTE_MAPPING) { + const sensors_feature *feature; + const sensors_chip *chip; + + feature = sensors_lookup_feature_nr(chip_features, + subfeature->mapping); + + chip = NULL; + while (!expr && + (chip = sensors_for_all_config_chips(name, chip))) + for (i = 0; i < chip->computes_count; i++) { + if (!strcmp(feature->name, + chip->computes[i].name)) { + expr = chip->computes[i].to_proc; + break; + } } + } to_write = value; if (expr) - if ((res = sensors_eval_expr(name, expr, value, &to_write))) + if ((res = sensors_eval_expr(chip_features, expr, + value, 0, &to_write))) return res; - if (sensors_write_proc(name, feature, to_write)) - return -SENSORS_ERR_PROC; - return 0; + return sensors_write_sysfs_attr(name, subfeature, to_write); } -const sensors_chip_name *sensors_get_detected_chips(int *nr) +const sensors_chip_name *sensors_get_detected_chips(const sensors_chip_name + *match, int *nr) { const sensors_chip_name *res; - res = (*nr >= sensors_proc_chips_count ? - NULL : &sensors_proc_chips[*nr].name); - (*nr)++; - return res; + + while (*nr < sensors_proc_chips_count) { + res = &sensors_proc_chips[(*nr)++].chip; + if (!match || sensors_match_chip(res, match)) + return res; + } + return NULL; } -const char *sensors_get_adapter_name(int bus_nr) +const char *sensors_get_adapter_name(const sensors_bus_id *bus) { int i; - if (bus_nr == SENSORS_CHIP_NAME_BUS_ISA) + /* bus types with a single instance */ + switch (bus->type) { + case SENSORS_BUS_TYPE_ISA: return "ISA adapter"; - if (bus_nr == SENSORS_CHIP_NAME_BUS_PCI) + case SENSORS_BUS_TYPE_PCI: return "PCI adapter"; - if (bus_nr == SENSORS_CHIP_NAME_BUS_DUMMY) - return "Dummy adapter"; + /* SPI should not be here, but for now SPI adapters have no name + so we don't have any custom string to return. */ + case SENSORS_BUS_TYPE_SPI: + return "SPI adapter"; + case SENSORS_BUS_TYPE_VIRTUAL: + return "Virtual device"; + case SENSORS_BUS_TYPE_ACPI: + return "ACPI interface"; + } + + /* bus types with several instances */ for (i = 0; i < sensors_proc_bus_count; i++) - if (sensors_proc_bus[i].number == bus_nr) + if (sensors_proc_bus[i].bus.type == bus->type && + sensors_proc_bus[i].bus.nr == bus->nr) return sensors_proc_bus[i].adapter; return NULL; } -/* This function is deprecated and will be dropped soon. */ -const char *sensors_get_algorithm_name(int bus_nr) +const sensors_feature * +sensors_get_features(const sensors_chip_name *name, int *nr) { - return "No longer available"; + const sensors_chip_features *chip; + + if (!(chip = sensors_lookup_chip(name))) + return NULL; /* No such chip */ + + while (*nr < chip->feature_count + && sensors_get_ignored(name, &chip->feature[*nr])) + (*nr)++; + if (*nr >= chip->feature_count) + return NULL; + return &chip->feature[(*nr)++]; } -/* nr1-1 is the last main feature found; nr2-1 is the last subfeature found */ -const sensors_feature_data *sensors_get_all_features(sensors_chip_name name, - int *nr1, int *nr2) +const sensors_subfeature * +sensors_get_all_subfeatures(const sensors_chip_name *name, + const sensors_feature *feature, int *nr) { - sensors_chip_feature *feature_list; + const sensors_chip_features *chip; + const sensors_subfeature *subfeature; + + if (!(chip = sensors_lookup_chip(name))) + return NULL; /* No such chip */ + + /* Seek directly to the first subfeature */ + if (*nr < feature->first_subfeature) + *nr = feature->first_subfeature; + + if (*nr >= chip->subfeature_count) + return NULL; /* end of list */ + subfeature = &chip->subfeature[(*nr)++]; + if (subfeature->mapping == feature->number) + return subfeature; + return NULL; /* end of subfeature list */ +} + +const sensors_subfeature * +sensors_get_subfeature(const sensors_chip_name *name, + const sensors_feature *feature, + sensors_subfeature_type type) +{ + const sensors_chip_features *chip; int i; - for (i = 0; sensors_chip_features_list[i].prefix; i++) - if (!strcasecmp(sensors_chip_features_list[i].prefix, name.prefix)) { - feature_list = sensors_chip_features_list[i].feature; - if (!*nr1 && !*nr2) { /* Return the first entry */ - if (!feature_list[0].data.name) /* The list may be empty */ - return NULL; - *nr1 = *nr2 = 1; - return &feature_list->data; - } - for ((*nr2)++; feature_list[*nr2 - 1].data.name; (*nr2)++) - if (feature_list[*nr2 - 1].data.mapping == - feature_list[*nr1 - 1].data.number) - return &((feature_list + *nr2 - 1)->data); - for ((*nr1)++; - feature_list[*nr1 - 1].data.name - && (feature_list[*nr1 - 1].data.mapping != - SENSORS_NO_MAPPING); (*nr1)++) ; - *nr2 = *nr1; - if (!feature_list[*nr1 - 1].data.name) - return NULL; - return &((feature_list + *nr1 - 1)->data); - } - return NULL; + if (!(chip = sensors_lookup_chip(name))) + return NULL; /* No such chip */ + + for (i = feature->first_subfeature; i < chip->subfeature_count && + chip->subfeature[i].mapping == feature->number; i++) { + if (chip->subfeature[i].type == type) + return &chip->subfeature[i]; + } + return NULL; /* No such subfeature */ } /* Evaluate an expression */ -int sensors_eval_expr(sensors_chip_name chipname, const sensors_expr * expr, - double val, double *result) +int sensors_eval_expr(const sensors_chip_features *chip_features, + const sensors_expr *expr, + double val, int depth, double *result) { double res1, res2; int res; - const sensors_chip_feature *feature; + const sensors_subfeature *subfeature; if (expr->kind == sensors_kind_val) { *result = expr->data.val; @@ -394,17 +449,19 @@ int sensors_eval_expr(sensors_chip_name chipname, const sensors_expr * expr, return 0; } if (expr->kind == sensors_kind_var) { - if (!(feature = sensors_lookup_feature_name(chipname.prefix, + if (!(subfeature = sensors_lookup_subfeature_name(chip_features, expr->data.var))) return -SENSORS_ERR_NO_ENTRY; - if (!(res = sensors_get_feature(chipname, feature->data.number, result))) - return res; - return 0; + return __sensors_get_value(&chip_features->chip, + subfeature->number, depth + 1, + result); } - if ((res = sensors_eval_expr(chipname, expr->data.subexpr.sub1, val, &res1))) + if ((res = sensors_eval_expr(chip_features, expr->data.subexpr.sub1, + val, depth, &res1))) return res; if (expr->data.subexpr.sub2 && - (res = sensors_eval_expr(chipname, expr->data.subexpr.sub2, val, &res2))) + (res = sensors_eval_expr(chip_features, expr->data.subexpr.sub2, + val, depth, &res2))) return res; switch (expr->data.subexpr.op) { case sensors_add: @@ -439,83 +496,60 @@ int sensors_eval_expr(sensors_chip_name chipname, const sensors_expr * expr, /* Execute all set statements for this particular chip. The chip may not contain wildcards! This function will return 0 on success, and <0 on failure. */ -int sensors_do_this_chip_sets(sensors_chip_name name) +static int sensors_do_this_chip_sets(const sensors_chip_name *name) { + const sensors_chip_features *chip_features; sensors_chip *chip; double value; - int i, j; + int i; int err = 0, res; - const sensors_chip_feature *feature; - int *feature_list = NULL; - int feature_count = 0; - int feature_max = 0; - int feature_nr; + const sensors_subfeature *subfeature; + + chip_features = sensors_lookup_chip(name); /* Can't fail */ for (chip = NULL; (chip = sensors_for_all_config_chips(name, chip));) for (i = 0; i < chip->sets_count; i++) { - feature = sensors_lookup_feature_name(name.prefix, + subfeature = sensors_lookup_subfeature_name(chip_features, chip->sets[i].name); - if (!feature) { + if (!subfeature) { sensors_parse_error("Unknown feature name", chip->sets[i].lineno); err = -SENSORS_ERR_NO_ENTRY; continue; } - feature_nr = feature->data.number; - /* Check whether we already set this feature */ - for (j = 0; j < feature_count; j++) - if (feature_list[j] == feature_nr) - break; - if (j != feature_count) - continue; - sensors_add_array_el(&feature_nr, &feature_list, - &feature_count, &feature_max, - sizeof(int)); - - res = sensors_eval_expr(name, chip->sets[i].value, 0, - &value); + res = sensors_eval_expr(chip_features, + chip->sets[i].value, 0, + 0, &value); if (res) { sensors_parse_error("Error parsing expression", chip->sets[i].lineno); err = res; continue; } - if ((res = sensors_set_feature(name, feature_nr, value))) { - sensors_parse_error("Failed to set feature", + if ((res = sensors_set_value(name, subfeature->number, + value))) { + sensors_parse_error("Failed to set value", chip->sets[i].lineno); err = res; continue; } } - free(feature_list); return err; } /* Execute all set statements for this particular chip. The chip may contain wildcards! This function will return 0 on success, and <0 on failure. */ -int sensors_do_chip_sets(sensors_chip_name name) +int sensors_do_chip_sets(const sensors_chip_name *name) { int nr, this_res; const sensors_chip_name *found_name; int res = 0; - for (nr = 0; (found_name = sensors_get_detected_chips(&nr));) - if (sensors_match_chip(name, *found_name)) { - this_res = sensors_do_this_chip_sets(*found_name); - if (!res) - res = this_res; - } + for (nr = 0; (found_name = sensors_get_detected_chips(name, &nr));) { + this_res = sensors_do_this_chip_sets(found_name); + if (this_res) + res = this_res; + } return res; } - -/* Execute all set statements for all detected chips. This is the same as - calling sensors_do_chip_sets with an all wildcards chip name */ -int sensors_do_all_sets(void) -{ - sensors_chip_name name = { SENSORS_CHIP_NAME_PREFIX_ANY, - SENSORS_CHIP_NAME_BUS_ANY, - SENSORS_CHIP_NAME_ADDR_ANY - }; - return sensors_do_chip_sets(name); -} diff --git a/lib/access.h b/lib/access.h index 57897694..86b79e9e 100644 --- a/lib/access.h +++ b/lib/access.h @@ -1,6 +1,7 @@ /* access.h - Part of libsensors, a Linux library for reading sensor data. Copyright (c) 1998, 1999 Frodo Looijaard + Copyright (C) 2007 Jean Delvare This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -14,7 +15,8 @@ You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + MA 02110-1301 USA. */ #ifndef LIB_SENSORS_ACCESS_H @@ -23,35 +25,9 @@ #include "sensors.h" #include "data.h" -/* Returns, one by one, a pointer to all sensor_chip structs of the - config file which match with the given chip name. Last should be - the value returned by the last call, or NULL if this is the first - call. Returns NULL if no more matches are found. Do not modify - the struct the return value points to! - Note that this visits the list of chips from last to first. Usually, - you want the match that was latest in the config file. */ -extern sensors_chip *sensors_for_all_config_chips(sensors_chip_name chip_name, - const sensors_chip *last); - -/* Look up a resource in the intern chip list, and return a pointer to it. - Do not modify the struct the return value points to! Returns NULL if - not found. */ -extern const sensors_chip_feature *sensors_lookup_feature_nr(const char *prefix, - int feature); - -/* Look up a resource in the intern chip list, and return a pointer to it. - Do not modify the struct the return value points to! Returns NULL if - not found.*/ -extern const sensors_chip_feature *sensors_lookup_feature_name - (const char *prefix, const char *feature); - -/* Substitute configuration bus numbers with real-world /proc bus numbers - in the chips lists */ -extern int sensors_substitute_busses(void); - - -/* Parse an i2c bus name into its components. Returns 0 on succes, a value from - error.h on failure. */ -extern int sensors_parse_i2cbus_name(const char *name, int *res); +/* Check whether the chip name is an 'absolute' name, which can only match + one chip, or whether it has wildcards. Returns 0 if it is absolute, 1 + if there are wildcards. */ +int sensors_chip_name_has_wildcards(const sensors_chip_name *chip); #endif /* def LIB_SENSORS_ACCESS_H */ diff --git a/lib/chips.c b/lib/chips.c deleted file mode 100644 index 9a5fc023..00000000 --- a/lib/chips.c +++ /dev/null @@ -1,6509 +0,0 @@ -/* - chips.c - Part of libsensors, a Linux library for reading sensor data. - Copyright (c) 1998, 1999 Frodo Looijaard - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#include "chips.h" -#include "data.h" -#include "sensors.h" -#include "kernel/include/sensors.h" - -/* For each chip, a list of features; - For each feature, the number, its name, the logical mapping (for example, - fan1_div belongs to fan1), the compute mapping, an access field, the - SYSCTL id of the /proc field, the value location of the /proc field, - and the magnitude. - The access field indicates whether resources are readable and writable. - Sometimes, a resource is neither; in this case, it is just a catch-all - category, for mappings. - The value location is the byte-offset where this value can be found in - the sysctl buffer. - The magnitude is the 10-power through which the read value must be - divided. */ - - -#define VALUE(x) (x-1) * sizeof(long) -#define NOMAP SENSORS_NO_MAPPING -#define R SENSORS_MODE_R -#define RW SENSORS_MODE_RW -#define NOSYSCTL 0 - -static sensors_chip_feature lm78_features[] = - { - { { SENSORS_LM78_IN0, "in0", NOMAP, NOMAP, R }, - LM78_SYSCTL_IN0, VALUE(3), 2 }, - { { SENSORS_LM78_IN1, "in1", NOMAP, NOMAP, R }, - LM78_SYSCTL_IN1, VALUE(3), 2 }, - { { SENSORS_LM78_IN2, "in2", NOMAP, NOMAP, R }, - LM78_SYSCTL_IN2, VALUE(3), 2 }, - { { SENSORS_LM78_IN3, "in3", NOMAP, NOMAP, R }, - LM78_SYSCTL_IN3, VALUE(3), 2 }, - { { SENSORS_LM78_IN4, "in4", NOMAP, NOMAP, R }, - LM78_SYSCTL_IN4, VALUE(3), 2 }, - { { SENSORS_LM78_IN5, "in5", NOMAP, NOMAP, R }, - LM78_SYSCTL_IN5, VALUE(3), 2 }, - { { SENSORS_LM78_IN6, "in6", NOMAP, NOMAP, R }, - LM78_SYSCTL_IN6, VALUE(3), 2 }, - { { SENSORS_LM78_IN0_MIN, "in0_min", SENSORS_LM78_IN0, SENSORS_LM78_IN0, RW }, - LM78_SYSCTL_IN0, VALUE(1), 2 }, - { { SENSORS_LM78_IN1_MIN, "in1_min", SENSORS_LM78_IN1, SENSORS_LM78_IN1, RW }, - LM78_SYSCTL_IN1, VALUE(1), 2 }, - { { SENSORS_LM78_IN2_MIN, "in2_min", SENSORS_LM78_IN2, SENSORS_LM78_IN2, RW }, - LM78_SYSCTL_IN2, VALUE(1), 2 }, - { { SENSORS_LM78_IN3_MIN, "in3_min", SENSORS_LM78_IN3, SENSORS_LM78_IN3, RW }, - LM78_SYSCTL_IN3, VALUE(1), 2 }, - { { SENSORS_LM78_IN4_MIN, "in4_min", SENSORS_LM78_IN4, SENSORS_LM78_IN4, RW }, - LM78_SYSCTL_IN4, VALUE(1), 2 }, -/* swap 5 and 6 min/max because compute lines will be inverting */ - { { SENSORS_LM78_IN5_MIN, "in5_min", SENSORS_LM78_IN5, SENSORS_LM78_IN5, RW }, - LM78_SYSCTL_IN5, VALUE(2), 2, "in5_max", 3 }, - { { SENSORS_LM78_IN6_MIN, "in6_min", SENSORS_LM78_IN6, SENSORS_LM78_IN6, RW }, - LM78_SYSCTL_IN6, VALUE(2), 2, "in6_max", 3 }, - { { SENSORS_LM78_IN0_MAX, "in0_max", SENSORS_LM78_IN0, SENSORS_LM78_IN0, RW }, - LM78_SYSCTL_IN0, VALUE(2), 2 }, - { { SENSORS_LM78_IN1_MAX, "in1_max", SENSORS_LM78_IN1, SENSORS_LM78_IN1, RW }, - LM78_SYSCTL_IN1, VALUE(2), 2 }, - { { SENSORS_LM78_IN2_MAX, "in2_max", SENSORS_LM78_IN2, SENSORS_LM78_IN2, RW }, - LM78_SYSCTL_IN2, VALUE(2), 2 }, - { { SENSORS_LM78_IN3_MAX, "in3_max", SENSORS_LM78_IN3, SENSORS_LM78_IN3, RW }, - LM78_SYSCTL_IN3, VALUE(2), 2 }, - { { SENSORS_LM78_IN4_MAX, "in4_max", SENSORS_LM78_IN4, SENSORS_LM78_IN4, RW }, - LM78_SYSCTL_IN4, VALUE(2), 2 }, - { { SENSORS_LM78_IN5_MAX, "in5_max", SENSORS_LM78_IN5, SENSORS_LM78_IN5, RW }, - LM78_SYSCTL_IN5, VALUE(1), 2, "in5_min", 3 }, - { { SENSORS_LM78_IN6_MAX, "in6_max", SENSORS_LM78_IN6, SENSORS_LM78_IN6, RW }, - LM78_SYSCTL_IN6, VALUE(1), 2, "in6_min", 3 }, - { { SENSORS_LM78_FAN1, "fan1", NOMAP, NOMAP, R }, - LM78_SYSCTL_FAN1, VALUE(2), 0 }, - { { SENSORS_LM78_FAN2, "fan2", NOMAP, NOMAP, R }, - LM78_SYSCTL_FAN2, VALUE(2), 0 }, - { { SENSORS_LM78_FAN3, "fan3", NOMAP, NOMAP, R }, - LM78_SYSCTL_FAN3, VALUE(2), 0 }, - { { SENSORS_LM78_FAN1_MIN, "fan1_min", SENSORS_LM78_FAN1, SENSORS_LM78_FAN1, - RW }, - LM78_SYSCTL_FAN1, VALUE(1), 0 }, - { { SENSORS_LM78_FAN2_MIN, "fan2_min", SENSORS_LM78_FAN2, SENSORS_LM78_FAN2, - RW }, - LM78_SYSCTL_FAN2, VALUE(1), 0 }, - { { SENSORS_LM78_FAN3_MIN, "fan3_min", SENSORS_LM78_FAN3, SENSORS_LM78_FAN3, - RW }, - LM78_SYSCTL_FAN3, VALUE(1), 0 }, - { { SENSORS_LM78_TEMP, "temp", NOMAP, NOMAP, R }, - LM78_SYSCTL_TEMP, VALUE(3), 1 }, - { { SENSORS_LM78_TEMP_HYST, "temp_hyst", SENSORS_LM78_TEMP, - SENSORS_LM78_TEMP, RW }, - LM78_SYSCTL_TEMP, VALUE(2), 1 }, - { { SENSORS_LM78_TEMP_OVER, "temp_over", SENSORS_LM78_TEMP, - SENSORS_LM78_TEMP, RW }, - LM78_SYSCTL_TEMP, VALUE(1), 1 }, - { { SENSORS_LM78_VID, "vid", NOMAP, NOMAP, R }, - LM78_SYSCTL_VID, VALUE(1), 2 }, - { { SENSORS_LM78_FAN1_DIV, "fan1_div", SENSORS_LM78_FAN1, NOMAP, RW }, - LM78_SYSCTL_FAN_DIV, VALUE(1), 0 }, - { { SENSORS_LM78_FAN2_DIV, "fan2_div", SENSORS_LM78_FAN2, NOMAP, RW }, - LM78_SYSCTL_FAN_DIV, VALUE(2), 0 }, - { { SENSORS_LM78_FAN3_DIV, "fan3_div", SENSORS_LM78_FAN3, NOMAP, R }, - LM78_SYSCTL_FAN_DIV, VALUE(3), 0 }, - { { SENSORS_LM78_ALARMS, "alarms", NOMAP, NOMAP, R }, - LM78_SYSCTL_ALARMS, VALUE(1), 0 }, - { { 0 }, 0 } - }; - -static sensors_chip_feature lm78j_features[] = - { - { { SENSORS_LM78J_IN0, "in0", NOMAP, NOMAP, R }, - LM78_SYSCTL_IN0, VALUE(3), 2 }, - { { SENSORS_LM78J_IN1, "in1", NOMAP, NOMAP, R }, - LM78_SYSCTL_IN1, VALUE(3), 2 }, - { { SENSORS_LM78J_IN2, "in2", NOMAP, NOMAP, R }, - LM78_SYSCTL_IN2, VALUE(3), 2 }, - { { SENSORS_LM78J_IN3, "in3", NOMAP, NOMAP, R }, - LM78_SYSCTL_IN3, VALUE(3), 2 }, - { { SENSORS_LM78J_IN4, "in4", NOMAP, NOMAP, R }, - LM78_SYSCTL_IN4, VALUE(3), 2 }, - { { SENSORS_LM78J_IN5, "in5", NOMAP, NOMAP, R }, - LM78_SYSCTL_IN5, VALUE(3), 2 }, - { { SENSORS_LM78J_IN6, "in6", NOMAP, NOMAP, R }, - LM78_SYSCTL_IN6, VALUE(3), 2 }, - { { SENSORS_LM78J_IN0_MIN, "in0_min", SENSORS_LM78J_IN0, SENSORS_LM78J_IN0, - RW }, - LM78_SYSCTL_IN0, VALUE(1), 2 }, - { { SENSORS_LM78J_IN1_MIN, "in1_min", SENSORS_LM78J_IN1, SENSORS_LM78J_IN1, - RW }, - LM78_SYSCTL_IN1, VALUE(1), 2 }, - { { SENSORS_LM78J_IN2_MIN, "in2_min", SENSORS_LM78J_IN2, SENSORS_LM78J_IN2, - RW }, - LM78_SYSCTL_IN2, VALUE(1), 2 }, - { { SENSORS_LM78J_IN3_MIN, "in3_min", SENSORS_LM78J_IN3, SENSORS_LM78J_IN3, - RW }, - LM78_SYSCTL_IN3, VALUE(1), 2 }, - { { SENSORS_LM78J_IN4_MIN, "in4_min", SENSORS_LM78J_IN4, SENSORS_LM78J_IN4, - RW }, - LM78_SYSCTL_IN4, VALUE(1), 2 }, -/* swap 5 and 6 min/max because compute lines will be inverting */ - { { SENSORS_LM78J_IN5_MIN, "in5_min", SENSORS_LM78J_IN5, SENSORS_LM78J_IN5, - RW }, - LM78_SYSCTL_IN5, VALUE(2), 2, "in5_max", 3 }, - { { SENSORS_LM78J_IN6_MIN, "in6_min", SENSORS_LM78J_IN6, SENSORS_LM78J_IN6, - RW }, - LM78_SYSCTL_IN6, VALUE(2), 2, "in6_max", 3 }, - { { SENSORS_LM78J_IN0_MAX, "in0_max", SENSORS_LM78J_IN0, SENSORS_LM78J_IN0, - RW }, - LM78_SYSCTL_IN0, VALUE(2), 2 }, - { { SENSORS_LM78J_IN1_MAX, "in1_max", SENSORS_LM78J_IN1, SENSORS_LM78J_IN1, - RW }, - LM78_SYSCTL_IN1, VALUE(2), 2 }, - { { SENSORS_LM78J_IN2_MAX, "in2_max", SENSORS_LM78J_IN2, SENSORS_LM78J_IN2, - RW }, - LM78_SYSCTL_IN2, VALUE(2), 2 }, - { { SENSORS_LM78J_IN3_MAX, "in3_max", SENSORS_LM78J_IN3, SENSORS_LM78J_IN3, - RW }, - LM78_SYSCTL_IN3, VALUE(2), 2 }, - { { SENSORS_LM78J_IN4_MAX, "in4_max", SENSORS_LM78J_IN4, SENSORS_LM78J_IN4, - RW }, - LM78_SYSCTL_IN4, VALUE(2), 2 }, - { { SENSORS_LM78J_IN5_MAX, "in5_max", SENSORS_LM78J_IN5, SENSORS_LM78J_IN5, - RW }, - LM78_SYSCTL_IN5, VALUE(1), 2, "in5_min", 3 }, - { { SENSORS_LM78J_IN6_MAX, "in6_max", SENSORS_LM78J_IN6, SENSORS_LM78J_IN6, - RW }, - LM78_SYSCTL_IN6, VALUE(1), 2, "in6_min", 3 }, - { { SENSORS_LM78J_FAN1, "fan1", NOMAP, NOMAP, R }, - LM78_SYSCTL_FAN1, VALUE(2), 0 }, - { { SENSORS_LM78J_FAN2, "fan2", NOMAP, NOMAP, R }, - LM78_SYSCTL_FAN2, VALUE(2), 0 }, - { { SENSORS_LM78J_FAN3, "fan3", NOMAP, NOMAP, R }, - LM78_SYSCTL_FAN3, VALUE(2), 0 }, - { { SENSORS_LM78J_FAN1_MIN, "fan1_min", SENSORS_LM78J_FAN1, - SENSORS_LM78J_FAN1, RW }, - LM78_SYSCTL_FAN1, VALUE(1), 0 }, - { { SENSORS_LM78J_FAN2_MIN, "fan2_min", SENSORS_LM78J_FAN2, - SENSORS_LM78J_FAN2, RW }, - LM78_SYSCTL_FAN2, VALUE(1), 0 }, - { { SENSORS_LM78J_FAN3_MIN, "fan3_min", SENSORS_LM78J_FAN3, - SENSORS_LM78J_FAN3, RW }, - LM78_SYSCTL_FAN3, VALUE(1), 0 }, - { { SENSORS_LM78J_TEMP, "temp", NOMAP, NOMAP, R }, - LM78_SYSCTL_TEMP, VALUE(3), 1 }, - { { SENSORS_LM78J_TEMP_HYST, "temp_hyst", SENSORS_LM78J_TEMP, - SENSORS_LM78J_TEMP, RW }, - LM78_SYSCTL_TEMP, VALUE(2), 1 }, - { { SENSORS_LM78J_TEMP_OVER, "temp_over", SENSORS_LM78J_TEMP, - SENSORS_LM78J_TEMP, RW }, - LM78_SYSCTL_TEMP, VALUE(1), 1 }, - { { SENSORS_LM78J_VID, "vid", NOMAP, NOMAP, R }, - LM78_SYSCTL_VID, VALUE(1), 2 }, - { { SENSORS_LM78J_FAN1_DIV, "fan1_div", SENSORS_LM78J_FAN1, NOMAP, RW }, - LM78_SYSCTL_FAN_DIV, VALUE(1), 0 }, - { { SENSORS_LM78J_FAN2_DIV, "fan2_div", SENSORS_LM78J_FAN2, NOMAP, RW }, - LM78_SYSCTL_FAN_DIV, VALUE(2), 0 }, - { { SENSORS_LM78J_FAN3_DIV, "fan3_div", SENSORS_LM78J_FAN3, NOMAP, R }, - LM78_SYSCTL_FAN_DIV, VALUE(3), 0 }, - { { SENSORS_LM78J_ALARMS, "alarms", NOMAP, NOMAP, R }, - LM78_SYSCTL_ALARMS, VALUE(1), 0 }, - { { 0 }, 0 } - }; - -static sensors_chip_feature lm79_features[] = - { - { { SENSORS_LM79_IN0, "in0", NOMAP, NOMAP, R }, - LM78_SYSCTL_IN0, VALUE(3), 2 }, - { { SENSORS_LM79_IN1, "in1", NOMAP, NOMAP, R }, - LM78_SYSCTL_IN1, VALUE(3), 2 }, - { { SENSORS_LM79_IN2, "in2", NOMAP, NOMAP, R }, - LM78_SYSCTL_IN2, VALUE(3), 2 }, - { { SENSORS_LM79_IN3, "in3", NOMAP, NOMAP, R }, - LM78_SYSCTL_IN3, VALUE(3), 2 }, - { { SENSORS_LM79_IN4, "in4", NOMAP, NOMAP, R }, - LM78_SYSCTL_IN4, VALUE(3), 2 }, - { { SENSORS_LM79_IN5, "in5", NOMAP, NOMAP, R }, - LM78_SYSCTL_IN5, VALUE(3), 2 }, - { { SENSORS_LM79_IN6, "in6", NOMAP, NOMAP, R }, - LM78_SYSCTL_IN6, VALUE(3), 2 }, - { { SENSORS_LM79_IN0_MIN, "in0_min", SENSORS_LM79_IN0, SENSORS_LM79_IN0, RW }, - LM78_SYSCTL_IN0, VALUE(1), 2 }, - { { SENSORS_LM79_IN1_MIN, "in1_min", SENSORS_LM79_IN1, SENSORS_LM79_IN1, RW }, - LM78_SYSCTL_IN1, VALUE(1), 2 }, - { { SENSORS_LM79_IN2_MIN, "in2_min", SENSORS_LM79_IN2, SENSORS_LM79_IN2, RW }, - LM78_SYSCTL_IN2, VALUE(1), 2 }, - { { SENSORS_LM79_IN3_MIN, "in3_min", SENSORS_LM79_IN3, SENSORS_LM79_IN3, RW }, - LM78_SYSCTL_IN3, VALUE(1), 2 }, - { { SENSORS_LM79_IN4_MIN, "in4_min", SENSORS_LM79_IN4, SENSORS_LM79_IN4, RW }, - LM78_SYSCTL_IN4, VALUE(1), 2 }, -/* swap 5 and 6 min/max because compute lines will be inverting */ - { { SENSORS_LM79_IN5_MIN, "in5_min", SENSORS_LM79_IN5, SENSORS_LM79_IN5, RW }, - LM78_SYSCTL_IN5, VALUE(2), 2, "in5_max", 3 }, - { { SENSORS_LM79_IN6_MIN, "in6_min", SENSORS_LM79_IN6, SENSORS_LM79_IN6, RW }, - LM78_SYSCTL_IN6, VALUE(2), 2, "in6_max", 3 }, - { { SENSORS_LM79_IN0_MAX, "in0_max", SENSORS_LM79_IN0, SENSORS_LM79_IN0, RW }, - LM78_SYSCTL_IN0, VALUE(2), 2 }, - { { SENSORS_LM79_IN1_MAX, "in1_max", SENSORS_LM79_IN1, SENSORS_LM79_IN1, RW }, - LM78_SYSCTL_IN1, VALUE(2), 2 }, - { { SENSORS_LM79_IN2_MAX, "in2_max", SENSORS_LM79_IN2, SENSORS_LM79_IN2, RW }, - LM78_SYSCTL_IN2, VALUE(2), 2 }, - { { SENSORS_LM79_IN3_MAX, "in3_max", SENSORS_LM79_IN3, SENSORS_LM79_IN3, RW }, - LM78_SYSCTL_IN3, VALUE(2), 2 }, - { { SENSORS_LM79_IN4_MAX, "in4_max", SENSORS_LM79_IN4, SENSORS_LM79_IN4, RW }, - LM78_SYSCTL_IN4, VALUE(2), 2 }, - { { SENSORS_LM79_IN5_MAX, "in5_max", SENSORS_LM79_IN5, SENSORS_LM79_IN5, RW }, - LM78_SYSCTL_IN5, VALUE(1), 2, "in5_min", 3 }, - { { SENSORS_LM79_IN6_MAX, "in6_max", SENSORS_LM79_IN6, SENSORS_LM79_IN6, RW }, - LM78_SYSCTL_IN6, VALUE(1), 2, "in6_min", 3 }, - { { SENSORS_LM79_FAN1, "fan1", NOMAP, NOMAP, R }, - LM78_SYSCTL_FAN1, VALUE(2), 0 }, - { { SENSORS_LM79_FAN2, "fan2", NOMAP, NOMAP, R }, - LM78_SYSCTL_FAN2, VALUE(2), 0 }, - { { SENSORS_LM79_FAN3, "fan3", NOMAP, NOMAP, R }, - LM78_SYSCTL_FAN3, VALUE(2), 0 }, - { { SENSORS_LM79_FAN1_MIN, "fan1_min", SENSORS_LM79_FAN1, SENSORS_LM79_FAN1, - RW }, - LM78_SYSCTL_FAN1, VALUE(1), 0 }, - { { SENSORS_LM79_FAN2_MIN, "fan2_min", SENSORS_LM79_FAN2, SENSORS_LM79_FAN2, - RW }, - LM78_SYSCTL_FAN2, VALUE(1), 0 }, - { { SENSORS_LM79_FAN3_MIN, "fan3_min", SENSORS_LM79_FAN3, SENSORS_LM79_FAN3, - RW }, - LM78_SYSCTL_FAN3, VALUE(1), 0 }, - { { SENSORS_LM79_TEMP, "temp", NOMAP, NOMAP, R }, - LM78_SYSCTL_TEMP, VALUE(3), 1 }, - { { SENSORS_LM79_TEMP_HYST, "temp_hyst", SENSORS_LM79_TEMP, - SENSORS_LM79_TEMP, RW }, - LM78_SYSCTL_TEMP, VALUE(2), 1 }, - { { SENSORS_LM79_TEMP_OVER, "temp_over", SENSORS_LM79_TEMP, - SENSORS_LM79_TEMP, RW }, - LM78_SYSCTL_TEMP, VALUE(1), 1 }, - { { SENSORS_LM79_VID, "vid", NOMAP, NOMAP, R }, - LM78_SYSCTL_VID, VALUE(1), 2 }, - { { SENSORS_LM79_FAN1_DIV, "fan1_div", SENSORS_LM79_FAN1, NOMAP, RW }, - LM78_SYSCTL_FAN_DIV, VALUE(1), 0 }, - { { SENSORS_LM79_FAN2_DIV, "fan2_div", SENSORS_LM79_FAN2, NOMAP, RW }, - LM78_SYSCTL_FAN_DIV, VALUE(2), 0 }, - { { SENSORS_LM79_FAN3_DIV, "fan3_div", SENSORS_LM79_FAN3, NOMAP, R }, - LM78_SYSCTL_FAN_DIV, VALUE(3), 0 }, - { { SENSORS_LM79_ALARMS, "alarms", NOMAP, NOMAP, R }, - LM78_SYSCTL_ALARMS, VALUE(1), 0 }, - { { 0 }, 0 } - }; - - -static sensors_chip_feature lm75_features[] = - { - { { SENSORS_LM75_TEMP, "temp", NOMAP, NOMAP, R }, - LM75_SYSCTL_TEMP, VALUE(3), 1 }, - { { SENSORS_LM75_TEMP_HYST, "temp_hyst", SENSORS_LM75_TEMP, - SENSORS_LM75_TEMP, RW }, - LM75_SYSCTL_TEMP, VALUE(2), 1 }, - { { SENSORS_LM75_TEMP_OVER, "temp_over", SENSORS_LM75_TEMP, - SENSORS_LM75_TEMP, RW }, - LM75_SYSCTL_TEMP, VALUE(1), 1 }, - { { 0 }, 0 } - }; - -static sensors_chip_feature adm1021_features[] = - { - { { SENSORS_ADM1021_TEMP, "temp", NOMAP, NOMAP, R }, - ADM1021_SYSCTL_TEMP, VALUE(3), 0 }, - { { SENSORS_ADM1021_TEMP_HYST, "temp_low", SENSORS_ADM1021_TEMP, - SENSORS_ADM1021_TEMP, RW }, - ADM1021_SYSCTL_TEMP, VALUE(2), 0 }, - { { SENSORS_ADM1021_TEMP_OVER, "temp_over", SENSORS_ADM1021_TEMP, - SENSORS_ADM1021_TEMP, RW }, - ADM1021_SYSCTL_TEMP, VALUE(1), 0 }, - { { SENSORS_ADM1021_REMOTE_TEMP, "remote_temp", NOMAP, NOMAP, R }, - ADM1021_SYSCTL_REMOTE_TEMP, VALUE(3), 0 }, - { { SENSORS_ADM1021_REMOTE_TEMP_HYST, "remote_temp_low", - SENSORS_ADM1021_REMOTE_TEMP, - SENSORS_ADM1021_REMOTE_TEMP, RW }, - ADM1021_SYSCTL_REMOTE_TEMP, VALUE(2), - 0 }, - { { SENSORS_ADM1021_REMOTE_TEMP_OVER, "remote_temp_over", - SENSORS_ADM1021_REMOTE_TEMP, - SENSORS_ADM1021_REMOTE_TEMP, RW }, - ADM1021_SYSCTL_REMOTE_TEMP, VALUE(1), - 0 }, - { { SENSORS_ADM1021_ALARMS, "alarms", NOMAP, NOMAP, R }, - ADM1021_SYSCTL_ALARMS, VALUE(1), 0 }, - { { SENSORS_ADM1021_DIE_CODE, "die_code", NOMAP, NOMAP, R }, - ADM1021_SYSCTL_DIE_CODE, VALUE(1), 0 }, - { { 0 }, 0 } - }; - -static sensors_chip_feature adm1023_features[] = - { - { { SENSORS_ADM1021_TEMP, "temp", NOMAP, NOMAP, R }, - ADM1021_SYSCTL_TEMP, VALUE(3), 0 }, - { { SENSORS_ADM1021_TEMP_HYST, "temp_low", SENSORS_ADM1021_TEMP, - SENSORS_ADM1021_TEMP, RW }, - ADM1021_SYSCTL_TEMP, VALUE(2), 0 }, - { { SENSORS_ADM1021_TEMP_OVER, "temp_over", SENSORS_ADM1021_TEMP, - SENSORS_ADM1021_TEMP, RW }, - ADM1021_SYSCTL_TEMP, VALUE(1), 0 }, - { { SENSORS_ADM1021_REMOTE_TEMP, "remote_temp", NOMAP, NOMAP, R }, - ADM1021_SYSCTL_REMOTE_TEMP, VALUE(4), 3 }, - { { SENSORS_ADM1021_REMOTE_TEMP_HYST, "remote_temp_low", - SENSORS_ADM1021_REMOTE_TEMP, - SENSORS_ADM1021_REMOTE_TEMP, RW }, - ADM1021_SYSCTL_REMOTE_TEMP, VALUE(2), - 3 }, - { { SENSORS_ADM1021_REMOTE_TEMP_OVER, "remote_temp_over", - SENSORS_ADM1021_REMOTE_TEMP, - SENSORS_ADM1021_REMOTE_TEMP, RW }, - ADM1021_SYSCTL_REMOTE_TEMP, VALUE(1), - 3 }, - { { SENSORS_ADM1021_ALARMS, "alarms", NOMAP, NOMAP, R }, - ADM1021_SYSCTL_ALARMS, VALUE(1), 0 }, - { { 0 }, 0 } - }; - - -static sensors_chip_feature adm1029_features[] = - { - { { SENSORS_ADM1029_TEMP1, "temp1", NOMAP, NOMAP, R }, - NOSYSCTL, VALUE(3), 3 }, - { { SENSORS_ADM1029_TEMP1_MAX, "temp1_max", - SENSORS_ADM1029_TEMP1, SENSORS_ADM1029_TEMP1, RW }, - NOSYSCTL, VALUE(1), 3 }, - { { SENSORS_ADM1029_TEMP1_MIN, "temp1_min", - SENSORS_ADM1029_TEMP1, SENSORS_ADM1029_TEMP1, RW }, - NOSYSCTL, VALUE(2), 3 }, - - { { SENSORS_ADM1029_TEMP2, "temp2", NOMAP, NOMAP, R }, - NOSYSCTL, VALUE(3), 3 }, - { { SENSORS_ADM1029_TEMP2_MAX, "temp2_max", - SENSORS_ADM1029_TEMP2, SENSORS_ADM1029_TEMP2, RW }, - NOSYSCTL, VALUE(1), 3 }, - { { SENSORS_ADM1029_TEMP2_MIN, "temp2_min", - SENSORS_ADM1029_TEMP2, SENSORS_ADM1029_TEMP2, RW }, - NOSYSCTL, VALUE(2), 3 }, - - { { SENSORS_ADM1029_TEMP3, "temp3", NOMAP, NOMAP, R }, - NOSYSCTL, VALUE(3), 3 }, - { { SENSORS_ADM1029_TEMP3_MAX, "temp3_max", - SENSORS_ADM1029_TEMP3, SENSORS_ADM1029_TEMP3, RW }, - NOSYSCTL, VALUE(1), 3 }, - { { SENSORS_ADM1029_TEMP3_MIN, "temp3_min", - SENSORS_ADM1029_TEMP3, SENSORS_ADM1029_TEMP3, RW }, - NOSYSCTL, VALUE(2), 3 }, - - { { SENSORS_ADM1029_FAN1, "fan1", NOMAP, NOMAP, R }, - NOSYSCTL, VALUE(2), 0 }, - { { SENSORS_ADM1029_FAN1_MIN, "fan1_min", - SENSORS_ADM1029_FAN1, SENSORS_ADM1029_FAN1, RW }, - NOSYSCTL, VALUE(1), 0 }, - { { SENSORS_ADM1029_FAN1_DIV, "fan1_div", - SENSORS_ADM1029_FAN1, NOMAP, RW }, - NOSYSCTL, VALUE(1), 0 }, - - { { SENSORS_ADM1029_FAN2, "fan2", NOMAP, NOMAP, R }, - NOSYSCTL, VALUE(2), 0 }, - { { SENSORS_ADM1029_FAN2_MIN, "fan2_min", - SENSORS_ADM1029_FAN2, SENSORS_ADM1029_FAN2, RW }, - NOSYSCTL, VALUE(1), 0 }, - { { SENSORS_ADM1029_FAN2_DIV, "fan2_div", - SENSORS_ADM1029_FAN2, NOMAP, RW }, - NOSYSCTL, VALUE(2), 0 }, - { { 0 }, 0 } - }; - - -static sensors_chip_feature adm1030_features[] = - { - { { SENSORS_ADM1031_TEMP1, "temp1", NOMAP, NOMAP, R }, - ADM1031_SYSCTL_TEMP1, VALUE(4), 3 }, - { { SENSORS_ADM1031_TEMP1_MAX, "temp1_max", SENSORS_ADM1031_TEMP1, - SENSORS_ADM1031_TEMP1, RW }, - ADM1031_SYSCTL_TEMP1, VALUE(1), 3 }, - { { SENSORS_ADM1031_TEMP1_MIN, "temp1_min", SENSORS_ADM1031_TEMP1, - SENSORS_ADM1031_TEMP1, RW }, - ADM1031_SYSCTL_TEMP1, VALUE(2), 3 }, - { { SENSORS_ADM1031_TEMP1_CRIT, "temp1_crit", SENSORS_ADM1031_TEMP1, - SENSORS_ADM1031_TEMP1, RW }, - ADM1031_SYSCTL_TEMP1, VALUE(3), 3 }, - - { { SENSORS_ADM1031_TEMP2, "temp2", NOMAP, NOMAP, R }, - ADM1031_SYSCTL_TEMP2, VALUE(4), 3 }, - { { SENSORS_ADM1031_TEMP2_MAX, "temp2_max", SENSORS_ADM1031_TEMP2, - SENSORS_ADM1031_TEMP2, RW }, - ADM1031_SYSCTL_TEMP2, VALUE(1), 3 }, - { { SENSORS_ADM1031_TEMP2_MIN, "temp2_min", SENSORS_ADM1031_TEMP2, - SENSORS_ADM1031_TEMP2, RW }, - ADM1031_SYSCTL_TEMP2, VALUE(2), 3 }, - { { SENSORS_ADM1031_TEMP2_CRIT, "temp2_crit", SENSORS_ADM1031_TEMP2, - SENSORS_ADM1031_TEMP2, RW }, - ADM1031_SYSCTL_TEMP2, VALUE(3), 3 }, - - { { SENSORS_ADM1031_FAN1, "fan1", NOMAP, NOMAP, R }, - ADM1031_SYSCTL_FAN1, VALUE(2), 0 }, - { { SENSORS_ADM1031_FAN1_MIN, "fan1_min", SENSORS_ADM1031_FAN1, - SENSORS_ADM1031_FAN1, RW }, - ADM1031_SYSCTL_FAN1, VALUE(1), 0 }, - { { SENSORS_ADM1031_FAN1_DIV, "fan1_div", SENSORS_ADM1031_FAN1, NOMAP, RW }, - ADM1031_SYSCTL_FAN_DIV, VALUE(1), 0 }, - - { { SENSORS_ADM1031_ALARMS, "alarms", NOMAP, NOMAP, R }, - ADM1031_SYSCTL_ALARMS, VALUE(1), 0 }, - { { 0 }, 0 } - }; - - -static sensors_chip_feature adm1031_features[] = - { - { { SENSORS_ADM1031_TEMP1, "temp1", NOMAP, NOMAP, R }, - ADM1031_SYSCTL_TEMP1, VALUE(4), 3 }, - { { SENSORS_ADM1031_TEMP1_MAX, "temp1_max", SENSORS_ADM1031_TEMP1, - SENSORS_ADM1031_TEMP1, RW }, - ADM1031_SYSCTL_TEMP1, VALUE(1), 3 }, - { { SENSORS_ADM1031_TEMP1_MIN, "temp1_min", SENSORS_ADM1031_TEMP1, - SENSORS_ADM1031_TEMP1, RW }, - ADM1031_SYSCTL_TEMP1, VALUE(2), 3 }, - { { SENSORS_ADM1031_TEMP1_CRIT, "temp1_crit", SENSORS_ADM1031_TEMP1, - SENSORS_ADM1031_TEMP1, RW }, - ADM1031_SYSCTL_TEMP1, VALUE(3), 3 }, - - { { SENSORS_ADM1031_TEMP2, "temp2", NOMAP, NOMAP, R }, - ADM1031_SYSCTL_TEMP2, VALUE(4), 3 }, - { { SENSORS_ADM1031_TEMP2_MAX, "temp2_max", SENSORS_ADM1031_TEMP2, - SENSORS_ADM1031_TEMP2, RW }, - ADM1031_SYSCTL_TEMP2, VALUE(1), 3 }, - { { SENSORS_ADM1031_TEMP2_MIN, "temp2_min", SENSORS_ADM1031_TEMP2, - SENSORS_ADM1031_TEMP2, RW }, - ADM1031_SYSCTL_TEMP2, VALUE(2), 3 }, - { { SENSORS_ADM1031_TEMP2_CRIT, "temp2_crit", SENSORS_ADM1031_TEMP2, - SENSORS_ADM1031_TEMP2, RW }, - ADM1031_SYSCTL_TEMP2, VALUE(3), 3 }, - - { { SENSORS_ADM1031_TEMP3, "temp3", NOMAP, NOMAP, R }, - ADM1031_SYSCTL_TEMP3, VALUE(4), 3 }, - { { SENSORS_ADM1031_TEMP3_MAX, "temp3_max", SENSORS_ADM1031_TEMP3, - SENSORS_ADM1031_TEMP3, RW }, - ADM1031_SYSCTL_TEMP3, VALUE(1), 3 }, - { { SENSORS_ADM1031_TEMP3_MIN, "temp3_min", SENSORS_ADM1031_TEMP3, - SENSORS_ADM1031_TEMP3, RW }, - ADM1031_SYSCTL_TEMP3, VALUE(2), 3 }, - { { SENSORS_ADM1031_TEMP3_CRIT, "temp3_crit", SENSORS_ADM1031_TEMP3, - SENSORS_ADM1031_TEMP3, RW }, - ADM1031_SYSCTL_TEMP3, VALUE(3), 3 }, - - { { SENSORS_ADM1031_FAN1, "fan1", NOMAP, NOMAP, R }, - ADM1031_SYSCTL_FAN1, VALUE(2), 0 }, - { { SENSORS_ADM1031_FAN1_MIN, "fan1_min", SENSORS_ADM1031_FAN1, - SENSORS_ADM1031_FAN1, RW }, - ADM1031_SYSCTL_FAN1, VALUE(1), 0 }, - { { SENSORS_ADM1031_FAN1_DIV, "fan1_div", SENSORS_ADM1031_FAN1, NOMAP, RW }, - ADM1031_SYSCTL_FAN_DIV, VALUE(1), 0 }, - - { { SENSORS_ADM1031_FAN2, "fan2", NOMAP, NOMAP, R }, - ADM1031_SYSCTL_FAN2, VALUE(2), 0 }, - { { SENSORS_ADM1031_FAN2_MIN, "fan2_min", SENSORS_ADM1031_FAN2, - SENSORS_ADM1031_FAN2, RW }, - ADM1031_SYSCTL_FAN2, VALUE(1), 0 }, - { { SENSORS_ADM1031_FAN2_DIV, "fan2_div", SENSORS_ADM1031_FAN2, NOMAP, RW }, - ADM1031_SYSCTL_FAN_DIV, VALUE(2), 0 }, - - { { SENSORS_ADM1031_ALARMS, "alarms", NOMAP, NOMAP, R }, - ADM1031_SYSCTL_ALARMS, VALUE(1), 0 }, - { { 0 }, 0 } - }; - -static sensors_chip_feature max1617_features[] = - { - { { SENSORS_MAX1617_TEMP, "temp", NOMAP, NOMAP, R }, - ADM1021_SYSCTL_TEMP, VALUE(3), 0 }, - { { SENSORS_MAX1617_TEMP_HYST, "temp_low", SENSORS_MAX1617_TEMP, - SENSORS_MAX1617_TEMP, RW }, - ADM1021_SYSCTL_TEMP, VALUE(2), 0 }, - { { SENSORS_MAX1617_TEMP_OVER, "temp_over", SENSORS_MAX1617_TEMP, - SENSORS_MAX1617_TEMP, RW }, - ADM1021_SYSCTL_TEMP, VALUE(1), 0 }, - { { SENSORS_MAX1617_REMOTE_TEMP, "remote_temp", NOMAP, NOMAP, R }, - ADM1021_SYSCTL_REMOTE_TEMP, VALUE(3), 0 }, - { { SENSORS_MAX1617_REMOTE_TEMP_HYST, "remote_temp_low", - SENSORS_MAX1617_REMOTE_TEMP, - SENSORS_MAX1617_REMOTE_TEMP, RW }, - ADM1021_SYSCTL_REMOTE_TEMP, VALUE(2), - 0 }, - { { SENSORS_MAX1617_REMOTE_TEMP_OVER, "remote_temp_over", - SENSORS_MAX1617_REMOTE_TEMP, - SENSORS_MAX1617_REMOTE_TEMP, RW }, - ADM1021_SYSCTL_REMOTE_TEMP, VALUE(1), - 0 }, - { { SENSORS_MAX1617_ALARMS, "alarms", NOMAP, NOMAP, R }, - ADM1021_SYSCTL_ALARMS, VALUE(1), 0 }, - { { 0 }, 0 } - }; - -static sensors_chip_feature max1617a_features[] = - { - { { SENSORS_MAX1617A_TEMP, "temp", NOMAP, NOMAP, R }, - ADM1021_SYSCTL_TEMP, VALUE(3), 0 }, - { { SENSORS_MAX1617A_TEMP_HYST, "temp_low", SENSORS_MAX1617A_TEMP, - SENSORS_MAX1617A_TEMP, RW }, - ADM1021_SYSCTL_TEMP, VALUE(2), 0 }, - { { SENSORS_MAX1617A_TEMP_OVER, "temp_over", SENSORS_MAX1617A_TEMP, - SENSORS_MAX1617A_TEMP, RW }, - ADM1021_SYSCTL_TEMP, VALUE(1), 0 }, - { { SENSORS_MAX1617A_REMOTE_TEMP, "remote_temp", NOMAP, NOMAP, R }, - ADM1021_SYSCTL_REMOTE_TEMP, VALUE(3), 0 }, - { { SENSORS_MAX1617A_REMOTE_TEMP_HYST, "remote_temp_low", - SENSORS_MAX1617A_REMOTE_TEMP, - SENSORS_MAX1617A_REMOTE_TEMP, RW }, - ADM1021_SYSCTL_REMOTE_TEMP, VALUE(2), - 0 }, - { { SENSORS_MAX1617A_REMOTE_TEMP_OVER, "remote_temp_over", - SENSORS_MAX1617A_REMOTE_TEMP, - SENSORS_MAX1617A_REMOTE_TEMP, RW }, - ADM1021_SYSCTL_REMOTE_TEMP, VALUE(1), - 0 }, - { { SENSORS_MAX1617A_ALARMS, "alarms", NOMAP, NOMAP, R }, - ADM1021_SYSCTL_ALARMS, VALUE(1), 0 }, - { { 0 }, 0 } - }; - -static sensors_chip_feature gl518_features[] = - { - { { SENSORS_GL518_VDD, "vdd", NOMAP, NOMAP, R }, - GL518_SYSCTL_VDD, VALUE(3), 2, "in0_input", 3 }, - { { SENSORS_GL518_VIN1, "vin1", NOMAP, NOMAP, R }, - GL518_SYSCTL_VIN1, VALUE(3), 2 }, - { { SENSORS_GL518_VIN2, "vin2", NOMAP, NOMAP, R }, - GL518_SYSCTL_VIN2, VALUE(3), 2 }, - { { SENSORS_GL518_VIN3, "vin3", NOMAP, NOMAP, R }, - GL518_SYSCTL_VIN3, VALUE(3), 2 }, - { { SENSORS_GL518_VDD_MIN, "vdd_min", SENSORS_GL518_VDD, SENSORS_GL518_VDD, - RW }, - GL518_SYSCTL_VDD, VALUE(1), 2 , "in0_min", 3 }, - { { SENSORS_GL518_VIN1_MIN, "vin1_min", SENSORS_GL518_VIN1, - SENSORS_GL518_VIN1, RW }, - GL518_SYSCTL_VIN1, VALUE(1), 2 }, - { { SENSORS_GL518_VIN2_MIN, "vin2_min", SENSORS_GL518_VIN2, - SENSORS_GL518_VIN2, RW }, - GL518_SYSCTL_VIN2, VALUE(1), 2 }, - { { SENSORS_GL518_VIN3_MIN, "vin3_min", SENSORS_GL518_VIN3, - SENSORS_GL518_VIN3, RW }, - GL518_SYSCTL_VIN3, VALUE(1), 2 }, - { { SENSORS_GL518_VDD_MAX, "vdd_max", SENSORS_GL518_VDD, SENSORS_GL518_VDD, - RW }, - GL518_SYSCTL_VDD, VALUE(2), 2 , "in0_max", 3 }, - { { SENSORS_GL518_VIN1_MAX, "vin1_max", SENSORS_GL518_VIN1, - SENSORS_GL518_VIN1, RW }, - GL518_SYSCTL_VIN1, VALUE(2), 2 }, - { { SENSORS_GL518_VIN2_MAX, "vin2_max", SENSORS_GL518_VIN2, - SENSORS_GL518_VIN2, RW }, - GL518_SYSCTL_VIN2, VALUE(2), 2 }, - { { SENSORS_GL518_VIN3_MAX, "vin3_max", SENSORS_GL518_VIN3, - SENSORS_GL518_VIN3, RW }, - GL518_SYSCTL_VIN3, VALUE(2), 2 }, - { { SENSORS_GL518_FAN1, "fan1", NOMAP, NOMAP, R }, - GL518_SYSCTL_FAN1, VALUE(2), 0 }, - { { SENSORS_GL518_FAN2, "fan2", NOMAP, NOMAP, R }, - GL518_SYSCTL_FAN2, VALUE(2), 0 }, - { { SENSORS_GL518_FAN1_MIN, "fan1_min", SENSORS_GL518_FAN1, - SENSORS_GL518_FAN1, RW }, - GL518_SYSCTL_FAN1, VALUE(1), 0 }, - { { SENSORS_GL518_FAN2_MIN, "fan2_min", SENSORS_GL518_FAN2, - SENSORS_GL518_FAN2, RW }, - GL518_SYSCTL_FAN2, VALUE(1), 0 }, - { { SENSORS_GL518_TEMP, "temp", NOMAP, NOMAP, R }, - GL518_SYSCTL_TEMP, VALUE(3), 1 }, - { { SENSORS_GL518_TEMP_HYST, "temp_hyst", SENSORS_GL518_TEMP, - SENSORS_GL518_TEMP, RW }, - GL518_SYSCTL_TEMP, VALUE(2), 1 }, - { { SENSORS_GL518_TEMP_OVER, "temp_over", SENSORS_GL518_TEMP, - SENSORS_GL518_TEMP, RW }, - GL518_SYSCTL_TEMP, VALUE(1), 1 }, - { { SENSORS_GL518_FAN1_DIV, "fan1_div", SENSORS_GL518_FAN1, NOMAP, RW }, - GL518_SYSCTL_FAN_DIV, VALUE(1), 0 }, - { { SENSORS_GL518_FAN2_DIV, "fan2_div", SENSORS_GL518_FAN2, NOMAP, RW }, - GL518_SYSCTL_FAN_DIV, VALUE(2), 0 }, - { { SENSORS_GL518_ALARMS, "alarms", NOMAP, NOMAP, R }, - GL518_SYSCTL_ALARMS, VALUE(1), 0 }, - { { SENSORS_GL518_BEEP_ENABLE, "beep_enable", SENSORS_GL518_ALARMS, NOMAP, - RW }, - GL518_SYSCTL_BEEP, VALUE(1), 0 }, - { { SENSORS_GL518_BEEPS, "beeps", SENSORS_GL518_ALARMS, SENSORS_GL518_ALARMS, - RW }, - GL518_SYSCTL_BEEP, VALUE(2), 0 }, - { { SENSORS_GL518_FAN1OFF, "fan1_off", SENSORS_GL518_FAN1, NOMAP, RW }, - GL518_SYSCTL_FAN1OFF, VALUE(1), 0, "fan1_auto", - 0 }, - { { SENSORS_GL518_FAN1PIN, "fan1_off_pin", SENSORS_GL518_FAN1OFF, NOMAP, RW }, - GL518_SYSCTL_FAN1OFF, VALUE(2), 0 }, - { { SENSORS_GL518_ITERATE, "iterate", NOMAP, NOMAP, RW }, - GL518_SYSCTL_ITERATE, VALUE(1), 0 }, - { { 0 }, 0 } - }; - -static sensors_chip_feature gl520_features[] = - { - { { SENSORS_GL520_VDD, "vdd", NOMAP, NOMAP, R }, - GL520_SYSCTL_VDD, VALUE(3), 2, "in0_input", 3 }, - { { SENSORS_GL520_VIN1, "vin1", NOMAP, NOMAP, R }, - GL520_SYSCTL_VIN1, VALUE(3), 2 }, - { { SENSORS_GL520_VIN2, "vin2", NOMAP, NOMAP, R }, - GL520_SYSCTL_VIN2, VALUE(3), 2 }, - { { SENSORS_GL520_VIN3, "vin3", NOMAP, NOMAP, R }, - GL520_SYSCTL_VIN3, VALUE(3), 2 }, - { { SENSORS_GL520_VIN4, "vin4", NOMAP, NOMAP, R }, - GL520_SYSCTL_VIN4, VALUE(3), 2 }, - { { SENSORS_GL520_VDD_MIN, "vdd_min", SENSORS_GL520_VDD, SENSORS_GL520_VDD, - RW }, - GL520_SYSCTL_VDD, VALUE(1), 2, "in0_min", 3 }, - { { SENSORS_GL520_VIN1_MIN, "vin1_min", SENSORS_GL520_VIN1, - SENSORS_GL520_VIN1, RW }, - GL520_SYSCTL_VIN1, VALUE(1), 2 }, - { { SENSORS_GL520_VIN2_MIN, "vin2_min", SENSORS_GL520_VIN2, - SENSORS_GL520_VIN2, RW }, - GL520_SYSCTL_VIN2, VALUE(1), 2 }, - { { SENSORS_GL520_VIN3_MIN, "vin3_min", SENSORS_GL520_VIN3, - SENSORS_GL520_VIN3, RW }, - GL520_SYSCTL_VIN3, VALUE(1), 2 }, - { { SENSORS_GL520_VIN4_MIN, "vin4_min", SENSORS_GL520_VIN4, - SENSORS_GL520_VIN4, RW }, - GL520_SYSCTL_VIN4, VALUE(1), 2 }, - { { SENSORS_GL520_VDD_MAX, "vdd_max", SENSORS_GL520_VDD, SENSORS_GL520_VDD, - RW }, - GL520_SYSCTL_VDD, VALUE(2), 2, "in0_max", 3 }, - { { SENSORS_GL520_VIN1_MAX, "vin1_max", SENSORS_GL520_VIN1, - SENSORS_GL520_VIN1, RW }, - GL520_SYSCTL_VIN1, VALUE(2), 2 }, - { { SENSORS_GL520_VIN2_MAX, "vin2_max", SENSORS_GL520_VIN2, - SENSORS_GL520_VIN2, RW }, - GL520_SYSCTL_VIN2, VALUE(2), 2 }, - { { SENSORS_GL520_VIN3_MAX, "vin3_max", SENSORS_GL520_VIN3, - SENSORS_GL520_VIN3, RW }, - GL520_SYSCTL_VIN3, VALUE(2), 2 }, - { { SENSORS_GL520_VIN4_MAX, "vin4_max", SENSORS_GL520_VIN4, - SENSORS_GL520_VIN4, RW }, - GL520_SYSCTL_VIN4, VALUE(2), 2 }, - { { SENSORS_GL520_FAN1, "fan1", NOMAP, NOMAP, R }, - GL520_SYSCTL_FAN1, VALUE(2), 0 }, - { { SENSORS_GL520_FAN2, "fan2", NOMAP, NOMAP, R }, - GL520_SYSCTL_FAN2, VALUE(2), 0 }, - { { SENSORS_GL520_FAN1_MIN, "fan1_min", SENSORS_GL520_FAN1, - SENSORS_GL520_FAN1, RW }, - GL520_SYSCTL_FAN1, VALUE(1), 0 }, - { { SENSORS_GL520_FAN2_MIN, "fan2_min", SENSORS_GL520_FAN2, - SENSORS_GL520_FAN2, RW }, - GL520_SYSCTL_FAN2, VALUE(1), 0 }, - { { SENSORS_GL520_TEMP1, "temp1", NOMAP, NOMAP, R }, - GL520_SYSCTL_TEMP1, VALUE(3), 1 }, - { { SENSORS_GL520_TEMP1_HYST, "temp1_hyst", SENSORS_GL520_TEMP1, - SENSORS_GL520_TEMP1, RW }, - GL520_SYSCTL_TEMP1, VALUE(2), 1 }, - { { SENSORS_GL520_TEMP1_OVER, "temp1_over", SENSORS_GL520_TEMP1, - SENSORS_GL520_TEMP1, RW }, - GL520_SYSCTL_TEMP1, VALUE(1), 1 }, - { { SENSORS_GL520_TEMP2, "temp2", NOMAP, NOMAP, R }, - GL520_SYSCTL_TEMP2, VALUE(3), 1 }, - { { SENSORS_GL520_TEMP2_HYST, "temp2_hyst", SENSORS_GL520_TEMP2, - SENSORS_GL520_TEMP2, RW }, - GL520_SYSCTL_TEMP2, VALUE(2), 1 }, - { { SENSORS_GL520_TEMP2_OVER, "temp2_over", SENSORS_GL520_TEMP2, - SENSORS_GL520_TEMP2, RW }, - GL520_SYSCTL_TEMP2, VALUE(1), 1 }, - { { SENSORS_GL520_VID, "vid", NOMAP, NOMAP, R }, - GL520_SYSCTL_VID, VALUE(1), 2 }, - { { SENSORS_GL520_FAN1_DIV, "fan1_div", SENSORS_GL520_FAN1, NOMAP, RW }, - GL520_SYSCTL_FAN_DIV, VALUE(1), 0 }, - { { SENSORS_GL520_FAN2_DIV, "fan2_div", SENSORS_GL520_FAN2, NOMAP, RW }, - GL520_SYSCTL_FAN_DIV, VALUE(2), 0 }, - { { SENSORS_GL520_ALARMS, "alarms", NOMAP, NOMAP, R }, - GL520_SYSCTL_ALARMS, VALUE(1), 0 }, - { { SENSORS_GL520_BEEP_ENABLE, "beep_enable", SENSORS_GL520_ALARMS, NOMAP, - RW }, - GL520_SYSCTL_BEEP, VALUE(1), 0 }, - { { SENSORS_GL520_BEEPS, "beeps", SENSORS_GL520_ALARMS, SENSORS_GL520_ALARMS, - RW }, - GL520_SYSCTL_BEEP, VALUE(2), 0 }, - { { SENSORS_GL520_FAN1OFF, "fan1_off", SENSORS_GL520_FAN1, NOMAP, RW }, - GL520_SYSCTL_FAN1OFF, VALUE(1), 0 }, - { { SENSORS_GL520_TWOTEMPS, "two_temps", NOMAP, NOMAP, RW }, - GL520_SYSCTL_CONFIG, VALUE(1), 0 }, - { { 0 }, 0 } - }; - -static sensors_chip_feature lm80_features[] = - { - { { SENSORS_LM80_IN0, "in0", NOMAP, NOMAP, R }, - LM80_SYSCTL_IN0, VALUE(3), 2 }, - { { SENSORS_LM80_IN1, "in1", NOMAP, NOMAP, R }, - LM80_SYSCTL_IN1, VALUE(3), 2 }, - { { SENSORS_LM80_IN2, "in2", NOMAP, NOMAP, R }, - LM80_SYSCTL_IN2, VALUE(3), 2 }, - { { SENSORS_LM80_IN3, "in3", NOMAP, NOMAP, R }, - LM80_SYSCTL_IN3, VALUE(3), 2 }, - { { SENSORS_LM80_IN4, "in4", NOMAP, NOMAP, R }, - LM80_SYSCTL_IN4, VALUE(3), 2 }, - { { SENSORS_LM80_IN5, "in5", NOMAP, NOMAP, R }, - LM80_SYSCTL_IN5, VALUE(3), 2 }, - { { SENSORS_LM80_IN6, "in6", NOMAP, NOMAP, R }, - LM80_SYSCTL_IN6, VALUE(3), 2 }, - { { SENSORS_LM80_IN0_MIN, "in0_min", SENSORS_LM80_IN0, SENSORS_LM80_IN0, RW }, - LM80_SYSCTL_IN0, VALUE(1), 2 }, - { { SENSORS_LM80_IN1_MIN, "in1_min", SENSORS_LM80_IN1, SENSORS_LM80_IN1, RW }, - LM80_SYSCTL_IN1, VALUE(1), 2 }, - { { SENSORS_LM80_IN2_MIN, "in2_min", SENSORS_LM80_IN2, SENSORS_LM80_IN2, RW }, - LM80_SYSCTL_IN2, VALUE(1), 2 }, - { { SENSORS_LM80_IN3_MIN, "in3_min", SENSORS_LM80_IN3, SENSORS_LM80_IN3, RW }, - LM80_SYSCTL_IN3, VALUE(1), 2 }, - { { SENSORS_LM80_IN4_MIN, "in4_min", SENSORS_LM80_IN4, SENSORS_LM80_IN4, RW }, - LM80_SYSCTL_IN4, VALUE(1), 2 }, - { { SENSORS_LM80_IN5_MIN, "in5_min", SENSORS_LM80_IN5, SENSORS_LM80_IN5, RW }, - LM80_SYSCTL_IN5, VALUE(1), 2 }, - { { SENSORS_LM80_IN6_MIN, "in6_min", SENSORS_LM80_IN6, SENSORS_LM80_IN6, RW }, - LM80_SYSCTL_IN6, VALUE(1), 2 }, - { { SENSORS_LM80_IN0_MAX, "in0_max", SENSORS_LM80_IN0, SENSORS_LM80_IN0, RW }, - LM80_SYSCTL_IN0, VALUE(2), 2 }, - { { SENSORS_LM80_IN1_MAX, "in1_max", SENSORS_LM80_IN1, SENSORS_LM80_IN1, RW }, - LM80_SYSCTL_IN1, VALUE(2), 2 }, - { { SENSORS_LM80_IN2_MAX, "in2_max", SENSORS_LM80_IN2, SENSORS_LM80_IN2, RW }, - LM80_SYSCTL_IN2, VALUE(2), 2 }, - { { SENSORS_LM80_IN3_MAX, "in3_max", SENSORS_LM80_IN3, SENSORS_LM80_IN3, RW }, - LM80_SYSCTL_IN3, VALUE(2), 2 }, - { { SENSORS_LM80_IN4_MAX, "in4_max", SENSORS_LM80_IN4, SENSORS_LM80_IN4, RW }, - LM80_SYSCTL_IN4, VALUE(2), 2 }, - { { SENSORS_LM80_IN5_MAX, "in5_max", SENSORS_LM80_IN5, SENSORS_LM80_IN5, RW }, - LM80_SYSCTL_IN5, VALUE(2), 2 }, - { { SENSORS_LM80_IN6_MAX, "in6_max", SENSORS_LM80_IN6, SENSORS_LM80_IN6, RW }, - LM80_SYSCTL_IN6, VALUE(2), 2 }, - { { SENSORS_LM80_FAN1, "fan1", NOMAP, NOMAP, R }, - LM80_SYSCTL_FAN1, VALUE(2), 0 }, - { { SENSORS_LM80_FAN2, "fan2", NOMAP, NOMAP, R }, - LM80_SYSCTL_FAN2, VALUE(2), 0 }, - { { SENSORS_LM80_FAN1_MIN, "fan1_min", SENSORS_LM80_FAN1, NOMAP, RW }, - LM80_SYSCTL_FAN1, VALUE(1), 0 }, - { { SENSORS_LM80_FAN2_MIN, "fan2_min", SENSORS_LM80_FAN2, NOMAP, RW }, - LM80_SYSCTL_FAN2, VALUE(1), 0 }, - { { SENSORS_LM80_TEMP, "temp", NOMAP, NOMAP, R }, - LM80_SYSCTL_TEMP, VALUE(5), 2 }, - { { SENSORS_LM80_TEMP_HOT_HYST, "temp_hot_hyst", SENSORS_LM80_TEMP, - SENSORS_LM80_TEMP, RW }, - LM80_SYSCTL_TEMP, VALUE(2), 2, - "temp1_max_hyst", 3 }, - { { SENSORS_LM80_TEMP_HOT_MAX, "temp_hot_max", SENSORS_LM80_TEMP, - SENSORS_LM80_TEMP, RW }, - LM80_SYSCTL_TEMP, VALUE(1), 2, "temp1_max", - 3 }, - { { SENSORS_LM80_TEMP_OS_HYST, "temp_os_hyst", SENSORS_LM80_TEMP, - SENSORS_LM80_TEMP, RW }, - LM80_SYSCTL_TEMP, VALUE(4), 2, - "temp1_crit_hyst", 3 }, - { { SENSORS_LM80_TEMP_OS_MAX, "temp_os_max", SENSORS_LM80_TEMP, - SENSORS_LM80_TEMP, RW }, - LM80_SYSCTL_TEMP, VALUE(3), 2, "temp1_crit", - 3 }, - { { SENSORS_LM80_FAN1_DIV, "fan1_div", SENSORS_LM80_FAN1, NOMAP, RW }, - LM80_SYSCTL_FAN_DIV, VALUE(1), 0 }, - { { SENSORS_LM80_FAN2_DIV, "fan2_div", SENSORS_LM80_FAN2, NOMAP, RW }, - LM80_SYSCTL_FAN_DIV, VALUE(2), 0 }, - { { SENSORS_LM80_ALARMS, "alarms", NOMAP, NOMAP, R }, - LM80_SYSCTL_ALARMS, VALUE(1), 0 }, - { { 0 }, 0 } - }; - - -static sensors_chip_feature lm83_features[] = - { - { { SENSORS_LM83_LOCAL_TEMP, "temp1", NOMAP, NOMAP, R }, - LM83_SYSCTL_LOCAL_TEMP, VALUE(2), 0 }, - { { SENSORS_LM83_LOCAL_HIGH, "temp1_high", SENSORS_LM83_LOCAL_TEMP, - SENSORS_LM83_LOCAL_TEMP, RW }, - LM83_SYSCTL_LOCAL_TEMP, VALUE(1), 0 }, - { { SENSORS_LM83_REMOTE1_TEMP, "temp2", NOMAP, NOMAP, R }, - LM83_SYSCTL_REMOTE1_TEMP, VALUE(2), 0 }, - { { SENSORS_LM83_REMOTE1_HIGH, "temp2_high", SENSORS_LM83_REMOTE1_TEMP, - SENSORS_LM83_REMOTE1_TEMP, RW }, - LM83_SYSCTL_REMOTE1_TEMP, VALUE(1), 0 }, - { { SENSORS_LM83_REMOTE2_TEMP, "temp3", NOMAP, NOMAP, R }, - LM83_SYSCTL_REMOTE2_TEMP, VALUE(2), 0 }, - { { SENSORS_LM83_REMOTE2_HIGH, "temp3_high", SENSORS_LM83_REMOTE2_TEMP, - SENSORS_LM83_REMOTE2_TEMP, RW }, - LM83_SYSCTL_REMOTE2_TEMP, VALUE(1), 0 }, - { { SENSORS_LM83_REMOTE3_TEMP, "temp4", NOMAP, NOMAP, R }, - LM83_SYSCTL_REMOTE3_TEMP, VALUE(2), 0 }, - { { SENSORS_LM83_REMOTE3_HIGH, "temp4_high", SENSORS_LM83_REMOTE3_TEMP, - SENSORS_LM83_REMOTE3_TEMP, RW }, - LM83_SYSCTL_REMOTE3_TEMP, VALUE(1), 0 }, - { { SENSORS_LM83_TCRIT, "tcrit", NOMAP, NOMAP, RW }, - LM83_SYSCTL_TCRIT, VALUE(1), 0, "temp3_crit", 3, - "temp_crit" }, - { { SENSORS_LM83_ALARMS, "alarms", NOMAP, NOMAP, R }, - LM83_SYSCTL_ALARMS, VALUE(1), 0 }, - { { 0 }, 0 } - }; - - -static sensors_chip_feature lm90_features[] = - { - { { SENSORS_LM90_LOCAL_TEMP, "temp1", NOMAP, NOMAP, R }, - LM90_SYSCTL_LOCAL_TEMP, VALUE(3), 0 }, - { { SENSORS_LM90_LOCAL_HIGH, "temp1_high", SENSORS_LM90_LOCAL_TEMP, - SENSORS_LM90_LOCAL_TEMP, RW }, - LM90_SYSCTL_LOCAL_TEMP, VALUE(1), 0 }, - { { SENSORS_LM90_LOCAL_LOW, "temp1_low", SENSORS_LM90_LOCAL_TEMP, - SENSORS_LM90_LOCAL_TEMP, RW }, - LM90_SYSCTL_LOCAL_TEMP, VALUE(2), 0 }, - { { SENSORS_LM90_REMOTE_TEMP, "temp2", NOMAP, NOMAP, R }, - LM90_SYSCTL_REMOTE_TEMP, VALUE(3), 1 }, - { { SENSORS_LM90_REMOTE_HIGH, "temp2_high", SENSORS_LM90_REMOTE_TEMP, - SENSORS_LM90_REMOTE_TEMP, RW }, - LM90_SYSCTL_REMOTE_TEMP, VALUE(1), 1 }, - { { SENSORS_LM90_REMOTE_LOW, "temp2_low", SENSORS_LM90_REMOTE_TEMP, - SENSORS_LM90_REMOTE_TEMP, RW }, - LM90_SYSCTL_REMOTE_TEMP, VALUE(2), 1 }, - { { SENSORS_LM90_LOCAL_TCRIT, "tcrit1", SENSORS_LM90_LOCAL_TEMP, - SENSORS_LM90_LOCAL_TEMP, RW }, - LM90_SYSCTL_LOCAL_TCRIT, VALUE(1), 0, - "temp1_crit", 3 }, - { { SENSORS_LM90_REMOTE_TCRIT, "tcrit2", SENSORS_LM90_REMOTE_TEMP, - SENSORS_LM90_REMOTE_TEMP, RW }, - LM90_SYSCTL_REMOTE_TCRIT, VALUE(1), 0, - "temp2_crit", 3 }, - { { SENSORS_LM90_LOCAL_TCRIT_HYST, "hyst1", SENSORS_LM90_LOCAL_TEMP, - SENSORS_LM90_LOCAL_TEMP, RW }, - LM90_SYSCTL_LOCAL_HYST, VALUE(1), 0, - "temp1_crit_hyst", 3 }, - { { SENSORS_LM90_REMOTE_TCRIT_HYST, "hyst2", SENSORS_LM90_REMOTE_TEMP, - SENSORS_LM90_REMOTE_TEMP, R }, - LM90_SYSCTL_REMOTE_HYST, VALUE(1), 0, - "temp2_crit_hyst", 3 }, - { { SENSORS_LM90_ALARMS, "alarms", NOMAP, NOMAP, R }, - LM90_SYSCTL_ALARMS, VALUE(1), 0 }, - { { 0 }, 0 } - }; - - -static sensors_chip_feature lm63_features[] = - { - { { SENSORS_LM63_LOCAL_TEMP, "temp1", NOMAP, NOMAP, R }, - LM63_SYSCTL_TEMP1, VALUE(2), 0 }, - { { SENSORS_LM63_LOCAL_HIGH, "temp1_high", SENSORS_LM63_LOCAL_TEMP, - SENSORS_LM63_LOCAL_TEMP, RW }, - LM63_SYSCTL_TEMP1, VALUE(1), 0 }, - { { SENSORS_LM63_REMOTE_TEMP, "temp2", NOMAP, NOMAP, R }, - LM63_SYSCTL_TEMP2, VALUE(3), 3 }, - { { SENSORS_LM63_REMOTE_HIGH, "temp2_high", SENSORS_LM63_REMOTE_TEMP, - SENSORS_LM63_REMOTE_TEMP, RW }, - LM63_SYSCTL_TEMP2, VALUE(1), 3 }, - { { SENSORS_LM63_REMOTE_LOW, "temp2_low", SENSORS_LM63_REMOTE_TEMP, - SENSORS_LM63_REMOTE_TEMP, RW }, - LM63_SYSCTL_TEMP2, VALUE(2), 3 }, - { { SENSORS_LM63_REMOTE_TCRIT, "temp2_crit", SENSORS_LM63_REMOTE_TEMP, - SENSORS_LM63_REMOTE_TEMP, R }, - LM63_SYSCTL_TEMP2_TCRIT, VALUE(1), 0 }, - { { SENSORS_LM63_REMOTE_TCRIT_HYST, "temp2_crit_hyst", - SENSORS_LM63_REMOTE_TEMP, - SENSORS_LM63_REMOTE_TEMP, RW }, - LM63_SYSCTL_TEMP2_TCRIT_HYST, VALUE(1), - 0, "temp2_crit_hyst", 3 }, - { { SENSORS_LM63_ALARMS, "alarms", NOMAP, NOMAP, R }, - LM63_SYSCTL_ALARMS, VALUE(1), 0 }, - { { SENSORS_LM63_FAN_LOW, "fan1_min", SENSORS_LM63_FAN, SENSORS_LM63_FAN, RW }, - LM63_SYSCTL_FAN1, VALUE(1), 0 }, - { { SENSORS_LM63_FAN, "fan1", NOMAP, NOMAP, R }, - LM63_SYSCTL_FAN1, VALUE(2), 0 }, - { { SENSORS_LM63_PWM, "pwm1", NOMAP, NOMAP, RW }, - LM63_SYSCTL_PWM1, VALUE(1), 0 }, - { { SENSORS_LM63_PWM_ENABLE, "pwm1_enable", SENSORS_LM63_PWM, NOMAP, RW }, - LM63_SYSCTL_PWM1, VALUE(2), 0 }, - { { 0 }, 0 } - }; - - -static sensors_chip_feature w83781d_features[] = - { - { { SENSORS_W83781D_IN0, "in0", NOMAP, NOMAP, R }, - W83781D_SYSCTL_IN0, VALUE(3), 2 }, - { { SENSORS_W83781D_IN1, "in1", NOMAP, NOMAP, R }, - W83781D_SYSCTL_IN1, VALUE(3), 2 }, - { { SENSORS_W83781D_IN2, "in2", NOMAP, NOMAP, R }, - W83781D_SYSCTL_IN2, VALUE(3), 2 }, - { { SENSORS_W83781D_IN3, "in3", NOMAP, NOMAP, R }, - W83781D_SYSCTL_IN3, VALUE(3), 2 }, - { { SENSORS_W83781D_IN4, "in4", NOMAP, NOMAP, R }, - W83781D_SYSCTL_IN4, VALUE(3), 2 }, - { { SENSORS_W83781D_IN5, "in5", NOMAP, NOMAP, R }, - W83781D_SYSCTL_IN5, VALUE(3), 2 }, - { { SENSORS_W83781D_IN6, "in6", NOMAP, NOMAP, R }, - W83781D_SYSCTL_IN6, VALUE(3), 2 }, - { { SENSORS_W83781D_IN0_MIN, "in0_min", SENSORS_W83781D_IN0, - SENSORS_W83781D_IN0, RW }, - W83781D_SYSCTL_IN0, VALUE(1), 2 }, - { { SENSORS_W83781D_IN1_MIN, "in1_min", SENSORS_W83781D_IN1, - SENSORS_W83781D_IN1, RW }, - W83781D_SYSCTL_IN1, VALUE(1), 2 }, - { { SENSORS_W83781D_IN2_MIN, "in2_min", SENSORS_W83781D_IN2, - SENSORS_W83781D_IN2, RW }, - W83781D_SYSCTL_IN2, VALUE(1), 2 }, - { { SENSORS_W83781D_IN3_MIN, "in3_min", SENSORS_W83781D_IN3, - SENSORS_W83781D_IN3, RW }, - W83781D_SYSCTL_IN3, VALUE(1), 2 }, - { { SENSORS_W83781D_IN4_MIN, "in4_min", SENSORS_W83781D_IN4, - SENSORS_W83781D_IN4, RW }, - W83781D_SYSCTL_IN4, VALUE(1), 2 }, -/* swap 5 and 6 min/max because compute lines will be inverting */ - { { SENSORS_W83781D_IN5_MIN, "in5_min", SENSORS_W83781D_IN5, - SENSORS_W83781D_IN5, RW }, - W83781D_SYSCTL_IN5, VALUE(2), 2, "in5_max", 3 }, - { { SENSORS_W83781D_IN6_MIN, "in6_min", SENSORS_W83781D_IN6, - SENSORS_W83781D_IN6, RW }, - W83781D_SYSCTL_IN6, VALUE(2), 2, "in6_max", 3 }, - { { SENSORS_W83781D_IN0_MAX, "in0_max", SENSORS_W83781D_IN0, - SENSORS_W83781D_IN0, RW }, - W83781D_SYSCTL_IN0, VALUE(2), 2 }, - { { SENSORS_W83781D_IN1_MAX, "in1_max", SENSORS_W83781D_IN1, - SENSORS_W83781D_IN1, RW }, - W83781D_SYSCTL_IN1, VALUE(2), 2 }, - { { SENSORS_W83781D_IN2_MAX, "in2_max", SENSORS_W83781D_IN2, - SENSORS_W83781D_IN2, RW }, - W83781D_SYSCTL_IN2, VALUE(2), 2 }, - { { SENSORS_W83781D_IN3_MAX, "in3_max", SENSORS_W83781D_IN3, - SENSORS_W83781D_IN3, RW }, - W83781D_SYSCTL_IN3, VALUE(2), 2 }, - { { SENSORS_W83781D_IN4_MAX, "in4_max", SENSORS_W83781D_IN4, - SENSORS_W83781D_IN4, RW }, - W83781D_SYSCTL_IN4, VALUE(2), 2 }, - { { SENSORS_W83781D_IN5_MAX, "in5_max", SENSORS_W83781D_IN5, - SENSORS_W83781D_IN5, RW }, - W83781D_SYSCTL_IN5, VALUE(1), 2, "in5_min", 3 }, - { { SENSORS_W83781D_IN6_MAX, "in6_max", SENSORS_W83781D_IN6, - SENSORS_W83781D_IN6, RW }, - W83781D_SYSCTL_IN6, VALUE(1), 2, "in6_min", 3 }, - { { SENSORS_W83781D_FAN1, "fan1", NOMAP, NOMAP, R }, - W83781D_SYSCTL_FAN1, VALUE(2), 0 }, - { { SENSORS_W83781D_FAN2, "fan2", NOMAP, NOMAP, R }, - W83781D_SYSCTL_FAN2, VALUE(2), 0 }, - { { SENSORS_W83781D_FAN3, "fan3", NOMAP, NOMAP, R }, - W83781D_SYSCTL_FAN3, VALUE(2), 0 }, - { { SENSORS_W83781D_FAN1_MIN, "fan1_min", SENSORS_W83781D_FAN1, - SENSORS_W83781D_FAN1, RW }, - W83781D_SYSCTL_FAN1, VALUE(1), 0 }, - { { SENSORS_W83781D_FAN2_MIN, "fan2_min", SENSORS_W83781D_FAN2, - SENSORS_W83781D_FAN2, RW }, - W83781D_SYSCTL_FAN2, VALUE(1), 0 }, - { { SENSORS_W83781D_FAN3_MIN, "fan3_min", SENSORS_W83781D_FAN3, - SENSORS_W83781D_FAN3, RW }, - W83781D_SYSCTL_FAN3, VALUE(1), 0 }, - { { SENSORS_W83781D_TEMP1, "temp1", NOMAP, NOMAP, R }, - W83781D_SYSCTL_TEMP1, VALUE(3), 1 }, - { { SENSORS_W83781D_TEMP1_HYST, "temp1_hyst", SENSORS_W83781D_TEMP1, - SENSORS_W83781D_TEMP1, RW }, - W83781D_SYSCTL_TEMP1, VALUE(2), 1 }, - { { SENSORS_W83781D_TEMP1_OVER, "temp1_over", SENSORS_W83781D_TEMP1, - SENSORS_W83781D_TEMP1, RW }, - W83781D_SYSCTL_TEMP1, VALUE(1), 1 }, - { { SENSORS_W83781D_TEMP2, "temp2", NOMAP, NOMAP, R }, - W83781D_SYSCTL_TEMP2, VALUE(3), 1 }, - { { SENSORS_W83781D_TEMP2_HYST, "temp2_hyst", SENSORS_W83781D_TEMP2, - SENSORS_W83781D_TEMP2, RW }, - W83781D_SYSCTL_TEMP2, VALUE(2), 1 }, - { { SENSORS_W83781D_TEMP2_OVER, "temp2_over", SENSORS_W83781D_TEMP2, - SENSORS_W83781D_TEMP2, RW }, - W83781D_SYSCTL_TEMP2, VALUE(1), 1 }, - { { SENSORS_W83781D_TEMP3, "temp3", NOMAP, NOMAP, R }, - W83781D_SYSCTL_TEMP3, VALUE(3), 1 }, - { { SENSORS_W83781D_TEMP3_HYST, "temp3_hyst", SENSORS_W83781D_TEMP3, - SENSORS_W83781D_TEMP3, RW }, - W83781D_SYSCTL_TEMP3, VALUE(2), 1 }, - { { SENSORS_W83781D_TEMP3_OVER, "temp3_over", SENSORS_W83781D_TEMP3, - SENSORS_W83781D_TEMP3, RW }, - W83781D_SYSCTL_TEMP3, VALUE(1), 1 }, - { { SENSORS_W83781D_VID, "vid", NOMAP, NOMAP, R }, - W83781D_SYSCTL_VID, VALUE(1), 3 }, - { { SENSORS_W83781D_VRM, "vrm", NOMAP, NOMAP, RW }, - W83781D_SYSCTL_VRM, VALUE(1), 1 }, - { { SENSORS_W83781D_FAN1_DIV, "fan1_div", SENSORS_W83781D_FAN1, NOMAP, RW }, - W83781D_SYSCTL_FAN_DIV, VALUE(1), 0 }, - { { SENSORS_W83781D_FAN2_DIV, "fan2_div", SENSORS_W83781D_FAN2, NOMAP, RW }, - W83781D_SYSCTL_FAN_DIV, VALUE(2), 0 }, - { { SENSORS_W83781D_FAN3_DIV, "fan3_div", SENSORS_W83781D_FAN3, NOMAP, RW }, - W83781D_SYSCTL_FAN_DIV, VALUE(3), 0 }, - { { SENSORS_W83781D_ALARMS, "alarms", NOMAP, NOMAP, R }, - W83781D_SYSCTL_ALARMS, VALUE(1), 0 }, - { { SENSORS_W83781D_BEEP_ENABLE, "beep_enable", SENSORS_W83781D_ALARMS, - NOMAP, RW }, - W83781D_SYSCTL_BEEP, VALUE(1), 0 }, - { { SENSORS_W83781D_BEEPS, "beeps", SENSORS_W83781D_ALARMS, - SENSORS_W83781D_ALARMS, RW }, - W83781D_SYSCTL_BEEP, VALUE(2), 0 }, - { { 0 }, 0 } - }; - -static sensors_chip_feature as99127f_features[] = - { - { { SENSORS_W83782D_IN0, "in0", NOMAP, NOMAP, R }, - W83781D_SYSCTL_IN0, VALUE(3), 2 }, - { { SENSORS_W83782D_IN1, "in1", NOMAP, NOMAP, R }, - W83781D_SYSCTL_IN1, VALUE(3), 2 }, - { { SENSORS_W83782D_IN2, "in2", NOMAP, NOMAP, R }, - W83781D_SYSCTL_IN2, VALUE(3), 2 }, - { { SENSORS_W83782D_IN3, "in3", NOMAP, NOMAP, R }, - W83781D_SYSCTL_IN3, VALUE(3), 2 }, - { { SENSORS_W83782D_IN4, "in4", NOMAP, NOMAP, R }, - W83781D_SYSCTL_IN4, VALUE(3), 2 }, - { { SENSORS_W83782D_IN5, "in5", NOMAP, NOMAP, R }, - W83781D_SYSCTL_IN5, VALUE(3), 2 }, - { { SENSORS_W83782D_IN6, "in6", NOMAP, NOMAP, R }, - W83781D_SYSCTL_IN6, VALUE(3), 2 }, - { { SENSORS_W83782D_IN0_MIN, "in0_min", SENSORS_W83782D_IN0, - SENSORS_W83782D_IN0, RW }, - W83781D_SYSCTL_IN0, VALUE(1), 2 }, - { { SENSORS_W83782D_IN1_MIN, "in1_min", SENSORS_W83782D_IN1, - SENSORS_W83782D_IN1, RW }, - W83781D_SYSCTL_IN1, VALUE(1), 2 }, - { { SENSORS_W83782D_IN2_MIN, "in2_min", SENSORS_W83782D_IN2, - SENSORS_W83782D_IN2, RW }, - W83781D_SYSCTL_IN2, VALUE(1), 2 }, - { { SENSORS_W83782D_IN3_MIN, "in3_min", SENSORS_W83782D_IN3, - SENSORS_W83782D_IN3, RW }, - W83781D_SYSCTL_IN3, VALUE(1), 2 }, - { { SENSORS_W83782D_IN4_MIN, "in4_min", SENSORS_W83782D_IN4, - SENSORS_W83782D_IN4, RW }, - W83781D_SYSCTL_IN4, VALUE(1), 2 }, -/* swap 5 and 6 min/max because compute lines will be inverting */ - { { SENSORS_W83782D_IN5_MIN, "in5_min", SENSORS_W83782D_IN5, - SENSORS_W83782D_IN5, RW }, - W83781D_SYSCTL_IN5, VALUE(2), 2, "in5_max", 3 }, - { { SENSORS_W83782D_IN6_MIN, "in6_min", SENSORS_W83782D_IN6, - SENSORS_W83782D_IN6, RW }, - W83781D_SYSCTL_IN6, VALUE(2), 2, "in6_max", 3 }, - { { SENSORS_W83782D_IN0_MAX, "in0_max", SENSORS_W83782D_IN0, - SENSORS_W83782D_IN0, RW }, - W83781D_SYSCTL_IN0, VALUE(2), 2 }, - { { SENSORS_W83782D_IN1_MAX, "in1_max", SENSORS_W83782D_IN1, - SENSORS_W83782D_IN1, RW }, - W83781D_SYSCTL_IN1, VALUE(2), 2 }, - { { SENSORS_W83782D_IN2_MAX, "in2_max", SENSORS_W83782D_IN2, - SENSORS_W83782D_IN2, RW }, - W83781D_SYSCTL_IN2, VALUE(2), 2 }, - { { SENSORS_W83782D_IN3_MAX, "in3_max", SENSORS_W83782D_IN3, - SENSORS_W83782D_IN3, RW }, - W83781D_SYSCTL_IN3, VALUE(2), 2 }, - { { SENSORS_W83782D_IN4_MAX, "in4_max", SENSORS_W83782D_IN4, - SENSORS_W83782D_IN4, RW }, - W83781D_SYSCTL_IN4, VALUE(2), 2 }, - { { SENSORS_W83782D_IN5_MAX, "in5_max", SENSORS_W83782D_IN5, - SENSORS_W83782D_IN5, RW }, - W83781D_SYSCTL_IN5, VALUE(1), 2, "in5_min", 3 }, - { { SENSORS_W83782D_IN6_MAX, "in6_max", SENSORS_W83782D_IN6, - SENSORS_W83782D_IN6, RW }, - W83781D_SYSCTL_IN6, VALUE(1), 2, "in6_min", 3 }, - { { SENSORS_W83782D_FAN1, "fan1", NOMAP, NOMAP, R }, - W83781D_SYSCTL_FAN1, VALUE(2), 0 }, - { { SENSORS_W83782D_FAN2, "fan2", NOMAP, NOMAP, R }, - W83781D_SYSCTL_FAN2, VALUE(2), 0 }, - { { SENSORS_W83782D_FAN3, "fan3", NOMAP, NOMAP, R }, - W83781D_SYSCTL_FAN3, VALUE(2), 0 }, - { { SENSORS_W83782D_FAN1_MIN, "fan1_min", SENSORS_W83782D_FAN1, - SENSORS_W83782D_FAN1, RW }, - W83781D_SYSCTL_FAN1, VALUE(1), 0 }, - { { SENSORS_W83782D_FAN2_MIN, "fan2_min", SENSORS_W83782D_FAN2, - SENSORS_W83782D_FAN2, RW }, - W83781D_SYSCTL_FAN2, VALUE(1), 0 }, - { { SENSORS_W83782D_FAN3_MIN, "fan3_min", SENSORS_W83782D_FAN3, - SENSORS_W83782D_FAN3, RW }, - W83781D_SYSCTL_FAN3, VALUE(1), 0 }, - { { SENSORS_W83782D_TEMP1, "temp1", NOMAP, NOMAP, R }, - W83781D_SYSCTL_TEMP1, VALUE(3), 1 }, - { { SENSORS_W83782D_TEMP1_HYST, "temp1_hyst", SENSORS_W83782D_TEMP1, - SENSORS_W83782D_TEMP1, RW }, - W83781D_SYSCTL_TEMP1, VALUE(2), 1 }, - { { SENSORS_W83782D_TEMP1_OVER, "temp1_over", SENSORS_W83782D_TEMP1, - SENSORS_W83782D_TEMP1, RW }, - W83781D_SYSCTL_TEMP1, VALUE(1), 1 }, - { { SENSORS_W83782D_TEMP2, "temp2", NOMAP, NOMAP, R }, - W83781D_SYSCTL_TEMP2, VALUE(3), 1 }, - { { SENSORS_W83782D_TEMP2_HYST, "temp2_hyst", SENSORS_W83782D_TEMP2, - SENSORS_W83782D_TEMP2, RW }, - W83781D_SYSCTL_TEMP2, VALUE(2), 1 }, - { { SENSORS_W83782D_TEMP2_OVER, "temp2_over", SENSORS_W83782D_TEMP2, - SENSORS_W83782D_TEMP2, RW }, - W83781D_SYSCTL_TEMP2, VALUE(1), 1 }, - { { SENSORS_W83782D_TEMP3, "temp3", NOMAP, NOMAP, R }, - W83781D_SYSCTL_TEMP3, VALUE(3), 1 }, - { { SENSORS_W83782D_TEMP3_HYST, "temp3_hyst", SENSORS_W83782D_TEMP3, - SENSORS_W83782D_TEMP3, RW }, - W83781D_SYSCTL_TEMP3, VALUE(2), 1 }, - { { SENSORS_W83782D_TEMP3_OVER, "temp3_over", SENSORS_W83782D_TEMP3, - SENSORS_W83782D_TEMP3, RW }, - W83781D_SYSCTL_TEMP3, VALUE(1), 1 }, - { { SENSORS_W83782D_VID, "vid", NOMAP, NOMAP, R }, - W83781D_SYSCTL_VID, VALUE(1), 3 }, - { { SENSORS_W83782D_VRM, "vrm", NOMAP, NOMAP, RW }, - W83781D_SYSCTL_VRM, VALUE(1), 1 }, - { { SENSORS_W83782D_FAN1_DIV, "fan1_div", SENSORS_W83782D_FAN1, NOMAP, RW }, - W83781D_SYSCTL_FAN_DIV, VALUE(1), 0 }, - { { SENSORS_W83782D_FAN2_DIV, "fan2_div", SENSORS_W83782D_FAN2, NOMAP, RW }, - W83781D_SYSCTL_FAN_DIV, VALUE(2), 0 }, - { { SENSORS_W83782D_FAN3_DIV, "fan3_div", SENSORS_W83782D_FAN3, NOMAP, RW }, - W83781D_SYSCTL_FAN_DIV, VALUE(3), 0 }, - { { SENSORS_W83782D_ALARMS, "alarms", NOMAP, NOMAP, R }, - W83781D_SYSCTL_ALARMS, VALUE(1), 0 }, - { { SENSORS_W83782D_BEEP_ENABLE, "beep_enable", SENSORS_W83782D_ALARMS, - NOMAP, RW }, - W83781D_SYSCTL_BEEP, VALUE(1), 0 }, - { { SENSORS_W83782D_BEEPS, "beeps", SENSORS_W83782D_ALARMS, - SENSORS_W83782D_ALARMS, RW }, - W83781D_SYSCTL_BEEP, VALUE(2), 0 }, - { { 0 }, 0 } - }; - -/* macro for LM93 voltage in/min/max entries */ -#define SENSORS_LM93_IN_MIN_MAX(nr) \ - { { SENSORS_LM93_IN##nr, "in" #nr, NOMAP, \ - NOMAP, R }, \ - LM93_SYSCTL_IN##nr, VALUE(3), 2}, \ - { { SENSORS_LM93_IN##nr##_MIN, "in" #nr "_min", SENSORS_LM93_IN##nr, \ - SENSORS_LM93_IN##nr, RW }, \ - LM93_SYSCTL_IN##nr, VALUE(1), 2 }, \ - { { SENSORS_LM93_IN##nr##_MAX, "in" #nr "_max", SENSORS_LM93_IN##nr, \ - SENSORS_LM93_IN##nr, RW }, \ - LM93_SYSCTL_IN##nr, VALUE(2), 2 } - -/* macro for LM93 fan/min entries */ -#define SENSORS_LM93_FAN_MIN(nr) \ - { { SENSORS_LM93_FAN##nr, "fan" #nr, NOMAP, NOMAP, R }, \ - LM93_SYSCTL_FAN##nr, VALUE(2), 0 }, \ - { { SENSORS_LM93_FAN##nr##_MIN, "fan" #nr "_min", \ - SENSORS_LM93_FAN##nr, SENSORS_LM93_FAN##nr, RW }, \ - LM93_SYSCTL_FAN##nr, VALUE(1), 0 } - -/* macro for LM93 temp/min/max entries */ -#define SENSORS_LM93_TEMP_MIN_MAX(nr) \ - { { SENSORS_LM93_TEMP##nr, "temp" #nr, NOMAP, NOMAP, R }, \ - LM93_SYSCTL_TEMP##nr, VALUE(3), 1 }, \ - { { SENSORS_LM93_TEMP##nr##_MAX, "temp" #nr "_max", \ - SENSORS_LM93_TEMP##nr, SENSORS_LM93_TEMP##nr, RW }, \ - LM93_SYSCTL_TEMP##nr, VALUE(1), 1 }, \ - { { SENSORS_LM93_TEMP##nr##_MIN, "temp" #nr "_min", \ - SENSORS_LM93_TEMP##nr, SENSORS_LM93_TEMP##nr, RW }, \ - LM93_SYSCTL_TEMP##nr, VALUE(2), 1 } - -static sensors_chip_feature lm93_features[] = { - SENSORS_LM93_IN_MIN_MAX(1), - SENSORS_LM93_IN_MIN_MAX(2), - SENSORS_LM93_IN_MIN_MAX(3), - SENSORS_LM93_IN_MIN_MAX(4), - SENSORS_LM93_IN_MIN_MAX(5), - SENSORS_LM93_IN_MIN_MAX(6), - SENSORS_LM93_IN_MIN_MAX(7), - SENSORS_LM93_IN_MIN_MAX(8), - SENSORS_LM93_IN_MIN_MAX(9), - SENSORS_LM93_IN_MIN_MAX(10), - SENSORS_LM93_IN_MIN_MAX(11), - SENSORS_LM93_IN_MIN_MAX(12), - SENSORS_LM93_IN_MIN_MAX(13), - SENSORS_LM93_IN_MIN_MAX(14), - SENSORS_LM93_IN_MIN_MAX(15), - SENSORS_LM93_IN_MIN_MAX(16), - SENSORS_LM93_FAN_MIN(1), - SENSORS_LM93_FAN_MIN(2), - SENSORS_LM93_FAN_MIN(3), - SENSORS_LM93_FAN_MIN(4), - SENSORS_LM93_TEMP_MIN_MAX(1), - SENSORS_LM93_TEMP_MIN_MAX(2), - SENSORS_LM93_TEMP_MIN_MAX(3), - { { SENSORS_LM93_VID1, "vid1", NOMAP, NOMAP, R }, - LM93_SYSCTL_VID1, VALUE(1), 3, "cpu0_vid", 3, "vid1" }, - { { SENSORS_LM93_VID2, "vid2", NOMAP, NOMAP, R }, - LM93_SYSCTL_VID2, VALUE(1), 3, "cpu1_vid", 3, "vid2" }, - { { SENSORS_LM93_ALARMS, "alarms", NOMAP, NOMAP, R }, - LM93_SYSCTL_ALARMS, VALUE(1), 0 }, - { { 0 }, 0 } -}; - -/* macro for ASB100 Bach voltage in/min/max entries */ -#define SENSORS_ASB100_IN_MIN_MAX(nr) \ - { { SENSORS_ASB100_IN##nr, "in" #nr, NOMAP, NOMAP, R }, \ - ASB100_SYSCTL_IN##nr, \ - VALUE(3), 2 }, \ - { { SENSORS_ASB100_IN##nr##_MIN, "in" #nr "_min", SENSORS_ASB100_IN##nr, \ - SENSORS_ASB100_IN##nr, RW }, \ - ASB100_SYSCTL_IN##nr, VALUE(1), 2 }, \ - { { SENSORS_ASB100_IN##nr##_MAX, "in" #nr "_max", SENSORS_ASB100_IN##nr, \ - SENSORS_ASB100_IN##nr, RW }, \ - ASB100_SYSCTL_IN##nr, VALUE(2), 2 } - -/* macro for ASB100 Bach fan/min/div entries */ -#define SENSORS_ASB100_FAN_MIN_DIV(nr, divmode) \ - { { SENSORS_ASB100_FAN##nr, "fan" #nr, NOMAP, \ - NOMAP, R}, \ - ASB100_SYSCTL_FAN##nr, VALUE(2), 0 }, \ - { { SENSORS_ASB100_FAN##nr##_MIN, "fan" #nr "_min", \ - SENSORS_ASB100_FAN##nr, SENSORS_ASB100_FAN##nr, RW }, \ - ASB100_SYSCTL_FAN##nr, VALUE(1), 0 }, \ - { { SENSORS_ASB100_FAN##nr##_DIV, "fan" #nr "_div", \ - SENSORS_ASB100_FAN##nr, NOMAP, divmode }, \ - ASB100_SYSCTL_FAN_DIV, VALUE(nr), 0 } - -/* macro for ASB100 Bach temperature/overtemp/hysteresis entries */ -#define SENSORS_ASB100_TEMP_OVER_HYST(nr) \ - { { SENSORS_ASB100_TEMP##nr, "temp" #nr, NOMAP, \ - NOMAP, R }, \ - ASB100_SYSCTL_TEMP##nr, VALUE(3), 1 }, \ - { { SENSORS_ASB100_TEMP##nr##_OVER, "temp" #nr "_over", \ - SENSORS_ASB100_TEMP##nr, SENSORS_ASB100_TEMP##nr, RW }, \ - ASB100_SYSCTL_TEMP##nr, VALUE(1), 1 }, \ - { { SENSORS_ASB100_TEMP##nr##_HYST, "temp" #nr "_hyst", \ - SENSORS_ASB100_TEMP##nr, SENSORS_ASB100_TEMP##nr, RW }, \ - ASB100_SYSCTL_TEMP##nr, VALUE(2), 1 } - -static sensors_chip_feature asb100_features[] = { - SENSORS_ASB100_IN_MIN_MAX(0), - SENSORS_ASB100_IN_MIN_MAX(1), - SENSORS_ASB100_IN_MIN_MAX(2), - SENSORS_ASB100_IN_MIN_MAX(3), - SENSORS_ASB100_IN_MIN_MAX(4), - SENSORS_ASB100_IN_MIN_MAX(5), - SENSORS_ASB100_IN_MIN_MAX(6), - SENSORS_ASB100_FAN_MIN_DIV(1, RW), - SENSORS_ASB100_FAN_MIN_DIV(2, RW), - SENSORS_ASB100_FAN_MIN_DIV(3, RW), - SENSORS_ASB100_TEMP_OVER_HYST(1), - SENSORS_ASB100_TEMP_OVER_HYST(2), - SENSORS_ASB100_TEMP_OVER_HYST(3), - SENSORS_ASB100_TEMP_OVER_HYST(4), - { { SENSORS_ASB100_VID, "vid", NOMAP, NOMAP, R }, - ASB100_SYSCTL_VID, VALUE(1), 3 }, - { { SENSORS_ASB100_VRM, "vrm", NOMAP, NOMAP, RW }, - ASB100_SYSCTL_VRM, VALUE(1), 1 }, - { { SENSORS_ASB100_ALARMS, "alarms", NOMAP, NOMAP, R }, - ASB100_SYSCTL_ALARMS, VALUE(1), 0 }, - { { 0 }, 0 } -}; - -static sensors_chip_feature w83782d_features[] = - { - { { SENSORS_W83782D_IN0, "in0", NOMAP, NOMAP, R }, - W83781D_SYSCTL_IN0, VALUE(3), 2 }, - { { SENSORS_W83782D_IN1, "in1", NOMAP, NOMAP, R }, - W83781D_SYSCTL_IN1, VALUE(3), 2 }, - { { SENSORS_W83782D_IN2, "in2", NOMAP, NOMAP, R }, - W83781D_SYSCTL_IN2, VALUE(3), 2 }, - { { SENSORS_W83782D_IN3, "in3", NOMAP, NOMAP, R }, - W83781D_SYSCTL_IN3, VALUE(3), 2 }, - { { SENSORS_W83782D_IN4, "in4", NOMAP, NOMAP, R }, - W83781D_SYSCTL_IN4, VALUE(3), 2 }, - { { SENSORS_W83782D_IN5, "in5", NOMAP, NOMAP, R }, - W83781D_SYSCTL_IN5, VALUE(3), 2 }, - { { SENSORS_W83782D_IN6, "in6", NOMAP, NOMAP, R }, - W83781D_SYSCTL_IN6, VALUE(3), 2 }, - { { SENSORS_W83782D_IN7, "in7", NOMAP, NOMAP, R }, - W83781D_SYSCTL_IN7, VALUE(3), 2 }, - { { SENSORS_W83782D_IN8, "in8", NOMAP, NOMAP, R }, - W83781D_SYSCTL_IN8, VALUE(3), 2 }, - { { SENSORS_W83782D_IN0_MIN, "in0_min", SENSORS_W83782D_IN0, - SENSORS_W83782D_IN0, RW }, - W83781D_SYSCTL_IN0, VALUE(1), 2 }, - { { SENSORS_W83782D_IN1_MIN, "in1_min", SENSORS_W83782D_IN1, - SENSORS_W83782D_IN1, RW }, - W83781D_SYSCTL_IN1, VALUE(1), 2 }, - { { SENSORS_W83782D_IN2_MIN, "in2_min", SENSORS_W83782D_IN2, - SENSORS_W83782D_IN2, RW }, - W83781D_SYSCTL_IN2, VALUE(1), 2 }, - { { SENSORS_W83782D_IN3_MIN, "in3_min", SENSORS_W83782D_IN3, - SENSORS_W83782D_IN3, RW }, - W83781D_SYSCTL_IN3, VALUE(1), 2 }, - { { SENSORS_W83782D_IN4_MIN, "in4_min", SENSORS_W83782D_IN4, - SENSORS_W83782D_IN4, RW }, - W83781D_SYSCTL_IN4, VALUE(1), 2 }, - { { SENSORS_W83782D_IN5_MIN, "in5_min", SENSORS_W83782D_IN5, - SENSORS_W83782D_IN5, RW }, - W83781D_SYSCTL_IN5, VALUE(1), 2 }, - { { SENSORS_W83782D_IN6_MIN, "in6_min", SENSORS_W83782D_IN6, - SENSORS_W83782D_IN6, RW }, - W83781D_SYSCTL_IN6, VALUE(1), 2 }, - { { SENSORS_W83782D_IN7_MIN, "in7_min", SENSORS_W83782D_IN7, - SENSORS_W83782D_IN7, RW }, - W83781D_SYSCTL_IN7, VALUE(1), 2 }, - { { SENSORS_W83782D_IN8_MIN, "in8_min", SENSORS_W83782D_IN8, - SENSORS_W83782D_IN8, RW }, - W83781D_SYSCTL_IN8, VALUE(1), 2 }, - { { SENSORS_W83782D_IN0_MAX, "in0_max", SENSORS_W83782D_IN0, - SENSORS_W83782D_IN0, RW }, - W83781D_SYSCTL_IN0, VALUE(2), 2 }, - { { SENSORS_W83782D_IN1_MAX, "in1_max", SENSORS_W83782D_IN1, - SENSORS_W83782D_IN1, RW }, - W83781D_SYSCTL_IN1, VALUE(2), 2 }, - { { SENSORS_W83782D_IN2_MAX, "in2_max", SENSORS_W83782D_IN2, - SENSORS_W83782D_IN2, RW }, - W83781D_SYSCTL_IN2, VALUE(2), 2 }, - { { SENSORS_W83782D_IN3_MAX, "in3_max", SENSORS_W83782D_IN3, - SENSORS_W83782D_IN3, RW }, - W83781D_SYSCTL_IN3, VALUE(2), 2 }, - { { SENSORS_W83782D_IN4_MAX, "in4_max", SENSORS_W83782D_IN4, - SENSORS_W83782D_IN4, RW }, - W83781D_SYSCTL_IN4, VALUE(2), 2 }, - { { SENSORS_W83782D_IN5_MAX, "in5_max", SENSORS_W83782D_IN5, - SENSORS_W83782D_IN5, RW }, - W83781D_SYSCTL_IN5, VALUE(2), 2 }, - { { SENSORS_W83782D_IN6_MAX, "in6_max", SENSORS_W83782D_IN6, - SENSORS_W83782D_IN6, RW }, - W83781D_SYSCTL_IN6, VALUE(2), 2 }, - { { SENSORS_W83782D_IN7_MAX, "in7_max", SENSORS_W83782D_IN7, - SENSORS_W83782D_IN7, RW }, - W83781D_SYSCTL_IN7, VALUE(2), 2 }, - { { SENSORS_W83782D_IN8_MAX, "in8_max", SENSORS_W83782D_IN8, - SENSORS_W83782D_IN8, RW }, - W83781D_SYSCTL_IN8, VALUE(2), 2 }, - { { SENSORS_W83782D_FAN1, "fan1", NOMAP, NOMAP, R }, - W83781D_SYSCTL_FAN1, VALUE(2), 0 }, - { { SENSORS_W83782D_FAN2, "fan2", NOMAP, NOMAP, R }, - W83781D_SYSCTL_FAN2, VALUE(2), 0 }, - { { SENSORS_W83782D_FAN3, "fan3", NOMAP, NOMAP, R }, - W83781D_SYSCTL_FAN3, VALUE(2), 0 }, - { { SENSORS_W83782D_FAN1_MIN, "fan1_min", SENSORS_W83782D_FAN1, - SENSORS_W83782D_FAN1, RW }, - W83781D_SYSCTL_FAN1, VALUE(1), 0 }, - { { SENSORS_W83782D_FAN2_MIN, "fan2_min", SENSORS_W83782D_FAN2, - SENSORS_W83782D_FAN2, RW }, - W83781D_SYSCTL_FAN2, VALUE(1), 0 }, - { { SENSORS_W83782D_FAN3_MIN, "fan3_min", SENSORS_W83782D_FAN3, - SENSORS_W83782D_FAN3, RW }, - W83781D_SYSCTL_FAN3, VALUE(1), 0 }, - { { SENSORS_W83782D_TEMP1, "temp1", NOMAP, NOMAP, R }, - W83781D_SYSCTL_TEMP1, VALUE(3), 1 }, - { { SENSORS_W83782D_TEMP1_HYST, "temp1_hyst", SENSORS_W83782D_TEMP1, - SENSORS_W83782D_TEMP1, RW }, - W83781D_SYSCTL_TEMP1, VALUE(2), 1 }, - { { SENSORS_W83782D_TEMP1_OVER, "temp1_over", SENSORS_W83782D_TEMP1, - SENSORS_W83782D_TEMP1, RW }, - W83781D_SYSCTL_TEMP1, VALUE(1), 1 }, - { { SENSORS_W83782D_TEMP2, "temp2", NOMAP, NOMAP, R }, - W83781D_SYSCTL_TEMP2, VALUE(3), 1 }, - { { SENSORS_W83782D_TEMP2_HYST, "temp2_hyst", SENSORS_W83782D_TEMP2, - SENSORS_W83782D_TEMP2, RW }, - W83781D_SYSCTL_TEMP2, VALUE(2), 1 }, - { { SENSORS_W83782D_TEMP2_OVER, "temp2_over", SENSORS_W83782D_TEMP2, - SENSORS_W83782D_TEMP2, RW }, - W83781D_SYSCTL_TEMP2, VALUE(1), 1 }, - { { SENSORS_W83782D_TEMP3, "temp3", NOMAP, NOMAP, R }, - W83781D_SYSCTL_TEMP3, VALUE(3), 1 }, - { { SENSORS_W83782D_TEMP3_HYST, "temp3_hyst", SENSORS_W83782D_TEMP3, - SENSORS_W83782D_TEMP3, RW }, - W83781D_SYSCTL_TEMP3, VALUE(2), 1 }, - { { SENSORS_W83782D_TEMP3_OVER, "temp3_over", SENSORS_W83782D_TEMP3, - SENSORS_W83782D_TEMP3, RW }, - W83781D_SYSCTL_TEMP3, VALUE(1), 1 }, - { { SENSORS_W83782D_VID, "vid", NOMAP, NOMAP, R }, - W83781D_SYSCTL_VID, VALUE(1), 3 }, - { { SENSORS_W83782D_VRM, "vrm", NOMAP, NOMAP, RW }, - W83781D_SYSCTL_VRM, VALUE(1), 1 }, - { { SENSORS_W83782D_FAN1_DIV, "fan1_div", SENSORS_W83782D_FAN1, NOMAP, RW }, - W83781D_SYSCTL_FAN_DIV, VALUE(1), 0 }, - { { SENSORS_W83782D_FAN2_DIV, "fan2_div", SENSORS_W83782D_FAN2, NOMAP, RW }, - W83781D_SYSCTL_FAN_DIV, VALUE(2), 0 }, - { { SENSORS_W83782D_FAN3_DIV, "fan3_div", SENSORS_W83782D_FAN3, NOMAP, RW }, - W83781D_SYSCTL_FAN_DIV, VALUE(3), 0 }, - { { SENSORS_W83782D_ALARMS, "alarms", NOMAP, NOMAP, R }, - W83781D_SYSCTL_ALARMS, VALUE(1), 0 }, - { { SENSORS_W83782D_BEEP_ENABLE, "beep_enable", SENSORS_W83782D_ALARMS, - NOMAP, RW }, - W83781D_SYSCTL_BEEP, VALUE(1), 0 }, - { { SENSORS_W83782D_BEEPS, "beeps", SENSORS_W83782D_ALARMS, - SENSORS_W83782D_ALARMS, RW }, - W83781D_SYSCTL_BEEP, VALUE(2), 0 }, - { { SENSORS_W83782D_SENS1, "sensor1", SENSORS_W83782D_TEMP1, NOMAP, RW }, - W83781D_SYSCTL_SENS1, VALUE(1), 0 }, - { { SENSORS_W83782D_SENS2, "sensor2", SENSORS_W83782D_TEMP2, NOMAP, RW }, - W83781D_SYSCTL_SENS2, VALUE(1), 0 }, - { { SENSORS_W83782D_SENS3, "sensor3", SENSORS_W83782D_TEMP3, NOMAP, RW }, - W83781D_SYSCTL_SENS3, VALUE(1), 0 }, - { { 0 }, 0 } - }; - -static sensors_chip_feature w83783s_features[] = - { - { { SENSORS_W83783S_IN0, "in0", NOMAP, NOMAP, R }, - W83781D_SYSCTL_IN0, VALUE(3), 2 }, - { { SENSORS_W83783S_IN2, "in2", NOMAP, NOMAP, R }, - W83781D_SYSCTL_IN2, VALUE(3), 2 }, - { { SENSORS_W83783S_IN3, "in3", NOMAP, NOMAP, R }, - W83781D_SYSCTL_IN3, VALUE(3), 2 }, - { { SENSORS_W83783S_IN4, "in4", NOMAP, NOMAP, R }, - W83781D_SYSCTL_IN4, VALUE(3), 2 }, - { { SENSORS_W83783S_IN5, "in5", NOMAP, NOMAP, R }, - W83781D_SYSCTL_IN5, VALUE(3), 2 }, - { { SENSORS_W83783S_IN6, "in6", NOMAP, NOMAP, R }, - W83781D_SYSCTL_IN6, VALUE(3), 2 }, - { { SENSORS_W83783S_IN0_MIN, "in0_min", SENSORS_W83783S_IN0, - SENSORS_W83783S_IN0, RW }, - W83781D_SYSCTL_IN0, VALUE(1), 2 }, - { { SENSORS_W83783S_IN2_MIN, "in2_min", SENSORS_W83783S_IN2, - SENSORS_W83783S_IN2, RW }, - W83781D_SYSCTL_IN2, VALUE(1), 2 }, - { { SENSORS_W83783S_IN3_MIN, "in3_min", SENSORS_W83783S_IN3, - SENSORS_W83783S_IN3, RW }, - W83781D_SYSCTL_IN3, VALUE(1), 2 }, - { { SENSORS_W83783S_IN4_MIN, "in4_min", SENSORS_W83783S_IN4, - SENSORS_W83783S_IN4, RW }, - W83781D_SYSCTL_IN4, VALUE(1), 2 }, - { { SENSORS_W83783S_IN5_MIN, "in5_min", SENSORS_W83783S_IN5, - SENSORS_W83783S_IN5, RW }, - W83781D_SYSCTL_IN5, VALUE(1), 2 }, - { { SENSORS_W83783S_IN6_MIN, "in6_min", SENSORS_W83783S_IN6, - SENSORS_W83783S_IN6, RW }, - W83781D_SYSCTL_IN6, VALUE(1), 2 }, - { { SENSORS_W83783S_IN0_MAX, "in0_max", SENSORS_W83783S_IN0, - SENSORS_W83783S_IN0, RW }, - W83781D_SYSCTL_IN0, VALUE(2), 2 }, - { { SENSORS_W83783S_IN2_MAX, "in2_max", SENSORS_W83783S_IN2, - SENSORS_W83783S_IN2, RW }, - W83781D_SYSCTL_IN2, VALUE(2), 2 }, - { { SENSORS_W83783S_IN3_MAX, "in3_max", SENSORS_W83783S_IN3, - SENSORS_W83783S_IN3, RW }, - W83781D_SYSCTL_IN3, VALUE(2), 2 }, - { { SENSORS_W83783S_IN4_MAX, "in4_max", SENSORS_W83783S_IN4, - SENSORS_W83783S_IN4, RW }, - W83781D_SYSCTL_IN4, VALUE(2), 2 }, - { { SENSORS_W83783S_IN5_MAX, "in5_max", SENSORS_W83783S_IN5, - SENSORS_W83783S_IN5, RW }, - W83781D_SYSCTL_IN5, VALUE(2), 2 }, - { { SENSORS_W83783S_IN6_MAX, "in6_max", SENSORS_W83783S_IN6, - SENSORS_W83783S_IN6, RW }, - W83781D_SYSCTL_IN6, VALUE(2), 2 }, - { { SENSORS_W83783S_FAN1, "fan1", NOMAP, NOMAP, R }, - W83781D_SYSCTL_FAN1, VALUE(2), 0 }, - { { SENSORS_W83783S_FAN2, "fan2", NOMAP, NOMAP, R }, - W83781D_SYSCTL_FAN2, VALUE(2), 0 }, - { { SENSORS_W83783S_FAN3, "fan3", NOMAP, NOMAP, R }, - W83781D_SYSCTL_FAN3, VALUE(2), 0 }, - { { SENSORS_W83783S_FAN1_MIN, "fan1_min", SENSORS_W83783S_FAN1, - SENSORS_W83783S_FAN1, RW }, - W83781D_SYSCTL_FAN1, VALUE(1), 0 }, - { { SENSORS_W83783S_FAN2_MIN, "fan2_min", SENSORS_W83783S_FAN2, - SENSORS_W83783S_FAN2, RW }, - W83781D_SYSCTL_FAN2, VALUE(1), 0 }, - { { SENSORS_W83783S_FAN3_MIN, "fan3_min", SENSORS_W83783S_FAN3, - SENSORS_W83783S_FAN3, RW }, - W83781D_SYSCTL_FAN3, VALUE(1), 0 }, - { { SENSORS_W83783S_TEMP1, "temp1", NOMAP, NOMAP, R }, - W83781D_SYSCTL_TEMP1, VALUE(3), 1 }, - { { SENSORS_W83783S_TEMP1_HYST, "temp1_hyst", SENSORS_W83783S_TEMP1, - SENSORS_W83783S_TEMP1, RW }, - W83781D_SYSCTL_TEMP1, VALUE(2), 1 }, - { { SENSORS_W83783S_TEMP1_OVER, "temp1_over", SENSORS_W83783S_TEMP1, - SENSORS_W83783S_TEMP1, RW }, - W83781D_SYSCTL_TEMP1, VALUE(1), 1 }, - { { SENSORS_W83783S_TEMP2, "temp2", NOMAP, NOMAP, R }, - W83781D_SYSCTL_TEMP2, VALUE(3), 1 }, - { { SENSORS_W83783S_TEMP2_HYST, "temp2_hyst", SENSORS_W83783S_TEMP2, - SENSORS_W83783S_TEMP2, RW }, - W83781D_SYSCTL_TEMP2, VALUE(2), 1 }, - { { SENSORS_W83783S_TEMP2_OVER, "temp2_over", SENSORS_W83783S_TEMP2, - SENSORS_W83783S_TEMP2, RW }, - W83781D_SYSCTL_TEMP2, VALUE(1), 1 }, - { { SENSORS_W83783S_VID, "vid", NOMAP, NOMAP, R }, - W83781D_SYSCTL_VID, VALUE(1), 3 }, - { { SENSORS_W83783S_VRM, "vrm", NOMAP, NOMAP, RW }, - W83781D_SYSCTL_VRM, VALUE(1), 1 }, - { { SENSORS_W83783S_FAN1_DIV, "fan1_div", SENSORS_W83783S_FAN1, NOMAP, RW }, - W83781D_SYSCTL_FAN_DIV, VALUE(1), 0 }, - { { SENSORS_W83783S_FAN2_DIV, "fan2_div", SENSORS_W83783S_FAN2, NOMAP, RW }, - W83781D_SYSCTL_FAN_DIV, VALUE(2), 0 }, - { { SENSORS_W83783S_FAN3_DIV, "fan3_div", SENSORS_W83783S_FAN3, NOMAP, RW }, - W83781D_SYSCTL_FAN_DIV, VALUE(3), 0 }, - { { SENSORS_W83783S_ALARMS, "alarms", NOMAP, NOMAP, R }, - W83781D_SYSCTL_ALARMS, VALUE(1), 0 }, - { { SENSORS_W83783S_BEEP_ENABLE, "beep_enable", SENSORS_W83783S_ALARMS, - NOMAP, RW }, - W83781D_SYSCTL_BEEP, VALUE(1), 0 }, - { { SENSORS_W83783S_BEEPS, "beeps", SENSORS_W83783S_ALARMS, - SENSORS_W83783S_ALARMS, RW }, - W83781D_SYSCTL_BEEP, VALUE(2), 0 }, - { { SENSORS_W83783S_SENS1, "sensor1", SENSORS_W83783S_TEMP1, NOMAP, RW }, - W83781D_SYSCTL_SENS1, VALUE(1), 0 }, - { { SENSORS_W83783S_SENS2, "sensor2", SENSORS_W83783S_TEMP2, NOMAP, RW }, - W83781D_SYSCTL_SENS2, VALUE(1), 0 }, - { { 0 }, 0 } - }; - -static sensors_chip_feature w83791d_features[] = - { - { { SENSORS_W83791D_IN0, "in0", NOMAP, NOMAP, R }, - W83781D_SYSCTL_IN0, VALUE(3), 2 }, - { { SENSORS_W83791D_IN1, "in1", NOMAP, NOMAP, R }, - W83781D_SYSCTL_IN1, VALUE(3), 2 }, - { { SENSORS_W83791D_IN2, "in2", NOMAP, NOMAP, R }, - W83781D_SYSCTL_IN2, VALUE(3), 2 }, - { { SENSORS_W83791D_IN3, "in3", NOMAP, NOMAP, R }, - W83781D_SYSCTL_IN3, VALUE(3), 2 }, - { { SENSORS_W83791D_IN4, "in4", NOMAP, NOMAP, R }, - W83781D_SYSCTL_IN4, VALUE(3), 2 }, - { { SENSORS_W83791D_IN5, "in5", NOMAP, NOMAP, R }, - W83781D_SYSCTL_IN5, VALUE(3), 2 }, - { { SENSORS_W83791D_IN6, "in6", NOMAP, NOMAP, R }, - W83781D_SYSCTL_IN6, VALUE(3), 2 }, - { { SENSORS_W83791D_IN7, "in7", NOMAP, NOMAP, R }, - W83781D_SYSCTL_IN7, VALUE(3), 2 }, - { { SENSORS_W83791D_IN8, "in8", NOMAP, NOMAP, R }, - W83781D_SYSCTL_IN8, VALUE(3), 2 }, - { { SENSORS_W83791D_IN9, "in9", NOMAP, NOMAP, R }, - W83781D_SYSCTL_IN9, VALUE(3), 2 }, - { { SENSORS_W83791D_IN0_MIN, "in0_min", SENSORS_W83791D_IN0, - SENSORS_W83791D_IN0, RW }, - W83781D_SYSCTL_IN0, VALUE(1), 2 }, - { { SENSORS_W83791D_IN1_MIN, "in1_min", SENSORS_W83791D_IN1, - SENSORS_W83791D_IN1, RW }, - W83781D_SYSCTL_IN1, VALUE(1), 2 }, - { { SENSORS_W83791D_IN2_MIN, "in2_min", SENSORS_W83791D_IN2, - SENSORS_W83791D_IN2, RW }, - W83781D_SYSCTL_IN2, VALUE(1), 2 }, - { { SENSORS_W83791D_IN3_MIN, "in3_min", SENSORS_W83791D_IN3, - SENSORS_W83791D_IN3, RW }, - W83781D_SYSCTL_IN3, VALUE(1), 2 }, - { { SENSORS_W83791D_IN4_MIN, "in4_min", SENSORS_W83791D_IN4, - SENSORS_W83791D_IN4, RW }, - W83781D_SYSCTL_IN4, VALUE(1), 2 }, - { { SENSORS_W83791D_IN5_MIN, "in5_min", SENSORS_W83791D_IN5, - SENSORS_W83791D_IN5, RW }, - W83781D_SYSCTL_IN5, VALUE(1), 2 }, - { { SENSORS_W83791D_IN6_MIN, "in6_min", SENSORS_W83791D_IN6, - SENSORS_W83791D_IN6, RW }, - W83781D_SYSCTL_IN6, VALUE(1), 2 }, - { { SENSORS_W83791D_IN7_MIN, "in7_min", SENSORS_W83791D_IN7, - SENSORS_W83791D_IN7, RW }, - W83781D_SYSCTL_IN7, VALUE(1), 2 }, - { { SENSORS_W83791D_IN8_MIN, "in8_min", SENSORS_W83791D_IN8, - SENSORS_W83791D_IN8, RW }, - W83781D_SYSCTL_IN8, VALUE(1), 2 }, - { { SENSORS_W83791D_IN9_MIN, "in9_min", SENSORS_W83791D_IN9, - SENSORS_W83791D_IN9, RW }, - W83781D_SYSCTL_IN9, VALUE(1), 2 }, - { { SENSORS_W83791D_IN0_MAX, "in0_max", SENSORS_W83791D_IN0, - SENSORS_W83791D_IN0, RW }, - W83781D_SYSCTL_IN0, VALUE(2), 2 }, - { { SENSORS_W83791D_IN1_MAX, "in1_max", SENSORS_W83791D_IN1, - SENSORS_W83791D_IN1, RW }, - W83781D_SYSCTL_IN1, VALUE(2), 2 }, - { { SENSORS_W83791D_IN2_MAX, "in2_max", SENSORS_W83791D_IN2, - SENSORS_W83791D_IN2, RW }, - W83781D_SYSCTL_IN2, VALUE(2), 2 }, - { { SENSORS_W83791D_IN3_MAX, "in3_max", SENSORS_W83791D_IN3, - SENSORS_W83791D_IN3, RW }, - W83781D_SYSCTL_IN3, VALUE(2), 2 }, - { { SENSORS_W83791D_IN4_MAX, "in4_max", SENSORS_W83791D_IN4, - SENSORS_W83791D_IN4, RW }, - W83781D_SYSCTL_IN4, VALUE(2), 2 }, - { { SENSORS_W83791D_IN5_MAX, "in5_max", SENSORS_W83791D_IN5, - SENSORS_W83791D_IN5, RW }, - W83781D_SYSCTL_IN5, VALUE(2), 2 }, - { { SENSORS_W83791D_IN6_MAX, "in6_max", SENSORS_W83791D_IN6, - SENSORS_W83791D_IN6, RW }, - W83781D_SYSCTL_IN6, VALUE(2), 2 }, - { { SENSORS_W83791D_IN7_MAX, "in7_max", SENSORS_W83791D_IN7, - SENSORS_W83791D_IN7, RW }, - W83781D_SYSCTL_IN7, VALUE(2), 2 }, - { { SENSORS_W83791D_IN8_MAX, "in8_max", SENSORS_W83791D_IN8, - SENSORS_W83791D_IN8, RW }, - W83781D_SYSCTL_IN8, VALUE(2), 2 }, - { { SENSORS_W83791D_IN9_MAX, "in9_max", SENSORS_W83791D_IN9, - SENSORS_W83791D_IN9, RW }, - W83781D_SYSCTL_IN9, VALUE(2), 2 }, - { { SENSORS_W83791D_FAN1, "fan1", NOMAP, NOMAP, R }, - W83781D_SYSCTL_FAN1, VALUE(2), 0 }, - { { SENSORS_W83791D_FAN2, "fan2", NOMAP, NOMAP, R }, - W83781D_SYSCTL_FAN2, VALUE(2), 0 }, - { { SENSORS_W83791D_FAN3, "fan3", NOMAP, NOMAP, R }, - W83781D_SYSCTL_FAN3, VALUE(2), 0 }, - { { SENSORS_W83791D_FAN4, "fan4", NOMAP, NOMAP, R }, - W83781D_SYSCTL_FAN4, VALUE(2), 0 }, - { { SENSORS_W83791D_FAN5, "fan5", NOMAP, NOMAP, R }, - W83781D_SYSCTL_FAN5, VALUE(2), 0 }, - { { SENSORS_W83791D_FAN1_MIN, "fan1_min", SENSORS_W83791D_FAN1, - SENSORS_W83791D_FAN1, RW }, - W83781D_SYSCTL_FAN1, VALUE(1), 0 }, - { { SENSORS_W83791D_FAN2_MIN, "fan2_min", SENSORS_W83791D_FAN2, - SENSORS_W83791D_FAN2, RW }, - W83781D_SYSCTL_FAN2, VALUE(1), 0 }, - { { SENSORS_W83791D_FAN3_MIN, "fan3_min", SENSORS_W83791D_FAN3, - SENSORS_W83791D_FAN3, RW }, - W83781D_SYSCTL_FAN3, VALUE(1), 0 }, - { { SENSORS_W83791D_FAN4_MIN, "fan4_min", SENSORS_W83791D_FAN4, - SENSORS_W83791D_FAN4, RW }, - W83781D_SYSCTL_FAN4, VALUE(1), 0 }, - { { SENSORS_W83791D_FAN5_MIN, "fan5_min", SENSORS_W83791D_FAN5, - SENSORS_W83791D_FAN5, RW }, - W83781D_SYSCTL_FAN5, VALUE(1), 0 }, - { { SENSORS_W83791D_TEMP1, "temp1", NOMAP, NOMAP, R }, - W83781D_SYSCTL_TEMP1, VALUE(3), 1 }, - { { SENSORS_W83791D_TEMP1_HYST, "temp1_hyst", SENSORS_W83791D_TEMP1, - SENSORS_W83791D_TEMP1, RW }, - W83781D_SYSCTL_TEMP1, VALUE(2), 1 }, - { { SENSORS_W83791D_TEMP1_OVER, "temp1_over", SENSORS_W83791D_TEMP1, - SENSORS_W83791D_TEMP1, RW }, - W83781D_SYSCTL_TEMP1, VALUE(1), 1 }, - { { SENSORS_W83791D_TEMP2, "temp2", NOMAP, NOMAP, R }, - W83781D_SYSCTL_TEMP2, VALUE(3), 1 }, - { { SENSORS_W83791D_TEMP2_HYST, "temp2_hyst", SENSORS_W83791D_TEMP2, - SENSORS_W83791D_TEMP2, RW }, - W83781D_SYSCTL_TEMP2, VALUE(2), 1 }, - { { SENSORS_W83791D_TEMP2_OVER, "temp2_over", SENSORS_W83791D_TEMP2, - SENSORS_W83791D_TEMP2, RW }, - W83781D_SYSCTL_TEMP2, VALUE(1), 1 }, - { { SENSORS_W83791D_TEMP3, "temp3", NOMAP, NOMAP, R }, - W83781D_SYSCTL_TEMP3, VALUE(3), 1 }, - { { SENSORS_W83791D_TEMP3_HYST, "temp3_hyst", SENSORS_W83791D_TEMP3, - SENSORS_W83791D_TEMP3, RW }, - W83781D_SYSCTL_TEMP3, VALUE(2), 1 }, - { { SENSORS_W83791D_TEMP3_OVER, "temp3_over", SENSORS_W83791D_TEMP3, - SENSORS_W83791D_TEMP3, RW }, - W83781D_SYSCTL_TEMP3, VALUE(1), 1 }, - { { SENSORS_W83791D_VID, "vid", NOMAP, NOMAP, R }, - W83781D_SYSCTL_VID, VALUE(1), 3 }, - { { SENSORS_W83791D_VRM, "vrm", NOMAP, NOMAP, RW }, - W83781D_SYSCTL_VRM, VALUE(1), 1 }, - { { SENSORS_W83791D_FAN1_DIV, "fan1_div", SENSORS_W83791D_FAN1, NOMAP, RW }, - W83781D_SYSCTL_FAN_DIV, VALUE(1), 0 }, - { { SENSORS_W83791D_FAN2_DIV, "fan2_div", SENSORS_W83791D_FAN2, NOMAP, RW }, - W83781D_SYSCTL_FAN_DIV, VALUE(2), 0 }, - { { SENSORS_W83791D_FAN3_DIV, "fan3_div", SENSORS_W83791D_FAN3, NOMAP, RW }, - W83781D_SYSCTL_FAN_DIV, VALUE(3), 0 }, - { { SENSORS_W83791D_FAN4_DIV, "fan4_div", SENSORS_W83791D_FAN4, NOMAP, RW }, - W83781D_SYSCTL_FAN_DIV, VALUE(4), 0 }, - { { SENSORS_W83791D_FAN5_DIV, "fan5_div", SENSORS_W83791D_FAN5, NOMAP, RW }, - W83781D_SYSCTL_FAN_DIV, VALUE(5), 0 }, - { { SENSORS_W83791D_ALARMS, "alarms", NOMAP, NOMAP, R }, - W83781D_SYSCTL_ALARMS, VALUE(1), 0 }, - { { SENSORS_W83791D_BEEP_ENABLE, "beep_enable", SENSORS_W83791D_ALARMS, - NOMAP, RW }, - W83781D_SYSCTL_BEEP, VALUE(1), 0 }, - { { SENSORS_W83791D_BEEPS, "beeps", SENSORS_W83791D_ALARMS, - SENSORS_W83791D_ALARMS, RW }, - W83781D_SYSCTL_BEEP, VALUE(2), 0 }, - { { 0 }, 0 } - }; - - -static sensors_chip_feature w83792d_features[] = - { - { { SENSORS_W83792D_IN0, "in0", NOMAP, NOMAP, R }, - W83792D_SYSCTL_IN0, VALUE(3), 3 }, - { { SENSORS_W83792D_IN1, "in1", NOMAP, NOMAP, R }, - W83792D_SYSCTL_IN1, VALUE(3), 3 }, - { { SENSORS_W83792D_IN2, "in2", NOMAP, NOMAP, R }, - W83792D_SYSCTL_IN2, VALUE(3), 3 }, - { { SENSORS_W83792D_IN3, "in3", NOMAP, NOMAP, R }, - W83792D_SYSCTL_IN3, VALUE(3), 3 }, - { { SENSORS_W83792D_IN4, "in4", NOMAP, NOMAP, R }, - W83792D_SYSCTL_IN4, VALUE(3), 3 }, - { { SENSORS_W83792D_IN5, "in5", NOMAP, NOMAP, R }, - W83792D_SYSCTL_IN5, VALUE(3), 3 }, - { { SENSORS_W83792D_IN6, "in6", NOMAP, NOMAP, R }, - W83792D_SYSCTL_IN6, VALUE(3), 3 }, - { { SENSORS_W83792D_IN7, "in7", NOMAP, NOMAP, R }, - W83792D_SYSCTL_IN7, VALUE(3), 3 }, - { { SENSORS_W83792D_IN8, "in8", NOMAP, NOMAP, R }, - W83792D_SYSCTL_IN8, VALUE(3), 3 }, - { { SENSORS_W83792D_IN0_MIN, "in0_min", SENSORS_W83792D_IN0, - SENSORS_W83792D_IN0, RW }, - W83792D_SYSCTL_IN0, VALUE(1), 3 }, - { { SENSORS_W83792D_IN1_MIN, "in1_min", SENSORS_W83792D_IN1, - SENSORS_W83792D_IN1, RW }, - W83792D_SYSCTL_IN1, VALUE(1), 3 }, - { { SENSORS_W83792D_IN2_MIN, "in2_min", SENSORS_W83792D_IN2, - SENSORS_W83792D_IN2, RW }, - W83792D_SYSCTL_IN2, VALUE(1), 3 }, - { { SENSORS_W83792D_IN3_MIN, "in3_min", SENSORS_W83792D_IN3, - SENSORS_W83792D_IN3, RW }, - W83792D_SYSCTL_IN3, VALUE(1), 3 }, - { { SENSORS_W83792D_IN4_MIN, "in4_min", SENSORS_W83792D_IN4, - SENSORS_W83792D_IN4, RW }, - W83792D_SYSCTL_IN4, VALUE(1), 3 }, - { { SENSORS_W83792D_IN5_MIN, "in5_min", SENSORS_W83792D_IN5, - SENSORS_W83792D_IN5, RW }, - W83792D_SYSCTL_IN5, VALUE(1), 3 }, - { { SENSORS_W83792D_IN6_MIN, "in6_min", SENSORS_W83792D_IN6, - SENSORS_W83792D_IN6, RW }, - W83792D_SYSCTL_IN6, VALUE(1), 3 }, - { { SENSORS_W83792D_IN7_MIN, "in7_min", SENSORS_W83792D_IN7, - SENSORS_W83792D_IN7, RW }, - W83792D_SYSCTL_IN7, VALUE(1), 3 }, - { { SENSORS_W83792D_IN8_MIN, "in8_min", SENSORS_W83792D_IN8, - SENSORS_W83792D_IN8, RW }, - W83792D_SYSCTL_IN8, VALUE(1), 3 }, - { { SENSORS_W83792D_IN0_MAX, "in0_max", SENSORS_W83792D_IN0, - SENSORS_W83792D_IN0, RW }, - W83792D_SYSCTL_IN0, VALUE(2), 3 }, - { { SENSORS_W83792D_IN1_MAX, "in1_max", SENSORS_W83792D_IN1, - SENSORS_W83792D_IN1, RW }, - W83792D_SYSCTL_IN1, VALUE(2), 3 }, - { { SENSORS_W83792D_IN2_MAX, "in2_max", SENSORS_W83792D_IN2, - SENSORS_W83792D_IN2, RW }, - W83792D_SYSCTL_IN2, VALUE(2), 3 }, - { { SENSORS_W83792D_IN3_MAX, "in3_max", SENSORS_W83792D_IN3, - SENSORS_W83792D_IN3, RW }, - W83792D_SYSCTL_IN3, VALUE(2), 3 }, - { { SENSORS_W83792D_IN4_MAX, "in4_max", SENSORS_W83792D_IN4, - SENSORS_W83792D_IN4, RW }, - W83792D_SYSCTL_IN4, VALUE(2), 3 }, - { { SENSORS_W83792D_IN5_MAX, "in5_max", SENSORS_W83792D_IN5, - SENSORS_W83792D_IN5, RW }, - W83792D_SYSCTL_IN5, VALUE(2), 3 }, - { { SENSORS_W83792D_IN6_MAX, "in6_max", SENSORS_W83792D_IN6, - SENSORS_W83792D_IN6, RW }, - W83792D_SYSCTL_IN6, VALUE(2), 3 }, - { { SENSORS_W83792D_IN7_MAX, "in7_max", SENSORS_W83792D_IN7, - SENSORS_W83792D_IN7, RW }, - W83792D_SYSCTL_IN7, VALUE(2), 3 }, - { { SENSORS_W83792D_IN8_MAX, "in8_max", SENSORS_W83792D_IN8, - SENSORS_W83792D_IN8, RW }, - W83792D_SYSCTL_IN8, VALUE(2), 3 }, - { { SENSORS_W83792D_FAN1, "fan1", NOMAP, NOMAP, R }, - W83792D_SYSCTL_FAN1, VALUE(2), 0 }, - { { SENSORS_W83792D_FAN2, "fan2", NOMAP, NOMAP, R }, - W83792D_SYSCTL_FAN2, VALUE(2), 0 }, - { { SENSORS_W83792D_FAN3, "fan3", NOMAP, NOMAP, R }, - W83792D_SYSCTL_FAN3, VALUE(2), 0 }, - { { SENSORS_W83792D_FAN4, "fan4", NOMAP, NOMAP, R }, - W83792D_SYSCTL_FAN4, VALUE(2), 0 }, - { { SENSORS_W83792D_FAN5, "fan5", NOMAP, NOMAP, R }, - W83792D_SYSCTL_FAN5, VALUE(2), 0 }, - { { SENSORS_W83792D_FAN6, "fan6", NOMAP, NOMAP, R }, - W83792D_SYSCTL_FAN6, VALUE(2), 0 }, - { { SENSORS_W83792D_FAN7, "fan7", NOMAP, NOMAP, R }, - W83792D_SYSCTL_FAN7, VALUE(2), 0 }, - { { SENSORS_W83792D_FAN1_MIN, "fan1_min", SENSORS_W83792D_FAN1, - SENSORS_W83792D_FAN1, RW }, - W83792D_SYSCTL_FAN1, VALUE(1), 0 }, - { { SENSORS_W83792D_FAN2_MIN, "fan2_min", SENSORS_W83792D_FAN2, - SENSORS_W83792D_FAN2, RW }, - W83792D_SYSCTL_FAN2, VALUE(1), 0 }, - { { SENSORS_W83792D_FAN3_MIN, "fan3_min", SENSORS_W83792D_FAN3, - SENSORS_W83792D_FAN3, RW }, - W83792D_SYSCTL_FAN3, VALUE(1), 0 }, - { { SENSORS_W83792D_FAN4_MIN, "fan4_min", SENSORS_W83792D_FAN4, - SENSORS_W83792D_FAN4, RW }, - W83792D_SYSCTL_FAN4, VALUE(1), 0 }, - { { SENSORS_W83792D_FAN5_MIN, "fan5_min", SENSORS_W83792D_FAN5, - SENSORS_W83792D_FAN5, RW }, - W83792D_SYSCTL_FAN5, VALUE(1), 0 }, - { { SENSORS_W83792D_FAN6_MIN, "fan6_min", SENSORS_W83792D_FAN6, - SENSORS_W83792D_FAN6, RW }, - W83792D_SYSCTL_FAN6, VALUE(1), 0 }, - { { SENSORS_W83792D_FAN7_MIN, "fan7_min", SENSORS_W83792D_FAN7, - SENSORS_W83792D_FAN7, RW }, - W83792D_SYSCTL_FAN7, VALUE(1), 0 }, - { { SENSORS_W83792D_TEMP1, "temp1", NOMAP, NOMAP, R }, - W83792D_SYSCTL_TEMP1, VALUE(3), 1 }, - { { SENSORS_W83792D_TEMP1_HYST, "temp1_hyst", SENSORS_W83792D_TEMP1, - SENSORS_W83792D_TEMP1, RW }, - W83792D_SYSCTL_TEMP1, VALUE(2), 1 }, - { { SENSORS_W83792D_TEMP1_OVER, "temp1_over", SENSORS_W83792D_TEMP1, - SENSORS_W83792D_TEMP1, RW }, - W83792D_SYSCTL_TEMP1, VALUE(1), 1 }, - { { SENSORS_W83792D_TEMP2, "temp2", NOMAP, NOMAP, R }, - W83792D_SYSCTL_TEMP2, VALUE(3), 1 }, - { { SENSORS_W83792D_TEMP2_HYST, "temp2_hyst", SENSORS_W83792D_TEMP2, - SENSORS_W83792D_TEMP2, RW }, - W83792D_SYSCTL_TEMP2, VALUE(2), 1 }, - { { SENSORS_W83792D_TEMP2_OVER, "temp2_over", SENSORS_W83792D_TEMP2, - SENSORS_W83792D_TEMP2, RW }, - W83792D_SYSCTL_TEMP2, VALUE(1), 1 }, - { { SENSORS_W83792D_TEMP3, "temp3", NOMAP, NOMAP, R }, - W83792D_SYSCTL_TEMP3, VALUE(3), 1 }, - { { SENSORS_W83792D_TEMP3_HYST, "temp3_hyst", SENSORS_W83792D_TEMP3, - SENSORS_W83792D_TEMP3, RW }, - W83792D_SYSCTL_TEMP3, VALUE(2), 1 }, - { { SENSORS_W83792D_TEMP3_OVER, "temp3_over", SENSORS_W83792D_TEMP3, - SENSORS_W83792D_TEMP3, RW }, - W83792D_SYSCTL_TEMP3, VALUE(1), 1 }, - /* { { SENSORS_W83792D_VID, "vid", NOMAP, NOMAP, R }, - W83792D_SYSCTL_VID, VALUE(1), 3 }, - { { SENSORS_W83792D_VRM, "vrm", NOMAP, NOMAP, RW }, - W83792D_SYSCTL_VRM, VALUE(1), 1 }, */ - { { SENSORS_W83792D_CHASSIS, "chassis", SENSORS_W83792D_CHASSIS, NOMAP, RW }, - W83792D_SYSCTL_CHASSIS, VALUE(1), 0 }, - { { SENSORS_W83792D_FAN1_DIV, "fan1_div", SENSORS_W83792D_FAN1, NOMAP, RW }, - W83792D_SYSCTL_FAN_DIV, VALUE(1), 0 }, - { { SENSORS_W83792D_FAN2_DIV, "fan2_div", SENSORS_W83792D_FAN2, NOMAP, RW }, - W83792D_SYSCTL_FAN_DIV, VALUE(2), 0 }, - { { SENSORS_W83792D_FAN3_DIV, "fan3_div", SENSORS_W83792D_FAN3, NOMAP, RW }, - W83792D_SYSCTL_FAN_DIV, VALUE(3), 0 }, - { { SENSORS_W83792D_FAN4_DIV, "fan4_div", SENSORS_W83792D_FAN4, NOMAP, RW }, - W83792D_SYSCTL_FAN_DIV, VALUE(4), 0 }, - { { SENSORS_W83792D_FAN5_DIV, "fan5_div", SENSORS_W83792D_FAN5, NOMAP, RW }, - W83792D_SYSCTL_FAN_DIV, VALUE(5), 0 }, - { { SENSORS_W83792D_FAN6_DIV, "fan6_div", SENSORS_W83792D_FAN6, NOMAP, RW }, - W83792D_SYSCTL_FAN_DIV, VALUE(6), 0 }, - { { SENSORS_W83792D_FAN7_DIV, "fan7_div", SENSORS_W83792D_FAN7, NOMAP, RW }, - W83792D_SYSCTL_FAN_DIV, VALUE(7), 0 }, - { { SENSORS_W83792D_ALARMS, "alarms", NOMAP, NOMAP, R }, - W83792D_SYSCTL_ALARMS, VALUE(1), 0 }, - { { 0 }, 0 } - }; - - -/* w83793 */ -#define SENSORS_W83793_FEATURES_IN(nr) \ - { { SENSORS_W83793_IN(nr), "in" #nr, NOMAP, NOMAP, R }, \ - NOSYSCTL, VALUE(3), 3 }, \ - { { SENSORS_W83793_IN_MIN(nr), "in" #nr "_min", \ - SENSORS_W83793_IN(nr), SENSORS_W83793_IN(nr), RW }, \ - NOSYSCTL, VALUE(1), 3 }, \ - { { SENSORS_W83793_IN_MAX(nr), "in" #nr "_max", \ - SENSORS_W83793_IN(nr), SENSORS_W83793_IN(nr), RW }, \ - NOSYSCTL, VALUE(2), 3 }, \ - { { SENSORS_W83793_IN_ALARM(nr), "in" #nr "_alarm", \ - SENSORS_W83793_IN(nr), NOMAP, R}, \ - NOSYSCTL, VALUE(1), 0 } - -#define SENSORS_W83793_FEATURES_FAN(nr) \ - { { SENSORS_W83793_FAN(nr), "fan" #nr, NOMAP, NOMAP, R }, \ - NOSYSCTL, VALUE(2), 0 }, \ - { { SENSORS_W83793_FAN_MIN(nr), "fan" #nr "_min", \ - SENSORS_W83793_FAN(nr), SENSORS_W83793_FAN(nr), RW }, \ - NOSYSCTL, VALUE(1), 0 }, \ - { { SENSORS_W83793_FAN_ALARM(nr), "fan" #nr "_alarm", \ - SENSORS_W83793_FAN(nr), NOMAP, R }, \ - NOSYSCTL, VALUE(1), 0 } - -#define SENSORS_W83793_FEATURES_TEMP(nr) \ - { { SENSORS_W83793_TEMP(nr), "temp" #nr, NOMAP, NOMAP, R }, \ - NOSYSCTL, VALUE(3), 3 }, \ - { { SENSORS_W83793_TEMP_CRIT(nr), "temp" #nr "_max", \ - SENSORS_W83793_TEMP(nr), SENSORS_W83793_TEMP(nr), RW }, \ - NOSYSCTL, VALUE(1), 3 }, \ - { { SENSORS_W83793_TEMP_CRIT_HYST(nr), "temp" #nr "_max_hyst", \ - SENSORS_W83793_TEMP(nr), SENSORS_W83793_TEMP(nr), \ - RW }, \ - NOSYSCTL, VALUE(2), 3 }, \ - { { SENSORS_W83793_TEMP_ALARM(nr), "temp" #nr "_alarm", \ - SENSORS_W83793_TEMP(nr), NOMAP, R }, \ - NOSYSCTL, VALUE(1), 0 } - -/* No support for Linux 2.4 yet (sysctl) */ -static sensors_chip_feature w83793_features[] = -{ - SENSORS_W83793_FEATURES_IN(0), - SENSORS_W83793_FEATURES_IN(1), - SENSORS_W83793_FEATURES_IN(2), - SENSORS_W83793_FEATURES_IN(3), - SENSORS_W83793_FEATURES_IN(4), - SENSORS_W83793_FEATURES_IN(5), - SENSORS_W83793_FEATURES_IN(6), - SENSORS_W83793_FEATURES_IN(7), - SENSORS_W83793_FEATURES_IN(8), - SENSORS_W83793_FEATURES_IN(9), - SENSORS_W83793_FEATURES_FAN(1), - SENSORS_W83793_FEATURES_FAN(2), - SENSORS_W83793_FEATURES_FAN(3), - SENSORS_W83793_FEATURES_FAN(4), - SENSORS_W83793_FEATURES_FAN(5), - SENSORS_W83793_FEATURES_FAN(6), - SENSORS_W83793_FEATURES_FAN(7), - SENSORS_W83793_FEATURES_FAN(8), - SENSORS_W83793_FEATURES_FAN(9), - SENSORS_W83793_FEATURES_FAN(10), - SENSORS_W83793_FEATURES_FAN(11), - SENSORS_W83793_FEATURES_FAN(12), - SENSORS_W83793_FEATURES_TEMP(1), - SENSORS_W83793_FEATURES_TEMP(2), - SENSORS_W83793_FEATURES_TEMP(3), - SENSORS_W83793_FEATURES_TEMP(4), - SENSORS_W83793_FEATURES_TEMP(5), - SENSORS_W83793_FEATURES_TEMP(6), - { { SENSORS_W83793_VID0, "cpu0_vid", NOMAP, NOMAP, R }, - NOSYSCTL, VALUE(1), 3 }, - { { SENSORS_W83793_VID1, "cpu1_vid", NOMAP, NOMAP, R }, - NOSYSCTL, VALUE(1), 3 }, - { { SENSORS_W83793_VRM, "vrm", NOMAP, NOMAP, RW }, - NOSYSCTL, VALUE(1), 1 }, - { { SENSORS_W83793_CHASSIS, "chassis", NOMAP, NOMAP, RW }, - NOSYSCTL, VALUE(1), 0 }, - { { 0 }, 0 } -}; - - -static sensors_chip_feature w83l785ts_features[] = - { - { { SENSORS_W83L785TS_TEMP, "temp", NOMAP, NOMAP, R }, - W83L785TS_SYSCTL_TEMP, VALUE(2), 0 }, - { { SENSORS_W83L785TS_TEMP_OVER, "temp_over", SENSORS_W83L785TS_TEMP, - SENSORS_W83L785TS_TEMP, R }, - W83L785TS_SYSCTL_TEMP, VALUE(1), 0 }, - { { 0 }, 0 } - }; - -/* W83627DHG uses same structure excluding in9* */ -static sensors_chip_feature w83627ehf_features[] = - { - { { SENSORS_W83627EHF_IN0, "in0", NOMAP, NOMAP, R }, - W83627EHF_SYSCTL_IN0, VALUE(3), 3 }, - { { SENSORS_W83627EHF_IN1, "in1", NOMAP, NOMAP, R }, - W83627EHF_SYSCTL_IN1, VALUE(3), 3 }, - { { SENSORS_W83627EHF_IN2, "in2", NOMAP, NOMAP, R }, - W83627EHF_SYSCTL_IN2, VALUE(3), 3 }, - { { SENSORS_W83627EHF_IN3, "in3", NOMAP, NOMAP, R }, - W83627EHF_SYSCTL_IN3, VALUE(3), 3 }, - { { SENSORS_W83627EHF_IN4, "in4", NOMAP, NOMAP, R }, - W83627EHF_SYSCTL_IN4, VALUE(3), 3 }, - { { SENSORS_W83627EHF_IN5, "in5", NOMAP, NOMAP, R }, - W83627EHF_SYSCTL_IN5, VALUE(3), 3 }, - { { SENSORS_W83627EHF_IN6, "in6", NOMAP, NOMAP, R }, - W83627EHF_SYSCTL_IN6, VALUE(3), 3 }, - { { SENSORS_W83627EHF_IN7, "in7", NOMAP, NOMAP, R }, - W83627EHF_SYSCTL_IN7, VALUE(3), 3 }, - { { SENSORS_W83627EHF_IN8, "in8", NOMAP, NOMAP, R }, - W83627EHF_SYSCTL_IN8, VALUE(3), 3 }, - { { SENSORS_W83627EHF_IN9, "in9", NOMAP, NOMAP, R }, - W83627EHF_SYSCTL_IN9, VALUE(3), 3 }, - { { SENSORS_W83627EHF_IN0_ALARM, "in0_alarm", SENSORS_W83627EHF_IN0, NOMAP, - R }, - NOSYSCTL, VALUE(1), 0 }, - { { SENSORS_W83627EHF_IN1_ALARM, "in1_alarm", SENSORS_W83627EHF_IN1, NOMAP, - R }, - NOSYSCTL, VALUE(1), 0 }, - { { SENSORS_W83627EHF_IN2_ALARM, "in2_alarm", SENSORS_W83627EHF_IN2, NOMAP, - R }, - NOSYSCTL, VALUE(1), 0 }, - { { SENSORS_W83627EHF_IN3_ALARM, "in3_alarm", SENSORS_W83627EHF_IN3, NOMAP, - R }, - NOSYSCTL, VALUE(1), 0 }, - { { SENSORS_W83627EHF_IN4_ALARM, "in4_alarm", SENSORS_W83627EHF_IN4, NOMAP, - R }, - NOSYSCTL, VALUE(1), 0 }, - { { SENSORS_W83627EHF_IN5_ALARM, "in5_alarm", SENSORS_W83627EHF_IN5, NOMAP, - R }, - NOSYSCTL, VALUE(1), 0 }, - { { SENSORS_W83627EHF_IN6_ALARM, "in6_alarm", SENSORS_W83627EHF_IN6, NOMAP, - R }, - NOSYSCTL, VALUE(1), 0 }, - { { SENSORS_W83627EHF_IN7_ALARM, "in7_alarm", SENSORS_W83627EHF_IN7, NOMAP, - R }, - NOSYSCTL, VALUE(1), 0 }, - { { SENSORS_W83627EHF_IN8_ALARM, "in8_alarm", SENSORS_W83627EHF_IN8, NOMAP, - R }, - NOSYSCTL, VALUE(1), 0 }, - { { SENSORS_W83627EHF_IN9_ALARM, "in9_alarm", SENSORS_W83627EHF_IN9, NOMAP, - R }, - NOSYSCTL, VALUE(1), 0 }, - { { SENSORS_W83627EHF_IN0_MIN, "in0_min", SENSORS_W83627EHF_IN0, - SENSORS_W83627EHF_IN0, RW }, - W83627EHF_SYSCTL_IN0, VALUE(1), 3 }, - { { SENSORS_W83627EHF_IN1_MIN, "in1_min", SENSORS_W83627EHF_IN1, - SENSORS_W83627EHF_IN1, RW }, - W83627EHF_SYSCTL_IN1, VALUE(1), 3 }, - { { SENSORS_W83627EHF_IN2_MIN, "in2_min", SENSORS_W83627EHF_IN2, - SENSORS_W83627EHF_IN2, RW }, - W83627EHF_SYSCTL_IN2, VALUE(1), 3 }, - { { SENSORS_W83627EHF_IN3_MIN, "in3_min", SENSORS_W83627EHF_IN3, - SENSORS_W83627EHF_IN3, RW }, - W83627EHF_SYSCTL_IN3, VALUE(1), 3 }, - { { SENSORS_W83627EHF_IN4_MIN, "in4_min", SENSORS_W83627EHF_IN4, - SENSORS_W83627EHF_IN4, RW }, - W83627EHF_SYSCTL_IN4, VALUE(1), 3 }, - { { SENSORS_W83627EHF_IN5_MIN, "in5_min", SENSORS_W83627EHF_IN5, - SENSORS_W83627EHF_IN5, RW }, - W83627EHF_SYSCTL_IN5, VALUE(1), 3 }, - { { SENSORS_W83627EHF_IN6_MIN, "in6_min", SENSORS_W83627EHF_IN6, - SENSORS_W83627EHF_IN6, RW }, - W83627EHF_SYSCTL_IN6, VALUE(1), 3 }, - { { SENSORS_W83627EHF_IN7_MIN, "in7_min", SENSORS_W83627EHF_IN7, - SENSORS_W83627EHF_IN7, RW }, - W83627EHF_SYSCTL_IN7, VALUE(1), 3 }, - { { SENSORS_W83627EHF_IN8_MIN, "in8_min", SENSORS_W83627EHF_IN8, - SENSORS_W83627EHF_IN8, RW }, - W83627EHF_SYSCTL_IN8, VALUE(1), 3 }, - { { SENSORS_W83627EHF_IN9_MIN, "in9_min", SENSORS_W83627EHF_IN9, - SENSORS_W83627EHF_IN9, RW }, - W83627EHF_SYSCTL_IN9, VALUE(1), 3 }, - { { SENSORS_W83627EHF_IN0_MAX, "in0_max", SENSORS_W83627EHF_IN0, - SENSORS_W83627EHF_IN0, RW }, - W83627EHF_SYSCTL_IN0, VALUE(2), 3 }, - { { SENSORS_W83627EHF_IN1_MAX, "in1_max", SENSORS_W83627EHF_IN1, - SENSORS_W83627EHF_IN1, RW }, - W83627EHF_SYSCTL_IN1, VALUE(2), 3 }, - { { SENSORS_W83627EHF_IN2_MAX, "in2_max", SENSORS_W83627EHF_IN2, - SENSORS_W83627EHF_IN2, RW }, - W83627EHF_SYSCTL_IN2, VALUE(2), 3 }, - { { SENSORS_W83627EHF_IN3_MAX, "in3_max", SENSORS_W83627EHF_IN3, - SENSORS_W83627EHF_IN3, RW }, - W83627EHF_SYSCTL_IN3, VALUE(2), 3 }, - { { SENSORS_W83627EHF_IN4_MAX, "in4_max", SENSORS_W83627EHF_IN4, - SENSORS_W83627EHF_IN4, RW }, - W83627EHF_SYSCTL_IN4, VALUE(2), 3 }, - { { SENSORS_W83627EHF_IN5_MAX, "in5_max", SENSORS_W83627EHF_IN5, - SENSORS_W83627EHF_IN5, RW }, - W83627EHF_SYSCTL_IN5, VALUE(2), 3 }, - { { SENSORS_W83627EHF_IN6_MAX, "in6_max", SENSORS_W83627EHF_IN6, - SENSORS_W83627EHF_IN6, RW }, - W83627EHF_SYSCTL_IN6, VALUE(2), 3 }, - { { SENSORS_W83627EHF_IN7_MAX, "in7_max", SENSORS_W83627EHF_IN7, - SENSORS_W83627EHF_IN7, RW }, - W83627EHF_SYSCTL_IN7, VALUE(2), 3 }, - { { SENSORS_W83627EHF_IN8_MAX, "in8_max", SENSORS_W83627EHF_IN8, - SENSORS_W83627EHF_IN8, RW }, - W83627EHF_SYSCTL_IN8, VALUE(2), 3 }, - { { SENSORS_W83627EHF_IN9_MAX, "in9_max", SENSORS_W83627EHF_IN9, - SENSORS_W83627EHF_IN9, RW }, - W83627EHF_SYSCTL_IN9, VALUE(2), 3 }, - { { SENSORS_W83627EHF_FAN1, "fan1", NOMAP, NOMAP, R }, - W83627EHF_SYSCTL_FAN1, VALUE(2), 0 }, - { { SENSORS_W83627EHF_FAN2, "fan2", NOMAP, NOMAP, R }, - W83627EHF_SYSCTL_FAN2, VALUE(2), 0 }, - { { SENSORS_W83627EHF_FAN3, "fan3", NOMAP, NOMAP, R }, - W83627EHF_SYSCTL_FAN3, VALUE(2), 0 }, - { { SENSORS_W83627EHF_FAN4, "fan4", NOMAP, NOMAP, R }, - W83627EHF_SYSCTL_FAN4, VALUE(2), 0 }, - { { SENSORS_W83627EHF_FAN5, "fan5", NOMAP, NOMAP, R }, - W83627EHF_SYSCTL_FAN5, VALUE(2), 0 }, - { { SENSORS_W83627EHF_FAN1_ALARM, "fan1_alarm", SENSORS_W83627EHF_FAN1, - NOMAP, R }, - NOSYSCTL, VALUE(1), 0 }, - { { SENSORS_W83627EHF_FAN2_ALARM, "fan2_alarm", SENSORS_W83627EHF_FAN2, - NOMAP, R }, - NOSYSCTL, VALUE(1), 0 }, - { { SENSORS_W83627EHF_FAN3_ALARM, "fan3_alarm", SENSORS_W83627EHF_FAN3, - NOMAP, R }, - NOSYSCTL, VALUE(1), 0 }, - { { SENSORS_W83627EHF_FAN4_ALARM, "fan4_alarm", SENSORS_W83627EHF_FAN4, - NOMAP, R }, - NOSYSCTL, VALUE(1), 0 }, - { { SENSORS_W83627EHF_FAN5_ALARM, "fan5_alarm", SENSORS_W83627EHF_FAN5, - NOMAP, R }, - NOSYSCTL, VALUE(1), 0 }, - { { SENSORS_W83627EHF_FAN1_MIN, "fan1_min", SENSORS_W83627EHF_FAN1, - SENSORS_W83627EHF_FAN1, RW }, - W83627EHF_SYSCTL_FAN1, VALUE(1), 0 }, - { { SENSORS_W83627EHF_FAN2_MIN, "fan2_min", SENSORS_W83627EHF_FAN2, - SENSORS_W83627EHF_FAN2, RW }, - W83627EHF_SYSCTL_FAN2, VALUE(1), 0 }, - { { SENSORS_W83627EHF_FAN3_MIN, "fan3_min", SENSORS_W83627EHF_FAN3, - SENSORS_W83627EHF_FAN3, RW }, - W83627EHF_SYSCTL_FAN3, VALUE(1), 0 }, - { { SENSORS_W83627EHF_FAN4_MIN, "fan4_min", SENSORS_W83627EHF_FAN4, - SENSORS_W83627EHF_FAN4, RW }, - W83627EHF_SYSCTL_FAN4, VALUE(1), 0 }, - { { SENSORS_W83627EHF_FAN5_MIN, "fan5_min", SENSORS_W83627EHF_FAN5, - SENSORS_W83627EHF_FAN5, RW }, - W83627EHF_SYSCTL_FAN5, VALUE(1), 0 }, - { { SENSORS_W83627EHF_FAN1_DIV, "fan1_div", SENSORS_W83627EHF_FAN1, NOMAP, R }, - W83627EHF_SYSCTL_FAN_DIV, VALUE(1), 0 }, - { { SENSORS_W83627EHF_FAN2_DIV, "fan2_div", SENSORS_W83627EHF_FAN2, NOMAP, R }, - W83627EHF_SYSCTL_FAN_DIV, VALUE(2), 0 }, - { { SENSORS_W83627EHF_FAN3_DIV, "fan3_div", SENSORS_W83627EHF_FAN3, NOMAP, R }, - W83627EHF_SYSCTL_FAN_DIV, VALUE(3), 0 }, - { { SENSORS_W83627EHF_FAN4_DIV, "fan4_div", SENSORS_W83627EHF_FAN4, NOMAP, R }, - W83627EHF_SYSCTL_FAN_DIV, VALUE(4), 0 }, - { { SENSORS_W83627EHF_FAN5_DIV, "fan5_div", SENSORS_W83627EHF_FAN5, NOMAP, R }, - W83627EHF_SYSCTL_FAN_DIV, VALUE(5), 0 }, - { { SENSORS_W83627EHF_TEMP1, "temp1", NOMAP, NOMAP, R }, - W83627EHF_SYSCTL_TEMP1, VALUE(3), 1 }, - { { SENSORS_W83627EHF_TEMP2, "temp2", NOMAP, NOMAP, R }, - W83627EHF_SYSCTL_TEMP2, VALUE(3), 1 }, - { { SENSORS_W83627EHF_TEMP3, "temp3", NOMAP, NOMAP, R }, - W83627EHF_SYSCTL_TEMP3, VALUE(3), 1 }, - { { SENSORS_W83627EHF_TEMP1_ALARM, "temp1_alarm", SENSORS_W83627EHF_TEMP1, - NOMAP, R }, - NOSYSCTL, VALUE(1), 0 }, - { { SENSORS_W83627EHF_TEMP2_ALARM, "temp2_alarm", SENSORS_W83627EHF_TEMP2, - NOMAP, R }, - NOSYSCTL, VALUE(1), 0 }, - { { SENSORS_W83627EHF_TEMP3_ALARM, "temp3_alarm", SENSORS_W83627EHF_TEMP3, - NOMAP, R }, - NOSYSCTL, VALUE(1), 0 }, - { { SENSORS_W83627EHF_TEMP1_OVER, "temp1_over", SENSORS_W83627EHF_TEMP1, - SENSORS_W83627EHF_TEMP1, RW }, - W83627EHF_SYSCTL_TEMP1, VALUE(1), 1 }, - { { SENSORS_W83627EHF_TEMP2_OVER, "temp2_over", SENSORS_W83627EHF_TEMP2, - SENSORS_W83627EHF_TEMP2, RW }, - W83627EHF_SYSCTL_TEMP2, VALUE(1), 1 }, - { { SENSORS_W83627EHF_TEMP3_OVER, "temp3_over", SENSORS_W83627EHF_TEMP3, - SENSORS_W83627EHF_TEMP3, RW }, - W83627EHF_SYSCTL_TEMP3, VALUE(1), 1 }, - { { SENSORS_W83627EHF_TEMP1_HYST, "temp1_hyst", SENSORS_W83627EHF_TEMP1, - SENSORS_W83627EHF_TEMP1, RW }, - W83627EHF_SYSCTL_TEMP1, VALUE(2), 1 }, - { { SENSORS_W83627EHF_TEMP2_HYST, "temp2_hyst", SENSORS_W83627EHF_TEMP2, - SENSORS_W83627EHF_TEMP2, RW }, - W83627EHF_SYSCTL_TEMP2, VALUE(2), 1 }, - { { SENSORS_W83627EHF_TEMP3_HYST, "temp3_hyst", SENSORS_W83627EHF_TEMP3, - SENSORS_W83627EHF_TEMP3, RW }, - W83627EHF_SYSCTL_TEMP3, VALUE(2), 1 }, - { { SENSORS_W83627EHF_TEMP1_TYPE, "sensor1", SENSORS_W83627EHF_TEMP1, - NOMAP, R }, - W83627EHF_SYSCTL_SENSOR1, VALUE(1), 0 }, - { { SENSORS_W83627EHF_TEMP2_TYPE, "sensor2", SENSORS_W83627EHF_TEMP2, - NOMAP, R }, - W83627EHF_SYSCTL_SENSOR2, VALUE(1), 0 }, - { { SENSORS_W83627EHF_TEMP3_TYPE, "sensor3", SENSORS_W83627EHF_TEMP3, - NOMAP, R }, - W83627EHF_SYSCTL_SENSOR3, VALUE(1), 0 }, - { { SENSORS_W83627EHF_VID, "vid", NOMAP, NOMAP, R }, - W83627EHF_SYSCTL_VID, VALUE(1), 3 }, - { { SENSORS_W83627EHF_VRM, "vrm", NOMAP, NOMAP, RW }, - W83627EHF_SYSCTL_VRM, VALUE(1), 1 }, - { { SENSORS_W83627EHF_ALARMS, "alarms", NOMAP, NOMAP, R }, - W83627EHF_SYSCTL_ALARMS, VALUE(1), 0 }, - { { 0 }, 0 } - }; - -static sensors_chip_feature adm9240_features[] = - { - { { SENSORS_ADM9240_IN0, "2.5V", NOMAP, NOMAP, R }, - ADM9240_SYSCTL_IN0, VALUE(3), 2, "in0_input", 3 }, - { { SENSORS_ADM9240_IN1, "Vccp1", NOMAP, NOMAP, R }, - ADM9240_SYSCTL_IN1, VALUE(3), 2, "in1_input", 3 }, - { { SENSORS_ADM9240_IN2, "3.3V", NOMAP, NOMAP, R }, - ADM9240_SYSCTL_IN2, VALUE(3), 2, "in2_input", 3 }, - { { SENSORS_ADM9240_IN3, "5V", NOMAP, NOMAP, R }, - ADM9240_SYSCTL_IN3, VALUE(3), 2, "in3_input", 3 }, - { { SENSORS_ADM9240_IN4, "12V", NOMAP, NOMAP, R }, - ADM9240_SYSCTL_IN4, VALUE(3), 2, "in4_input", 3 }, - { { SENSORS_ADM9240_IN5, "Vccp2", NOMAP, NOMAP, R }, - ADM9240_SYSCTL_IN5, VALUE(3), 2, "in5_input", 3 }, - { { SENSORS_ADM9240_IN0_MIN, "2.5V_min", SENSORS_ADM9240_IN0, - SENSORS_ADM9240_IN0, RW }, - ADM9240_SYSCTL_IN0, VALUE(1), 2, "in0_min", 3 }, - { { SENSORS_ADM9240_IN1_MIN, "Vccp1_min", SENSORS_ADM9240_IN1, - SENSORS_ADM9240_IN1, RW }, - ADM9240_SYSCTL_IN1, VALUE(1), 2, "in1_min", 3 }, - { { SENSORS_ADM9240_IN2_MIN, "3.3V_min", SENSORS_ADM9240_IN2, - SENSORS_ADM9240_IN2, RW }, - ADM9240_SYSCTL_IN2, VALUE(1), 2, "in2_min", 3 }, - { { SENSORS_ADM9240_IN3_MIN, "5V_min", SENSORS_ADM9240_IN3, - SENSORS_ADM9240_IN3, RW }, - ADM9240_SYSCTL_IN3, VALUE(1), 2, "in3_min", 3 }, - { { SENSORS_ADM9240_IN4_MIN, "12V_min", SENSORS_ADM9240_IN4, - SENSORS_ADM9240_IN4, RW }, - ADM9240_SYSCTL_IN4, VALUE(1), 2, "in4_min", 3 }, - { { SENSORS_ADM9240_IN5_MIN, "Vccp2_min", SENSORS_ADM9240_IN5, - SENSORS_ADM9240_IN5, RW }, - ADM9240_SYSCTL_IN5, VALUE(1), 2, "in5_min", 3 }, - { { SENSORS_ADM9240_IN0_MAX, "2.5V_max", SENSORS_ADM9240_IN0, - SENSORS_ADM9240_IN0, RW }, - ADM9240_SYSCTL_IN0, VALUE(2), 2, "in0_max", 3 }, - { { SENSORS_ADM9240_IN1_MAX, "Vccp1_max", SENSORS_ADM9240_IN1, - SENSORS_ADM9240_IN1, RW }, - ADM9240_SYSCTL_IN1, VALUE(2), 2, "in1_max", 3 }, - { { SENSORS_ADM9240_IN2_MAX, "3.3V_max", SENSORS_ADM9240_IN2, - SENSORS_ADM9240_IN2, RW }, - ADM9240_SYSCTL_IN2, VALUE(2), 2, "in2_max", 3 }, - { { SENSORS_ADM9240_IN3_MAX, "5V_max", SENSORS_ADM9240_IN3, - SENSORS_ADM9240_IN3, RW }, - ADM9240_SYSCTL_IN3, VALUE(2), 2, "in3_max", 3 }, - { { SENSORS_ADM9240_IN4_MAX, "12V_max", SENSORS_ADM9240_IN4, - SENSORS_ADM9240_IN4, RW }, - ADM9240_SYSCTL_IN4, VALUE(2), 2, "in4_max", 3 }, - { { SENSORS_ADM9240_IN5_MAX, "Vccp2_max", SENSORS_ADM9240_IN5, - SENSORS_ADM9240_IN5, RW }, - ADM9240_SYSCTL_IN5, VALUE(2), 2, "in5_max", 3 }, - { { SENSORS_ADM9240_FAN1, "fan1", NOMAP, NOMAP, R }, - ADM9240_SYSCTL_FAN1, VALUE(2), 0 }, - { { SENSORS_ADM9240_FAN2, "fan2", NOMAP, NOMAP, R }, - ADM9240_SYSCTL_FAN2, VALUE(2), 0 }, - { { SENSORS_ADM9240_FAN1_MIN, "fan1_min", SENSORS_ADM9240_FAN1, - SENSORS_ADM9240_FAN1, RW }, - ADM9240_SYSCTL_FAN1, VALUE(1), 0 }, - { { SENSORS_ADM9240_FAN2_MIN, "fan2_min", SENSORS_ADM9240_FAN2, - SENSORS_ADM9240_FAN2, RW }, - ADM9240_SYSCTL_FAN2, VALUE(1), 0 }, - { { SENSORS_ADM9240_TEMP, "temp", NOMAP, NOMAP, R }, - ADM9240_SYSCTL_TEMP, VALUE(3), 1 }, - { { SENSORS_ADM9240_TEMP_HYST, "temp_hyst", SENSORS_ADM9240_TEMP, - SENSORS_ADM9240_TEMP, RW }, - ADM9240_SYSCTL_TEMP, VALUE(2), 1 }, - { { SENSORS_ADM9240_TEMP_OVER, "temp_over", SENSORS_ADM9240_TEMP, - SENSORS_ADM9240_TEMP, RW }, - ADM9240_SYSCTL_TEMP, VALUE(1), 1 }, - { { SENSORS_ADM9240_VID, "vid", NOMAP, NOMAP, R }, - ADM9240_SYSCTL_VID, VALUE(1), 2 }, - { { SENSORS_ADM9240_FAN1_DIV, "fan1_div", SENSORS_ADM9240_FAN1, NOMAP, RW }, - ADM9240_SYSCTL_FAN_DIV, VALUE(1), 0 }, - { { SENSORS_ADM9240_FAN2_DIV, "fan2_div", SENSORS_ADM9240_FAN2, NOMAP, RW }, - ADM9240_SYSCTL_FAN_DIV, VALUE(2), 0 }, - { { SENSORS_ADM9240_ALARMS, "alarms", NOMAP, NOMAP, R }, - ADM9240_SYSCTL_ALARMS, VALUE(1), 0 }, - { { SENSORS_ADM9240_ANALOG_OUT, "analog_out", NOMAP, NOMAP, RW }, - ADM9240_SYSCTL_ANALOG_OUT, VALUE(1), 0, - "aout_output", 3 }, - { { 0 }, 0 } - }; - -static sensors_chip_feature adm1024_features[] = - { - { { SENSORS_ADM1024_IN0, "2.5V", NOMAP, NOMAP, R }, - ADM1024_SYSCTL_IN0, VALUE(3), 2, "in0_input", 3 }, - { { SENSORS_ADM1024_IN1, "Vccp1", NOMAP, NOMAP, R }, - ADM1024_SYSCTL_IN1, VALUE(3), 2, "in1_input", 3 }, - { { SENSORS_ADM1024_IN2, "3.3V", NOMAP, NOMAP, R }, - ADM1024_SYSCTL_IN2, VALUE(3), 2, "in2_input", 3 }, - { { SENSORS_ADM1024_IN3, "5V", NOMAP, NOMAP, R }, - ADM1024_SYSCTL_IN3, VALUE(3), 2, "in3_input", 3 }, - { { SENSORS_ADM1024_IN4, "12V", NOMAP, NOMAP, R }, - ADM1024_SYSCTL_IN4, VALUE(3), 2, "in4_input", 3 }, - { { SENSORS_ADM1024_IN5, "Vccp2", NOMAP, NOMAP, R }, - ADM1024_SYSCTL_IN5, VALUE(3), 2, "in5_input", 3 }, - { { SENSORS_ADM1024_IN0_MIN, "2.5V_min", SENSORS_ADM1024_IN0, - SENSORS_ADM1024_IN0, RW }, - ADM1024_SYSCTL_IN0, VALUE(1), 2, "in0_min", 3 }, - { { SENSORS_ADM1024_IN1_MIN, "Vccp1_min", SENSORS_ADM1024_IN1, - SENSORS_ADM1024_IN1, RW }, - ADM1024_SYSCTL_IN1, VALUE(1), 2, "in1_min", 3 }, - { { SENSORS_ADM1024_IN2_MIN, "3.3V_min", SENSORS_ADM1024_IN2, - SENSORS_ADM1024_IN2, RW }, - ADM1024_SYSCTL_IN2, VALUE(1), 2, "in2_min", 3 }, - { { SENSORS_ADM1024_IN3_MIN, "5V_min", SENSORS_ADM1024_IN3, - SENSORS_ADM1024_IN3, RW }, - ADM1024_SYSCTL_IN3, VALUE(1), 2, "in3_min", 3 }, - { { SENSORS_ADM1024_IN4_MIN, "12V_min", SENSORS_ADM1024_IN4, - SENSORS_ADM1024_IN4, RW }, - ADM1024_SYSCTL_IN4, VALUE(1), 2, "in4_min", 3 }, - { { SENSORS_ADM1024_IN5_MIN, "Vccp2_min", SENSORS_ADM1024_IN5, - SENSORS_ADM1024_IN5, RW }, - ADM1024_SYSCTL_IN5, VALUE(1), 2, "in5_min", 3 }, - { { SENSORS_ADM1024_IN0_MAX, "2.5V_max", SENSORS_ADM1024_IN0, - SENSORS_ADM1024_IN0, RW }, - ADM1024_SYSCTL_IN0, VALUE(2), 2, "in0_max", 3 }, - { { SENSORS_ADM1024_IN1_MAX, "Vccp1_max", SENSORS_ADM1024_IN1, - SENSORS_ADM1024_IN1, RW }, - ADM1024_SYSCTL_IN1, VALUE(2), 2, "in1_max", 3 }, - { { SENSORS_ADM1024_IN2_MAX, "3.3V_max", SENSORS_ADM1024_IN2, - SENSORS_ADM1024_IN2, RW }, - ADM1024_SYSCTL_IN2, VALUE(2), 2, "in2_max", 3 }, - { { SENSORS_ADM1024_IN3_MAX, "5V_max", SENSORS_ADM1024_IN3, - SENSORS_ADM1024_IN3, RW }, - ADM1024_SYSCTL_IN3, VALUE(2), 2, "in3_max", 3 }, - { { SENSORS_ADM1024_IN4_MAX, "12V_max", SENSORS_ADM1024_IN4, - SENSORS_ADM1024_IN4, RW }, - ADM1024_SYSCTL_IN4, VALUE(2), 2, "in4_max", 3 }, - { { SENSORS_ADM1024_IN5_MAX, "Vccp2_max", SENSORS_ADM1024_IN5, - SENSORS_ADM1024_IN5, RW }, - ADM1024_SYSCTL_IN5, VALUE(2), 2, "in5_max", 3 }, - { { SENSORS_ADM1024_FAN1, "fan1", NOMAP, NOMAP, R }, - ADM1024_SYSCTL_FAN1, VALUE(2), 0 }, - { { SENSORS_ADM1024_FAN2, "fan2", NOMAP, NOMAP, R }, - ADM1024_SYSCTL_FAN2, VALUE(2), 0 }, - { { SENSORS_ADM1024_FAN1_MIN, "fan1_min", SENSORS_ADM1024_FAN1, - SENSORS_ADM1024_FAN1, RW }, - ADM1024_SYSCTL_FAN1, VALUE(1), 0 }, - { { SENSORS_ADM1024_FAN2_MIN, "fan2_min", SENSORS_ADM1024_FAN2, - SENSORS_ADM1024_FAN2, RW }, - ADM1024_SYSCTL_FAN2, VALUE(1), 0 }, - { { SENSORS_ADM1024_TEMP, "temp", NOMAP, NOMAP, R }, - ADM1024_SYSCTL_TEMP, VALUE(3), 1 }, - { { SENSORS_ADM1024_TEMP1, "temp1", NOMAP, NOMAP, R }, - ADM1024_SYSCTL_TEMP1, VALUE(3), 1, "temp2_input", 3 }, - { { SENSORS_ADM1024_TEMP2, "temp2", NOMAP, NOMAP, R }, - ADM1024_SYSCTL_TEMP2, VALUE(3), 1, "temp3_input", 3 }, - { { SENSORS_ADM1024_TEMP_HYST, "temp_hyst", SENSORS_ADM1024_TEMP, - SENSORS_ADM1024_TEMP, RW }, - ADM1024_SYSCTL_TEMP, VALUE(2), 1, "temp1_min", 3 }, - { { SENSORS_ADM1024_TEMP_OVER, "temp_over", SENSORS_ADM1024_TEMP, - SENSORS_ADM1024_TEMP, RW }, - ADM1024_SYSCTL_TEMP, VALUE(1), 1 }, - { { SENSORS_ADM1024_TEMP1_HYST, "temp1_hyst", SENSORS_ADM1024_TEMP1, - SENSORS_ADM1024_TEMP1, RW }, - ADM1024_SYSCTL_TEMP1, VALUE(2), 1, "temp2_min", 3 }, - { { SENSORS_ADM1024_TEMP1_OVER, "temp1_over", SENSORS_ADM1024_TEMP1, - SENSORS_ADM1024_TEMP1, RW }, - ADM1024_SYSCTL_TEMP1, VALUE(1), 1, "temp2_max", 3 }, - { { SENSORS_ADM1024_TEMP2_HYST, "temp2_hyst", SENSORS_ADM1024_TEMP2, - SENSORS_ADM1024_TEMP2, RW }, - ADM1024_SYSCTL_TEMP2, VALUE(2), 1, "temp3_min", 3 }, - { { SENSORS_ADM1024_TEMP2_OVER, "temp2_over", SENSORS_ADM1024_TEMP2, - SENSORS_ADM1024_TEMP2, RW }, - ADM1024_SYSCTL_TEMP2, VALUE(1), 1, "temp3_max", 3 }, - { { SENSORS_ADM1024_VID, "vid", NOMAP, NOMAP, R }, - ADM1024_SYSCTL_VID, VALUE(1), 2 }, - { { SENSORS_ADM1024_FAN1_DIV, "fan1_div", SENSORS_ADM1024_FAN1, NOMAP, RW }, - ADM1024_SYSCTL_FAN_DIV, VALUE(1), 0 }, - { { SENSORS_ADM1024_FAN2_DIV, "fan2_div", SENSORS_ADM1024_FAN2, NOMAP, RW }, - ADM1024_SYSCTL_FAN_DIV, VALUE(2), 0 }, - { { SENSORS_ADM1024_ALARMS, "alarms", NOMAP, NOMAP, R }, - ADM1024_SYSCTL_ALARMS, VALUE(1), 0 }, - { { SENSORS_ADM1024_ANALOG_OUT, "analog_out", NOMAP, NOMAP, RW }, - ADM1024_SYSCTL_ANALOG_OUT, VALUE(1), 0 }, - { { 0 }, 0 } - }; - -static sensors_chip_feature sis5595_features[] = - { - { { SENSORS_SIS5595_IN0, "in0", NOMAP, NOMAP, R }, - SIS5595_SYSCTL_IN0, VALUE(3), 2 }, - { { SENSORS_SIS5595_IN1, "in1", NOMAP, NOMAP, R }, - SIS5595_SYSCTL_IN1, VALUE(3), 2 }, - { { SENSORS_SIS5595_IN2, "in2", NOMAP, NOMAP, R }, - SIS5595_SYSCTL_IN2, VALUE(3), 2 }, - { { SENSORS_SIS5595_IN3, "in3", NOMAP, NOMAP, R }, - SIS5595_SYSCTL_IN3, VALUE(3), 2 }, - { { SENSORS_SIS5595_IN4, "in4", NOMAP, NOMAP, R }, - SIS5595_SYSCTL_IN4, VALUE(3), 2 }, - { { SENSORS_SIS5595_IN0_MIN, "in0_min", SENSORS_SIS5595_IN0, - SENSORS_SIS5595_IN0, RW }, - SIS5595_SYSCTL_IN0, VALUE(1), 2 }, - { { SENSORS_SIS5595_IN1_MIN, "in1_min", SENSORS_SIS5595_IN1, - SENSORS_SIS5595_IN1, RW }, - SIS5595_SYSCTL_IN1, VALUE(1), 2 }, - { { SENSORS_SIS5595_IN2_MIN, "in2_min", SENSORS_SIS5595_IN2, - SENSORS_SIS5595_IN2, RW }, - SIS5595_SYSCTL_IN2, VALUE(1), 2 }, - { { SENSORS_SIS5595_IN3_MIN, "in3_min", SENSORS_SIS5595_IN3, - SENSORS_SIS5595_IN3, RW }, - SIS5595_SYSCTL_IN3, VALUE(1), 2 }, - { { SENSORS_SIS5595_IN4_MIN, "in4_min", SENSORS_SIS5595_IN4, - SENSORS_SIS5595_IN4, RW }, - SIS5595_SYSCTL_IN4, VALUE(1), 2 }, - { { SENSORS_SIS5595_IN0_MAX, "in0_max", SENSORS_SIS5595_IN0, - SENSORS_SIS5595_IN0, RW }, - SIS5595_SYSCTL_IN0, VALUE(2), 2 }, - { { SENSORS_SIS5595_IN1_MAX, "in1_max", SENSORS_SIS5595_IN1, - SENSORS_SIS5595_IN1, RW }, - SIS5595_SYSCTL_IN1, VALUE(2), 2 }, - { { SENSORS_SIS5595_IN2_MAX, "in2_max", SENSORS_SIS5595_IN2, - SENSORS_SIS5595_IN2, RW }, - SIS5595_SYSCTL_IN2, VALUE(2), 2 }, - { { SENSORS_SIS5595_IN3_MAX, "in3_max", SENSORS_SIS5595_IN3, - SENSORS_SIS5595_IN3, RW }, - SIS5595_SYSCTL_IN3, VALUE(2), 2 }, - { { SENSORS_SIS5595_IN4_MAX, "in4_max", SENSORS_SIS5595_IN4, - SENSORS_SIS5595_IN4, RW }, - SIS5595_SYSCTL_IN4, VALUE(2), 2 }, - { { SENSORS_SIS5595_FAN1, "fan1", NOMAP, NOMAP, R }, - SIS5595_SYSCTL_FAN1, VALUE(2), 0 }, - { { SENSORS_SIS5595_FAN2, "fan2", NOMAP, NOMAP, R }, - SIS5595_SYSCTL_FAN2, VALUE(2), 0 }, - { { SENSORS_SIS5595_FAN1_MIN, "fan1_min", SENSORS_SIS5595_FAN1, - SENSORS_SIS5595_FAN1, RW }, - SIS5595_SYSCTL_FAN1, VALUE(1), 0 }, - { { SENSORS_SIS5595_FAN2_MIN, "fan2_min", SENSORS_SIS5595_FAN2, - SENSORS_SIS5595_FAN2, RW }, - SIS5595_SYSCTL_FAN2, VALUE(1), 0 }, - { { SENSORS_SIS5595_TEMP, "temp", NOMAP, NOMAP, R }, - SIS5595_SYSCTL_TEMP, VALUE(3), 1 }, - { { SENSORS_SIS5595_TEMP_HYST, "temp_hyst", SENSORS_SIS5595_TEMP, - SENSORS_SIS5595_TEMP, RW }, - SIS5595_SYSCTL_TEMP, VALUE(2), 1 }, - { { SENSORS_SIS5595_TEMP_OVER, "temp_over", SENSORS_SIS5595_TEMP, - SENSORS_SIS5595_TEMP, RW }, - SIS5595_SYSCTL_TEMP, VALUE(1), 1 }, - { { SENSORS_SIS5595_FAN1_DIV, "fan1_div", SENSORS_SIS5595_FAN1, NOMAP, RW }, - SIS5595_SYSCTL_FAN_DIV, VALUE(1), 0 }, - { { SENSORS_SIS5595_FAN2_DIV, "fan2_div", SENSORS_SIS5595_FAN2, NOMAP, RW }, - SIS5595_SYSCTL_FAN_DIV, VALUE(2), 0 }, - { { SENSORS_SIS5595_ALARMS, "alarms", NOMAP, NOMAP, R }, - SIS5595_SYSCTL_ALARMS, VALUE(1), 0 }, - { { 0 }, 0 } - }; - -static sensors_chip_feature maxi_cg_features[] = - { - { { SENSORS_MAXI_CG_FAN1, "fan1", NOMAP, NOMAP, R }, - MAXI_SYSCTL_FAN1, VALUE(3), 0 }, - { { SENSORS_MAXI_CG_FAN2, "fan2", NOMAP, NOMAP, R }, - MAXI_SYSCTL_FAN2, VALUE(3), 0 }, - { { SENSORS_MAXI_CG_FAN3, "fan3", NOMAP, NOMAP, R }, - MAXI_SYSCTL_FAN3, VALUE(3), 0 }, - { { SENSORS_MAXI_CG_FAN1_MIN, "fan1_min", SENSORS_MAXI_CG_FAN1, - SENSORS_MAXI_CG_FAN1, RW }, - MAXI_SYSCTL_FAN1, VALUE(1), 0 }, - { { SENSORS_MAXI_CG_FAN2_MIN, "fan2_min", SENSORS_MAXI_CG_FAN2, - SENSORS_MAXI_CG_FAN2, RW }, - MAXI_SYSCTL_FAN2, VALUE(1), 0 }, - { { SENSORS_MAXI_CG_FAN3_MIN, "fan3_min", SENSORS_MAXI_CG_FAN3, - SENSORS_MAXI_CG_FAN3, RW }, - MAXI_SYSCTL_FAN3, VALUE(1), 0 }, - { { SENSORS_MAXI_CG_FAN1_DIV, "fan1_div", SENSORS_MAXI_CG_FAN1, NOMAP, R }, - MAXI_SYSCTL_FAN1, VALUE(2), 0 }, - { { SENSORS_MAXI_CG_FAN2_DIV, "fan2_div", SENSORS_MAXI_CG_FAN2, NOMAP, R }, - MAXI_SYSCTL_FAN2, VALUE(2), 0 }, - { { SENSORS_MAXI_CG_FAN3_DIV, "fan3_div", SENSORS_MAXI_CG_FAN3, NOMAP, R }, - MAXI_SYSCTL_FAN3, VALUE(2), 0 }, - { { SENSORS_MAXI_CG_TEMP1, "temp1", NOMAP, NOMAP, R }, - MAXI_SYSCTL_TEMP1, VALUE(3), 1 }, - { { SENSORS_MAXI_CG_TEMP2, "temp2", NOMAP, NOMAP, R }, - MAXI_SYSCTL_TEMP2, VALUE(3), 1 }, - { { SENSORS_MAXI_CG_TEMP3, "temp3", NOMAP, NOMAP, R }, - MAXI_SYSCTL_TEMP3, VALUE(3), 1 }, - { { SENSORS_MAXI_CG_TEMP4, "temp4", NOMAP, NOMAP, R }, - MAXI_SYSCTL_TEMP4, VALUE(3), 1 }, - { { SENSORS_MAXI_CG_TEMP5, "temp5", NOMAP, NOMAP, R }, - MAXI_SYSCTL_TEMP5, VALUE(3), 1 }, - { { SENSORS_MAXI_CG_TEMP1_MAX, "temp1_max", SENSORS_MAXI_CG_TEMP1, - SENSORS_MAXI_CG_TEMP1, R }, - MAXI_SYSCTL_TEMP1, VALUE(1), 1 }, - { { SENSORS_MAXI_CG_TEMP2_MAX, "temp2_max", SENSORS_MAXI_CG_TEMP2, - SENSORS_MAXI_CG_TEMP2, R }, - MAXI_SYSCTL_TEMP2, VALUE(1), 1 }, - { { SENSORS_MAXI_CG_TEMP3_MAX, "temp3_max", SENSORS_MAXI_CG_TEMP3, - SENSORS_MAXI_CG_TEMP3, R }, - MAXI_SYSCTL_TEMP3, VALUE(1), 1 }, - { { SENSORS_MAXI_CG_TEMP4_MAX, "temp4_max", SENSORS_MAXI_CG_TEMP4, - SENSORS_MAXI_CG_TEMP4, R }, - MAXI_SYSCTL_TEMP4, VALUE(1), 1 }, - { { SENSORS_MAXI_CG_TEMP5_MAX, "temp5_max", SENSORS_MAXI_CG_TEMP5, - SENSORS_MAXI_CG_TEMP5, R }, - MAXI_SYSCTL_TEMP5, VALUE(1), 1 }, - { { SENSORS_MAXI_CG_TEMP1_HYST, "temp1_hyst", SENSORS_MAXI_CG_TEMP1, - SENSORS_MAXI_CG_TEMP1, R }, - MAXI_SYSCTL_TEMP1, VALUE(2), 1 }, - { { SENSORS_MAXI_CG_TEMP2_HYST, "temp2_hyst", SENSORS_MAXI_CG_TEMP2, - SENSORS_MAXI_CG_TEMP2, R }, - MAXI_SYSCTL_TEMP2, VALUE(2), 1 }, - { { SENSORS_MAXI_CG_TEMP3_HYST, "temp3_hyst", SENSORS_MAXI_CG_TEMP3, - SENSORS_MAXI_CG_TEMP3, R }, - MAXI_SYSCTL_TEMP3, VALUE(2), 1 }, - { { SENSORS_MAXI_CG_TEMP4_HYST, "temp4_hyst", SENSORS_MAXI_CG_TEMP4, - SENSORS_MAXI_CG_TEMP4, R }, - MAXI_SYSCTL_TEMP4, VALUE(2), 1 }, - { { SENSORS_MAXI_CG_TEMP5_HYST, "temp5_hyst", SENSORS_MAXI_CG_TEMP5, - SENSORS_MAXI_CG_TEMP5, R }, - MAXI_SYSCTL_TEMP5, VALUE(2), 1 }, - { { SENSORS_MAXI_CG_PLL, "pll", NOMAP, NOMAP, R }, - MAXI_SYSCTL_PLL, VALUE(3), 2 }, - { { SENSORS_MAXI_CG_PLL_MIN, "pll_min", SENSORS_MAXI_CG_PLL, - SENSORS_MAXI_CG_PLL, RW }, - MAXI_SYSCTL_PLL, VALUE(1), 2 }, - { { SENSORS_MAXI_CG_PLL_MAX, "pll_max", SENSORS_MAXI_CG_PLL, - SENSORS_MAXI_CG_PLL, RW }, - MAXI_SYSCTL_PLL, VALUE(2), 2 }, - { { SENSORS_MAXI_CG_VID1, "vid1", NOMAP, NOMAP, R }, - MAXI_SYSCTL_VID1, VALUE(3), 4, "in0_input", 3 }, - { { SENSORS_MAXI_CG_VID2, "vid2", NOMAP, NOMAP, R }, - MAXI_SYSCTL_VID2, VALUE(3), 4, "in1_input", 3 }, - { { SENSORS_MAXI_CG_VID3, "vid3", NOMAP, NOMAP, R }, - MAXI_SYSCTL_VID3, VALUE(3), 4, "in2_input", 3 }, - { { SENSORS_MAXI_CG_VID4, "vid4", NOMAP, NOMAP, R }, - MAXI_SYSCTL_VID4, VALUE(3), 4, "in3_input", 3 }, - { { SENSORS_MAXI_CG_VID1_MIN, "vid1_min", SENSORS_MAXI_CG_VID1, - SENSORS_MAXI_CG_VID1, RW }, - MAXI_SYSCTL_VID1, VALUE(1), 4, "in0_min", 3 }, - { { SENSORS_MAXI_CG_VID2_MIN, "vid2_min", SENSORS_MAXI_CG_VID2, - SENSORS_MAXI_CG_VID2, RW }, - MAXI_SYSCTL_VID2, VALUE(1), 4, "in1_min", 3 }, - { { SENSORS_MAXI_CG_VID3_MIN, "vid3_min", SENSORS_MAXI_CG_VID3, - SENSORS_MAXI_CG_VID3, RW }, - MAXI_SYSCTL_VID3, VALUE(1), 4, "in2_min", 3 }, - { { SENSORS_MAXI_CG_VID4_MIN, "vid4_min", SENSORS_MAXI_CG_VID4, - SENSORS_MAXI_CG_VID4, RW }, - MAXI_SYSCTL_VID4, VALUE(1), 4, "in3_min", 3 }, - { { SENSORS_MAXI_CG_VID1_MAX, "vid1_max", SENSORS_MAXI_CG_VID1, - SENSORS_MAXI_CG_VID1, RW }, - MAXI_SYSCTL_VID1, VALUE(2), 4, "in0_max", 3 }, - { { SENSORS_MAXI_CG_VID2_MAX, "vid2_max", SENSORS_MAXI_CG_VID2, - SENSORS_MAXI_CG_VID2, RW }, - MAXI_SYSCTL_VID2, VALUE(2), 4, "in1_max", 3 }, - { { SENSORS_MAXI_CG_VID3_MAX, "vid3_max", SENSORS_MAXI_CG_VID3, - SENSORS_MAXI_CG_VID3, RW }, - MAXI_SYSCTL_VID3, VALUE(2), 4, "in2_max", 3 }, - { { SENSORS_MAXI_CG_VID4_MAX, "vid4_max", SENSORS_MAXI_CG_VID4, - SENSORS_MAXI_CG_VID4, RW }, - MAXI_SYSCTL_VID4, VALUE(2), 4, "in3_max", 3 }, - { { SENSORS_MAXI_CG_ALARMS, "alarms", NOMAP, NOMAP, R }, - MAXI_SYSCTL_ALARMS, VALUE(1), 0 }, - { { 0 }, 0 } - }; - -static sensors_chip_feature maxi_co_features[] = - { - { { SENSORS_MAXI_CO_FAN1, "fan1", NOMAP, NOMAP, R }, - MAXI_SYSCTL_FAN1, VALUE(3), 0 }, - { { SENSORS_MAXI_CO_FAN2, "fan2", NOMAP, NOMAP, R }, - MAXI_SYSCTL_FAN2, VALUE(3), 0 }, - { { SENSORS_MAXI_CO_FAN3, "fan3", NOMAP, NOMAP, R }, - MAXI_SYSCTL_FAN3, VALUE(3), 0 }, - { { SENSORS_MAXI_CO_FAN1_MIN, "fan1_min", SENSORS_MAXI_CO_FAN1, - SENSORS_MAXI_CO_FAN1, RW }, - MAXI_SYSCTL_FAN1, VALUE(1), 0 }, - { { SENSORS_MAXI_CO_FAN2_MIN, "fan2_min", SENSORS_MAXI_CO_FAN2, - SENSORS_MAXI_CO_FAN2, RW }, - MAXI_SYSCTL_FAN2, VALUE(1), 0 }, - { { SENSORS_MAXI_CO_FAN3_MIN, "fan3_min", SENSORS_MAXI_CO_FAN3, - SENSORS_MAXI_CO_FAN3, RW }, - MAXI_SYSCTL_FAN3, VALUE(1), 0 }, - { { SENSORS_MAXI_CO_FAN1_DIV, "fan1_div", SENSORS_MAXI_CO_FAN1, NOMAP, R }, - MAXI_SYSCTL_FAN1, VALUE(2), 0 }, - { { SENSORS_MAXI_CO_FAN2_DIV, "fan2_div", SENSORS_MAXI_CO_FAN2, NOMAP, R }, - MAXI_SYSCTL_FAN2, VALUE(2), 0 }, - { { SENSORS_MAXI_CO_FAN3_DIV, "fan3_div", SENSORS_MAXI_CO_FAN3, NOMAP, R }, - MAXI_SYSCTL_FAN3, VALUE(2), 0 }, - { { SENSORS_MAXI_CO_TEMP1, "temp1", NOMAP, NOMAP, R }, - MAXI_SYSCTL_TEMP1, VALUE(3), 1 }, - { { SENSORS_MAXI_CO_TEMP2, "temp2", NOMAP, NOMAP, R }, - MAXI_SYSCTL_TEMP2, VALUE(3), 1 }, - { { SENSORS_MAXI_CO_TEMP3, "temp3", NOMAP, NOMAP, R }, - MAXI_SYSCTL_TEMP3, VALUE(3), 1 }, - { { SENSORS_MAXI_CO_TEMP4, "temp4", NOMAP, NOMAP, R }, - MAXI_SYSCTL_TEMP4, VALUE(3), 1 }, - { { SENSORS_MAXI_CO_TEMP5, "temp5", NOMAP, NOMAP, R }, - MAXI_SYSCTL_TEMP5, VALUE(3), 1 }, - { { SENSORS_MAXI_CO_TEMP1_MAX, "temp1_max", SENSORS_MAXI_CO_TEMP1, - SENSORS_MAXI_CO_TEMP1, R }, - MAXI_SYSCTL_TEMP1, VALUE(1), 1 }, - { { SENSORS_MAXI_CO_TEMP2_MAX, "temp2_max", SENSORS_MAXI_CO_TEMP2, - SENSORS_MAXI_CO_TEMP2, R }, - MAXI_SYSCTL_TEMP2, VALUE(1), 1 }, - { { SENSORS_MAXI_CO_TEMP3_MAX, "temp3_max", SENSORS_MAXI_CO_TEMP3, - SENSORS_MAXI_CO_TEMP3, R }, - MAXI_SYSCTL_TEMP3, VALUE(1), 1 }, - { { SENSORS_MAXI_CO_TEMP4_MAX, "temp4_max", SENSORS_MAXI_CO_TEMP4, - SENSORS_MAXI_CO_TEMP4, R }, - MAXI_SYSCTL_TEMP4, VALUE(1), 1 }, - { { SENSORS_MAXI_CO_TEMP5_MAX, "temp5_max", SENSORS_MAXI_CO_TEMP5, - SENSORS_MAXI_CO_TEMP5, R }, - MAXI_SYSCTL_TEMP5, VALUE(1), 1 }, - { { SENSORS_MAXI_CO_TEMP1_HYST, "temp1_hyst", SENSORS_MAXI_CO_TEMP1, - SENSORS_MAXI_CO_TEMP1, R }, - MAXI_SYSCTL_TEMP1, VALUE(2), 1 }, - { { SENSORS_MAXI_CO_TEMP2_HYST, "temp2_hyst", SENSORS_MAXI_CO_TEMP2, - SENSORS_MAXI_CO_TEMP2, R }, - MAXI_SYSCTL_TEMP2, VALUE(2), 1 }, - { { SENSORS_MAXI_CO_TEMP3_HYST, "temp3_hyst", SENSORS_MAXI_CO_TEMP3, - SENSORS_MAXI_CO_TEMP3, R }, - MAXI_SYSCTL_TEMP3, VALUE(2), 1 }, - { { SENSORS_MAXI_CO_TEMP4_HYST, "temp4_hyst", SENSORS_MAXI_CO_TEMP4, - SENSORS_MAXI_CO_TEMP4, R }, - MAXI_SYSCTL_TEMP4, VALUE(2), 1 }, - { { SENSORS_MAXI_CO_TEMP5_HYST, "temp5_hyst", SENSORS_MAXI_CO_TEMP5, - SENSORS_MAXI_CO_TEMP5, R }, - MAXI_SYSCTL_TEMP5, VALUE(2), 1 }, - { { SENSORS_MAXI_CO_PLL, "pll", NOMAP, NOMAP, R }, - MAXI_SYSCTL_PLL, VALUE(3), 2 }, - { { SENSORS_MAXI_CO_PLL_MIN, "pll_min", SENSORS_MAXI_CO_PLL, - SENSORS_MAXI_CO_PLL, RW }, - MAXI_SYSCTL_PLL, VALUE(1), 2 }, - { { SENSORS_MAXI_CO_PLL_MAX, "pll_max", SENSORS_MAXI_CO_PLL, - SENSORS_MAXI_CO_PLL, RW }, - MAXI_SYSCTL_PLL, VALUE(2), 2 }, - { { SENSORS_MAXI_CO_VID1, "vid1", NOMAP, NOMAP, R }, - MAXI_SYSCTL_VID1, VALUE(3), 4, "in0_input", 3 }, - { { SENSORS_MAXI_CO_VID2, "vid2", NOMAP, NOMAP, R }, - MAXI_SYSCTL_VID2, VALUE(3), 4, "in1_input", 3 }, - { { SENSORS_MAXI_CO_VID3, "vid3", NOMAP, NOMAP, R }, - MAXI_SYSCTL_VID3, VALUE(3), 4, "in2_input", 3 }, - { { SENSORS_MAXI_CO_VID4, "vid4", NOMAP, NOMAP, R }, - MAXI_SYSCTL_VID4, VALUE(3), 4, "in3_input", 3 }, - { { SENSORS_MAXI_CO_VID1_MIN, "vid1_min", SENSORS_MAXI_CO_VID1, - SENSORS_MAXI_CO_VID1, RW }, - MAXI_SYSCTL_VID1, VALUE(1), 4, "in0_min", 3 }, - { { SENSORS_MAXI_CO_VID2_MIN, "vid2_min", SENSORS_MAXI_CO_VID2, - SENSORS_MAXI_CO_VID2, RW }, - MAXI_SYSCTL_VID2, VALUE(1), 4, "in1_min", 3 }, - { { SENSORS_MAXI_CO_VID3_MIN, "vid3_min", SENSORS_MAXI_CO_VID3, - SENSORS_MAXI_CO_VID3, RW }, - MAXI_SYSCTL_VID3, VALUE(1), 4, "in2_min", 3 }, - { { SENSORS_MAXI_CO_VID4_MIN, "vid4_min", SENSORS_MAXI_CO_VID4, - SENSORS_MAXI_CO_VID4, RW }, - MAXI_SYSCTL_VID4, VALUE(1), 4, "in3_min", 3 }, - { { SENSORS_MAXI_CO_VID1_MAX, "vid1_max", SENSORS_MAXI_CO_VID1, - SENSORS_MAXI_CO_VID1, RW }, - MAXI_SYSCTL_VID1, VALUE(2), 4, "in0_max", 3 }, - { { SENSORS_MAXI_CO_VID2_MAX, "vid2_max", SENSORS_MAXI_CO_VID2, - SENSORS_MAXI_CO_VID2, RW }, - MAXI_SYSCTL_VID2, VALUE(2), 4, "in1_max", 3 }, - { { SENSORS_MAXI_CG_VID3_MAX, "vid3_max", SENSORS_MAXI_CO_VID3, - SENSORS_MAXI_CO_VID3, RW }, - MAXI_SYSCTL_VID3, VALUE(2), 4, "in2_max", 3 }, - { { SENSORS_MAXI_CO_VID4_MAX, "vid4_max", SENSORS_MAXI_CO_VID4, - SENSORS_MAXI_CG_VID4, RW }, - MAXI_SYSCTL_VID4, VALUE(2), 4, "in3_max", 3 }, - { { SENSORS_MAXI_CO_ALARMS, "alarms", NOMAP, NOMAP, R }, - MAXI_SYSCTL_ALARMS, VALUE(1), 0 }, - { { 0 }, 0 } - }; - -static sensors_chip_feature maxi_as_features[] = - { - { { SENSORS_MAXI_AS_FAN1, "fan1", NOMAP, NOMAP, R }, - MAXI_SYSCTL_FAN1, VALUE(3), 0 }, - { { SENSORS_MAXI_AS_FAN2, "fan2", NOMAP, NOMAP, R }, - MAXI_SYSCTL_FAN2, VALUE(3), 0 }, - { { SENSORS_MAXI_AS_FAN3, "fan3", NOMAP, NOMAP, R }, - MAXI_SYSCTL_FAN3, VALUE(3), 0 }, - { { SENSORS_MAXI_AS_FAN1_MIN, "fan1_min", SENSORS_MAXI_AS_FAN1, - SENSORS_MAXI_AS_FAN1, RW }, - MAXI_SYSCTL_FAN1, VALUE(1), 0 }, - { { SENSORS_MAXI_AS_FAN2_MIN, "fan2_min", SENSORS_MAXI_AS_FAN2, - SENSORS_MAXI_AS_FAN2, RW }, - MAXI_SYSCTL_FAN2, VALUE(1), 0 }, - { { SENSORS_MAXI_AS_FAN3_MIN, "fan3_min", SENSORS_MAXI_AS_FAN3, - SENSORS_MAXI_AS_FAN3, RW }, - MAXI_SYSCTL_FAN3, VALUE(1), 0 }, - { { SENSORS_MAXI_AS_FAN1_DIV, "fan1_div", SENSORS_MAXI_AS_FAN1, NOMAP, R }, - MAXI_SYSCTL_FAN1, VALUE(2), 0 }, - { { SENSORS_MAXI_AS_FAN2_DIV, "fan2_div", SENSORS_MAXI_AS_FAN2, NOMAP, R }, - MAXI_SYSCTL_FAN2, VALUE(2), 0 }, - { { SENSORS_MAXI_AS_FAN3_DIV, "fan3_div", SENSORS_MAXI_AS_FAN3, NOMAP, R }, - MAXI_SYSCTL_FAN3, VALUE(2), 0 }, - { { SENSORS_MAXI_AS_TEMP1, "temp1", NOMAP, NOMAP, R }, - MAXI_SYSCTL_TEMP1, VALUE(3), 1 }, - { { SENSORS_MAXI_AS_TEMP2, "temp2", NOMAP, NOMAP, R }, - MAXI_SYSCTL_TEMP2, VALUE(3), 1 }, - { { SENSORS_MAXI_AS_TEMP3, "temp3", NOMAP, NOMAP, R }, - MAXI_SYSCTL_TEMP3, VALUE(3), 1 }, - { { SENSORS_MAXI_AS_TEMP4, "temp4", NOMAP, NOMAP, R }, - MAXI_SYSCTL_TEMP4, VALUE(3), 1 }, - { { SENSORS_MAXI_AS_TEMP5, "temp5", NOMAP, NOMAP, R }, - MAXI_SYSCTL_TEMP5, VALUE(3), 1 }, - { { SENSORS_MAXI_AS_TEMP1_MAX, "temp1_max", SENSORS_MAXI_AS_TEMP1, - SENSORS_MAXI_AS_TEMP1, R }, - MAXI_SYSCTL_TEMP1, VALUE(1), 1 }, - { { SENSORS_MAXI_AS_TEMP2_MAX, "temp2_max", SENSORS_MAXI_AS_TEMP2, - SENSORS_MAXI_AS_TEMP2, R }, - MAXI_SYSCTL_TEMP2, VALUE(1), 1 }, - { { SENSORS_MAXI_AS_TEMP3_MAX, "temp3_max", SENSORS_MAXI_AS_TEMP3, - SENSORS_MAXI_AS_TEMP3, R }, - MAXI_SYSCTL_TEMP3, VALUE(1), 1 }, - { { SENSORS_MAXI_AS_TEMP4_MAX, "temp4_max", SENSORS_MAXI_AS_TEMP4, - SENSORS_MAXI_AS_TEMP4, R }, - MAXI_SYSCTL_TEMP4, VALUE(1), 1 }, - { { SENSORS_MAXI_AS_TEMP5_MAX, "temp5_max", SENSORS_MAXI_AS_TEMP5, - SENSORS_MAXI_AS_TEMP5, R }, - MAXI_SYSCTL_TEMP5, VALUE(1), 1 }, - { { SENSORS_MAXI_AS_TEMP1_HYST, "temp1_hyst", SENSORS_MAXI_AS_TEMP1, - SENSORS_MAXI_AS_TEMP1, R }, - MAXI_SYSCTL_TEMP1, VALUE(2), 1 }, - { { SENSORS_MAXI_AS_TEMP2_HYST, "temp2_hyst", SENSORS_MAXI_AS_TEMP2, - SENSORS_MAXI_AS_TEMP2, R }, - MAXI_SYSCTL_TEMP2, VALUE(2), 1 }, - { { SENSORS_MAXI_AS_TEMP3_HYST, "temp3_hyst", SENSORS_MAXI_AS_TEMP3, - SENSORS_MAXI_AS_TEMP3, R }, - MAXI_SYSCTL_TEMP3, VALUE(2), 1 }, - { { SENSORS_MAXI_AS_TEMP4_HYST, "temp4_hyst", SENSORS_MAXI_AS_TEMP4, - SENSORS_MAXI_AS_TEMP4, R }, - MAXI_SYSCTL_TEMP4, VALUE(2), 1 }, - { { SENSORS_MAXI_AS_TEMP5_HYST, "temp5_hyst", SENSORS_MAXI_AS_TEMP5, - SENSORS_MAXI_AS_TEMP5, R }, - MAXI_SYSCTL_TEMP5, VALUE(2), 1 }, - { { SENSORS_MAXI_AS_PLL, "pll", NOMAP, NOMAP, R }, - MAXI_SYSCTL_PLL, VALUE(3), 2 }, - { { SENSORS_MAXI_AS_PLL_MIN, "pll_min", SENSORS_MAXI_AS_PLL, - SENSORS_MAXI_AS_PLL, RW }, - MAXI_SYSCTL_PLL, VALUE(1), 2 }, - { { SENSORS_MAXI_AS_PLL_MAX, "pll_max", SENSORS_MAXI_AS_PLL, - SENSORS_MAXI_AS_PLL, RW }, - MAXI_SYSCTL_PLL, VALUE(2), 2 }, - { { SENSORS_MAXI_AS_VID1, "vid1", NOMAP, NOMAP, R }, - MAXI_SYSCTL_VID1, VALUE(3), 4, "in0_input", 3 }, - { { SENSORS_MAXI_AS_VID2, "vid2", NOMAP, NOMAP, R }, - MAXI_SYSCTL_VID2, VALUE(3), 4, "in1_input", 3 }, - { { SENSORS_MAXI_AS_VID3, "vid3", NOMAP, NOMAP, R }, - MAXI_SYSCTL_VID3, VALUE(3), 4, "in2_input", 3 }, - { { SENSORS_MAXI_AS_VID4, "vid4", NOMAP, NOMAP, R }, - MAXI_SYSCTL_VID4, VALUE(3), 4, "in3_input", 3 }, - { { SENSORS_MAXI_AS_VID1_MIN, "vid1_min", SENSORS_MAXI_AS_VID1, - SENSORS_MAXI_AS_VID1, RW }, - MAXI_SYSCTL_VID1, VALUE(1), 4, "in0_min", 3 }, - { { SENSORS_MAXI_AS_VID2_MIN, "vid2_min", SENSORS_MAXI_AS_VID2, - SENSORS_MAXI_AS_VID2, RW }, - MAXI_SYSCTL_VID2, VALUE(1), 4, "in1_min", 3 }, - { { SENSORS_MAXI_AS_VID3_MIN, "vid3_min", SENSORS_MAXI_AS_VID3, - SENSORS_MAXI_AS_VID3, RW }, - MAXI_SYSCTL_VID3, VALUE(1), 4, "in2_min", 3 }, - { { SENSORS_MAXI_AS_VID4_MIN, "vid4_min", SENSORS_MAXI_AS_VID4, - SENSORS_MAXI_AS_VID4, RW }, - MAXI_SYSCTL_VID4, VALUE(1), 4, "in3_min", 3 }, - { { SENSORS_MAXI_AS_VID1_MAX, "vid1_max", SENSORS_MAXI_AS_VID1, - SENSORS_MAXI_AS_VID1, RW }, - MAXI_SYSCTL_VID1, VALUE(2), 4, "in0_max", 3 }, - { { SENSORS_MAXI_AS_VID2_MAX, "vid2_max", SENSORS_MAXI_AS_VID2, - SENSORS_MAXI_AS_VID2, RW }, - MAXI_SYSCTL_VID2, VALUE(2), 4, "in1_max", 3 }, - { { SENSORS_MAXI_AS_VID3_MAX, "vid3_max", SENSORS_MAXI_AS_VID3, - SENSORS_MAXI_AS_VID3, RW }, - MAXI_SYSCTL_VID3, VALUE(2), 4, "in2_max", 3 }, - { { SENSORS_MAXI_AS_VID4_MAX, "vid4_max", SENSORS_MAXI_AS_VID4, - SENSORS_MAXI_CG_VID4, RW }, - MAXI_SYSCTL_VID4, VALUE(2), 4, "in3_max", 3 }, - { { SENSORS_MAXI_AS_ALARMS, "alarms", NOMAP, NOMAP, R }, - MAXI_SYSCTL_ALARMS, VALUE(1), 0 }, - { { 0 }, 0 } - }; - -static sensors_chip_feature thmc50_features[] = - { - { { SENSORS_THMC50_TEMP, "temp", NOMAP, NOMAP, R }, - THMC50_SYSCTL_TEMP, VALUE(3), 0 }, - { { SENSORS_THMC50_TEMP_HYST, "temp_hyst", SENSORS_THMC50_TEMP, - SENSORS_THMC50_TEMP, RW }, - THMC50_SYSCTL_TEMP, VALUE(2), 0, - "temp1_min", 3 }, - { { SENSORS_THMC50_TEMP_OVER, "temp_over", SENSORS_THMC50_TEMP, - SENSORS_THMC50_TEMP, RW }, - THMC50_SYSCTL_TEMP, VALUE(1), 0 }, - { { SENSORS_THMC50_REMOTE_TEMP, "remote_temp", NOMAP, NOMAP, R }, - THMC50_SYSCTL_REMOTE_TEMP, VALUE(3), 0 }, - { { SENSORS_THMC50_REMOTE_TEMP_HYST, "remote_temp_hyst", - SENSORS_THMC50_REMOTE_TEMP, - SENSORS_THMC50_REMOTE_TEMP, RW }, - THMC50_SYSCTL_REMOTE_TEMP, VALUE(2), - 0, "temp2_min", 3 }, - { { SENSORS_THMC50_REMOTE_TEMP_OVER, "remote_temp_over", - SENSORS_THMC50_REMOTE_TEMP, - SENSORS_THMC50_REMOTE_TEMP, RW }, - THMC50_SYSCTL_REMOTE_TEMP, VALUE(1), - 0 }, - { { SENSORS_ADM1022_REMOTE_TEMP2, "remote_temp2", NOMAP, NOMAP, R }, - NOSYSCTL, VALUE(3), - 0, "temp3_input", 3 }, - { { SENSORS_ADM1022_REMOTE_TEMP2_HYST, "remote_temp2_hyst", - SENSORS_ADM1022_REMOTE_TEMP2, - SENSORS_ADM1022_REMOTE_TEMP2, RW }, - NOSYSCTL, VALUE(2), - 0, "temp3_min", 3 }, - { { SENSORS_ADM1022_REMOTE_TEMP2_OVER, "remote_temp2_over", - SENSORS_ADM1022_REMOTE_TEMP2, - SENSORS_ADM1022_REMOTE_TEMP2, RW }, - NOSYSCTL, VALUE(1), - 0, "temp3_max", 3 }, - { { SENSORS_THMC50_ANALOG_OUT, "analog output", NOMAP, NOMAP, RW }, - THMC50_SYSCTL_ANALOG_OUT, VALUE(1), 0, - "pwm1", 0 }, - { { SENSORS_THMC50_INTER, "interrupts", NOMAP, NOMAP, R }, - THMC50_SYSCTL_INTER, VALUE(1), 0 }, - { { SENSORS_THMC50_INTER_MASK, "interrupt mask", NOMAP, NOMAP, RW }, - THMC50_SYSCTL_INTER_MASK, VALUE(1), 0 }, - { { SENSORS_THMC50_DIE_CODE, "die_code", NOMAP, NOMAP, R }, - THMC50_SYSCTL_DIE_CODE, VALUE(1), 0 }, - { { 0 }, 0 } - }; - -static sensors_chip_feature adm1025_features[] = - { - { { SENSORS_ADM1025_IN0, "in0", NOMAP, NOMAP, R }, - ADM1025_SYSCTL_IN0, VALUE(3), 2 }, - { { SENSORS_ADM1025_IN1, "in1", NOMAP, NOMAP, R }, - ADM1025_SYSCTL_IN1, VALUE(3), 2 }, - { { SENSORS_ADM1025_IN2, "in2", NOMAP, NOMAP, R }, - ADM1025_SYSCTL_IN2, VALUE(3), 2 }, - { { SENSORS_ADM1025_IN3, "in3", NOMAP, NOMAP, R }, - ADM1025_SYSCTL_IN3, VALUE(3), 2 }, - { { SENSORS_ADM1025_IN4, "in4", NOMAP, NOMAP, R }, - ADM1025_SYSCTL_IN4, VALUE(3), 2 }, - { { SENSORS_ADM1025_IN5, "in5", NOMAP, NOMAP, R }, - ADM1025_SYSCTL_IN5, VALUE(3), 2 }, - { { SENSORS_ADM1025_IN0_MIN, "in0_min", SENSORS_ADM1025_IN0, - SENSORS_ADM1025_IN0, RW }, - ADM1025_SYSCTL_IN0, VALUE(1), 2 }, - { { SENSORS_ADM1025_IN1_MIN, "in1_min", SENSORS_ADM1025_IN1, - SENSORS_ADM1025_IN1, RW }, - ADM1025_SYSCTL_IN1, VALUE(1), 2 }, - { { SENSORS_ADM1025_IN2_MIN, "in2_min", SENSORS_ADM1025_IN2, - SENSORS_ADM1025_IN2, RW }, - ADM1025_SYSCTL_IN2, VALUE(1), 2 }, - { { SENSORS_ADM1025_IN3_MIN, "in3_min", SENSORS_ADM1025_IN3, - SENSORS_ADM1025_IN3, RW }, - ADM1025_SYSCTL_IN3, VALUE(1), 2 }, - { { SENSORS_ADM1025_IN4_MIN, "in4_min", SENSORS_ADM1025_IN4, - SENSORS_ADM1025_IN4, RW }, - ADM1025_SYSCTL_IN4, VALUE(1), 2 }, - { { SENSORS_ADM1025_IN5_MIN, "in5_min", SENSORS_ADM1025_IN5, - SENSORS_ADM1025_IN5, RW }, - ADM1025_SYSCTL_IN5, VALUE(1), 2 }, - { { SENSORS_ADM1025_IN0_MAX, "in0_max", SENSORS_ADM1025_IN0, - SENSORS_ADM1025_IN0, RW }, - ADM1025_SYSCTL_IN0, VALUE(2), 2 }, - { { SENSORS_ADM1025_IN1_MAX, "in1_max", SENSORS_ADM1025_IN1, - SENSORS_ADM1025_IN1, RW }, - ADM1025_SYSCTL_IN1, VALUE(2), 2 }, - { { SENSORS_ADM1025_IN2_MAX, "in2_max", SENSORS_ADM1025_IN2, - SENSORS_ADM1025_IN2, RW }, - ADM1025_SYSCTL_IN2, VALUE(2), 2 }, - { { SENSORS_ADM1025_IN3_MAX, "in3_max", SENSORS_ADM1025_IN3, - SENSORS_ADM1025_IN3, RW }, - ADM1025_SYSCTL_IN3, VALUE(2), 2 }, - { { SENSORS_ADM1025_IN4_MAX, "in4_max", SENSORS_ADM1025_IN4, - SENSORS_ADM1025_IN4, RW }, - ADM1025_SYSCTL_IN4, VALUE(2), 2 }, - { { SENSORS_ADM1025_IN5_MAX, "in5_max", SENSORS_ADM1025_IN5, - SENSORS_ADM1025_IN5, RW }, - ADM1025_SYSCTL_IN5, VALUE(2), 2 }, - { { SENSORS_ADM1025_TEMP1, "temp1", NOMAP, NOMAP, R }, - ADM1025_SYSCTL_RTEMP, VALUE(3), 1 }, - { { SENSORS_ADM1025_TEMP1_LOW, "temp1_low", SENSORS_ADM1025_TEMP1, - SENSORS_ADM1025_TEMP1, RW }, - ADM1025_SYSCTL_RTEMP, VALUE(2), 1 }, - { { SENSORS_ADM1025_TEMP1_HIGH, "temp1_high", SENSORS_ADM1025_TEMP1, - SENSORS_ADM1025_TEMP1, RW }, - ADM1025_SYSCTL_RTEMP, VALUE(1), 1 }, - { { SENSORS_ADM1025_TEMP2, "temp2", NOMAP, NOMAP, R }, - ADM1025_SYSCTL_TEMP, VALUE(3), 1 }, - { { SENSORS_ADM1025_TEMP2_LOW, "temp2_low", SENSORS_ADM1025_TEMP2, - SENSORS_ADM1025_TEMP2, RW }, - ADM1025_SYSCTL_TEMP, VALUE(2), 1 }, - { { SENSORS_ADM1025_TEMP2_HIGH, "temp2_high", SENSORS_ADM1025_TEMP2, - SENSORS_ADM1025_TEMP2, RW }, - ADM1025_SYSCTL_TEMP, VALUE(1), 1 }, - { { SENSORS_ADM1025_VID, "vid", NOMAP, NOMAP, R }, - ADM1025_SYSCTL_VID, VALUE(1), 3, "cpu0_vid", 3, - "in1_ref" }, - { { SENSORS_ADM1025_VRM, "vrm", NOMAP, NOMAP, RW }, - ADM1025_SYSCTL_VRM, VALUE(1), 1 }, - { { SENSORS_ADM1025_ALARMS, "alarms", NOMAP, NOMAP, R }, - ADM1025_SYSCTL_ALARMS, VALUE(1), 0 }, - { { 0 }, 0 } - }; - - -static sensors_chip_feature adm1026_features[] = { - { { SENSORS_ADM1026_ALARMS, "alarms", NOMAP, NOMAP, R }, - ADM1026_SYSCTL_ALARMS, VALUE(1), 0 }, - { { SENSORS_ADM1026_ALARM_MASK, "alarm_mask", SENSORS_ADM1026_ALARMS, NOMAP, - R }, - ADM1026_SYSCTL_ALARM_MASK, VALUE(1), 0 }, - { { SENSORS_ADM1026_GPIO, "gpio", NOMAP, NOMAP, R }, - ADM1026_SYSCTL_GPIO, VALUE(1), 0 }, - { { SENSORS_ADM1026_GPIO_MASK, "gpio_mask", SENSORS_ADM1026_GPIO, NOMAP, R }, - ADM1026_SYSCTL_GPIO_MASK, VALUE(1), 0 }, - { { SENSORS_ADM1026_VID, "vid", NOMAP, NOMAP, R }, - ADM1026_SYSCTL_VID, VALUE(1), 3 }, - { { SENSORS_ADM1026_VRM, "vrm", NOMAP, NOMAP, RW }, - ADM1026_SYSCTL_VRM, VALUE(1), 1 }, - { { SENSORS_ADM1026_PWM, "pwm", NOMAP, NOMAP, RW }, - ADM1026_SYSCTL_PWM, VALUE(1), 0 }, - { { SENSORS_ADM1026_AFC_PWM, "afc_pwm", NOMAP, NOMAP, RW }, - ADM1026_SYSCTL_PWM, VALUE(1), 0 }, - { { SENSORS_ADM1026_DAC, "analog_out", NOMAP, NOMAP, RW }, - ADM1026_SYSCTL_ANALOG_OUT, VALUE(1), 0 }, - { { SENSORS_ADM1026_AFC_DAC, "afc_analog_out", SENSORS_ADM1026_DAC, NOMAP, - RW }, - ADM1026_SYSCTL_AFC, VALUE(2), 0 }, - - { { SENSORS_ADM1026_IN0, "in0", NOMAP, NOMAP, R }, - ADM1026_SYSCTL_IN0, VALUE(3), 3 }, - { { SENSORS_ADM1026_IN0_MIN, "in0_min", SENSORS_ADM1026_IN0, - SENSORS_ADM1026_IN0, RW }, - ADM1026_SYSCTL_IN0, VALUE(1), 3 }, - { { SENSORS_ADM1026_IN0_MAX, "in0_max", SENSORS_ADM1026_IN0, - SENSORS_ADM1026_IN0, RW }, - ADM1026_SYSCTL_IN0, VALUE(2), 3 }, - { { SENSORS_ADM1026_IN1, "in1", NOMAP, NOMAP, R }, - ADM1026_SYSCTL_IN1, VALUE(3), 3 }, - { { SENSORS_ADM1026_IN1_MIN, "in1_min", SENSORS_ADM1026_IN1, - SENSORS_ADM1026_IN1, RW }, - ADM1026_SYSCTL_IN1, VALUE(1), 3 }, - { { SENSORS_ADM1026_IN1_MAX, "in1_max", SENSORS_ADM1026_IN1, - SENSORS_ADM1026_IN1, RW }, - ADM1026_SYSCTL_IN1, VALUE(2), 3 }, - { { SENSORS_ADM1026_IN2, "in2", NOMAP, NOMAP, R }, - ADM1026_SYSCTL_IN2, VALUE(3), 3 }, - { { SENSORS_ADM1026_IN2_MIN, "in2_min", SENSORS_ADM1026_IN2, - SENSORS_ADM1026_IN2, RW }, - ADM1026_SYSCTL_IN2, VALUE(1), 3 }, - { { SENSORS_ADM1026_IN2_MAX, "in2_max", SENSORS_ADM1026_IN2, - SENSORS_ADM1026_IN2, RW }, - ADM1026_SYSCTL_IN2, VALUE(2), 3 }, - { { SENSORS_ADM1026_IN3, "in3", NOMAP, NOMAP, R }, - ADM1026_SYSCTL_IN3, VALUE(3), 3 }, - { { SENSORS_ADM1026_IN3_MIN, "in3_min", SENSORS_ADM1026_IN3, - SENSORS_ADM1026_IN3, RW }, - ADM1026_SYSCTL_IN3, VALUE(1), 3 }, - { { SENSORS_ADM1026_IN3_MAX, "in3_max", SENSORS_ADM1026_IN3, - SENSORS_ADM1026_IN3, RW }, - ADM1026_SYSCTL_IN3, VALUE(2), 3 }, - { { SENSORS_ADM1026_IN4, "in4", NOMAP, NOMAP, R }, - ADM1026_SYSCTL_IN4, VALUE(3), 3 }, - { { SENSORS_ADM1026_IN4_MIN, "in4_min", SENSORS_ADM1026_IN4, - SENSORS_ADM1026_IN4, RW }, - ADM1026_SYSCTL_IN4, VALUE(1), 3 }, - { { SENSORS_ADM1026_IN4_MAX, "in4_max", SENSORS_ADM1026_IN4, - SENSORS_ADM1026_IN4, RW }, - ADM1026_SYSCTL_IN4, VALUE(2), 3 }, - { { SENSORS_ADM1026_IN5, "in5", NOMAP, NOMAP, R }, - ADM1026_SYSCTL_IN5, VALUE(3), 3 }, - { { SENSORS_ADM1026_IN5_MIN, "in5_min", SENSORS_ADM1026_IN5, - SENSORS_ADM1026_IN5, RW }, - ADM1026_SYSCTL_IN5, VALUE(1), 3 }, - { { SENSORS_ADM1026_IN5_MAX, "in5_max", SENSORS_ADM1026_IN5, - SENSORS_ADM1026_IN5, RW }, - ADM1026_SYSCTL_IN5, VALUE(2), 3 }, - { { SENSORS_ADM1026_IN6, "in6", NOMAP, NOMAP, R }, - ADM1026_SYSCTL_IN6, VALUE(3), 3 }, - { { SENSORS_ADM1026_IN6_MIN, "in6_min", SENSORS_ADM1026_IN6, - SENSORS_ADM1026_IN6, RW }, - ADM1026_SYSCTL_IN6, VALUE(1), 3 }, - { { SENSORS_ADM1026_IN6_MAX, "in6_max", SENSORS_ADM1026_IN6, - SENSORS_ADM1026_IN6, RW }, - ADM1026_SYSCTL_IN6, VALUE(2), 3 }, - { { SENSORS_ADM1026_IN7, "in7", NOMAP, NOMAP, R }, - ADM1026_SYSCTL_IN7, VALUE(3), 3 }, - { { SENSORS_ADM1026_IN7_MIN, "in7_min", SENSORS_ADM1026_IN7, - SENSORS_ADM1026_IN7, RW }, - ADM1026_SYSCTL_IN7, VALUE(1), 3 }, - { { SENSORS_ADM1026_IN7_MAX, "in7_max", SENSORS_ADM1026_IN7, - SENSORS_ADM1026_IN7, RW }, - ADM1026_SYSCTL_IN7, VALUE(2), 3 }, - { { SENSORS_ADM1026_IN8, "in8", NOMAP, NOMAP, R }, - ADM1026_SYSCTL_IN8, VALUE(3), 3 }, - { { SENSORS_ADM1026_IN8_MIN, "in8_min", SENSORS_ADM1026_IN8, - SENSORS_ADM1026_IN8, RW }, - ADM1026_SYSCTL_IN8, VALUE(1), 3 }, - { { SENSORS_ADM1026_IN8_MAX, "in8_max", SENSORS_ADM1026_IN8, - SENSORS_ADM1026_IN8, RW }, - ADM1026_SYSCTL_IN8, VALUE(2), 3 }, - { { SENSORS_ADM1026_IN9, "in9", NOMAP, NOMAP, R }, - ADM1026_SYSCTL_IN9, VALUE(3), 3 }, - { { SENSORS_ADM1026_IN9_MIN, "in9_min", SENSORS_ADM1026_IN9, - SENSORS_ADM1026_IN9, RW }, - ADM1026_SYSCTL_IN9, VALUE(1), 3 }, - { { SENSORS_ADM1026_IN9_MAX, "in9_max", SENSORS_ADM1026_IN9, - SENSORS_ADM1026_IN9, RW }, - ADM1026_SYSCTL_IN9, VALUE(2), 3 }, - { { SENSORS_ADM1026_IN10, "in10", NOMAP, NOMAP, R }, - ADM1026_SYSCTL_IN10, VALUE(3), 3 }, - { { SENSORS_ADM1026_IN10_MIN, "in10_min", SENSORS_ADM1026_IN10, - SENSORS_ADM1026_IN10, RW }, - ADM1026_SYSCTL_IN10, VALUE(1), 3 }, - { { SENSORS_ADM1026_IN10_MAX, "in10_max", SENSORS_ADM1026_IN10, - SENSORS_ADM1026_IN10, RW }, - ADM1026_SYSCTL_IN10, VALUE(2), 3 }, - { { SENSORS_ADM1026_IN11, "in11", NOMAP, NOMAP, R }, - ADM1026_SYSCTL_IN11, VALUE(3), 3 }, - { { SENSORS_ADM1026_IN11_MIN, "in11_min", SENSORS_ADM1026_IN11, - SENSORS_ADM1026_IN11, RW }, - ADM1026_SYSCTL_IN11, VALUE(1), 3 }, - { { SENSORS_ADM1026_IN11_MAX, "in11_max", SENSORS_ADM1026_IN11, - SENSORS_ADM1026_IN11, RW }, - ADM1026_SYSCTL_IN11, VALUE(2), 3 }, - { { SENSORS_ADM1026_IN12, "in12", NOMAP, NOMAP, R }, - ADM1026_SYSCTL_IN12, VALUE(3), 3 }, - { { SENSORS_ADM1026_IN12_MIN, "in12_min", SENSORS_ADM1026_IN12, - SENSORS_ADM1026_IN12, RW }, - ADM1026_SYSCTL_IN12, VALUE(1), 3 }, - { { SENSORS_ADM1026_IN12_MAX, "in12_max", SENSORS_ADM1026_IN12, - SENSORS_ADM1026_IN12, RW }, - ADM1026_SYSCTL_IN12, VALUE(2), 3 }, - { { SENSORS_ADM1026_IN13, "in13", NOMAP, NOMAP, R }, - ADM1026_SYSCTL_IN13, VALUE(3), 3 }, - { { SENSORS_ADM1026_IN13_MIN, "in13_min", SENSORS_ADM1026_IN13, - SENSORS_ADM1026_IN13, RW }, - ADM1026_SYSCTL_IN13, VALUE(1), 3 }, - { { SENSORS_ADM1026_IN13_MAX, "in13_max", SENSORS_ADM1026_IN13, - SENSORS_ADM1026_IN13, RW }, - ADM1026_SYSCTL_IN13, VALUE(2), 3 }, - { { SENSORS_ADM1026_IN14, "in14", NOMAP, NOMAP, R }, - ADM1026_SYSCTL_IN14, VALUE(3), 3 }, - { { SENSORS_ADM1026_IN14_MIN, "in14_min", SENSORS_ADM1026_IN14, - SENSORS_ADM1026_IN14, RW }, - ADM1026_SYSCTL_IN14, VALUE(1), 3 }, - { { SENSORS_ADM1026_IN14_MAX, "in14_max", SENSORS_ADM1026_IN14, - SENSORS_ADM1026_IN14, RW }, - ADM1026_SYSCTL_IN14, VALUE(2), 3 }, - { { SENSORS_ADM1026_IN15, "in15", NOMAP, NOMAP, R }, - ADM1026_SYSCTL_IN15, VALUE(3), 3 }, - { { SENSORS_ADM1026_IN15_MIN, "in15_min", SENSORS_ADM1026_IN15, - SENSORS_ADM1026_IN15, RW }, - ADM1026_SYSCTL_IN15, VALUE(1), 3 }, - { { SENSORS_ADM1026_IN15_MAX, "in15_max", SENSORS_ADM1026_IN15, - SENSORS_ADM1026_IN15, RW }, - ADM1026_SYSCTL_IN15, VALUE(2), 3 }, - { { SENSORS_ADM1026_IN16, "in16", NOMAP, NOMAP, R }, - ADM1026_SYSCTL_IN16, VALUE(3), 3 }, - { { SENSORS_ADM1026_IN16_MIN, "in16_min", SENSORS_ADM1026_IN16, - SENSORS_ADM1026_IN16, RW }, - ADM1026_SYSCTL_IN16, VALUE(1), 3 }, - { { SENSORS_ADM1026_IN16_MAX, "in16_max", SENSORS_ADM1026_IN16, - SENSORS_ADM1026_IN16, RW }, - ADM1026_SYSCTL_IN16, VALUE(2), 3 }, - { { SENSORS_ADM1026_FAN0, "fan0", NOMAP, NOMAP, R }, - ADM1026_SYSCTL_FAN0, VALUE(2), 0, "fan8_input", - 0 }, - { { SENSORS_ADM1026_FAN0_MIN, "fan0_min", SENSORS_ADM1026_FAN0, - SENSORS_ADM1026_FAN0, RW }, - ADM1026_SYSCTL_FAN0, VALUE(1), 0, "fan8_min", - 0 }, - { { SENSORS_ADM1026_FAN0_DIV, "fan0_div", SENSORS_ADM1026_FAN0, NOMAP, RW }, - ADM1026_SYSCTL_FAN_DIV, VALUE(1), 0, - "fan8_div", 0 }, - { { SENSORS_ADM1026_FAN1, "fan1", NOMAP, NOMAP, R }, - ADM1026_SYSCTL_FAN1, VALUE(2), 0 }, - { { SENSORS_ADM1026_FAN1_MIN, "fan1_min", SENSORS_ADM1026_FAN1, - SENSORS_ADM1026_FAN1, RW }, - ADM1026_SYSCTL_FAN1, VALUE(1), 0 }, - { { SENSORS_ADM1026_FAN1_DIV, "fan1_div", SENSORS_ADM1026_FAN1, NOMAP, RW }, - ADM1026_SYSCTL_FAN_DIV, VALUE(2), 0 }, - { { SENSORS_ADM1026_FAN2, "fan2", NOMAP, NOMAP, R }, - ADM1026_SYSCTL_FAN2, VALUE(2), 0 }, - { { SENSORS_ADM1026_FAN2_MIN, "fan2_min", SENSORS_ADM1026_FAN2, - SENSORS_ADM1026_FAN2, RW }, - ADM1026_SYSCTL_FAN2, VALUE(1), 0 }, - { { SENSORS_ADM1026_FAN2_DIV, "fan2_div", SENSORS_ADM1026_FAN2, NOMAP, RW }, - ADM1026_SYSCTL_FAN_DIV, VALUE(3), 0 }, - { { SENSORS_ADM1026_FAN3, "fan3", NOMAP, NOMAP, R }, - ADM1026_SYSCTL_FAN3, VALUE(2), 0 }, - { { SENSORS_ADM1026_FAN3_MIN, "fan3_min", SENSORS_ADM1026_FAN3, - SENSORS_ADM1026_FAN3, RW }, - ADM1026_SYSCTL_FAN3, VALUE(1), 0 }, - { { SENSORS_ADM1026_FAN3_DIV, "fan3_div", SENSORS_ADM1026_FAN3, NOMAP, RW }, - ADM1026_SYSCTL_FAN_DIV, VALUE(4), 0 }, - { { SENSORS_ADM1026_FAN4, "fan4", NOMAP, NOMAP, R }, - ADM1026_SYSCTL_FAN4, VALUE(2), 0 }, - { { SENSORS_ADM1026_FAN4_MIN, "fan4_min", SENSORS_ADM1026_FAN4, - SENSORS_ADM1026_FAN4, RW }, - ADM1026_SYSCTL_FAN4, VALUE(1), 0 }, - { { SENSORS_ADM1026_FAN4_DIV, "fan4_div", SENSORS_ADM1026_FAN4, NOMAP, RW }, - ADM1026_SYSCTL_FAN_DIV, VALUE(5), 0 }, - { { SENSORS_ADM1026_FAN5, "fan5", NOMAP, NOMAP, R }, - ADM1026_SYSCTL_FAN5, VALUE(2), 0 }, - { { SENSORS_ADM1026_FAN5_MIN, "fan5_min", SENSORS_ADM1026_FAN5, - SENSORS_ADM1026_FAN5, RW }, - ADM1026_SYSCTL_FAN5, VALUE(1), 0 }, - { { SENSORS_ADM1026_FAN5_DIV, "fan5_div", SENSORS_ADM1026_FAN5, NOMAP, RW }, - ADM1026_SYSCTL_FAN_DIV, VALUE(6), 0 }, - { { SENSORS_ADM1026_FAN6, "fan6", NOMAP, NOMAP, R }, - ADM1026_SYSCTL_FAN6, VALUE(2), 0 }, - { { SENSORS_ADM1026_FAN6_MIN, "fan6_min", SENSORS_ADM1026_FAN6, - SENSORS_ADM1026_FAN6, RW }, - ADM1026_SYSCTL_FAN6, VALUE(1), 0 }, - { { SENSORS_ADM1026_FAN6_DIV, "fan6_div", SENSORS_ADM1026_FAN6, NOMAP, RW }, - ADM1026_SYSCTL_FAN_DIV, VALUE(7), 0 }, - { { SENSORS_ADM1026_FAN7, "fan7", NOMAP, NOMAP, R }, - ADM1026_SYSCTL_FAN7, VALUE(2), 0 }, - { { SENSORS_ADM1026_FAN7_MIN, "fan7_min", SENSORS_ADM1026_FAN7, - SENSORS_ADM1026_FAN7, RW }, - ADM1026_SYSCTL_FAN7, VALUE(1), 0 }, - { { SENSORS_ADM1026_FAN7_DIV, "fan7_div", SENSORS_ADM1026_FAN7, NOMAP, RW }, - ADM1026_SYSCTL_FAN_DIV, VALUE(8), 0 }, - { { SENSORS_ADM1026_TEMP1, "temp1", NOMAP, NOMAP, R }, - ADM1026_SYSCTL_TEMP1, VALUE(3), 0 }, - { { SENSORS_ADM1026_TEMP1_MIN, "temp1_min", SENSORS_ADM1026_TEMP1, - SENSORS_ADM1026_TEMP1, RW }, - ADM1026_SYSCTL_TEMP1, VALUE(1), 0 }, - { { SENSORS_ADM1026_TEMP1_MAX, "temp1_max", SENSORS_ADM1026_TEMP1, - SENSORS_ADM1026_TEMP1, RW }, - ADM1026_SYSCTL_TEMP1, VALUE(2), 0 }, - { { SENSORS_ADM1026_TEMP1_OFFSET, "temp1_offset", SENSORS_ADM1026_TEMP1, - NOMAP, RW }, - ADM1026_SYSCTL_TEMP_OFFSET1, VALUE(1), 0 }, - { { SENSORS_ADM1026_TEMP1_TMIN, "temp1_tmin", SENSORS_ADM1026_TEMP1, - SENSORS_ADM1026_TEMP1, RW }, - ADM1026_SYSCTL_TEMP_TMIN1, VALUE(1), 0 }, - { { SENSORS_ADM1026_TEMP1_THERM, "temp1_therm", SENSORS_ADM1026_TEMP1, - SENSORS_ADM1026_TEMP1, RW }, - ADM1026_SYSCTL_TEMP_THERM1, VALUE(1), 0, "temp1_crit", 3 }, - { { SENSORS_ADM1026_TEMP2, "temp2", NOMAP, NOMAP, R }, - ADM1026_SYSCTL_TEMP2, VALUE(3), 0 }, - { { SENSORS_ADM1026_TEMP2_MIN, "temp2_min", SENSORS_ADM1026_TEMP2, - SENSORS_ADM1026_TEMP2, RW }, - ADM1026_SYSCTL_TEMP2, VALUE(1), 0 }, - { { SENSORS_ADM1026_TEMP2_MAX, "temp2_max", SENSORS_ADM1026_TEMP2, - SENSORS_ADM1026_TEMP2, RW }, - ADM1026_SYSCTL_TEMP2, VALUE(2), 0 }, - { { SENSORS_ADM1026_TEMP2_OFFSET, "temp2_offset", SENSORS_ADM1026_TEMP2, - NOMAP, RW }, - ADM1026_SYSCTL_TEMP_OFFSET2, VALUE(1), 0 }, - { { SENSORS_ADM1026_TEMP2_TMIN, "temp2_tmin", SENSORS_ADM1026_TEMP2, - SENSORS_ADM1026_TEMP2, RW }, - ADM1026_SYSCTL_TEMP_TMIN2, VALUE(1), 0 }, - { { SENSORS_ADM1026_TEMP2_THERM, "temp2_therm", SENSORS_ADM1026_TEMP2, - SENSORS_ADM1026_TEMP2, RW }, - ADM1026_SYSCTL_TEMP_THERM2, VALUE(1), 0, "temp2_crit", 3 }, - { { SENSORS_ADM1026_TEMP3, "temp3", NOMAP, NOMAP, R }, - ADM1026_SYSCTL_TEMP3, VALUE(3), 0 }, - { { SENSORS_ADM1026_TEMP3_MIN, "temp3_min", SENSORS_ADM1026_TEMP3, - SENSORS_ADM1026_TEMP3, RW }, - ADM1026_SYSCTL_TEMP3, VALUE(1), 0 }, - { { SENSORS_ADM1026_TEMP3_MAX, "temp3_max", SENSORS_ADM1026_TEMP3, - SENSORS_ADM1026_TEMP3, RW }, - ADM1026_SYSCTL_TEMP3, VALUE(2), 0 }, - { { SENSORS_ADM1026_TEMP3_OFFSET, "temp3_offset", SENSORS_ADM1026_TEMP3, - NOMAP, RW }, - ADM1026_SYSCTL_TEMP_OFFSET3, VALUE(1), 0 }, - { { SENSORS_ADM1026_TEMP3_TMIN, "temp3_tmin", SENSORS_ADM1026_TEMP3, - SENSORS_ADM1026_TEMP3, RW }, - ADM1026_SYSCTL_TEMP_TMIN3, VALUE(1), 0 }, - { { SENSORS_ADM1026_TEMP3_THERM, "temp3_therm", SENSORS_ADM1026_TEMP3, - SENSORS_ADM1026_TEMP3, RW }, - ADM1026_SYSCTL_TEMP_THERM3, VALUE(1), 0, "temp3_crit", 3 }, - { { 0 }, 0 } - }; - - -static sensors_chip_feature via686a_features[] = - { - { { SENSORS_VIA686A_IN0, "2.0V", NOMAP, NOMAP, R }, - VIA686A_SYSCTL_IN0, VALUE(3), 2, "in0_input", 3 }, - { { SENSORS_VIA686A_IN1, "2.5V", NOMAP, NOMAP, R }, - VIA686A_SYSCTL_IN1, VALUE(3), 2, "in1_input", 3 }, - { { SENSORS_VIA686A_IN2, "3.3V", NOMAP, NOMAP, R }, - VIA686A_SYSCTL_IN2, VALUE(3), 2, "in2_input", 3 }, - { { SENSORS_VIA686A_IN3, "5.0V", NOMAP, NOMAP, R }, - VIA686A_SYSCTL_IN3, VALUE(3), 2, "in3_input", 3 }, - { { SENSORS_VIA686A_IN4, "12V", NOMAP, NOMAP, R }, - VIA686A_SYSCTL_IN4, VALUE(3), 2, "in4_input", 3 }, - { { SENSORS_VIA686A_IN0_MIN, "in0_min", SENSORS_VIA686A_IN0, - SENSORS_VIA686A_IN0, RW }, - VIA686A_SYSCTL_IN0, VALUE(1), 2 }, - { { SENSORS_VIA686A_IN1_MIN, "in1_min", SENSORS_VIA686A_IN1, - SENSORS_VIA686A_IN1, RW }, - VIA686A_SYSCTL_IN1, VALUE(1), 2 }, - { { SENSORS_VIA686A_IN2_MIN, "in2_min", SENSORS_VIA686A_IN2, - SENSORS_VIA686A_IN2, RW }, - VIA686A_SYSCTL_IN2, VALUE(1), 2 }, - { { SENSORS_VIA686A_IN3_MIN, "in3_min", SENSORS_VIA686A_IN3, - SENSORS_VIA686A_IN3, RW }, - VIA686A_SYSCTL_IN3, VALUE(1), 2 }, - { { SENSORS_VIA686A_IN4_MIN, "in4_min", SENSORS_VIA686A_IN4, - SENSORS_VIA686A_IN4, RW }, - VIA686A_SYSCTL_IN4, VALUE(1), 2 }, - { { SENSORS_VIA686A_IN0_MAX, "in0_max", SENSORS_VIA686A_IN0, - SENSORS_VIA686A_IN0, RW }, - VIA686A_SYSCTL_IN0, VALUE(2), 2 }, - { { SENSORS_VIA686A_IN1_MAX, "in1_max", SENSORS_VIA686A_IN1, - SENSORS_VIA686A_IN1, RW }, - VIA686A_SYSCTL_IN1, VALUE(2), 2 }, - { { SENSORS_VIA686A_IN2_MAX, "in2_max", SENSORS_VIA686A_IN2, - SENSORS_VIA686A_IN2, RW }, - VIA686A_SYSCTL_IN2, VALUE(2), 2 }, - { { SENSORS_VIA686A_IN3_MAX, "in3_max", SENSORS_VIA686A_IN3, - SENSORS_VIA686A_IN3, RW }, - VIA686A_SYSCTL_IN3, VALUE(2), 2 }, - { { SENSORS_VIA686A_IN4_MAX, "in4_max", SENSORS_VIA686A_IN4, - SENSORS_VIA686A_IN4, RW }, - VIA686A_SYSCTL_IN4, VALUE(2), 2 }, - { { SENSORS_VIA686A_FAN1, "fan1", NOMAP, NOMAP, R }, - VIA686A_SYSCTL_FAN1, VALUE(2), 0 }, - { { SENSORS_VIA686A_FAN2, "fan2", NOMAP, NOMAP, R }, - VIA686A_SYSCTL_FAN2, VALUE(2), 0 }, - { { SENSORS_VIA686A_FAN1_MIN, "fan1_min", SENSORS_VIA686A_FAN1, - SENSORS_VIA686A_FAN1, RW }, - VIA686A_SYSCTL_FAN1, VALUE(1), 0 }, - { { SENSORS_VIA686A_FAN2_MIN, "fan2_min", SENSORS_VIA686A_FAN2, - SENSORS_VIA686A_FAN2, RW }, - VIA686A_SYSCTL_FAN2, VALUE(1), 0 }, - { { SENSORS_VIA686A_TEMP, "temp1", NOMAP, NOMAP, R }, - VIA686A_SYSCTL_TEMP, VALUE(3), 1 }, - { { SENSORS_VIA686A_TEMP_HYST, "temp1_hyst", SENSORS_VIA686A_TEMP, - SENSORS_VIA686A_TEMP, RW }, - VIA686A_SYSCTL_TEMP, VALUE(2), 1 }, - { { SENSORS_VIA686A_TEMP_OVER, "temp1_over", SENSORS_VIA686A_TEMP, - SENSORS_VIA686A_TEMP, RW }, - VIA686A_SYSCTL_TEMP, VALUE(1), 1 }, - { { SENSORS_VIA686A_TEMP2, "temp2", NOMAP, NOMAP, R }, - VIA686A_SYSCTL_TEMP2, VALUE(3), 1 }, - { { SENSORS_VIA686A_TEMP2_HYST, "temp2_hyst", SENSORS_VIA686A_TEMP2, - SENSORS_VIA686A_TEMP2, RW }, - VIA686A_SYSCTL_TEMP2, VALUE(2), 1 }, - { { SENSORS_VIA686A_TEMP2_OVER, "temp2_over", SENSORS_VIA686A_TEMP2, - SENSORS_VIA686A_TEMP2, RW }, - VIA686A_SYSCTL_TEMP2, VALUE(1), 1 }, - { { SENSORS_VIA686A_TEMP3, "temp3", NOMAP, NOMAP, R }, - VIA686A_SYSCTL_TEMP3, VALUE(3), 1 }, - { { SENSORS_VIA686A_TEMP3_HYST, "temp3_hyst", SENSORS_VIA686A_TEMP3, - SENSORS_VIA686A_TEMP3, RW }, - VIA686A_SYSCTL_TEMP3, VALUE(2), 1 }, - { { SENSORS_VIA686A_TEMP3_OVER, "temp3_over", SENSORS_VIA686A_TEMP3, - SENSORS_VIA686A_TEMP3, RW }, - VIA686A_SYSCTL_TEMP3, VALUE(1), 1 }, - { { SENSORS_VIA686A_FAN1_DIV, "fan1_div", SENSORS_VIA686A_FAN1, NOMAP, RW }, - VIA686A_SYSCTL_FAN_DIV, VALUE(1), 0 }, - { { SENSORS_VIA686A_FAN2_DIV, "fan2_div", SENSORS_VIA686A_FAN2, NOMAP, RW }, - VIA686A_SYSCTL_FAN_DIV, VALUE(2), 0 }, - { { SENSORS_VIA686A_ALARMS, "alarms", NOMAP, NOMAP, R }, - VIA686A_SYSCTL_ALARMS, VALUE(1) }, - { { 0 }, 0 } - }; - -static sensors_chip_feature ddcmon_features[] = - { - { { SENSORS_DDCMON_MAN_ID, "Manufacturer ID", NOMAP, NOMAP, R }, - DDCMON_SYSCTL_ID, VALUE(1), 0 }, - { { SENSORS_DDCMON_PROD_ID, "Model Number", NOMAP, NOMAP, R }, - DDCMON_SYSCTL_ID, VALUE(2), 0 }, - { { SENSORS_DDCMON_VERSIZE, "Monitor Size (cm)", NOMAP, NOMAP, R }, - DDCMON_SYSCTL_SIZE, VALUE(1), 0 }, - { { SENSORS_DDCMON_HORSIZE, "hsize", SENSORS_DDCMON_VERSIZE, NOMAP, R }, - DDCMON_SYSCTL_SIZE, VALUE(2), 0 }, - { { SENSORS_DDCMON_VERSYNCMIN, "Vertical Sync (Hz)", NOMAP, NOMAP, R }, - DDCMON_SYSCTL_SYNC, VALUE(1), 0 }, - { { SENSORS_DDCMON_VERSYNCMAX, "v_sync_max", SENSORS_DDCMON_VERSYNCMIN, - NOMAP, R }, - DDCMON_SYSCTL_SYNC, VALUE(2), 0 }, - { { SENSORS_DDCMON_HORSYNCMIN, "Horizontal Sync (KHz)", NOMAP, NOMAP, R }, - DDCMON_SYSCTL_SYNC, VALUE(3), 0 }, - { { SENSORS_DDCMON_HORSYNCMAX, "h_sync_max", SENSORS_DDCMON_HORSYNCMIN, - NOMAP, R }, - DDCMON_SYSCTL_SYNC, VALUE(4), 0 }, - { { SENSORS_DDCMON_TIMINGS, "Established Timings", NOMAP, NOMAP, R }, - DDCMON_SYSCTL_TIMINGS, VALUE(1), 0 }, - { { SENSORS_DDCMON_SERIAL, "Serial Number", NOMAP, NOMAP, R }, - DDCMON_SYSCTL_SERIAL, VALUE(1), 0 }, - { { SENSORS_DDCMON_YEAR, "Manufacture Time", NOMAP, NOMAP, R }, - DDCMON_SYSCTL_TIME, VALUE(1), 0 }, - { { SENSORS_DDCMON_WEEK, "week", SENSORS_DDCMON_YEAR, NOMAP, R }, - DDCMON_SYSCTL_TIME, VALUE(2), 0 }, - { { SENSORS_DDCMON_EDID_VER, "EDID Version", NOMAP, NOMAP, R }, - DDCMON_SYSCTL_EDID, VALUE(1), 0 }, - { { SENSORS_DDCMON_EDID_REV, "revision", SENSORS_DDCMON_EDID_VER, NOMAP, R }, - DDCMON_SYSCTL_EDID, VALUE(2), 0 }, - { { SENSORS_DDCMON_GAMMA, "Gamma Factor", NOMAP, NOMAP, R }, - DDCMON_SYSCTL_GAMMA, VALUE(1), 2 }, - { { SENSORS_DDCMON_DPMS, "DPMS Modes", NOMAP, NOMAP, R }, - DDCMON_SYSCTL_DPMS, VALUE(1), 0 }, - { { SENSORS_DDCMON_TIMING1_HOR, "Standard Timing 1", NOMAP, NOMAP, R }, - DDCMON_SYSCTL_TIMING1, VALUE(1), 0 }, - { { SENSORS_DDCMON_TIMING1_VER, "vertical", SENSORS_DDCMON_TIMING1_HOR, - NOMAP, R }, - DDCMON_SYSCTL_TIMING1, VALUE(2), 0 }, - { { SENSORS_DDCMON_TIMING1_REF, "refresh", SENSORS_DDCMON_TIMING1_HOR, NOMAP, - R }, - DDCMON_SYSCTL_TIMING1, VALUE(3), 0 }, - { { SENSORS_DDCMON_TIMING2_HOR, "Standard Timing 2", NOMAP, NOMAP, R }, - DDCMON_SYSCTL_TIMING2, VALUE(1), 0 }, - { { SENSORS_DDCMON_TIMING2_VER, "vertical", SENSORS_DDCMON_TIMING2_HOR, - NOMAP, R }, - DDCMON_SYSCTL_TIMING2, VALUE(2), 0 }, - { { SENSORS_DDCMON_TIMING2_REF, "refresh", SENSORS_DDCMON_TIMING2_HOR, NOMAP, - R }, - DDCMON_SYSCTL_TIMING2, VALUE(3), 0 }, - { { SENSORS_DDCMON_TIMING3_HOR, "Standard Timing 3", NOMAP, NOMAP, R }, - DDCMON_SYSCTL_TIMING3, VALUE(1), 0 }, - { { SENSORS_DDCMON_TIMING3_VER, "vertical", SENSORS_DDCMON_TIMING3_HOR, - NOMAP, R }, - DDCMON_SYSCTL_TIMING3, VALUE(2), 0 }, - { { SENSORS_DDCMON_TIMING3_REF, "refresh", SENSORS_DDCMON_TIMING3_HOR, NOMAP, - R }, - DDCMON_SYSCTL_TIMING3, VALUE(3), 0 }, - { { SENSORS_DDCMON_TIMING4_HOR, "Standard Timing 4", NOMAP, NOMAP, R }, - DDCMON_SYSCTL_TIMING4, VALUE(1), 0 }, - { { SENSORS_DDCMON_TIMING4_VER, "vertical", SENSORS_DDCMON_TIMING4_HOR, - NOMAP, R }, - DDCMON_SYSCTL_TIMING4, VALUE(2), 0 }, - { { SENSORS_DDCMON_TIMING4_REF, "refresh", SENSORS_DDCMON_TIMING4_HOR, NOMAP, - R }, - DDCMON_SYSCTL_TIMING4, VALUE(3), 0 }, - { { SENSORS_DDCMON_TIMING5_HOR, "Standard Timing 5", NOMAP, NOMAP, R }, - DDCMON_SYSCTL_TIMING5, VALUE(1), 0 }, - { { SENSORS_DDCMON_TIMING5_VER, "vertical", SENSORS_DDCMON_TIMING5_HOR, - NOMAP, R }, - DDCMON_SYSCTL_TIMING5, VALUE(2), 0 }, - { { SENSORS_DDCMON_TIMING5_REF, "refresh", SENSORS_DDCMON_TIMING5_HOR, NOMAP, - R }, - DDCMON_SYSCTL_TIMING5, VALUE(3), 0 }, - { { SENSORS_DDCMON_TIMING6_HOR, "Standard Timing 6", NOMAP, NOMAP, R }, - DDCMON_SYSCTL_TIMING6, VALUE(1), 0 }, - { { SENSORS_DDCMON_TIMING6_VER, "vertical", SENSORS_DDCMON_TIMING6_HOR, - NOMAP, R }, - DDCMON_SYSCTL_TIMING6, VALUE(2), 0 }, - { { SENSORS_DDCMON_TIMING6_REF, "refresh", SENSORS_DDCMON_TIMING6_HOR, NOMAP, - R }, - DDCMON_SYSCTL_TIMING6, VALUE(3), 0 }, - { { SENSORS_DDCMON_TIMING7_HOR, "Standard Timing 7", NOMAP, NOMAP, R }, - DDCMON_SYSCTL_TIMING7, VALUE(1), 0 }, - { { SENSORS_DDCMON_TIMING7_VER, "vertical", SENSORS_DDCMON_TIMING7_HOR, - NOMAP, R }, - DDCMON_SYSCTL_TIMING7, VALUE(2), 0 }, - { { SENSORS_DDCMON_TIMING7_REF, "refresh", SENSORS_DDCMON_TIMING7_HOR, NOMAP, - R }, - DDCMON_SYSCTL_TIMING7, VALUE(3), 0 }, - { { SENSORS_DDCMON_TIMING8_HOR, "Standard Timing 8", NOMAP, NOMAP, R }, - DDCMON_SYSCTL_TIMING8, VALUE(1), 0 }, - { { SENSORS_DDCMON_TIMING8_VER, "vertical", SENSORS_DDCMON_TIMING8_HOR, - NOMAP, R }, - DDCMON_SYSCTL_TIMING8, VALUE(2), 0 }, - { { SENSORS_DDCMON_TIMING8_REF, "refresh", SENSORS_DDCMON_TIMING8_HOR, NOMAP, - R }, - DDCMON_SYSCTL_TIMING8, VALUE(3), 0 }, - { { SENSORS_DDCMON_MAXCLOCK, "Max Pixel Clock (MHz)", NOMAP, NOMAP, R }, - DDCMON_SYSCTL_MAXCLOCK, VALUE(1), 0 }, - { { 0 }, 0 } - }; - -static sensors_chip_feature eeprom_features[] = - { - { { SENSORS_EEPROM_TYPE, "Memory type", NOMAP, NOMAP, R }, - EEPROM_SYSCTL1, VALUE(3), 0 }, -/* cheat and use the row-address-bits label for the total size in sensors */ - { { SENSORS_EEPROM_ROWADDR, "Memory size (MB)", NOMAP, NOMAP, R }, - EEPROM_SYSCTL1, VALUE(4), 0 }, - { { SENSORS_EEPROM_COLADDR, "col", NOMAP, NOMAP, R }, - EEPROM_SYSCTL1, VALUE(5), 0 }, - { { SENSORS_EEPROM_NUMROWS, "num rows", NOMAP, NOMAP, R }, - EEPROM_SYSCTL1, VALUE(6), 0 }, - { { SENSORS_EEPROM_BANKS, "banks", NOMAP, NOMAP, R }, - EEPROM_SYSCTL2, VALUE(2), 0 }, -/* for Sony Vaio's eeproms */ - { { SENSORS_EEPROM_VAIO_NAME, "Machine name", NOMAP, NOMAP, R }, - EEPROM_SYSCTL9, VALUE(1), 0 }, - { { SENSORS_EEPROM_VAIO_NAME+1, "name2", NOMAP, NOMAP, R }, - EEPROM_SYSCTL9, VALUE(2), 0 }, - { { SENSORS_EEPROM_VAIO_NAME+2, "name3", NOMAP, NOMAP, R }, - EEPROM_SYSCTL9, VALUE(3), 0 }, - { { SENSORS_EEPROM_VAIO_NAME+3, "name4", NOMAP, NOMAP, R }, - EEPROM_SYSCTL9, VALUE(4), 0 }, - { { SENSORS_EEPROM_VAIO_NAME+4, "name5", NOMAP, NOMAP, R }, - EEPROM_SYSCTL9, VALUE(5), 0 }, - { { SENSORS_EEPROM_VAIO_NAME+5, "name6", NOMAP, NOMAP, R }, - EEPROM_SYSCTL9, VALUE(6), 0 }, - { { SENSORS_EEPROM_VAIO_NAME+6, "name7", NOMAP, NOMAP, R }, - EEPROM_SYSCTL9, VALUE(7), 0 }, - { { SENSORS_EEPROM_VAIO_NAME+7, "name8", NOMAP, NOMAP, R }, - EEPROM_SYSCTL9, VALUE(8), 0 }, - { { SENSORS_EEPROM_VAIO_NAME+8, "name9", NOMAP, NOMAP, R }, - EEPROM_SYSCTL9, VALUE(9), 0 }, - { { SENSORS_EEPROM_VAIO_NAME+9, "name10", NOMAP, NOMAP, R }, - EEPROM_SYSCTL9, VALUE(10), 0 }, - { { SENSORS_EEPROM_VAIO_NAME+10, "name11", NOMAP, NOMAP, R }, - EEPROM_SYSCTL9, VALUE(11), 0 }, - { { SENSORS_EEPROM_VAIO_NAME+11, "name12", NOMAP, NOMAP, R }, - EEPROM_SYSCTL9, VALUE(12), 0 }, - { { SENSORS_EEPROM_VAIO_NAME+12, "name13", NOMAP, NOMAP, R }, - EEPROM_SYSCTL9, VALUE(13), 0 }, - { { SENSORS_EEPROM_VAIO_NAME+13, "name14", NOMAP, NOMAP, R }, - EEPROM_SYSCTL9, VALUE(14), 0 }, - { { SENSORS_EEPROM_VAIO_NAME+14, "name15", NOMAP, NOMAP, R }, - EEPROM_SYSCTL9, VALUE(15), 0 }, - { { SENSORS_EEPROM_VAIO_NAME+15, "name16", NOMAP, NOMAP, R }, - EEPROM_SYSCTL9, VALUE(16), 0 }, - { { SENSORS_EEPROM_VAIO_NAME+16, "name17", NOMAP, NOMAP, R }, - EEPROM_SYSCTL10, VALUE(1), 0 }, - { { SENSORS_EEPROM_VAIO_NAME+17, "name18", NOMAP, NOMAP, R }, - EEPROM_SYSCTL10, VALUE(2), 0 }, - { { SENSORS_EEPROM_VAIO_NAME+18, "name19", NOMAP, NOMAP, R }, - EEPROM_SYSCTL10, VALUE(3), 0 }, - { { SENSORS_EEPROM_VAIO_NAME+19, "name20", NOMAP, NOMAP, R }, - EEPROM_SYSCTL10, VALUE(4), 0 }, - { { SENSORS_EEPROM_VAIO_NAME+20, "name21", NOMAP, NOMAP, R }, - EEPROM_SYSCTL10, VALUE(5), 0 }, - { { SENSORS_EEPROM_VAIO_NAME+21, "name22", NOMAP, NOMAP, R }, - EEPROM_SYSCTL10, VALUE(6), 0 }, - { { SENSORS_EEPROM_VAIO_NAME+22, "name23", NOMAP, NOMAP, R }, - EEPROM_SYSCTL10, VALUE(7), 0 }, - { { SENSORS_EEPROM_VAIO_NAME+23, "name24", NOMAP, NOMAP, R }, - EEPROM_SYSCTL10, VALUE(8), 0 }, - { { SENSORS_EEPROM_VAIO_NAME+24, "name25", NOMAP, NOMAP, R }, - EEPROM_SYSCTL10, VALUE(9), 0 }, - { { SENSORS_EEPROM_VAIO_NAME+25, "name26", NOMAP, NOMAP, R }, - EEPROM_SYSCTL10, VALUE(10), 0 }, - { { SENSORS_EEPROM_VAIO_NAME+26, "name27", NOMAP, NOMAP, R }, - EEPROM_SYSCTL10, VALUE(11), 0 }, - { { SENSORS_EEPROM_VAIO_NAME+27, "name28", NOMAP, NOMAP, R }, - EEPROM_SYSCTL10, VALUE(12), 0 }, - { { SENSORS_EEPROM_VAIO_NAME+28, "name29", NOMAP, NOMAP, R }, - EEPROM_SYSCTL10, VALUE(13), 0 }, - { { SENSORS_EEPROM_VAIO_NAME+29, "name30", NOMAP, NOMAP, R }, - EEPROM_SYSCTL10, VALUE(14), 0 }, - { { SENSORS_EEPROM_VAIO_NAME+30, "name31", NOMAP, NOMAP, R }, - EEPROM_SYSCTL10, VALUE(15), 0 }, - { { SENSORS_EEPROM_VAIO_NAME+31, "name32", NOMAP, NOMAP, R }, - EEPROM_SYSCTL10, VALUE(16), 0 }, - { { SENSORS_EEPROM_VAIO_SERIAL, "Serial number", NOMAP, NOMAP, R }, - EEPROM_SYSCTL13, VALUE(1), 0 }, - { { SENSORS_EEPROM_VAIO_SERIAL+1, "serial2", NOMAP, NOMAP, R }, - EEPROM_SYSCTL13, VALUE(2), 0 }, - { { SENSORS_EEPROM_VAIO_SERIAL+2, "serial3", NOMAP, NOMAP, R }, - EEPROM_SYSCTL13, VALUE(3), 0 }, - { { SENSORS_EEPROM_VAIO_SERIAL+3, "serial4", NOMAP, NOMAP, R }, - EEPROM_SYSCTL13, VALUE(4), 0 }, - { { SENSORS_EEPROM_VAIO_SERIAL+4, "serial5", NOMAP, NOMAP, R }, - EEPROM_SYSCTL13, VALUE(5), 0 }, - { { SENSORS_EEPROM_VAIO_SERIAL+5, "serial6", NOMAP, NOMAP, R }, - EEPROM_SYSCTL13, VALUE(6), 0 }, - { { SENSORS_EEPROM_VAIO_SERIAL+6, "serial7", NOMAP, NOMAP, R }, - EEPROM_SYSCTL13, VALUE(7), 0 }, - { { SENSORS_EEPROM_VAIO_SERIAL+7, "serial8", NOMAP, NOMAP, R }, - EEPROM_SYSCTL13, VALUE(8), 0 }, - { { SENSORS_EEPROM_VAIO_SERIAL+8, "serial9", NOMAP, NOMAP, R }, - EEPROM_SYSCTL13, VALUE(9), 0 }, - { { SENSORS_EEPROM_VAIO_SERIAL+9, "serial10", NOMAP, NOMAP, R }, - EEPROM_SYSCTL13, VALUE(10), 0 }, - { { SENSORS_EEPROM_VAIO_SERIAL+10, "serial11", NOMAP, NOMAP, R }, - EEPROM_SYSCTL13, VALUE(11), 0 }, - { { SENSORS_EEPROM_VAIO_SERIAL+11, "serial12", NOMAP, NOMAP, R }, - EEPROM_SYSCTL13, VALUE(12), 0 }, - { { SENSORS_EEPROM_VAIO_SERIAL+12, "serial13", NOMAP, NOMAP, R }, - EEPROM_SYSCTL13, VALUE(13), 0 }, - { { SENSORS_EEPROM_VAIO_SERIAL+13, "serial14", NOMAP, NOMAP, R }, - EEPROM_SYSCTL13, VALUE(14), 0 }, - { { SENSORS_EEPROM_VAIO_SERIAL+14, "serial15", NOMAP, NOMAP, R }, - EEPROM_SYSCTL13, VALUE(15), 0 }, - { { SENSORS_EEPROM_VAIO_SERIAL+15, "serial16", NOMAP, NOMAP, R }, - EEPROM_SYSCTL13, VALUE(16), 0 }, - { { SENSORS_EEPROM_VAIO_SERIAL+16, "serial17", NOMAP, NOMAP, R }, - EEPROM_SYSCTL14, VALUE(1), 0 }, - { { SENSORS_EEPROM_VAIO_SERIAL+17, "serial18", NOMAP, NOMAP, R }, - EEPROM_SYSCTL14, VALUE(2), 0 }, - { { SENSORS_EEPROM_VAIO_SERIAL+18, "serial19", NOMAP, NOMAP, R }, - EEPROM_SYSCTL14, VALUE(3), 0 }, - { { SENSORS_EEPROM_VAIO_SERIAL+19, "serial20", NOMAP, NOMAP, R }, - EEPROM_SYSCTL14, VALUE(4), 0 }, - { { SENSORS_EEPROM_VAIO_SERIAL+20, "serial21", NOMAP, NOMAP, R }, - EEPROM_SYSCTL14, VALUE(5), 0 }, - { { SENSORS_EEPROM_VAIO_SERIAL+21, "serial22", NOMAP, NOMAP, R }, - EEPROM_SYSCTL14, VALUE(6), 0 }, - { { SENSORS_EEPROM_VAIO_SERIAL+22, "serial23", NOMAP, NOMAP, R }, - EEPROM_SYSCTL14, VALUE(7), 0 }, - { { SENSORS_EEPROM_VAIO_SERIAL+23, "serial24", NOMAP, NOMAP, R }, - EEPROM_SYSCTL14, VALUE(8), 0 }, - { { SENSORS_EEPROM_VAIO_SERIAL+24, "serial25", NOMAP, NOMAP, R }, - EEPROM_SYSCTL14, VALUE(9), 0 }, - { { SENSORS_EEPROM_VAIO_SERIAL+25, "serial26", NOMAP, NOMAP, R }, - EEPROM_SYSCTL14, VALUE(10), 0 }, - { { SENSORS_EEPROM_VAIO_SERIAL+26, "serial27", NOMAP, NOMAP, R }, - EEPROM_SYSCTL14, VALUE(11), 0 }, - { { SENSORS_EEPROM_VAIO_SERIAL+27, "serial28", NOMAP, NOMAP, R }, - EEPROM_SYSCTL14, VALUE(12), 0 }, - { { SENSORS_EEPROM_VAIO_SERIAL+28, "serial29", NOMAP, NOMAP, R }, - EEPROM_SYSCTL14, VALUE(13), 0 }, - { { SENSORS_EEPROM_VAIO_SERIAL+29, "serial30", NOMAP, NOMAP, R }, - EEPROM_SYSCTL14, VALUE(14), 0 }, - { { SENSORS_EEPROM_VAIO_SERIAL+30, "serial31", NOMAP, NOMAP, R }, - EEPROM_SYSCTL14, VALUE(15), 0 }, - { { SENSORS_EEPROM_VAIO_SERIAL+31, "serial32", NOMAP, NOMAP, R }, - EEPROM_SYSCTL14, VALUE(16), 0 }, -/* for monitor's edid */ - { { SENSORS_EEPROM_EDID_HEADER, "EDID header", NOMAP, NOMAP, R }, - EEPROM_SYSCTL1, VALUE(1), 0 }, -/* for Shuttle EEPROMS */ - { { SENSORS_EEPROM_SHUTTLE, "Ethernet Address", NOMAP, NOMAP, R }, - EEPROM_SYSCTL1, VALUE(1), 0 }, - { { SENSORS_EEPROM_SHUTTLE, "shuttle2", NOMAP, NOMAP, R }, - EEPROM_SYSCTL1, VALUE(2), 0 }, - { { SENSORS_EEPROM_SHUTTLE, "shuttle3", NOMAP, NOMAP, R }, - EEPROM_SYSCTL1, VALUE(3), 0 }, - { { SENSORS_EEPROM_SHUTTLE, "shuttle4", NOMAP, NOMAP, R }, - EEPROM_SYSCTL1, VALUE(4), 0 }, - { { SENSORS_EEPROM_SHUTTLE, "shuttle5", NOMAP, NOMAP, R }, - EEPROM_SYSCTL1, VALUE(5), 0 }, - { { SENSORS_EEPROM_SHUTTLE, "shuttle6", NOMAP, NOMAP, R }, - EEPROM_SYSCTL1, VALUE(6), 0 }, - { { 0 }, 0 } - }; - -/* NOTE: Many shared values with adm1027_features !!! */ -static sensors_chip_feature lm85_features[] = - { - { { SENSORS_LM85_IN0, "in0", NOMAP, NOMAP, R }, - LM85_SYSCTL_IN0, VALUE(3), 3 }, - { { SENSORS_LM85_IN1, "in1", NOMAP, NOMAP, R }, - LM85_SYSCTL_IN1, VALUE(3), 3 }, - { { SENSORS_LM85_IN2, "in2", NOMAP, NOMAP, R }, - LM85_SYSCTL_IN2, VALUE(3), 3 }, - { { SENSORS_LM85_IN3, "in3", NOMAP, NOMAP, R }, - LM85_SYSCTL_IN3, VALUE(3), 3 }, - { { SENSORS_LM85_IN4, "in4", NOMAP, NOMAP, R }, - LM85_SYSCTL_IN4, VALUE(3), 3 }, - { { SENSORS_LM85_IN5, "in5", NOMAP, NOMAP, R }, - EMC6D100_SYSCTL_IN5, VALUE(3), 3 }, - { { SENSORS_LM85_IN6, "in6", NOMAP, NOMAP, R }, - EMC6D100_SYSCTL_IN6, VALUE(3), 3 }, - { { SENSORS_LM85_IN7, "in7", NOMAP, NOMAP, R }, - EMC6D100_SYSCTL_IN7, VALUE(3), 3 }, - { { SENSORS_LM85_IN0_MIN, "in0_min", SENSORS_LM85_IN0, SENSORS_LM85_IN0, RW }, - LM85_SYSCTL_IN0, VALUE(1), 3 }, - { { SENSORS_LM85_IN1_MIN, "in1_min", SENSORS_LM85_IN1, SENSORS_LM85_IN1, RW }, - LM85_SYSCTL_IN1, VALUE(1), 3 }, - { { SENSORS_LM85_IN2_MIN, "in2_min", SENSORS_LM85_IN2, SENSORS_LM85_IN2, RW }, - LM85_SYSCTL_IN2, VALUE(1), 3 }, - { { SENSORS_LM85_IN3_MIN, "in3_min", SENSORS_LM85_IN3, SENSORS_LM85_IN3, RW }, - LM85_SYSCTL_IN3, VALUE(1), 3 }, - { { SENSORS_LM85_IN4_MIN, "in4_min", SENSORS_LM85_IN4, SENSORS_LM85_IN4, RW }, - LM85_SYSCTL_IN4, VALUE(1), 3 }, - { { SENSORS_LM85_IN5_MIN, "in5_min", SENSORS_LM85_IN5, SENSORS_LM85_IN5, RW }, - EMC6D100_SYSCTL_IN5, VALUE(1), 3 }, - { { SENSORS_LM85_IN6_MIN, "in6_min", SENSORS_LM85_IN6, SENSORS_LM85_IN6, RW }, - EMC6D100_SYSCTL_IN6, VALUE(1), 3 }, - { { SENSORS_LM85_IN7_MIN, "in7_min", SENSORS_LM85_IN7, SENSORS_LM85_IN7, RW }, - EMC6D100_SYSCTL_IN7, VALUE(1), 3 }, - { { SENSORS_LM85_IN0_MAX, "in0_max", SENSORS_LM85_IN0, SENSORS_LM85_IN0, RW }, - LM85_SYSCTL_IN0, VALUE(2), 3 }, - { { SENSORS_LM85_IN1_MAX, "in1_max", SENSORS_LM85_IN1, SENSORS_LM85_IN1, RW }, - LM85_SYSCTL_IN1, VALUE(2), 3 }, - { { SENSORS_LM85_IN2_MAX, "in2_max", SENSORS_LM85_IN2, SENSORS_LM85_IN2, RW }, - LM85_SYSCTL_IN2, VALUE(2), 3 }, - { { SENSORS_LM85_IN3_MAX, "in3_max", SENSORS_LM85_IN3, SENSORS_LM85_IN3, RW }, - LM85_SYSCTL_IN3, VALUE(2), 3 }, - { { SENSORS_LM85_IN4_MAX, "in4_max", SENSORS_LM85_IN4, SENSORS_LM85_IN4, RW }, - LM85_SYSCTL_IN4, VALUE(2), 3 }, - { { SENSORS_LM85_IN5_MAX, "in5_max", SENSORS_LM85_IN5, SENSORS_LM85_IN5, RW }, - EMC6D100_SYSCTL_IN5, VALUE(2), 3 }, - { { SENSORS_LM85_IN6_MAX, "in6_max", SENSORS_LM85_IN6, SENSORS_LM85_IN6, RW }, - EMC6D100_SYSCTL_IN6, VALUE(2), 3 }, - { { SENSORS_LM85_IN7_MAX, "in7_max", SENSORS_LM85_IN7, SENSORS_LM85_IN7, RW }, - EMC6D100_SYSCTL_IN7, VALUE(2), 3 }, - { { SENSORS_LM85_FAN1, "fan1", NOMAP, NOMAP, R }, - LM85_SYSCTL_FAN1, VALUE(2), 0 }, - { { SENSORS_LM85_FAN2, "fan2", NOMAP, NOMAP, R }, - LM85_SYSCTL_FAN2, VALUE(2), 0 }, - { { SENSORS_LM85_FAN3, "fan3", NOMAP, NOMAP, R }, - LM85_SYSCTL_FAN3, VALUE(2), 0 }, - { { SENSORS_LM85_FAN4, "fan4", NOMAP, NOMAP, R }, - LM85_SYSCTL_FAN4, VALUE(2), 0 }, - { { SENSORS_LM85_FAN1_MIN, "fan1_min", SENSORS_LM85_FAN1, SENSORS_LM85_FAN1, - RW }, - LM85_SYSCTL_FAN1, VALUE(1), 0 }, - { { SENSORS_LM85_FAN2_MIN, "fan2_min", SENSORS_LM85_FAN2, SENSORS_LM85_FAN2, - RW }, - LM85_SYSCTL_FAN2, VALUE(1), 0 }, - { { SENSORS_LM85_FAN3_MIN, "fan3_min", SENSORS_LM85_FAN3, SENSORS_LM85_FAN3, - RW }, - LM85_SYSCTL_FAN3, VALUE(1), 0 }, - { { SENSORS_LM85_FAN4_MIN, "fan4_min", SENSORS_LM85_FAN4, SENSORS_LM85_FAN4, - RW }, - LM85_SYSCTL_FAN4, VALUE(1), 0 }, - { { SENSORS_LM85_TEMP1, "temp1", NOMAP, NOMAP, R }, - LM85_SYSCTL_TEMP1, VALUE(3), 2 }, - { { SENSORS_LM85_TEMP2, "temp2", NOMAP, NOMAP, R }, - LM85_SYSCTL_TEMP2, VALUE(3), 2 }, - { { SENSORS_LM85_TEMP3, "temp3", NOMAP, NOMAP, R }, - LM85_SYSCTL_TEMP3, VALUE(3), 2 }, - { { SENSORS_LM85_TEMP1_MIN, "temp1_min", SENSORS_LM85_TEMP1, - SENSORS_LM85_TEMP1, RW }, - LM85_SYSCTL_TEMP1, VALUE(1), 2 }, - { { SENSORS_LM85_TEMP2_MIN, "temp2_min", SENSORS_LM85_TEMP2, - SENSORS_LM85_TEMP2, RW }, - LM85_SYSCTL_TEMP2, VALUE(1), 2 }, - { { SENSORS_LM85_TEMP3_MIN, "temp3_min", SENSORS_LM85_TEMP3, - SENSORS_LM85_TEMP3, RW }, - LM85_SYSCTL_TEMP3, VALUE(1), 2 }, - { { SENSORS_LM85_TEMP1_MAX, "temp1_max", SENSORS_LM85_TEMP1, - SENSORS_LM85_TEMP1, RW }, - LM85_SYSCTL_TEMP1, VALUE(2), 2 }, - { { SENSORS_LM85_TEMP2_MAX, "temp2_max", SENSORS_LM85_TEMP2, - SENSORS_LM85_TEMP2, RW }, - LM85_SYSCTL_TEMP2, VALUE(2), 2 }, - { { SENSORS_LM85_TEMP3_MAX, "temp3_max", SENSORS_LM85_TEMP3, - SENSORS_LM85_TEMP3, RW }, - LM85_SYSCTL_TEMP3, VALUE(2), 2 }, - { { SENSORS_LM85_VID, "vid", NOMAP, NOMAP, R }, - LM85_SYSCTL_VID, VALUE(1), 3 }, - { { SENSORS_LM85_VRM, "vrm", NOMAP, NOMAP, RW }, - LM85_SYSCTL_VRM, VALUE(1), 1 }, - { { SENSORS_LM85_ALARMS, "alarms", NOMAP, NOMAP, R }, - LM85_SYSCTL_ALARMS, VALUE(1), 0 }, - { { SENSORS_LM85_PWM1, "pwm1", NOMAP, NOMAP, RW }, - LM85_SYSCTL_PWM1, VALUE(1), 0 }, - { { SENSORS_LM85_PWM2, "pwm2", NOMAP, NOMAP, RW }, - LM85_SYSCTL_PWM2, VALUE(1), 0 }, - { { SENSORS_LM85_PWM3, "pwm3", NOMAP, NOMAP, RW }, - LM85_SYSCTL_PWM3, VALUE(1), 0 }, - { { SENSORS_LM85_PWM1_SPINUP, "pwm1_spinup", SENSORS_LM85_PWM1, NOMAP, RW }, - LM85_SYSCTL_PWM_CFG1, VALUE(1), 1 }, - { { SENSORS_LM85_PWM2_SPINUP, "pwm2_spinup", SENSORS_LM85_PWM2, NOMAP, RW }, - LM85_SYSCTL_PWM_CFG2, VALUE(1), 1 }, - { { SENSORS_LM85_PWM3_SPINUP, "pwm3_spinup", SENSORS_LM85_PWM3, NOMAP, RW }, - LM85_SYSCTL_PWM_CFG3, VALUE(1), 1 }, - { { SENSORS_LM85_PWM1_MIN, "pwm1_min", SENSORS_LM85_PWM1, NOMAP, RW }, - LM85_SYSCTL_PWM_CFG1, VALUE(2), 1 }, - { { SENSORS_LM85_PWM2_MIN, "pwm2_min", SENSORS_LM85_PWM2, NOMAP, RW }, - LM85_SYSCTL_PWM_CFG2, VALUE(2), 1 }, - { { SENSORS_LM85_PWM3_MIN, "pwm3_min", SENSORS_LM85_PWM3, NOMAP, RW }, - LM85_SYSCTL_PWM_CFG3, VALUE(2), 1 }, - { { SENSORS_LM85_PWM1_FREQ, "pwm1_freq", SENSORS_LM85_PWM1, NOMAP, RW }, - LM85_SYSCTL_PWM_CFG1, VALUE(3), 1 }, - { { SENSORS_LM85_PWM2_FREQ, "pwm2_freq", SENSORS_LM85_PWM2, NOMAP, RW }, - LM85_SYSCTL_PWM_CFG2, VALUE(3), 1 }, - { { SENSORS_LM85_PWM3_FREQ, "pwm3_freq", SENSORS_LM85_PWM3, NOMAP, RW }, - LM85_SYSCTL_PWM_CFG3, VALUE(3), 1 }, - { { SENSORS_LM85_PWM1_MIN_CTL, "pwm1_min_ctl", SENSORS_LM85_PWM1, NOMAP, RW }, - LM85_SYSCTL_PWM_CFG1, VALUE(4), 1 }, - { { SENSORS_LM85_PWM2_MIN_CTL, "pwm2_min_ctl", SENSORS_LM85_PWM2, NOMAP, RW }, - LM85_SYSCTL_PWM_CFG2, VALUE(4), 1 }, - { { SENSORS_LM85_PWM3_MIN_CTL, "pwm3_min_ctl", SENSORS_LM85_PWM3, NOMAP, RW }, - LM85_SYSCTL_PWM_CFG3, VALUE(4), 1 }, - { { SENSORS_LM85_PWM1_INVERT, "pwm1_invert", SENSORS_LM85_PWM1, NOMAP, RW }, - LM85_SYSCTL_PWM_CFG1, VALUE(5), 0 }, - { { SENSORS_LM85_PWM2_INVERT, "pwm2_invert", SENSORS_LM85_PWM2, NOMAP, RW }, - LM85_SYSCTL_PWM_CFG2, VALUE(5), 0 }, - { { SENSORS_LM85_PWM3_INVERT, "pwm3_invert", SENSORS_LM85_PWM3, NOMAP, RW }, - LM85_SYSCTL_PWM_CFG3, VALUE(5), 0 }, - { { SENSORS_LM85_PWM1_ZONE, "pwm1_zone", SENSORS_LM85_PWM1, NOMAP, RW }, - LM85_SYSCTL_PWM_ZONE1, VALUE(1), 0 }, - { { SENSORS_LM85_PWM2_ZONE, "pwm2_zone", SENSORS_LM85_PWM2, NOMAP, RW }, - LM85_SYSCTL_PWM_ZONE2, VALUE(1), 0 }, - { { SENSORS_LM85_PWM3_ZONE, "pwm3_zone", SENSORS_LM85_PWM3, NOMAP, RW }, - LM85_SYSCTL_PWM_ZONE3, VALUE(1), 0 }, - { { SENSORS_LM85_ZONE1_LIMIT, "zone1_limit", SENSORS_LM85_TEMP1, NOMAP, RW }, - LM85_SYSCTL_ZONE1, VALUE(1), 1 }, - { { SENSORS_LM85_ZONE2_LIMIT, "zone2_limit", SENSORS_LM85_TEMP2, NOMAP, RW }, - LM85_SYSCTL_ZONE2, VALUE(1), 1 }, - { { SENSORS_LM85_ZONE3_LIMIT, "zone3_limit", SENSORS_LM85_TEMP3, NOMAP, RW }, - LM85_SYSCTL_ZONE3, VALUE(1), 1 }, - { { SENSORS_LM85_ZONE1_HYST, "zone1_hyst", SENSORS_LM85_TEMP1, NOMAP, RW }, - LM85_SYSCTL_ZONE1, VALUE(2), 1 }, - { { SENSORS_LM85_ZONE2_HYST, "zone2_hyst", SENSORS_LM85_TEMP2, NOMAP, RW }, - LM85_SYSCTL_ZONE2, VALUE(2), 1 }, - { { SENSORS_LM85_ZONE3_HYST, "zone3_hyst", SENSORS_LM85_TEMP3, NOMAP, RW }, - LM85_SYSCTL_ZONE3, VALUE(2), 1 }, - { { SENSORS_LM85_ZONE1_RANGE, "zone1_range", SENSORS_LM85_TEMP1, NOMAP, RW }, - LM85_SYSCTL_ZONE1, VALUE(3), 1 }, - { { SENSORS_LM85_ZONE2_RANGE, "zone2_range", SENSORS_LM85_TEMP2, NOMAP, RW }, - LM85_SYSCTL_ZONE2, VALUE(3), 1 }, - { { SENSORS_LM85_ZONE3_RANGE, "zone3_range", SENSORS_LM85_TEMP3, NOMAP, RW }, - LM85_SYSCTL_ZONE3, VALUE(3), 1 }, - { { SENSORS_LM85_ZONE1_CRITICAL, "zone1_critical", SENSORS_LM85_TEMP1, NOMAP, - RW }, - LM85_SYSCTL_ZONE1, VALUE(4), 1 }, - { { SENSORS_LM85_ZONE2_CRITICAL, "zone2_critical", SENSORS_LM85_TEMP2, NOMAP, - RW }, - LM85_SYSCTL_ZONE2, VALUE(4), 1 }, - { { SENSORS_LM85_ZONE3_CRITICAL, "zone3_critical", SENSORS_LM85_TEMP3, NOMAP, - RW }, - LM85_SYSCTL_ZONE3, VALUE(4), 1 }, - - { { SENSORS_LM85_PWM1_SPINUP_CTL, "pwm1_spinup_ctl", SENSORS_LM85_PWM1, - NOMAP, RW }, - LM85_SYSCTL_SPINUP_CTL, VALUE(1), 0 }, - { { SENSORS_LM85_PWM2_SPINUP_CTL, "pwm2_spinup_ctl", SENSORS_LM85_PWM2, - NOMAP, RW }, - LM85_SYSCTL_SPINUP_CTL, VALUE(2), 0 }, - { { SENSORS_LM85_PWM3_SPINUP_CTL, "pwm3_spinup_ctl", SENSORS_LM85_PWM3, - NOMAP, RW }, - LM85_SYSCTL_SPINUP_CTL, VALUE(3), 0 }, - { { SENSORS_LM85_FAN1_TACH_MODE, "fan1_tach_mode", SENSORS_LM85_FAN1, NOMAP, - RW }, - LM85_SYSCTL_TACH_MODE, VALUE(1), 0 }, - { { SENSORS_LM85_FAN2_TACH_MODE, "fan2_tach_mode", SENSORS_LM85_FAN2, NOMAP, - RW }, - LM85_SYSCTL_TACH_MODE, VALUE(2), 0 }, - { { SENSORS_LM85_FAN3_TACH_MODE, "fan3_tach_mode", SENSORS_LM85_FAN3, NOMAP, - RW }, - LM85_SYSCTL_TACH_MODE, VALUE(3), 0 }, - { { SENSORS_LM85_ZONE1_SMOOTH, "zone1_smooth", SENSORS_LM85_TEMP1, NOMAP, RW }, - LM85_SYSCTL_SMOOTH1, VALUE(1), 1 }, - { { SENSORS_LM85_ZONE2_SMOOTH, "zone2_smooth", SENSORS_LM85_TEMP2, NOMAP, RW }, - LM85_SYSCTL_SMOOTH2, VALUE(1), 1 }, - { { SENSORS_LM85_ZONE3_SMOOTH, "zone3_smooth", SENSORS_LM85_TEMP3, NOMAP, RW }, - LM85_SYSCTL_SMOOTH3, VALUE(1), 1 }, - { { 0 }, 0 } - }; - -/* NOTE: Many shared values with lm85_features !!! */ -static sensors_chip_feature adm1027_features[] = - { - { { SENSORS_LM85_IN0, "in0", NOMAP, NOMAP, R }, - LM85_SYSCTL_IN0, VALUE(3), 3 }, - { { SENSORS_LM85_IN1, "in1", NOMAP, NOMAP, R }, - LM85_SYSCTL_IN1, VALUE(3), 3 }, - { { SENSORS_LM85_IN2, "in2", NOMAP, NOMAP, R }, - LM85_SYSCTL_IN2, VALUE(3), 3 }, - { { SENSORS_LM85_IN3, "in3", NOMAP, NOMAP, R }, - LM85_SYSCTL_IN3, VALUE(3), 3 }, - { { SENSORS_LM85_IN4, "in4", NOMAP, NOMAP, R }, - LM85_SYSCTL_IN4, VALUE(3), 3 }, - { { SENSORS_LM85_IN0_MIN, "in0_min", SENSORS_LM85_IN0, SENSORS_LM85_IN0, RW }, - LM85_SYSCTL_IN0, VALUE(1), 3 }, - { { SENSORS_LM85_IN1_MIN, "in1_min", SENSORS_LM85_IN1, SENSORS_LM85_IN1, RW }, - LM85_SYSCTL_IN1, VALUE(1), 3 }, - { { SENSORS_LM85_IN2_MIN, "in2_min", SENSORS_LM85_IN2, SENSORS_LM85_IN2, RW }, - LM85_SYSCTL_IN2, VALUE(1), 3 }, - { { SENSORS_LM85_IN3_MIN, "in3_min", SENSORS_LM85_IN3, SENSORS_LM85_IN3, RW }, - LM85_SYSCTL_IN3, VALUE(1), 3 }, - { { SENSORS_LM85_IN4_MIN, "in4_min", SENSORS_LM85_IN4, SENSORS_LM85_IN4, RW }, - LM85_SYSCTL_IN4, VALUE(1), 3 }, - { { SENSORS_LM85_IN0_MAX, "in0_max", SENSORS_LM85_IN0, SENSORS_LM85_IN0, RW }, - LM85_SYSCTL_IN0, VALUE(2), 3 }, - { { SENSORS_LM85_IN1_MAX, "in1_max", SENSORS_LM85_IN1, SENSORS_LM85_IN1, RW }, - LM85_SYSCTL_IN1, VALUE(2), 3 }, - { { SENSORS_LM85_IN2_MAX, "in2_max", SENSORS_LM85_IN2, SENSORS_LM85_IN2, RW }, - LM85_SYSCTL_IN2, VALUE(2), 3 }, - { { SENSORS_LM85_IN3_MAX, "in3_max", SENSORS_LM85_IN3, SENSORS_LM85_IN3, RW }, - LM85_SYSCTL_IN3, VALUE(2), 3 }, - { { SENSORS_LM85_IN4_MAX, "in4_max", SENSORS_LM85_IN4, SENSORS_LM85_IN4, RW }, - LM85_SYSCTL_IN4, VALUE(2), 3 }, - { { SENSORS_LM85_FAN1, "fan1", NOMAP, NOMAP, R }, - LM85_SYSCTL_FAN1, VALUE(2), 0 }, - { { SENSORS_LM85_FAN2, "fan2", NOMAP, NOMAP, R }, - LM85_SYSCTL_FAN2, VALUE(2), 0 }, - { { SENSORS_LM85_FAN3, "fan3", NOMAP, NOMAP, R }, - LM85_SYSCTL_FAN3, VALUE(2), 0 }, - { { SENSORS_LM85_FAN4, "fan4", NOMAP, NOMAP, R }, - LM85_SYSCTL_FAN4, VALUE(2), 0 }, - { { SENSORS_LM85_FAN1_MIN, "fan1_min", SENSORS_LM85_FAN1, SENSORS_LM85_FAN1, - RW }, - LM85_SYSCTL_FAN1, VALUE(1), 0 }, - { { SENSORS_LM85_FAN2_MIN, "fan2_min", SENSORS_LM85_FAN2, SENSORS_LM85_FAN2, - RW }, - LM85_SYSCTL_FAN2, VALUE(1), 0 }, - { { SENSORS_LM85_FAN3_MIN, "fan3_min", SENSORS_LM85_FAN3, SENSORS_LM85_FAN3, - RW }, - LM85_SYSCTL_FAN3, VALUE(1), 0 }, - { { SENSORS_LM85_FAN4_MIN, "fan4_min", SENSORS_LM85_FAN4, SENSORS_LM85_FAN4, - RW }, - LM85_SYSCTL_FAN4, VALUE(1), 0 }, - { { SENSORS_LM85_TEMP1, "temp1", NOMAP, NOMAP, R }, - LM85_SYSCTL_TEMP1, VALUE(3), 2 }, - { { SENSORS_LM85_TEMP2, "temp2", NOMAP, NOMAP, R }, - LM85_SYSCTL_TEMP2, VALUE(3), 2 }, - { { SENSORS_LM85_TEMP3, "temp3", NOMAP, NOMAP, R }, - LM85_SYSCTL_TEMP3, VALUE(3), 2 }, - { { SENSORS_LM85_TEMP1_MIN, "temp1_min", SENSORS_LM85_TEMP1, - SENSORS_LM85_TEMP1, RW }, - LM85_SYSCTL_TEMP1, VALUE(1), 2 }, - { { SENSORS_LM85_TEMP2_MIN, "temp2_min", SENSORS_LM85_TEMP2, - SENSORS_LM85_TEMP2, RW }, - LM85_SYSCTL_TEMP2, VALUE(1), 2 }, - { { SENSORS_LM85_TEMP3_MIN, "temp3_min", SENSORS_LM85_TEMP3, - SENSORS_LM85_TEMP3, RW }, - LM85_SYSCTL_TEMP3, VALUE(1), 2 }, - { { SENSORS_LM85_TEMP1_MAX, "temp1_max", SENSORS_LM85_TEMP1, - SENSORS_LM85_TEMP1, RW }, - LM85_SYSCTL_TEMP1, VALUE(2), 2 }, - { { SENSORS_LM85_TEMP2_MAX, "temp2_max", SENSORS_LM85_TEMP2, - SENSORS_LM85_TEMP2, RW }, - LM85_SYSCTL_TEMP2, VALUE(2), 2 }, - { { SENSORS_LM85_TEMP3_MAX, "temp3_max", SENSORS_LM85_TEMP3, - SENSORS_LM85_TEMP3, RW }, - LM85_SYSCTL_TEMP3, VALUE(2), 2 }, - { { SENSORS_LM85_VID, "vid", NOMAP, NOMAP, R }, - LM85_SYSCTL_VID, VALUE(1), 3 }, - { { SENSORS_LM85_VRM, "vrm", NOMAP, NOMAP, RW }, - LM85_SYSCTL_VRM, VALUE(1), 1 }, - { { SENSORS_LM85_ALARMS, "alarms", NOMAP, NOMAP, R }, - LM85_SYSCTL_ALARMS, VALUE(1), 0 }, - { { SENSORS_LM85_PWM1, "pwm1", NOMAP, NOMAP, RW }, - LM85_SYSCTL_PWM1, VALUE(1), 0 }, - { { SENSORS_LM85_PWM2, "pwm2", NOMAP, NOMAP, RW }, - LM85_SYSCTL_PWM2, VALUE(1), 0 }, - { { SENSORS_LM85_PWM3, "pwm3", NOMAP, NOMAP, RW }, - LM85_SYSCTL_PWM3, VALUE(1), 0 }, - { { SENSORS_LM85_PWM1_SPINUP, "pwm1_spinup", SENSORS_LM85_PWM1, NOMAP, RW }, - LM85_SYSCTL_PWM_CFG1, VALUE(1), 1 }, - { { SENSORS_LM85_PWM2_SPINUP, "pwm2_spinup", SENSORS_LM85_PWM2, NOMAP, RW }, - LM85_SYSCTL_PWM_CFG2, VALUE(1), 1 }, - { { SENSORS_LM85_PWM3_SPINUP, "pwm3_spinup", SENSORS_LM85_PWM3, NOMAP, RW }, - LM85_SYSCTL_PWM_CFG3, VALUE(1), 1 }, - { { SENSORS_LM85_PWM1_MIN, "pwm1_min", SENSORS_LM85_PWM1, NOMAP, RW }, - LM85_SYSCTL_PWM_CFG1, VALUE(2), 1 }, - { { SENSORS_LM85_PWM2_MIN, "pwm2_min", SENSORS_LM85_PWM2, NOMAP, RW }, - LM85_SYSCTL_PWM_CFG2, VALUE(2), 1 }, - { { SENSORS_LM85_PWM3_MIN, "pwm3_min", SENSORS_LM85_PWM3, NOMAP, RW }, - LM85_SYSCTL_PWM_CFG3, VALUE(2), 1 }, - { { SENSORS_LM85_PWM1_FREQ, "pwm1_freq", SENSORS_LM85_PWM1, NOMAP, RW }, - LM85_SYSCTL_PWM_CFG1, VALUE(3), 1 }, - { { SENSORS_LM85_PWM2_FREQ, "pwm2_freq", SENSORS_LM85_PWM2, NOMAP, RW }, - LM85_SYSCTL_PWM_CFG2, VALUE(3), 1 }, - { { SENSORS_LM85_PWM3_FREQ, "pwm3_freq", SENSORS_LM85_PWM3, NOMAP, RW }, - LM85_SYSCTL_PWM_CFG3, VALUE(3), 1 }, - { { SENSORS_LM85_PWM1_MIN_CTL, "pwm1_min_ctl", SENSORS_LM85_PWM1, NOMAP, RW }, - LM85_SYSCTL_PWM_CFG1, VALUE(4), 1 }, - { { SENSORS_LM85_PWM2_MIN_CTL, "pwm2_min_ctl", SENSORS_LM85_PWM2, NOMAP, RW }, - LM85_SYSCTL_PWM_CFG2, VALUE(4), 1 }, - { { SENSORS_LM85_PWM3_MIN_CTL, "pwm3_min_ctl", SENSORS_LM85_PWM3, NOMAP, RW }, - LM85_SYSCTL_PWM_CFG3, VALUE(4), 1 }, - { { SENSORS_LM85_PWM1_INVERT, "pwm1_invert", SENSORS_LM85_PWM1, NOMAP, RW }, - LM85_SYSCTL_PWM_CFG1, VALUE(5), 0 }, - { { SENSORS_LM85_PWM2_INVERT, "pwm2_invert", SENSORS_LM85_PWM2, NOMAP, RW }, - LM85_SYSCTL_PWM_CFG2, VALUE(5), 0 }, - { { SENSORS_LM85_PWM3_INVERT, "pwm3_invert", SENSORS_LM85_PWM3, NOMAP, RW }, - LM85_SYSCTL_PWM_CFG3, VALUE(5), 0 }, - { { SENSORS_LM85_PWM1_ZONE, "pwm1_zone", SENSORS_LM85_PWM1, NOMAP, RW }, - LM85_SYSCTL_PWM_ZONE1, VALUE(1), 0 }, - { { SENSORS_LM85_PWM2_ZONE, "pwm2_zone", SENSORS_LM85_PWM2, NOMAP, RW }, - LM85_SYSCTL_PWM_ZONE2, VALUE(1), 0 }, - { { SENSORS_LM85_PWM3_ZONE, "pwm3_zone", SENSORS_LM85_PWM3, NOMAP, RW }, - LM85_SYSCTL_PWM_ZONE3, VALUE(1), 0 }, - { { SENSORS_LM85_ZONE1_LIMIT, "zone1_limit", SENSORS_LM85_TEMP1, NOMAP, RW }, - LM85_SYSCTL_ZONE1, VALUE(1), 1 }, - { { SENSORS_LM85_ZONE2_LIMIT, "zone2_limit", SENSORS_LM85_TEMP2, NOMAP, RW }, - LM85_SYSCTL_ZONE2, VALUE(1), 1 }, - { { SENSORS_LM85_ZONE3_LIMIT, "zone3_limit", SENSORS_LM85_TEMP3, NOMAP, RW }, - LM85_SYSCTL_ZONE3, VALUE(1), 1 }, - { { SENSORS_LM85_ZONE1_HYST, "zone1_hyst", SENSORS_LM85_TEMP1, NOMAP, RW }, - LM85_SYSCTL_ZONE1, VALUE(2), 1 }, - { { SENSORS_LM85_ZONE2_HYST, "zone2_hyst", SENSORS_LM85_TEMP2, NOMAP, RW }, - LM85_SYSCTL_ZONE2, VALUE(2), 1 }, - { { SENSORS_LM85_ZONE3_HYST, "zone3_hyst", SENSORS_LM85_TEMP3, NOMAP, RW }, - LM85_SYSCTL_ZONE3, VALUE(2), 1 }, - { { SENSORS_LM85_ZONE1_RANGE, "zone1_range", SENSORS_LM85_TEMP1, NOMAP, RW }, - LM85_SYSCTL_ZONE1, VALUE(3), 1 }, - { { SENSORS_LM85_ZONE2_RANGE, "zone2_range", SENSORS_LM85_TEMP2, NOMAP, RW }, - LM85_SYSCTL_ZONE2, VALUE(3), 1 }, - { { SENSORS_LM85_ZONE3_RANGE, "zone3_range", SENSORS_LM85_TEMP3, NOMAP, RW }, - LM85_SYSCTL_ZONE3, VALUE(3), 1 }, - { { SENSORS_LM85_ZONE1_CRITICAL, "zone1_critical", SENSORS_LM85_TEMP1, NOMAP, - RW }, - LM85_SYSCTL_ZONE1, VALUE(4), 1 }, - { { SENSORS_LM85_ZONE2_CRITICAL, "zone2_critical", SENSORS_LM85_TEMP2, NOMAP, - RW }, - LM85_SYSCTL_ZONE2, VALUE(4), 1 }, - { { SENSORS_LM85_ZONE3_CRITICAL, "zone3_critical", SENSORS_LM85_TEMP3, NOMAP, - RW }, - LM85_SYSCTL_ZONE3, VALUE(4), 1 }, - - { { SENSORS_ADM1027_FAN1_TACH_MODE, "fan1_tach_mode", SENSORS_LM85_FAN1, - NOMAP, RW }, - ADM1027_SYSCTL_TACH_MODE, VALUE(1), 0 }, - { { SENSORS_ADM1027_FAN2_TACH_MODE, "fan2_tach_mode", SENSORS_LM85_FAN2, - NOMAP, RW }, - ADM1027_SYSCTL_TACH_MODE, VALUE(2), 0 }, - { { SENSORS_ADM1027_FAN3_TACH_MODE, "fan3_tach_mode", SENSORS_LM85_FAN3, - NOMAP, RW }, - ADM1027_SYSCTL_TACH_MODE, VALUE(3), 0 }, - { { SENSORS_ADM1027_FAN4_TACH_MODE, "fan4_tach_mode", SENSORS_LM85_FAN4, - NOMAP, RW }, - ADM1027_SYSCTL_TACH_MODE, VALUE(4), 0 }, - { { SENSORS_ADM1027_PWM1_SMOOTH, "pwm1_smooth", SENSORS_LM85_PWM1, NOMAP, RW }, - LM85_SYSCTL_SMOOTH1, VALUE(1), 1 }, - { { SENSORS_ADM1027_PWM2_SMOOTH, "pwm2_smooth", SENSORS_LM85_PWM2, NOMAP, RW }, - LM85_SYSCTL_SMOOTH2, VALUE(1), 1 }, - { { SENSORS_ADM1027_PWM3_SMOOTH, "pwm3_smooth", SENSORS_LM85_PWM3, NOMAP, RW }, - LM85_SYSCTL_SMOOTH3, VALUE(1), 1 }, - { { SENSORS_ADM1027_TEMP1_OFFSET, "temp1_offset", SENSORS_LM85_TEMP1, - SENSORS_LM85_TEMP1, RW }, - ADM1027_SYSCTL_TEMP_OFFSET1, VALUE(1), 2 }, - { { SENSORS_ADM1027_TEMP2_OFFSET, "temp2_offset", SENSORS_LM85_TEMP2, - SENSORS_LM85_TEMP2, RW }, - ADM1027_SYSCTL_TEMP_OFFSET2, VALUE(1), 2 }, - { { SENSORS_ADM1027_TEMP3_OFFSET, "temp3_offset", SENSORS_LM85_TEMP3, - SENSORS_LM85_TEMP3, RW }, - ADM1027_SYSCTL_TEMP_OFFSET3, VALUE(1), 2 }, - { { SENSORS_ADM1027_FAN1_PPR, "fan1_ppr", SENSORS_LM85_FAN1, NOMAP, RW }, - ADM1027_SYSCTL_FAN_PPR, VALUE(1), 0 }, - { { SENSORS_ADM1027_FAN2_PPR, "fan2_ppr", SENSORS_LM85_FAN2, NOMAP, RW }, - ADM1027_SYSCTL_FAN_PPR, VALUE(2), 0 }, - { { SENSORS_ADM1027_FAN3_PPR, "fan3_ppr", SENSORS_LM85_FAN3, NOMAP, RW }, - ADM1027_SYSCTL_FAN_PPR, VALUE(3), 0 }, - { { SENSORS_ADM1027_FAN4_PPR, "fan4_ppr", SENSORS_LM85_FAN4, NOMAP, RW }, - ADM1027_SYSCTL_FAN_PPR, VALUE(4), 0 }, - { { SENSORS_ADM1027_ALARM_MASK, "alarm_mask", NOMAP, NOMAP, RW }, - ADM1027_SYSCTL_ALARM_MASK, VALUE(1), 0 }, - { { 0 }, 0 } - }; - -static sensors_chip_feature lm87_features[] = - { - { { SENSORS_LM87_IN0, "2.5V", NOMAP, NOMAP, R }, - LM87_SYSCTL_IN0, VALUE(3), 2, "in0_input", 3 }, - { { SENSORS_LM87_IN1, "Vccp1", NOMAP, NOMAP, R }, - LM87_SYSCTL_IN1, VALUE(3), 2, "in1_input", 3 }, - { { SENSORS_LM87_IN2, "3.3V", NOMAP, NOMAP, R }, - LM87_SYSCTL_IN2, VALUE(3), 2, "in2_input", 3 }, - { { SENSORS_LM87_IN3, "5V", NOMAP, NOMAP, R }, - LM87_SYSCTL_IN3, VALUE(3), 2, "in3_input", 3 }, - { { SENSORS_LM87_IN4, "12V", NOMAP, NOMAP, R }, - LM87_SYSCTL_IN4, VALUE(3), 2, "in4_input", 3 }, - { { SENSORS_LM87_IN5, "Vccp2", NOMAP, NOMAP, R }, - LM87_SYSCTL_IN5, VALUE(3), 2, "in5_input", 3 }, - { { SENSORS_LM87_AIN1, "AIN1", NOMAP, NOMAP, R }, - LM87_SYSCTL_AIN1, VALUE(3), 0, "in6_input", 3 }, - { { SENSORS_LM87_AIN2, "AIN2", NOMAP, NOMAP, R }, - LM87_SYSCTL_AIN2, VALUE(3), 0, "in7_input", 3 }, - { { SENSORS_LM87_IN0_MIN, "2.5V_min", SENSORS_LM87_IN0, SENSORS_LM87_IN0, RW }, - LM87_SYSCTL_IN0, VALUE(1), 2, "in0_min", 3 }, - { { SENSORS_LM87_IN1_MIN, "Vccp1_min", SENSORS_LM87_IN1, SENSORS_LM87_IN1, - RW }, - LM87_SYSCTL_IN1, VALUE(1), 2, "in1_min", 3 }, - { { SENSORS_LM87_IN2_MIN, "3.3V_min", SENSORS_LM87_IN2, SENSORS_LM87_IN2, RW }, - LM87_SYSCTL_IN2, VALUE(1), 2, "in2_min", 3 }, - { { SENSORS_LM87_IN3_MIN, "5V_min", SENSORS_LM87_IN3, SENSORS_LM87_IN3, RW }, - LM87_SYSCTL_IN3, VALUE(1), 2, "in3_min", 3 }, - { { SENSORS_LM87_IN4_MIN, "12V_min", SENSORS_LM87_IN4, SENSORS_LM87_IN4, RW }, - LM87_SYSCTL_IN4, VALUE(1), 2, "in4_min", 3 }, - { { SENSORS_LM87_IN5_MIN, "Vccp2_min", SENSORS_LM87_IN5, SENSORS_LM87_IN5, - RW }, - LM87_SYSCTL_IN5, VALUE(1), 2, "in5_min", 3 }, - { { SENSORS_LM87_AIN1_MIN, "AIN1_min", SENSORS_LM87_AIN1, SENSORS_LM87_AIN1, - RW }, - LM87_SYSCTL_AIN1, VALUE(1), 0, "in6_min", 3 }, - { { SENSORS_LM87_AIN2_MIN, "AIN2_min", SENSORS_LM87_AIN2, SENSORS_LM87_AIN2, - RW }, - LM87_SYSCTL_AIN2, VALUE(1), 0, "in7_min", 3 }, - { { SENSORS_LM87_IN0_MAX, "2.5V_max", SENSORS_LM87_IN0, SENSORS_LM87_IN0, RW }, - LM87_SYSCTL_IN0, VALUE(2), 2, "in0_max", 3 }, - { { SENSORS_LM87_IN1_MAX, "Vccp1_max", SENSORS_LM87_IN1, SENSORS_LM87_IN1, - RW }, - LM87_SYSCTL_IN1, VALUE(2), 2, "in1_max", 3 }, - { { SENSORS_LM87_IN2_MAX, "3.3V_max", SENSORS_LM87_IN2, SENSORS_LM87_IN2, RW }, - LM87_SYSCTL_IN2, VALUE(2), 2, "in2_max", 3 }, - { { SENSORS_LM87_IN3_MAX, "5V_max", SENSORS_LM87_IN3, SENSORS_LM87_IN3, RW }, - LM87_SYSCTL_IN3, VALUE(2), 2, "in3_max", 3 }, - { { SENSORS_LM87_IN4_MAX, "12V_max", SENSORS_LM87_IN4, SENSORS_LM87_IN4, RW }, - LM87_SYSCTL_IN4, VALUE(2), 2, "in4_max", 3 }, - { { SENSORS_LM87_IN5_MAX, "Vccp2_max", SENSORS_LM87_IN5, SENSORS_LM87_IN5, - RW }, - LM87_SYSCTL_IN5, VALUE(2), 2, "in5_max", 3 }, - { { SENSORS_LM87_AIN1_MAX, "AIN1_max", SENSORS_LM87_AIN1, SENSORS_LM87_AIN1, - RW }, - LM87_SYSCTL_AIN1, VALUE(2), 0, "in6_max", 3 }, - { { SENSORS_LM87_AIN2_MAX, "AIN2_max", SENSORS_LM87_AIN2, SENSORS_LM87_AIN2, - RW }, - LM87_SYSCTL_AIN2, VALUE(2), 0, "in7_max", 3 }, - { { SENSORS_LM87_FAN1, "fan1", NOMAP, NOMAP, R }, - LM87_SYSCTL_FAN1, VALUE(2), 0 }, - { { SENSORS_LM87_FAN2, "fan2", NOMAP, NOMAP, R }, - LM87_SYSCTL_FAN2, VALUE(2), 0 }, - { { SENSORS_LM87_FAN1_MIN, "fan1_min", SENSORS_LM87_FAN1, SENSORS_LM87_FAN1, - RW }, - LM87_SYSCTL_FAN1, VALUE(1), 0 }, - { { SENSORS_LM87_FAN2_MIN, "fan2_min", SENSORS_LM87_FAN2, SENSORS_LM87_FAN2, - RW }, - LM87_SYSCTL_FAN2, VALUE(1), 0 }, - { { SENSORS_LM87_TEMP3, "temp3", NOMAP, NOMAP, R }, - LM87_SYSCTL_TEMP3, VALUE(3), 1 }, - { { SENSORS_LM87_TEMP2, "CPU_Temp", NOMAP, NOMAP, R }, - LM87_SYSCTL_TEMP2, VALUE(3), 1, "temp2_input", 3 }, - { { SENSORS_LM87_TEMP1, "temp1", NOMAP, NOMAP, R }, - LM87_SYSCTL_TEMP1, VALUE(3), 1 }, - { { SENSORS_LM87_TEMP1_HYST, "temp1_min", SENSORS_LM87_TEMP1, - SENSORS_LM87_TEMP1, RW }, - LM87_SYSCTL_TEMP1, VALUE(2), 1 }, - { { SENSORS_LM87_TEMP1_OVER, "temp1_max", SENSORS_LM87_TEMP1, - SENSORS_LM87_TEMP1, RW }, - LM87_SYSCTL_TEMP1, VALUE(1), 1 }, - { { SENSORS_LM87_TEMP2_HYST, "temp2_min", SENSORS_LM87_TEMP2, - SENSORS_LM87_TEMP2, RW }, - LM87_SYSCTL_TEMP2, VALUE(2), 1 }, - { { SENSORS_LM87_TEMP2_OVER, "temp2_max", SENSORS_LM87_TEMP2, - SENSORS_LM87_TEMP2, RW }, - LM87_SYSCTL_TEMP2, VALUE(1), 1 }, - { { SENSORS_LM87_TEMP3_HYST, "temp3_min", SENSORS_LM87_TEMP3, - SENSORS_LM87_TEMP3, RW }, - LM87_SYSCTL_TEMP3, VALUE(2), 1 }, - { { SENSORS_LM87_TEMP3_OVER, "temp3_max", SENSORS_LM87_TEMP3, - SENSORS_LM87_TEMP3, RW }, - LM87_SYSCTL_TEMP3, VALUE(1), 1 }, - { { SENSORS_LM87_VID, "vid", NOMAP, NOMAP, R }, - LM87_SYSCTL_VID, VALUE(1), 3 }, - { { SENSORS_LM87_VRM, "vrm", NOMAP, NOMAP, RW }, - LM87_SYSCTL_VRM, VALUE(1), 1 }, -/* Ho hum, this will be wrong if fan1 is disabled, but fan2 isn't.. fix?? */ - { { SENSORS_LM87_FAN1_DIV, "fan1_div", SENSORS_LM87_FAN1, NOMAP, RW }, - LM87_SYSCTL_FAN_DIV, VALUE(1), 0 }, - { { SENSORS_LM87_FAN2_DIV, "fan2_div", SENSORS_LM87_FAN2, NOMAP, RW }, - LM87_SYSCTL_FAN_DIV, VALUE(2), 0 }, - { { SENSORS_LM87_ALARMS, "alarms", NOMAP, NOMAP, R }, - LM87_SYSCTL_ALARMS, VALUE(1), 0 }, - { { SENSORS_LM87_ANALOG_OUT, "analog_out", NOMAP, NOMAP, RW }, - LM87_SYSCTL_ANALOG_OUT, VALUE(1), 0 , - "aout_output", 3 }, - { { 0 }, 0 } - }; - -static sensors_chip_feature mtp008_features[] = - { - { { SENSORS_MTP008_IN0, "in0", NOMAP, NOMAP, R }, - MTP008_SYSCTL_IN0, VALUE(3), 2 }, - { { SENSORS_MTP008_IN1, "in1", NOMAP, NOMAP, R }, - MTP008_SYSCTL_IN1, VALUE(3), 2 }, - { { SENSORS_MTP008_IN2, "in2", NOMAP, NOMAP, R }, - MTP008_SYSCTL_IN2, VALUE(3), 2 }, - { { SENSORS_MTP008_IN3, "in3", NOMAP, NOMAP, R }, - MTP008_SYSCTL_IN3, VALUE(3), 2 }, - { { SENSORS_MTP008_IN4, "in4", NOMAP, NOMAP, R }, - MTP008_SYSCTL_IN4, VALUE(3), 2 }, - { { SENSORS_MTP008_IN5, "in5", NOMAP, NOMAP, R }, - MTP008_SYSCTL_IN5, VALUE(3), 2 }, - { { SENSORS_MTP008_IN6, "in6", NOMAP, NOMAP, R }, - MTP008_SYSCTL_IN6, VALUE(3), 2 }, - { { SENSORS_MTP008_IN0_MIN, "in0_min", SENSORS_MTP008_IN0, - SENSORS_MTP008_IN0, RW }, - MTP008_SYSCTL_IN0, VALUE(1), 2 }, - { { SENSORS_MTP008_IN1_MIN, "in1_min", SENSORS_MTP008_IN1, - SENSORS_MTP008_IN1, RW }, - MTP008_SYSCTL_IN1, VALUE(1), 2 }, - { { SENSORS_MTP008_IN2_MIN, "in2_min", SENSORS_MTP008_IN2, - SENSORS_MTP008_IN2, RW }, - MTP008_SYSCTL_IN2, VALUE(1), 2 }, - { { SENSORS_MTP008_IN3_MIN, "in3_min", SENSORS_MTP008_IN3, - SENSORS_MTP008_IN3, RW }, - MTP008_SYSCTL_IN3, VALUE(1), 2 }, - { { SENSORS_MTP008_IN4_MIN, "in4_min", SENSORS_MTP008_IN4, - SENSORS_MTP008_IN4, RW }, - MTP008_SYSCTL_IN4, VALUE(1), 2 }, - { { SENSORS_MTP008_IN5_MIN, "in5_min", SENSORS_MTP008_IN5, - SENSORS_MTP008_IN5, RW }, - MTP008_SYSCTL_IN5, VALUE(1), 2 }, - { { SENSORS_MTP008_IN6_MIN, "in6_min", SENSORS_MTP008_IN6, - SENSORS_MTP008_IN6, RW }, - MTP008_SYSCTL_IN6, VALUE(1), 2 }, - { { SENSORS_MTP008_IN0_MAX, "in0_max", SENSORS_MTP008_IN0, - SENSORS_MTP008_IN0, RW }, - MTP008_SYSCTL_IN0, VALUE(2), 2 }, - { { SENSORS_MTP008_IN1_MAX, "in1_max", SENSORS_MTP008_IN1, - SENSORS_MTP008_IN1, RW }, - MTP008_SYSCTL_IN1, VALUE(2), 2 }, - { { SENSORS_MTP008_IN2_MAX, "in2_max", SENSORS_MTP008_IN2, - SENSORS_MTP008_IN2, RW }, - MTP008_SYSCTL_IN2, VALUE(2), 2 }, - { { SENSORS_MTP008_IN3_MAX, "in3_max", SENSORS_MTP008_IN3, - SENSORS_MTP008_IN3, RW }, - MTP008_SYSCTL_IN3, VALUE(2), 2 }, - { { SENSORS_MTP008_IN4_MAX, "in4_max", SENSORS_MTP008_IN4, - SENSORS_MTP008_IN4, RW }, - MTP008_SYSCTL_IN4, VALUE(2), 2 }, - { { SENSORS_MTP008_IN5_MAX, "in5_max", SENSORS_MTP008_IN5, - SENSORS_MTP008_IN5, RW }, - MTP008_SYSCTL_IN5, VALUE(2), 2 }, - { { SENSORS_MTP008_IN6_MAX, "in6_max", SENSORS_MTP008_IN6, - SENSORS_MTP008_IN6, RW }, - MTP008_SYSCTL_IN6, VALUE(2), 2 }, - { { SENSORS_MTP008_FAN1, "fan1", NOMAP, NOMAP, R }, - MTP008_SYSCTL_FAN1, VALUE(2), 0 }, - { { SENSORS_MTP008_FAN2, "fan2", NOMAP, NOMAP, R }, - MTP008_SYSCTL_FAN2, VALUE(2), 0 }, - { { SENSORS_MTP008_FAN3, "fan3", NOMAP, NOMAP, R }, - MTP008_SYSCTL_FAN3, VALUE(2), 0 }, - { { SENSORS_MTP008_FAN1_MIN, "fan1_min", SENSORS_MTP008_FAN1, - SENSORS_MTP008_FAN1, RW }, - MTP008_SYSCTL_FAN1, VALUE(1), 0 }, - { { SENSORS_MTP008_FAN2_MIN, "fan2_min", SENSORS_MTP008_FAN2, - SENSORS_MTP008_FAN2, RW }, - MTP008_SYSCTL_FAN2, VALUE(1), 0 }, - { { SENSORS_MTP008_FAN3_MIN, "fan3_min", SENSORS_MTP008_FAN3, - SENSORS_MTP008_FAN3, RW }, - MTP008_SYSCTL_FAN3, VALUE(1), 0 }, - { { SENSORS_MTP008_TEMP1, "temp1", NOMAP, NOMAP, R }, - MTP008_SYSCTL_TEMP1, VALUE(3), 1 }, - { { SENSORS_MTP008_TEMP2, "temp2", NOMAP, NOMAP, R }, - MTP008_SYSCTL_TEMP2, VALUE(3), 1 }, - { { SENSORS_MTP008_TEMP3, "temp3", NOMAP, NOMAP, R }, - MTP008_SYSCTL_TEMP3, VALUE(3), 1 }, - { { SENSORS_MTP008_TEMP1_OVER, "temp1_over", SENSORS_MTP008_TEMP1, - SENSORS_MTP008_TEMP1, RW }, - MTP008_SYSCTL_TEMP1, VALUE(1), 1 }, - { { SENSORS_MTP008_TEMP2_OVER, "temp2_over", SENSORS_MTP008_TEMP2, - SENSORS_MTP008_TEMP2, RW }, - MTP008_SYSCTL_TEMP2, VALUE(1), 1 }, - { { SENSORS_MTP008_TEMP3_OVER, "temp3_over", SENSORS_MTP008_TEMP3, - SENSORS_MTP008_TEMP3, RW }, - MTP008_SYSCTL_TEMP3, VALUE(1), 1 }, - { { SENSORS_MTP008_TEMP1_HYST, "temp1_hyst", SENSORS_MTP008_TEMP1, - SENSORS_MTP008_TEMP1, RW }, - MTP008_SYSCTL_TEMP1, VALUE(2), 1 }, - { { SENSORS_MTP008_TEMP2_HYST, "temp2_hyst", SENSORS_MTP008_TEMP2, - SENSORS_MTP008_TEMP2, RW }, - MTP008_SYSCTL_TEMP2, VALUE(2), 1 }, - { { SENSORS_MTP008_TEMP3_HYST, "temp3_hyst", SENSORS_MTP008_TEMP3, - SENSORS_MTP008_TEMP3, RW }, - MTP008_SYSCTL_TEMP3, VALUE(2), 1 }, - { { SENSORS_MTP008_VID, "vid", NOMAP, NOMAP, R }, - MTP008_SYSCTL_VID, VALUE(1), 2 }, - { { SENSORS_MTP008_FAN1_DIV, "fan1_div", NOMAP, NOMAP, RW }, - MTP008_SYSCTL_FAN_DIV, VALUE(1), 0 }, - { { SENSORS_MTP008_FAN2_DIV, "fan2_div", NOMAP, NOMAP, RW }, - MTP008_SYSCTL_FAN_DIV, VALUE(2), 0 }, - { { SENSORS_MTP008_FAN3_DIV, "fan3_div", NOMAP, NOMAP, RW }, - MTP008_SYSCTL_FAN_DIV, VALUE(3), 0 }, - { { SENSORS_MTP008_ALARMS, "alarms", NOMAP, NOMAP, R }, - MTP008_SYSCTL_ALARMS, VALUE(1), 0 }, - { { SENSORS_MTP008_BEEP, "beeps", NOMAP, NOMAP, R }, - MTP008_SYSCTL_BEEP, VALUE(1), 0 }, - { { 0 }, 0 } - }; - -static sensors_chip_feature ds1621_features[] = - { - { { SENSORS_DS1621_TEMP, "temp", NOMAP, NOMAP, R }, - DS1621_SYSCTL_TEMP, VALUE(3), 1 }, - { { SENSORS_DS1621_TEMP_HYST, "temp_hyst", SENSORS_DS1621_TEMP, - SENSORS_DS1621_TEMP, RW }, - DS1621_SYSCTL_TEMP, VALUE(2), 1, "temp1_min", - 3 }, - { { SENSORS_DS1621_TEMP_OVER, "temp_over", SENSORS_DS1621_TEMP, - SENSORS_DS1621_TEMP, RW }, - DS1621_SYSCTL_TEMP, VALUE(1), 1 }, - { { SENSORS_DS1621_ALARMS, "alarms", NOMAP, NOMAP, R }, - DS1621_SYSCTL_ALARMS, VALUE(1), 0 }, - { { 0 }, 0 } - }; - -static sensors_chip_feature it87_features[] = - { - { { SENSORS_IT87_IN0, "in0", NOMAP, NOMAP, R }, - IT87_SYSCTL_IN0, VALUE(3), 2 }, - { { SENSORS_IT87_IN1, "in1", NOMAP, NOMAP, R }, - IT87_SYSCTL_IN1, VALUE(3), 2 }, - { { SENSORS_IT87_IN2, "in2", NOMAP, NOMAP, R }, - IT87_SYSCTL_IN2, VALUE(3), 2 }, - { { SENSORS_IT87_IN3, "in3", NOMAP, NOMAP, R }, - IT87_SYSCTL_IN3, VALUE(3), 2 }, - { { SENSORS_IT87_IN4, "in4", NOMAP, NOMAP, R }, - IT87_SYSCTL_IN4, VALUE(3), 2 }, - { { SENSORS_IT87_IN5, "in5", NOMAP, NOMAP, R }, - IT87_SYSCTL_IN5, VALUE(3), 2 }, - { { SENSORS_IT87_IN6, "in6", NOMAP, NOMAP, R }, - IT87_SYSCTL_IN6, VALUE(3), 2 }, - { { SENSORS_IT87_IN7, "in7", NOMAP, NOMAP, R }, - IT87_SYSCTL_IN7, VALUE(3), 2 }, - { { SENSORS_IT87_IN8, "in8", NOMAP, NOMAP, R }, - IT87_SYSCTL_IN8, VALUE(3), 2 }, - { { SENSORS_IT87_IN0_MIN, "in0_min", SENSORS_IT87_IN0, SENSORS_IT87_IN0, RW }, - IT87_SYSCTL_IN0, VALUE(1), 2 }, - { { SENSORS_IT87_IN1_MIN, "in1_min", SENSORS_IT87_IN1, SENSORS_IT87_IN1, RW }, - IT87_SYSCTL_IN1, VALUE(1), 2 }, - { { SENSORS_IT87_IN2_MIN, "in2_min", SENSORS_IT87_IN2, SENSORS_IT87_IN2, RW }, - IT87_SYSCTL_IN2, VALUE(1), 2 }, - { { SENSORS_IT87_IN3_MIN, "in3_min", SENSORS_IT87_IN3, SENSORS_IT87_IN3, RW }, - IT87_SYSCTL_IN3, VALUE(1), 2 }, - { { SENSORS_IT87_IN4_MIN, "in4_min", SENSORS_IT87_IN4, SENSORS_IT87_IN4, RW }, - IT87_SYSCTL_IN4, VALUE(1), 2 }, - { { SENSORS_IT87_IN5_MIN, "in5_min", SENSORS_IT87_IN5, SENSORS_IT87_IN5, RW }, - IT87_SYSCTL_IN5, VALUE(1), 2 }, - { { SENSORS_IT87_IN6_MIN, "in6_min", SENSORS_IT87_IN6, SENSORS_IT87_IN6, RW }, - IT87_SYSCTL_IN6, VALUE(1), 2 }, - { { SENSORS_IT87_IN7_MIN, "in7_min", SENSORS_IT87_IN7, SENSORS_IT87_IN7, RW }, - IT87_SYSCTL_IN7, VALUE(1), 2 }, - { { SENSORS_IT87_IN0_MAX, "in0_max", SENSORS_IT87_IN0, SENSORS_IT87_IN0, RW }, - IT87_SYSCTL_IN0, VALUE(2), 2 }, - { { SENSORS_IT87_IN1_MAX, "in1_max", SENSORS_IT87_IN1, SENSORS_IT87_IN1, RW }, - IT87_SYSCTL_IN1, VALUE(2), 2 }, - { { SENSORS_IT87_IN2_MAX, "in2_max", SENSORS_IT87_IN2, SENSORS_IT87_IN2, RW }, - IT87_SYSCTL_IN2, VALUE(2), 2 }, - { { SENSORS_IT87_IN3_MAX, "in3_max", SENSORS_IT87_IN3, SENSORS_IT87_IN3, RW }, - IT87_SYSCTL_IN3, VALUE(2), 2 }, - { { SENSORS_IT87_IN4_MAX, "in4_max", SENSORS_IT87_IN4, SENSORS_IT87_IN4, RW }, - IT87_SYSCTL_IN4, VALUE(2), 2 }, - { { SENSORS_IT87_IN5_MAX, "in5_max", SENSORS_IT87_IN5, SENSORS_IT87_IN5, RW }, - IT87_SYSCTL_IN5, VALUE(2), 2 }, - { { SENSORS_IT87_IN6_MAX, "in6_max", SENSORS_IT87_IN6, SENSORS_IT87_IN6, RW }, - IT87_SYSCTL_IN6, VALUE(2), 2 }, - { { SENSORS_IT87_IN7_MAX, "in7_max", SENSORS_IT87_IN7, SENSORS_IT87_IN7, RW }, - IT87_SYSCTL_IN7, VALUE(2), 2 }, - { { SENSORS_IT87_FAN1, "fan1", NOMAP, NOMAP, R }, - IT87_SYSCTL_FAN1, VALUE(2), 0 }, - { { SENSORS_IT87_FAN2, "fan2", NOMAP, NOMAP, R }, - IT87_SYSCTL_FAN2, VALUE(2), 0 }, - { { SENSORS_IT87_FAN3, "fan3", NOMAP, NOMAP, R }, - IT87_SYSCTL_FAN3, VALUE(2), 0 }, - { { SENSORS_IT87_FAN4, "fan4", NOMAP, NOMAP, R }, - NOSYSCTL, VALUE(2), 0 }, - { { SENSORS_IT87_FAN5, "fan5", NOMAP, NOMAP, R }, - NOSYSCTL, VALUE(2), 0 }, - { { SENSORS_IT87_FAN1_MIN, "fan1_min", SENSORS_IT87_FAN1, SENSORS_IT87_FAN1, - RW }, - IT87_SYSCTL_FAN1, VALUE(1), 0 }, - { { SENSORS_IT87_FAN2_MIN, "fan2_min", SENSORS_IT87_FAN2, SENSORS_IT87_FAN2, - RW }, - IT87_SYSCTL_FAN2, VALUE(1), 0 }, - { { SENSORS_IT87_FAN3_MIN, "fan3_min", SENSORS_IT87_FAN3, SENSORS_IT87_FAN3, - RW }, - IT87_SYSCTL_FAN3, VALUE(1), 0 }, - { { SENSORS_IT87_FAN4_MIN, "fan4_min", SENSORS_IT87_FAN4, SENSORS_IT87_FAN4, - RW }, - NOSYSCTL, VALUE(1), 0 }, - { { SENSORS_IT87_FAN5_MIN, "fan5_min", SENSORS_IT87_FAN5, SENSORS_IT87_FAN5, - RW }, - NOSYSCTL, VALUE(1), 0 }, - { { SENSORS_IT87_TEMP1, "temp1", NOMAP, NOMAP, R }, - IT87_SYSCTL_TEMP1, VALUE(3), 1 }, - { { SENSORS_IT87_TEMP2, "temp2", NOMAP, NOMAP, R }, - IT87_SYSCTL_TEMP2, VALUE(3), 1 }, - { { SENSORS_IT87_TEMP3, "temp3", NOMAP, NOMAP, R }, - IT87_SYSCTL_TEMP3, VALUE(3), 1 }, - { { SENSORS_IT87_TEMP1_LOW, "temp1_low", SENSORS_IT87_TEMP1, - SENSORS_IT87_TEMP1, RW }, - IT87_SYSCTL_TEMP1, VALUE(2), 1 }, - { { SENSORS_IT87_TEMP2_LOW, "temp2_low", SENSORS_IT87_TEMP2, - SENSORS_IT87_TEMP2, RW }, - IT87_SYSCTL_TEMP2, VALUE(2), 1 }, - { { SENSORS_IT87_TEMP3_LOW, "temp3_low", SENSORS_IT87_TEMP3, - SENSORS_IT87_TEMP3, RW }, - IT87_SYSCTL_TEMP3, VALUE(2), 1 }, - { { SENSORS_IT87_TEMP1_HIGH, "temp1_over", SENSORS_IT87_TEMP1, - SENSORS_IT87_TEMP1, RW }, - IT87_SYSCTL_TEMP1, VALUE(1), 1 }, - { { SENSORS_IT87_TEMP2_HIGH, "temp2_over", SENSORS_IT87_TEMP2, - SENSORS_IT87_TEMP2, RW }, - IT87_SYSCTL_TEMP2, VALUE(1), 1 }, - { { SENSORS_IT87_TEMP3_HIGH, "temp3_over", SENSORS_IT87_TEMP3, - SENSORS_IT87_TEMP3, RW }, - IT87_SYSCTL_TEMP3, VALUE(1), 1 }, - { { SENSORS_IT87_VID, "vid", NOMAP, NOMAP, R }, - IT87_SYSCTL_VID, VALUE(1), 2 }, - { { SENSORS_IT87_FAN1_DIV, "fan1_div", SENSORS_IT87_FAN1, NOMAP, RW }, - IT87_SYSCTL_FAN_DIV, VALUE(1), 0 }, - { { SENSORS_IT87_FAN2_DIV, "fan2_div", SENSORS_IT87_FAN2, NOMAP, RW }, - IT87_SYSCTL_FAN_DIV, VALUE(2), 0 }, - { { SENSORS_IT87_FAN3_DIV, "fan3_div", SENSORS_IT87_FAN3, NOMAP, RW }, - IT87_SYSCTL_FAN_DIV, VALUE(3), 0 }, - { { SENSORS_IT87_ALARMS, "alarms", NOMAP, NOMAP, R }, - IT87_SYSCTL_ALARMS, VALUE(1) }, - { { SENSORS_IT87_SENS1, "sensor1", SENSORS_IT87_TEMP1, NOMAP, RW }, - IT87_SYSCTL_SENS1, VALUE(1), 0 }, - { { SENSORS_IT87_SENS2, "sensor2", SENSORS_IT87_TEMP2, NOMAP, RW }, - IT87_SYSCTL_SENS2, VALUE(1), 0 }, - { { SENSORS_IT87_SENS3, "sensor3", SENSORS_IT87_TEMP3, NOMAP, RW }, - IT87_SYSCTL_SENS3, VALUE(1), 0 }, - { { 0 }, 0 } - }; - -static sensors_chip_feature fscpos_features[] = - { - { { SENSORS_FSCPOS_REV, "rev", NOMAP, NOMAP, R }, - FSCPOS_SYSCTL_REV, VALUE(1), 0 }, - { { SENSORS_FSCPOS_EVENT, "event", NOMAP, NOMAP, R }, - FSCPOS_SYSCTL_EVENT, VALUE(1), 0 }, - { { SENSORS_FSCPOS_CONTROL, "control", NOMAP, NOMAP, RW }, - FSCPOS_SYSCTL_CONTROL, VALUE(1), 0 }, - { { SENSORS_FSCPOS_VOLTAGE1, "volt12", NOMAP, NOMAP, R }, - FSCPOS_SYSCTL_VOLT0, VALUE(1), 2, "in0_input", - 3 }, - { { SENSORS_FSCPOS_VOLTAGE2, "volt5", NOMAP, NOMAP, R }, - FSCPOS_SYSCTL_VOLT1, VALUE(1), 2, "in1_input", - 3 }, - { { SENSORS_FSCPOS_VOLTAGE3, "voltbatt", NOMAP, NOMAP, R }, - FSCPOS_SYSCTL_VOLT2, VALUE(1), 2, "in2_input", - 3 }, - { { SENSORS_FSCPOS_TEMP1, "temp1", NOMAP, NOMAP, R }, - FSCPOS_SYSCTL_TEMP0, VALUE(2), 0 }, - { { SENSORS_FSCPOS_TEMP2, "temp2", NOMAP, NOMAP, R }, - FSCPOS_SYSCTL_TEMP1, VALUE(2), 0 }, - { { SENSORS_FSCPOS_TEMP3, "temp3", NOMAP, NOMAP, R }, - FSCPOS_SYSCTL_TEMP2, VALUE(2), 0 }, - { { SENSORS_FSCPOS_TEMP1_STATE, "temp1_state", SENSORS_FSCPOS_TEMP1, - SENSORS_FSCPOS_TEMP1, RW }, - FSCPOS_SYSCTL_TEMP0, VALUE(1), 0 }, - { { SENSORS_FSCPOS_TEMP2_STATE, "temp2_state", SENSORS_FSCPOS_TEMP2, - SENSORS_FSCPOS_TEMP2, RW }, - FSCPOS_SYSCTL_TEMP1, VALUE(1), 0 }, - { { SENSORS_FSCPOS_TEMP3_STATE, "temp3_state", SENSORS_FSCPOS_TEMP3, - SENSORS_FSCPOS_TEMP3, RW }, - FSCPOS_SYSCTL_TEMP2, VALUE(1), 0 }, - { { SENSORS_FSCPOS_FAN1, "fan1", NOMAP, NOMAP, R }, - FSCPOS_SYSCTL_FAN0, VALUE(4), 0 }, - { { SENSORS_FSCPOS_FAN2, "fan2", NOMAP, NOMAP, R }, - FSCPOS_SYSCTL_FAN1, VALUE(4), 0 }, - { { SENSORS_FSCPOS_FAN3, "fan3", NOMAP, NOMAP, R }, - FSCPOS_SYSCTL_FAN2, VALUE(4), 0 }, - { { SENSORS_FSCPOS_FAN1_MIN, "fan1_min", SENSORS_FSCPOS_FAN1, - SENSORS_FSCPOS_FAN1, RW }, - FSCPOS_SYSCTL_FAN0, VALUE(2), 0, "pwm1", 0 }, - { { SENSORS_FSCPOS_FAN2_MIN, "fan2_min", SENSORS_FSCPOS_FAN2, - SENSORS_FSCPOS_FAN2, RW }, - FSCPOS_SYSCTL_FAN1, VALUE(2), 0, "pwm2", 0 }, - { { SENSORS_FSCPOS_FAN1_STATE, "fan1_state", SENSORS_FSCPOS_FAN1, - SENSORS_FSCPOS_FAN1, RW }, - FSCPOS_SYSCTL_FAN0, VALUE(1), 0 }, - { { SENSORS_FSCPOS_FAN2_STATE, "fan2_state", SENSORS_FSCPOS_FAN2, - SENSORS_FSCPOS_FAN2, RW }, - FSCPOS_SYSCTL_FAN1, VALUE(1), 0 }, - { { SENSORS_FSCPOS_FAN3_STATE, "fan3_state", SENSORS_FSCPOS_FAN3, - SENSORS_FSCPOS_FAN3, RW }, - FSCPOS_SYSCTL_FAN2, VALUE(1), 0 }, - { { SENSORS_FSCPOS_FAN1_RIPPLE, "fan1_ripple", SENSORS_FSCPOS_FAN1, - SENSORS_FSCPOS_FAN1, RW }, - FSCPOS_SYSCTL_FAN0, VALUE(3), 0 }, - { { SENSORS_FSCPOS_FAN2_RIPPLE, "fan2_ripple", SENSORS_FSCPOS_FAN2, - SENSORS_FSCPOS_FAN2, RW }, - FSCPOS_SYSCTL_FAN1, VALUE(3), 0 }, - { { SENSORS_FSCPOS_FAN3_RIPPLE, "fan3_ripple", SENSORS_FSCPOS_FAN3, - SENSORS_FSCPOS_FAN3, RW }, - FSCPOS_SYSCTL_FAN2, VALUE(3), 0 }, - { { SENSORS_FSCPOS_WDOG_PRESET, "wdog_preset", NOMAP, NOMAP, RW }, - FSCPOS_SYSCTL_WDOG, VALUE(1), 0 }, - { { SENSORS_FSCPOS_WDOG_STATE, "wdog_state", SENSORS_FSCPOS_WDOG_PRESET, - SENSORS_FSCPOS_WDOG_PRESET, RW }, - FSCPOS_SYSCTL_WDOG, VALUE(2), 0 }, - { { SENSORS_FSCPOS_WDOG_CONTROL, "wdog_control", SENSORS_FSCPOS_WDOG_PRESET, - SENSORS_FSCPOS_WDOG_PRESET, RW }, - FSCPOS_SYSCTL_WDOG, VALUE(3), 0 }, - /* below this line are features only exported with the new fschmd drv */ - { { SENSORS_FSCHMD_TEMP_ALARM(1), "temp1_alarm", SENSORS_FSCPOS_TEMP1, - NOMAP, R }, NOSYSCTL, VALUE(1), 0 }, - { { SENSORS_FSCHMD_TEMP_ALARM(2), "temp2_alarm", SENSORS_FSCPOS_TEMP2, - NOMAP, R }, NOSYSCTL, VALUE(1), 0 }, - { { SENSORS_FSCHMD_TEMP_ALARM(3), "temp3_alarm", SENSORS_FSCPOS_TEMP3, - NOMAP, R }, NOSYSCTL, VALUE(1), 0 }, - { { SENSORS_FSCHMD_TEMP_FAULT(1), "temp1_fault", SENSORS_FSCPOS_TEMP1, - NOMAP, R }, NOSYSCTL, VALUE(1), 0 }, - { { SENSORS_FSCHMD_TEMP_FAULT(2), "temp2_fault", SENSORS_FSCPOS_TEMP2, - NOMAP, R }, NOSYSCTL, VALUE(1), 0 }, - { { SENSORS_FSCHMD_TEMP_FAULT(3), "temp3_fault", SENSORS_FSCPOS_TEMP3, - NOMAP, R }, NOSYSCTL, VALUE(1), 0 }, - { { SENSORS_FSCHMD_FAN_ALARM(1), "fan1_alarm", SENSORS_FSCPOS_FAN1, - NOMAP, R }, NOSYSCTL, VALUE(1), 0 }, - { { SENSORS_FSCHMD_FAN_ALARM(2), "fan2_alarm", SENSORS_FSCPOS_FAN2, - NOMAP, R }, NOSYSCTL, VALUE(1), 0 }, - { { SENSORS_FSCHMD_FAN_ALARM(3), "fan3_alarm", SENSORS_FSCPOS_FAN3, - NOMAP, R }, NOSYSCTL, VALUE(1), 0 }, - { { SENSORS_FSCHMD_FAN_FAULT(1), "fan1_fault", SENSORS_FSCPOS_FAN1, - NOMAP, R }, NOSYSCTL, VALUE(1), 0 }, - { { SENSORS_FSCHMD_FAN_FAULT(2), "fan2_fault", SENSORS_FSCPOS_FAN2, - NOMAP, R }, NOSYSCTL, VALUE(1), 0 }, - { { SENSORS_FSCHMD_FAN_FAULT(3), "fan3_fault", SENSORS_FSCPOS_FAN3, - NOMAP, R }, NOSYSCTL, VALUE(1), 0 }, - { { 0 }, 0 } - }; - -static sensors_chip_feature fscscy_features[] = - { - { { SENSORS_FSCSCY_REV, "rev", NOMAP, NOMAP, R }, - FSCSCY_SYSCTL_REV, VALUE(1), 0 }, - { { SENSORS_FSCSCY_EVENT, "event", NOMAP, NOMAP, R }, - FSCSCY_SYSCTL_EVENT, VALUE(1), 0 }, - { { SENSORS_FSCSCY_CONTROL, "control", NOMAP, NOMAP, RW }, - FSCSCY_SYSCTL_CONTROL, VALUE(1), 0 }, - { { SENSORS_FSCSCY_VOLTAGE1, "volt12", NOMAP, NOMAP, R }, - FSCSCY_SYSCTL_VOLT0, VALUE(1), 2 }, - { { SENSORS_FSCSCY_VOLTAGE2, "volt5", NOMAP, NOMAP, R }, - FSCSCY_SYSCTL_VOLT1, VALUE(1), 2 }, - { { SENSORS_FSCSCY_VOLTAGE3, "voltbatt", NOMAP, NOMAP, R }, - FSCSCY_SYSCTL_VOLT2, VALUE(1), 2 }, - { { SENSORS_FSCSCY_TEMP1, "temp1", NOMAP, NOMAP, R }, - FSCSCY_SYSCTL_TEMP0, VALUE(2), 0 }, - { { SENSORS_FSCSCY_TEMP2, "temp2", NOMAP, NOMAP, R }, - FSCSCY_SYSCTL_TEMP1, VALUE(2), 0 }, - { { SENSORS_FSCSCY_TEMP3, "temp3", NOMAP, NOMAP, R }, - FSCSCY_SYSCTL_TEMP2, VALUE(2), 0 }, - { { SENSORS_FSCSCY_TEMP4, "temp4", NOMAP, NOMAP, R }, - FSCSCY_SYSCTL_TEMP3, VALUE(2), 0 }, - { { SENSORS_FSCSCY_TEMP1_STATE, "temp1_state", SENSORS_FSCSCY_TEMP1, - SENSORS_FSCSCY_TEMP1, RW }, - FSCSCY_SYSCTL_TEMP0, VALUE(1), 0 }, - { { SENSORS_FSCSCY_TEMP2_STATE, "temp2_state", SENSORS_FSCSCY_TEMP2, - SENSORS_FSCSCY_TEMP2, RW }, - FSCSCY_SYSCTL_TEMP1, VALUE(1), 0 }, - { { SENSORS_FSCSCY_TEMP3_STATE, "temp3_state", SENSORS_FSCSCY_TEMP3, - SENSORS_FSCSCY_TEMP3, RW }, - FSCSCY_SYSCTL_TEMP2, VALUE(1), 0 }, - { { SENSORS_FSCSCY_TEMP4_STATE, "temp4_state", SENSORS_FSCSCY_TEMP4, - SENSORS_FSCSCY_TEMP4, RW }, - FSCSCY_SYSCTL_TEMP3, VALUE(1), 0 }, - { { SENSORS_FSCSCY_TEMP1_LIM, "temp1_lim", SENSORS_FSCSCY_TEMP1, - SENSORS_FSCSCY_TEMP1, R }, - FSCSCY_SYSCTL_TEMP0, VALUE(3), 0 }, - { { SENSORS_FSCSCY_TEMP2_LIM, "temp2_lim", SENSORS_FSCSCY_TEMP2, - SENSORS_FSCSCY_TEMP2, R }, - FSCSCY_SYSCTL_TEMP1, VALUE(3), 0 }, - { { SENSORS_FSCSCY_TEMP3_LIM, "temp3_lim", SENSORS_FSCSCY_TEMP3, - SENSORS_FSCSCY_TEMP3, R }, - FSCSCY_SYSCTL_TEMP2, VALUE(3), 0 }, - { { SENSORS_FSCSCY_TEMP4_LIM, "temp4_lim", SENSORS_FSCSCY_TEMP4, - SENSORS_FSCSCY_TEMP4, R }, - FSCSCY_SYSCTL_TEMP3, VALUE(3), 0 }, - { { SENSORS_FSCSCY_TEMP1_MIN, "temp1_min", SENSORS_FSCSCY_TEMP1, - SENSORS_FSCSCY_TEMP1, R }, - FSCSCY_SYSCTL_TEMP0, VALUE(4), 0 }, - { { SENSORS_FSCSCY_TEMP2_MIN, "temp2_min", SENSORS_FSCSCY_TEMP2, - SENSORS_FSCSCY_TEMP2, R }, - FSCSCY_SYSCTL_TEMP1, VALUE(4), 0 }, - { { SENSORS_FSCSCY_TEMP3_MIN, "temp3_min", SENSORS_FSCSCY_TEMP3, - SENSORS_FSCSCY_TEMP3, R }, - FSCSCY_SYSCTL_TEMP2, VALUE(4), 0 }, - { { SENSORS_FSCSCY_TEMP4_MIN, "temp4_min", SENSORS_FSCSCY_TEMP4, - SENSORS_FSCSCY_TEMP4, R }, - FSCSCY_SYSCTL_TEMP3, VALUE(4), 0 }, - { { SENSORS_FSCSCY_TEMP1_MAX, "temp1_max", SENSORS_FSCSCY_TEMP1, - SENSORS_FSCSCY_TEMP1, R }, - FSCSCY_SYSCTL_TEMP0, VALUE(5), 0 }, - { { SENSORS_FSCSCY_TEMP2_MAX, "temp2_max", SENSORS_FSCSCY_TEMP2, - SENSORS_FSCSCY_TEMP2, R }, - FSCSCY_SYSCTL_TEMP1, VALUE(5), 0 }, - { { SENSORS_FSCSCY_TEMP3_MAX, "temp3_max", SENSORS_FSCSCY_TEMP3, - SENSORS_FSCSCY_TEMP3, R }, - FSCSCY_SYSCTL_TEMP2, VALUE(5), 0 }, - { { SENSORS_FSCSCY_TEMP4_MAX, "temp4_max", SENSORS_FSCSCY_TEMP4, - SENSORS_FSCSCY_TEMP4, R }, - FSCSCY_SYSCTL_TEMP3, VALUE(5), 0 }, - { { SENSORS_FSCSCY_FAN1, "fan1", NOMAP, NOMAP, R }, - FSCSCY_SYSCTL_FAN0, VALUE(4), 0 }, - { { SENSORS_FSCSCY_FAN2, "fan2", NOMAP, NOMAP, R }, - FSCSCY_SYSCTL_FAN1, VALUE(4), 0 }, - { { SENSORS_FSCSCY_FAN3, "fan3", NOMAP, NOMAP, R }, - FSCSCY_SYSCTL_FAN2, VALUE(4), 0 }, - { { SENSORS_FSCSCY_FAN4, "fan4", NOMAP, NOMAP, R }, - FSCSCY_SYSCTL_FAN3, VALUE(4), 0 }, - { { SENSORS_FSCSCY_FAN5, "fan5", NOMAP, NOMAP, R }, - FSCSCY_SYSCTL_FAN4, VALUE(4), 0 }, - { { SENSORS_FSCSCY_FAN6, "fan6", NOMAP, NOMAP, R }, - FSCSCY_SYSCTL_FAN5, VALUE(4), 0 }, - { { SENSORS_FSCSCY_FAN1_MIN, "fan1_min", SENSORS_FSCSCY_FAN1, - SENSORS_FSCSCY_FAN1, RW }, - FSCSCY_SYSCTL_FAN0, VALUE(2), 0 }, - { { SENSORS_FSCSCY_FAN2_MIN, "fan2_min", SENSORS_FSCSCY_FAN2, - SENSORS_FSCSCY_FAN2, RW }, - FSCSCY_SYSCTL_FAN1, VALUE(2), 0 }, - { { SENSORS_FSCSCY_FAN3_MIN, "fan3_min", SENSORS_FSCSCY_FAN3, - SENSORS_FSCSCY_FAN3, RW }, - FSCSCY_SYSCTL_FAN2, VALUE(2), 0 }, - { { SENSORS_FSCSCY_FAN4_MIN, "fan4_min", SENSORS_FSCSCY_FAN4, - SENSORS_FSCSCY_FAN4, RW }, - FSCSCY_SYSCTL_FAN3, VALUE(2), 0 }, - { { SENSORS_FSCSCY_FAN5_MIN, "fan5_min", SENSORS_FSCSCY_FAN5, - SENSORS_FSCSCY_FAN5, RW }, - FSCSCY_SYSCTL_FAN4, VALUE(2), 0 }, - { { SENSORS_FSCSCY_FAN6_MIN, "fan6_min", SENSORS_FSCSCY_FAN6, - SENSORS_FSCSCY_FAN6, RW }, - FSCSCY_SYSCTL_FAN5, VALUE(2), 0 }, - { { SENSORS_FSCSCY_FAN1_STATE, "fan1_state", SENSORS_FSCSCY_FAN1, - SENSORS_FSCSCY_FAN1, RW }, - FSCSCY_SYSCTL_FAN0, VALUE(1), 0 }, - { { SENSORS_FSCSCY_FAN2_STATE, "fan2_state", SENSORS_FSCSCY_FAN2, - SENSORS_FSCSCY_FAN2, RW }, - FSCSCY_SYSCTL_FAN1, VALUE(1), 0 }, - { { SENSORS_FSCSCY_FAN3_STATE, "fan3_state", SENSORS_FSCSCY_FAN3, - SENSORS_FSCSCY_FAN3, RW }, - FSCSCY_SYSCTL_FAN2, VALUE(1), 0 }, - { { SENSORS_FSCSCY_FAN4_STATE, "fan4_state", SENSORS_FSCSCY_FAN4, - SENSORS_FSCSCY_FAN4, RW }, - FSCSCY_SYSCTL_FAN3, VALUE(1), 0 }, - { { SENSORS_FSCSCY_FAN5_STATE, "fan5_state", SENSORS_FSCSCY_FAN5, - SENSORS_FSCSCY_FAN5, RW }, - FSCSCY_SYSCTL_FAN4, VALUE(1), 0 }, - { { SENSORS_FSCSCY_FAN6_STATE, "fan6_state", SENSORS_FSCSCY_FAN6, - SENSORS_FSCSCY_FAN6, RW }, - FSCSCY_SYSCTL_FAN5, VALUE(1), 0 }, - { { SENSORS_FSCSCY_FAN1_RIPPLE, "fan1_ripple", SENSORS_FSCSCY_FAN1, - SENSORS_FSCSCY_FAN1, RW }, - FSCSCY_SYSCTL_FAN0, VALUE(3), 0 }, - { { SENSORS_FSCSCY_FAN2_RIPPLE, "fan2_ripple", SENSORS_FSCSCY_FAN2, - SENSORS_FSCSCY_FAN2, RW }, - FSCSCY_SYSCTL_FAN1, VALUE(3), 0 }, - { { SENSORS_FSCSCY_FAN3_RIPPLE, "fan3_ripple", SENSORS_FSCSCY_FAN3, - SENSORS_FSCSCY_FAN3, RW }, - FSCSCY_SYSCTL_FAN2, VALUE(3), 0 }, - { { SENSORS_FSCSCY_FAN4_RIPPLE, "fan4_ripple", SENSORS_FSCSCY_FAN4, - SENSORS_FSCSCY_FAN4, RW }, - FSCSCY_SYSCTL_FAN3, VALUE(3), 0 }, - { { SENSORS_FSCSCY_FAN5_RIPPLE, "fan5_ripple", SENSORS_FSCSCY_FAN5, - SENSORS_FSCSCY_FAN5, RW }, - FSCSCY_SYSCTL_FAN4, VALUE(3), 0 }, - { { SENSORS_FSCSCY_FAN6_RIPPLE, "fan6_ripple", SENSORS_FSCSCY_FAN6, - SENSORS_FSCSCY_FAN6, RW }, - FSCSCY_SYSCTL_FAN5, VALUE(3), 0 }, - { { SENSORS_FSCSCY_WDOG_PRESET, "wdog_preset", NOMAP, NOMAP, RW }, - FSCSCY_SYSCTL_WDOG, VALUE(1), 0 }, - { { SENSORS_FSCSCY_WDOG_STATE, "wdog_state", SENSORS_FSCSCY_WDOG_PRESET, - SENSORS_FSCSCY_WDOG_PRESET, RW }, - FSCSCY_SYSCTL_WDOG, VALUE(2), 0 }, - { { SENSORS_FSCSCY_WDOG_CONTROL, "wdog_control", SENSORS_FSCSCY_WDOG_PRESET, - SENSORS_FSCSCY_WDOG_PRESET, RW }, - FSCSCY_SYSCTL_WDOG, VALUE(3), 0 }, - /* below this line are features only exported with the new fschmd drv */ - { { SENSORS_FSCHMD_TEMP_ALARM(1), "temp1_alarm", SENSORS_FSCSCY_TEMP1, - NOMAP, R }, NOSYSCTL, VALUE(1), 0 }, - { { SENSORS_FSCHMD_TEMP_ALARM(2), "temp2_alarm", SENSORS_FSCSCY_TEMP2, - NOMAP, R }, NOSYSCTL, VALUE(1), 0 }, - { { SENSORS_FSCHMD_TEMP_ALARM(3), "temp3_alarm", SENSORS_FSCSCY_TEMP3, - NOMAP, R }, NOSYSCTL, VALUE(1), 0 }, - { { SENSORS_FSCHMD_TEMP_ALARM(4), "temp4_alarm", SENSORS_FSCSCY_TEMP4, - NOMAP, R }, NOSYSCTL, VALUE(1), 0 }, - { { SENSORS_FSCHMD_TEMP_FAULT(1), "temp1_fault", SENSORS_FSCSCY_TEMP1, - NOMAP, R }, NOSYSCTL, VALUE(1), 0 }, - { { SENSORS_FSCHMD_TEMP_FAULT(2), "temp2_fault", SENSORS_FSCSCY_TEMP2, - NOMAP, R }, NOSYSCTL, VALUE(1), 0 }, - { { SENSORS_FSCHMD_TEMP_FAULT(3), "temp3_fault", SENSORS_FSCSCY_TEMP3, - NOMAP, R }, NOSYSCTL, VALUE(1), 0 }, - { { SENSORS_FSCHMD_TEMP_FAULT(4), "temp4_fault", SENSORS_FSCSCY_TEMP4, - NOMAP, R }, NOSYSCTL, VALUE(1), 0 }, - { { SENSORS_FSCHMD_FAN_ALARM(1), "fan1_alarm", SENSORS_FSCSCY_FAN1, - NOMAP, R }, NOSYSCTL, VALUE(1), 0 }, - { { SENSORS_FSCHMD_FAN_ALARM(2), "fan2_alarm", SENSORS_FSCSCY_FAN2, - NOMAP, R }, NOSYSCTL, VALUE(1), 0 }, - { { SENSORS_FSCHMD_FAN_ALARM(3), "fan3_alarm", SENSORS_FSCSCY_FAN3, - NOMAP, R }, NOSYSCTL, VALUE(1), 0 }, - { { SENSORS_FSCHMD_FAN_ALARM(4), "fan4_alarm", SENSORS_FSCSCY_FAN4, - NOMAP, R }, NOSYSCTL, VALUE(1), 0 }, - { { SENSORS_FSCHMD_FAN_ALARM(5), "fan5_alarm", SENSORS_FSCSCY_FAN5, - NOMAP, R }, NOSYSCTL, VALUE(1), 0 }, - { { SENSORS_FSCHMD_FAN_ALARM(6), "fan6_alarm", SENSORS_FSCSCY_FAN6, - NOMAP, R }, NOSYSCTL, VALUE(1), 0 }, - { { SENSORS_FSCHMD_FAN_FAULT(1), "fan1_fault", SENSORS_FSCSCY_FAN1, - NOMAP, R }, NOSYSCTL, VALUE(1), 0 }, - { { SENSORS_FSCHMD_FAN_FAULT(2), "fan2_fault", SENSORS_FSCSCY_FAN2, - NOMAP, R }, NOSYSCTL, VALUE(1), 0 }, - { { SENSORS_FSCHMD_FAN_FAULT(3), "fan3_fault", SENSORS_FSCSCY_FAN3, - NOMAP, R }, NOSYSCTL, VALUE(1), 0 }, - { { SENSORS_FSCHMD_FAN_FAULT(4), "fan4_fault", SENSORS_FSCSCY_FAN4, - NOMAP, R }, NOSYSCTL, VALUE(1), 0 }, - { { SENSORS_FSCHMD_FAN_FAULT(5), "fan5_fault", SENSORS_FSCSCY_FAN5, - NOMAP, R }, NOSYSCTL, VALUE(1), 0 }, - { { SENSORS_FSCHMD_FAN_FAULT(6), "fan6_fault", SENSORS_FSCSCY_FAN6, - NOMAP, R }, NOSYSCTL, VALUE(1), 0 }, - { { 0 }, 0 } - }; - - static sensors_chip_feature fscher_features[] = - { - { { SENSORS_FSCHER_REV, "rev", NOMAP, NOMAP, R }, - FSCHER_SYSCTL_REV, VALUE(1), 0 }, - { { SENSORS_FSCHER_EVENT, "alarms", NOMAP, NOMAP, R }, - FSCHER_SYSCTL_EVENT, VALUE(1), 0 }, - { { SENSORS_FSCHER_CONTROL, "control", NOMAP, NOMAP, RW }, - FSCHER_SYSCTL_CONTROL, VALUE(1), 0 }, - { { SENSORS_FSCHER_VOLTAGE1, "in0", NOMAP, NOMAP, R }, - FSCHER_SYSCTL_VOLT0, VALUE(1), 2 }, - { { SENSORS_FSCHER_VOLTAGE2, "in1", NOMAP, NOMAP, R }, - FSCHER_SYSCTL_VOLT1, VALUE(1), 2 }, - { { SENSORS_FSCHER_VOLTAGE3, "in2", NOMAP, NOMAP, R }, - FSCHER_SYSCTL_VOLT2, VALUE(1), 2 }, - { { SENSORS_FSCHER_TEMP1, "temp1", NOMAP, NOMAP, R }, - FSCHER_SYSCTL_TEMP0, VALUE(2), 0 }, - { { SENSORS_FSCHER_TEMP2, "temp2", NOMAP, NOMAP, R }, - FSCHER_SYSCTL_TEMP1, VALUE(2), 0 }, - { { SENSORS_FSCHER_TEMP3, "temp3", NOMAP, NOMAP, R }, - FSCHER_SYSCTL_TEMP2, VALUE(2), 0 }, - { { SENSORS_FSCHER_TEMP1_STATE, "temp1_state", SENSORS_FSCHER_TEMP1, - SENSORS_FSCHER_TEMP1, RW }, - FSCHER_SYSCTL_TEMP0, VALUE(1), 0 }, - { { SENSORS_FSCHER_TEMP2_STATE, "temp2_state", SENSORS_FSCHER_TEMP2, - SENSORS_FSCHER_TEMP2, RW }, - FSCHER_SYSCTL_TEMP1, VALUE(1), 0 }, - { { SENSORS_FSCHER_TEMP3_STATE, "temp3_state", SENSORS_FSCHER_TEMP3, - SENSORS_FSCHER_TEMP3, RW }, - FSCHER_SYSCTL_TEMP2, VALUE(1), 0 }, - { { SENSORS_FSCHER_FAN1, "fan1", NOMAP, NOMAP, R }, - FSCHER_SYSCTL_FAN0, VALUE(3), 0 }, - { { SENSORS_FSCHER_FAN2, "fan2", NOMAP, NOMAP, R }, - FSCHER_SYSCTL_FAN1, VALUE(3), 0 }, - { { SENSORS_FSCHER_FAN3, "fan3", NOMAP, NOMAP, R }, - FSCHER_SYSCTL_FAN2, VALUE(3), 0 }, - { { SENSORS_FSCHER_PWM1, "pwm1", SENSORS_FSCHER_FAN1, NOMAP, RW }, - FSCHER_SYSCTL_PWM0, VALUE(1), 0 }, - { { SENSORS_FSCHER_PWM2, "pwm2", SENSORS_FSCHER_FAN2, NOMAP, RW }, - FSCHER_SYSCTL_PWM1, VALUE(1), 0 }, - { { SENSORS_FSCHER_PWM3, "pwm3", SENSORS_FSCHER_FAN3, NOMAP, RW }, - FSCHER_SYSCTL_PWM2, VALUE(1), 0 }, - { { SENSORS_FSCHER_FAN1_STATE, "fan1_state", SENSORS_FSCHER_FAN1, - SENSORS_FSCHER_FAN1, RW }, - FSCHER_SYSCTL_FAN0, VALUE(1), 0 }, - { { SENSORS_FSCHER_FAN2_STATE, "fan2_state", SENSORS_FSCHER_FAN2, - SENSORS_FSCHER_FAN2, RW }, - FSCHER_SYSCTL_FAN1, VALUE(1), 0 }, - { { SENSORS_FSCHER_FAN3_STATE, "fan3_state", SENSORS_FSCHER_FAN3, - SENSORS_FSCHER_FAN3, RW }, - FSCHER_SYSCTL_FAN2, VALUE(1), 0 }, - { { SENSORS_FSCHER_FAN1_RIPPLE, "fan1_ripple", SENSORS_FSCHER_FAN1, - SENSORS_FSCHER_FAN1, RW }, - FSCHER_SYSCTL_FAN0, VALUE(2), 0 }, - { { SENSORS_FSCHER_FAN2_RIPPLE, "fan2_ripple", SENSORS_FSCHER_FAN2, - SENSORS_FSCHER_FAN2, RW }, - FSCHER_SYSCTL_FAN1, VALUE(2), 0 }, - { { SENSORS_FSCHER_FAN3_RIPPLE, "fan3_ripple", SENSORS_FSCHER_FAN3, - SENSORS_FSCHER_FAN3, RW }, - FSCHER_SYSCTL_FAN2, VALUE(2), 0 }, - { { SENSORS_FSCHER_WDOG_PRESET, "wdog_preset", NOMAP, NOMAP, RW }, - FSCHER_SYSCTL_WDOG, VALUE(1), 0 }, - { { SENSORS_FSCHER_WDOG_STATE, "wdog_state", SENSORS_FSCHER_WDOG_PRESET, - SENSORS_FSCHER_WDOG_PRESET, RW }, - FSCHER_SYSCTL_WDOG, VALUE(2), 0 }, - { { SENSORS_FSCHER_WDOG_CONTROL, "wdog_control", SENSORS_FSCHER_WDOG_PRESET, - SENSORS_FSCHER_WDOG_PRESET, RW }, - FSCHER_SYSCTL_WDOG, VALUE(3), 0 }, - /* below this line are features only exported with the new fschmd drv */ - { { SENSORS_FSCHMD_TEMP_MAX(1), "temp1_max", SENSORS_FSCHER_TEMP1, - SENSORS_FSCHER_TEMP1, RW }, - NOSYSCTL, VALUE(1), 0 }, - { { SENSORS_FSCHMD_TEMP_MAX(2), "temp2_max", SENSORS_FSCHER_TEMP2, - SENSORS_FSCHER_TEMP2, RW }, - NOSYSCTL, VALUE(1), 0 }, - { { SENSORS_FSCHMD_TEMP_MAX(3), "temp3_max", SENSORS_FSCHER_TEMP3, - SENSORS_FSCHER_TEMP3, RW }, - NOSYSCTL, VALUE(1), 0 }, - { { SENSORS_FSCHMD_TEMP_ALARM(1), "temp1_alarm", SENSORS_FSCHER_TEMP1, - NOMAP, R }, NOSYSCTL, VALUE(1), 0 }, - { { SENSORS_FSCHMD_TEMP_ALARM(2), "temp2_alarm", SENSORS_FSCHER_TEMP2, - NOMAP, R }, NOSYSCTL, VALUE(1), 0 }, - { { SENSORS_FSCHMD_TEMP_ALARM(3), "temp3_alarm", SENSORS_FSCHER_TEMP3, - NOMAP, R }, NOSYSCTL, VALUE(1), 0 }, - { { SENSORS_FSCHMD_TEMP_FAULT(1), "temp1_fault", SENSORS_FSCHER_TEMP1, - NOMAP, R }, NOSYSCTL, VALUE(1), 0 }, - { { SENSORS_FSCHMD_TEMP_FAULT(2), "temp2_fault", SENSORS_FSCHER_TEMP2, - NOMAP, R }, NOSYSCTL, VALUE(1), 0 }, - { { SENSORS_FSCHMD_TEMP_FAULT(3), "temp3_fault", SENSORS_FSCHER_TEMP3, - NOMAP, R }, NOSYSCTL, VALUE(1), 0 }, - { { SENSORS_FSCHMD_FAN_ALARM(1), "fan1_alarm", SENSORS_FSCHER_FAN1, - NOMAP, R }, NOSYSCTL, VALUE(1), 0 }, - { { SENSORS_FSCHMD_FAN_ALARM(2), "fan2_alarm", SENSORS_FSCHER_FAN2, - NOMAP, R }, NOSYSCTL, VALUE(1), 0 }, - { { SENSORS_FSCHMD_FAN_ALARM(3), "fan3_alarm", SENSORS_FSCHER_FAN3, - NOMAP, R }, NOSYSCTL, VALUE(1), 0 }, - { { SENSORS_FSCHMD_FAN_FAULT(1), "fan1_fault", SENSORS_FSCHER_FAN1, - NOMAP, R }, NOSYSCTL, VALUE(1), 0 }, - { { SENSORS_FSCHMD_FAN_FAULT(2), "fan2_fault", SENSORS_FSCHER_FAN2, - NOMAP, R }, NOSYSCTL, VALUE(1), 0 }, - { { SENSORS_FSCHMD_FAN_FAULT(3), "fan3_fault", SENSORS_FSCHER_FAN3, - NOMAP, R }, NOSYSCTL, VALUE(1), 0 }, - { { 0 }, 0 } - }; - - static sensors_chip_feature pcf8591_features[] = - { - { { SENSORS_PCF8591_AIN_CONF, "ain_conf", NOMAP, NOMAP, RW }, - PCF8591_SYSCTL_AIN_CONF, VALUE(1), 0 }, - { { SENSORS_PCF8591_CH0, "ch0", NOMAP, NOMAP, R }, - PCF8591_SYSCTL_CH0, VALUE(1), 2, "in0_input", 3 }, - { { SENSORS_PCF8591_CH1, "ch1", NOMAP, NOMAP, R }, - PCF8591_SYSCTL_CH1, VALUE(1), 2, "in1_input", 3 }, - { { SENSORS_PCF8591_CH2, "ch2", NOMAP, NOMAP, R }, - PCF8591_SYSCTL_CH2, VALUE(1), 2, "in2_input", 3 }, - { { SENSORS_PCF8591_CH3, "ch3", NOMAP, NOMAP, R }, - PCF8591_SYSCTL_CH3, VALUE(1), 2, "in3_input", 3 }, - { { SENSORS_PCF8591_AOUT_ENABLE, "aout_enable", NOMAP, NOMAP, RW }, - PCF8591_SYSCTL_AOUT_ENABLE, VALUE(1), 0, - "out0_enable", 0 }, - { { SENSORS_PCF8591_AOUT, "aout", NOMAP, NOMAP, RW }, - PCF8591_SYSCTL_AOUT, VALUE(1), 2, "out0_output", - 3 }, - { { 0 }, 0 } - }; - - -static sensors_chip_feature vt1211_features[] = - { - { { SENSORS_VT1211_IN0, "in0", NOMAP, NOMAP, R }, - VT1211_SYSCTL_IN0, VALUE(3), 2 }, - { { SENSORS_VT1211_IN1, "in1", NOMAP, NOMAP, R }, - VT1211_SYSCTL_IN1, VALUE(3), 2 }, - { { SENSORS_VT1211_IN2, "in2", NOMAP, NOMAP, R }, - VT1211_SYSCTL_IN2, VALUE(3), 2 }, - { { SENSORS_VT1211_IN3, "in3", NOMAP, NOMAP, R }, - VT1211_SYSCTL_IN3, VALUE(3), 2 }, - { { SENSORS_VT1211_IN4, "in4", NOMAP, NOMAP, R }, - VT1211_SYSCTL_IN4, VALUE(3), 2 }, - { { SENSORS_VT1211_IN5, "in5", NOMAP, NOMAP, R }, - VT1211_SYSCTL_IN5, VALUE(3), 2 }, - { { SENSORS_VT1211_IN0_MIN, "in0_min", SENSORS_VT1211_IN0, - SENSORS_VT1211_IN0, RW }, - VT1211_SYSCTL_IN0, VALUE(1), 2 }, - { { SENSORS_VT1211_IN1_MIN, "in1_min", SENSORS_VT1211_IN1, - SENSORS_VT1211_IN1, RW }, - VT1211_SYSCTL_IN1, VALUE(1), 2 }, - { { SENSORS_VT1211_IN2_MIN, "in2_min", SENSORS_VT1211_IN2, - SENSORS_VT1211_IN2, RW }, - VT1211_SYSCTL_IN2, VALUE(1), 2 }, - { { SENSORS_VT1211_IN3_MIN, "in3_min", SENSORS_VT1211_IN3, - SENSORS_VT1211_IN3, RW }, - VT1211_SYSCTL_IN3, VALUE(1), 2 }, - { { SENSORS_VT1211_IN4_MIN, "in4_min", SENSORS_VT1211_IN4, - SENSORS_VT1211_IN4, RW }, - VT1211_SYSCTL_IN4, VALUE(1), 2 }, - { { SENSORS_VT1211_IN5_MIN, "in5_min", SENSORS_VT1211_IN5, - SENSORS_VT1211_IN5, RW }, - VT1211_SYSCTL_IN5, VALUE(1), 2 }, - { { SENSORS_VT1211_IN0_MAX, "in0_max", SENSORS_VT1211_IN0, - SENSORS_VT1211_IN0, RW }, - VT1211_SYSCTL_IN0, VALUE(2), 2 }, - { { SENSORS_VT1211_IN1_MAX, "in1_max", SENSORS_VT1211_IN1, - SENSORS_VT1211_IN1, RW }, - VT1211_SYSCTL_IN1, VALUE(2), 2 }, - { { SENSORS_VT1211_IN2_MAX, "in2_max", SENSORS_VT1211_IN2, - SENSORS_VT1211_IN2, RW }, - VT1211_SYSCTL_IN2, VALUE(2), 2 }, - { { SENSORS_VT1211_IN3_MAX, "in3_max", SENSORS_VT1211_IN3, - SENSORS_VT1211_IN3, RW }, - VT1211_SYSCTL_IN3, VALUE(2), 2 }, - { { SENSORS_VT1211_IN4_MAX, "in4_max", SENSORS_VT1211_IN4, - SENSORS_VT1211_IN4, RW }, - VT1211_SYSCTL_IN4, VALUE(2), 2 }, - { { SENSORS_VT1211_IN5_MAX, "in5_max", SENSORS_VT1211_IN5, - SENSORS_VT1211_IN5, RW }, - VT1211_SYSCTL_IN5, VALUE(2), 2 }, - { { SENSORS_VT1211_FAN1, "fan1", NOMAP, NOMAP, R }, - VT1211_SYSCTL_FAN1, VALUE(2), 0 }, - { { SENSORS_VT1211_FAN2, "fan2", NOMAP, NOMAP, R }, - VT1211_SYSCTL_FAN2, VALUE(2), 0 }, - { { SENSORS_VT1211_FAN1_MIN, "fan1_min", SENSORS_VT1211_FAN1, - SENSORS_VT1211_FAN1, RW }, - VT1211_SYSCTL_FAN1, VALUE(1), 0 }, - { { SENSORS_VT1211_FAN2_MIN, "fan2_min", SENSORS_VT1211_FAN2, - SENSORS_VT1211_FAN2, RW }, - VT1211_SYSCTL_FAN2, VALUE(1), 0 }, - { { SENSORS_VT1211_TEMP1, "temp1", NOMAP, NOMAP, R }, - VT1211_SYSCTL_TEMP1, VALUE(3), 1 }, - { { SENSORS_VT1211_TEMP1_HYST, "temp1_hyst", SENSORS_VT1211_TEMP1, - SENSORS_VT1211_TEMP1, RW }, - VT1211_SYSCTL_TEMP1, VALUE(2), 1 }, - { { SENSORS_VT1211_TEMP1_OVER, "temp1_over", SENSORS_VT1211_TEMP1, - SENSORS_VT1211_TEMP1, RW }, - VT1211_SYSCTL_TEMP1, VALUE(1), 1 }, - { { SENSORS_VT1211_TEMP2, "temp2", NOMAP, NOMAP, R }, - VT1211_SYSCTL_TEMP2, VALUE(3), 1 }, - { { SENSORS_VT1211_TEMP2_HYST, "temp2_hyst", SENSORS_VT1211_TEMP2, - SENSORS_VT1211_TEMP2, RW }, - VT1211_SYSCTL_TEMP2, VALUE(2), 1 }, - { { SENSORS_VT1211_TEMP2_OVER, "temp2_over", SENSORS_VT1211_TEMP2, - SENSORS_VT1211_TEMP2, RW }, - VT1211_SYSCTL_TEMP2, VALUE(1), 1 }, - { { SENSORS_VT1211_TEMP3, "temp3", NOMAP, NOMAP, R }, - VT1211_SYSCTL_TEMP3, VALUE(3), 3 }, - { { SENSORS_VT1211_TEMP3_HYST, "temp3_hyst", SENSORS_VT1211_TEMP3, - SENSORS_VT1211_TEMP3, RW }, - VT1211_SYSCTL_TEMP3, VALUE(2), 3 }, - { { SENSORS_VT1211_TEMP3_OVER, "temp3_over", SENSORS_VT1211_TEMP3, - SENSORS_VT1211_TEMP3, RW }, - VT1211_SYSCTL_TEMP3, VALUE(1), 3 }, - { { SENSORS_VT1211_TEMP4, "temp4", NOMAP, NOMAP, R }, - VT1211_SYSCTL_TEMP4, VALUE(3), 3 }, - { { SENSORS_VT1211_TEMP4_HYST, "temp4_hyst", SENSORS_VT1211_TEMP4, - SENSORS_VT1211_TEMP4, RW }, - VT1211_SYSCTL_TEMP4, VALUE(2), 3 }, - { { SENSORS_VT1211_TEMP4_OVER, "temp4_over", SENSORS_VT1211_TEMP4, - SENSORS_VT1211_TEMP4, RW }, - VT1211_SYSCTL_TEMP4, VALUE(1), 3 }, - { { SENSORS_VT1211_TEMP5, "temp5", NOMAP, NOMAP, R }, - VT1211_SYSCTL_TEMP5, VALUE(3), 3 }, - { { SENSORS_VT1211_TEMP5_HYST, "temp5_hyst", SENSORS_VT1211_TEMP5, - SENSORS_VT1211_TEMP5, RW }, - VT1211_SYSCTL_TEMP5, VALUE(2), 3 }, - { { SENSORS_VT1211_TEMP5_OVER, "temp5_over", SENSORS_VT1211_TEMP5, - SENSORS_VT1211_TEMP5, RW }, - VT1211_SYSCTL_TEMP5, VALUE(1), 3 }, - { { SENSORS_VT1211_TEMP6, "temp6", NOMAP, NOMAP, R }, - VT1211_SYSCTL_TEMP6, VALUE(3), 3 }, - { { SENSORS_VT1211_TEMP6_HYST, "temp6_hyst", SENSORS_VT1211_TEMP6, - SENSORS_VT1211_TEMP6, RW }, - VT1211_SYSCTL_TEMP6, VALUE(2), 3 }, - { { SENSORS_VT1211_TEMP6_OVER, "temp6_over", SENSORS_VT1211_TEMP6, - SENSORS_VT1211_TEMP6, RW }, - VT1211_SYSCTL_TEMP6, VALUE(1), 3 }, - { { SENSORS_VT1211_TEMP7, "temp7", NOMAP, NOMAP, R }, - VT1211_SYSCTL_TEMP7, VALUE(3), 3 }, - { { SENSORS_VT1211_TEMP7_HYST, "temp7_hyst", SENSORS_VT1211_TEMP7, - SENSORS_VT1211_TEMP7, RW }, - VT1211_SYSCTL_TEMP7, VALUE(2), 3 }, - { { SENSORS_VT1211_TEMP7_OVER, "temp7_over", SENSORS_VT1211_TEMP7, - SENSORS_VT1211_TEMP7, RW }, - VT1211_SYSCTL_TEMP7, VALUE(1), 3 }, - { { SENSORS_VT1211_FAN1_DIV, "fan1_div", SENSORS_VT1211_FAN1, NOMAP, RW }, - VT1211_SYSCTL_FAN_DIV, VALUE(1), 0 }, - { { SENSORS_VT1211_FAN2_DIV, "fan2_div", SENSORS_VT1211_FAN2, NOMAP, RW }, - VT1211_SYSCTL_FAN_DIV, VALUE(2), 0 }, - { { SENSORS_VT1211_ALARMS, "alarms", NOMAP, NOMAP, R }, - VT1211_SYSCTL_ALARMS, VALUE(1), 0 }, - { { SENSORS_VT1211_VID, "vid", NOMAP, NOMAP, R }, - VT1211_SYSCTL_VID, VALUE(1), 3 }, - { { SENSORS_VT1211_VRM, "vrm", NOMAP, NOMAP, RW }, - VT1211_SYSCTL_VRM, VALUE(1), 1 }, - { { SENSORS_VT1211_UCH, "config", NOMAP, NOMAP, RW }, - VT1211_SYSCTL_UCH, VALUE(1), 0, "uch_config" }, - { { 0 }, 0 } - }; - -static sensors_chip_feature smsc47m1_features[] = - { - { { SENSORS_SMSC47M1_FAN1, "fan1", NOMAP, NOMAP, R }, - SMSC47M1_SYSCTL_FAN1, VALUE(2), 0 }, - { { SENSORS_SMSC47M1_FAN2, "fan2", NOMAP, NOMAP, R }, - SMSC47M1_SYSCTL_FAN2, VALUE(2), 0 }, - { { SENSORS_SMSC47M1_FAN1_MIN, "fan1_min", SENSORS_SMSC47M1_FAN1, - SENSORS_SMSC47M1_FAN1, RW }, - SMSC47M1_SYSCTL_FAN1, VALUE(1), 0 }, - { { SENSORS_SMSC47M1_FAN2_MIN, "fan2_min", SENSORS_SMSC47M1_FAN2, - SENSORS_SMSC47M1_FAN2, RW }, - SMSC47M1_SYSCTL_FAN2, VALUE(1), 0 }, - { { SENSORS_SMSC47M1_FAN1_DIV, "fan1_div", SENSORS_SMSC47M1_FAN1, NOMAP, RW }, - SMSC47M1_SYSCTL_FAN_DIV, VALUE(1), 0 }, - { { SENSORS_SMSC47M1_FAN2_DIV, "fan2_div", SENSORS_SMSC47M1_FAN2, NOMAP, RW }, - SMSC47M1_SYSCTL_FAN_DIV, VALUE(2), 0 }, - { { SENSORS_SMSC47M1_ALARMS, "alarms", NOMAP, NOMAP, R }, - SMSC47M1_SYSCTL_ALARMS, VALUE(1), 0 }, - { { 0 }, 0 } - }; - -static sensors_chip_feature smsc47m2_features[] = - { - { { SENSORS_SMSC47M1_FAN1, "fan1", NOMAP, NOMAP, R }, - SMSC47M1_SYSCTL_FAN1, VALUE(2), 0 }, - { { SENSORS_SMSC47M1_FAN2, "fan2", NOMAP, NOMAP, R }, - SMSC47M1_SYSCTL_FAN2, VALUE(2), 0 }, - { { SENSORS_SMSC47M1_FAN3, "fan3", NOMAP, NOMAP, R }, - SMSC47M1_SYSCTL_FAN3, VALUE(2), 0 }, - { { SENSORS_SMSC47M1_FAN1_MIN, "fan1_min", SENSORS_SMSC47M1_FAN1, - SENSORS_SMSC47M1_FAN1, RW }, - SMSC47M1_SYSCTL_FAN1, VALUE(1), 0 }, - { { SENSORS_SMSC47M1_FAN2_MIN, "fan2_min", SENSORS_SMSC47M1_FAN2, - SENSORS_SMSC47M1_FAN2, RW }, - SMSC47M1_SYSCTL_FAN2, VALUE(1), 0 }, - { { SENSORS_SMSC47M1_FAN3_MIN, "fan3_min", SENSORS_SMSC47M1_FAN3, - SENSORS_SMSC47M1_FAN3, RW }, - SMSC47M1_SYSCTL_FAN3, VALUE(1), 0 }, - { { SENSORS_SMSC47M1_FAN1_DIV, "fan1_div", SENSORS_SMSC47M1_FAN1, NOMAP, RW }, - SMSC47M1_SYSCTL_FAN_DIV, VALUE(1), 0 }, - { { SENSORS_SMSC47M1_FAN2_DIV, "fan2_div", SENSORS_SMSC47M1_FAN2, NOMAP, RW }, - SMSC47M1_SYSCTL_FAN_DIV, VALUE(2), 0 }, - { { SENSORS_SMSC47M1_FAN3_DIV, "fan3_div", SENSORS_SMSC47M1_FAN3, NOMAP, RW }, - SMSC47M1_SYSCTL_FAN_DIV, VALUE(3), 0 }, - { { SENSORS_SMSC47M1_ALARMS, "alarms", NOMAP, NOMAP, R }, - SMSC47M1_SYSCTL_ALARMS, VALUE(1), 0 }, - { { 0 }, 0 } - }; - -static sensors_chip_feature smsc47m192_features[] = - { - { { SENSORS_SMSC47M192_IN(0), "in0", NOMAP, NOMAP, R }, - NOSYSCTL, VALUE(3), 3 }, - { { SENSORS_SMSC47M192_IN(1), "in1", NOMAP, NOMAP, R }, - NOSYSCTL, VALUE(3), 3 }, - { { SENSORS_SMSC47M192_IN(2), "in2", NOMAP, NOMAP, R }, - NOSYSCTL, VALUE(3), 3 }, - { { SENSORS_SMSC47M192_IN(3), "in3", NOMAP, NOMAP, R }, - NOSYSCTL, VALUE(3), 3 }, - { { SENSORS_SMSC47M192_IN(4), "in4", NOMAP, NOMAP, R }, - NOSYSCTL, VALUE(3), 3 }, - { { SENSORS_SMSC47M192_IN(5), "in5", NOMAP, NOMAP, R }, - NOSYSCTL, VALUE(3), 3 }, - { { SENSORS_SMSC47M192_IN(6), "in6", NOMAP, NOMAP, R }, - NOSYSCTL, VALUE(3), 3 }, - { { SENSORS_SMSC47M192_IN(7), "in7", NOMAP, NOMAP, R }, - NOSYSCTL, VALUE(3), 3 }, - { { SENSORS_SMSC47M192_IN_MIN(0), "in0_min", SENSORS_SMSC47M192_IN(0), - SENSORS_SMSC47M192_IN(0), RW }, - NOSYSCTL, VALUE(1), 3 }, - { { SENSORS_SMSC47M192_IN_MIN(1), "in1_min", SENSORS_SMSC47M192_IN(1), - SENSORS_SMSC47M192_IN(1), RW }, - NOSYSCTL, VALUE(1), 3 }, - { { SENSORS_SMSC47M192_IN_MIN(2), "in2_min", SENSORS_SMSC47M192_IN(2), - SENSORS_SMSC47M192_IN(2), RW }, - NOSYSCTL, VALUE(1), 3 }, - { { SENSORS_SMSC47M192_IN_MIN(3), "in3_min", SENSORS_SMSC47M192_IN(3), - SENSORS_SMSC47M192_IN(3), RW }, - NOSYSCTL, VALUE(1), 3 }, - { { SENSORS_SMSC47M192_IN_MIN(4), "in4_min", SENSORS_SMSC47M192_IN(4), - SENSORS_SMSC47M192_IN(4), RW }, - NOSYSCTL, VALUE(1), 3 }, - { { SENSORS_SMSC47M192_IN_MIN(5), "in5_min", SENSORS_SMSC47M192_IN(5), - SENSORS_SMSC47M192_IN(5), RW }, - NOSYSCTL, VALUE(1), 3 }, - { { SENSORS_SMSC47M192_IN_MIN(6), "in6_min", SENSORS_SMSC47M192_IN(6), - SENSORS_SMSC47M192_IN(6), RW }, - NOSYSCTL, VALUE(1), 3 }, - { { SENSORS_SMSC47M192_IN_MIN(7), "in7_min", SENSORS_SMSC47M192_IN(7), - SENSORS_SMSC47M192_IN(7), RW }, - NOSYSCTL, VALUE(1), 3 }, - { { SENSORS_SMSC47M192_IN_MAX(0), "in0_max", SENSORS_SMSC47M192_IN(0), - SENSORS_SMSC47M192_IN(0), RW }, - NOSYSCTL, VALUE(2), 3 }, - { { SENSORS_SMSC47M192_IN_MAX(1), "in1_max", SENSORS_SMSC47M192_IN(1), - SENSORS_SMSC47M192_IN(1), RW }, - NOSYSCTL, VALUE(2), 3 }, - { { SENSORS_SMSC47M192_IN_MAX(2), "in2_max", SENSORS_SMSC47M192_IN(2), - SENSORS_SMSC47M192_IN(2), RW }, - NOSYSCTL, VALUE(2), 3 }, - { { SENSORS_SMSC47M192_IN_MAX(3), "in3_max", SENSORS_SMSC47M192_IN(3), - SENSORS_SMSC47M192_IN(3), RW }, - NOSYSCTL, VALUE(2), 3 }, - { { SENSORS_SMSC47M192_IN_MAX(4), "in4_max", SENSORS_SMSC47M192_IN(4), - SENSORS_SMSC47M192_IN(4), RW }, - NOSYSCTL, VALUE(2), 3 }, - { { SENSORS_SMSC47M192_IN_MAX(5), "in5_max", SENSORS_SMSC47M192_IN(5), - SENSORS_SMSC47M192_IN(5), RW }, - NOSYSCTL, VALUE(2), 3 }, - { { SENSORS_SMSC47M192_IN_MAX(6), "in6_max", SENSORS_SMSC47M192_IN(6), - SENSORS_SMSC47M192_IN(6), RW }, - NOSYSCTL, VALUE(2), 3 }, - { { SENSORS_SMSC47M192_IN_MAX(7), "in7_max", SENSORS_SMSC47M192_IN(7), - SENSORS_SMSC47M192_IN(7), RW }, - NOSYSCTL, VALUE(2), 3 }, - { { SENSORS_SMSC47M192_IN_ALARM(0), "in0_alarm", SENSORS_SMSC47M192_IN(0), - NOMAP, R }, - NOSYSCTL, VALUE(1), 0 }, - { { SENSORS_SMSC47M192_IN_ALARM(1), "in1_alarm", SENSORS_SMSC47M192_IN(1), - NOMAP, R }, - NOSYSCTL, VALUE(1), 0 }, - { { SENSORS_SMSC47M192_IN_ALARM(2), "in2_alarm", SENSORS_SMSC47M192_IN(2), - NOMAP, R }, - NOSYSCTL, VALUE(1), 0 }, - { { SENSORS_SMSC47M192_IN_ALARM(3), "in3_alarm", SENSORS_SMSC47M192_IN(3), - NOMAP, R }, - NOSYSCTL, VALUE(1), 0 }, - { { SENSORS_SMSC47M192_IN_ALARM(4), "in4_alarm", SENSORS_SMSC47M192_IN(4), - NOMAP, R }, - NOSYSCTL, VALUE(1), 0 }, - { { SENSORS_SMSC47M192_IN_ALARM(5), "in5_alarm", SENSORS_SMSC47M192_IN(5), - NOMAP, R }, - NOSYSCTL, VALUE(1), 0 }, - { { SENSORS_SMSC47M192_IN_ALARM(6), "in6_alarm", SENSORS_SMSC47M192_IN(6), - NOMAP, R }, - NOSYSCTL, VALUE(1), 0 }, - { { SENSORS_SMSC47M192_IN_ALARM(7), "in7_alarm", SENSORS_SMSC47M192_IN(7), - NOMAP, R }, - NOSYSCTL, VALUE(1), 0 }, - { { SENSORS_SMSC47M192_TEMP(1), "temp1", NOMAP, NOMAP, R }, - NOSYSCTL, VALUE(3), 0 }, - { { SENSORS_SMSC47M192_TEMP(2), "temp2", NOMAP, NOMAP, R }, - NOSYSCTL, VALUE(3), 0 }, - { { SENSORS_SMSC47M192_TEMP(3), "temp3", NOMAP, NOMAP, R }, - NOSYSCTL, VALUE(3), 0 }, - { { SENSORS_SMSC47M192_TEMP_MIN(1), "temp1_min", SENSORS_SMSC47M192_TEMP(1), - SENSORS_SMSC47M192_TEMP(1), RW }, - NOSYSCTL, VALUE(2), 0 }, - { { SENSORS_SMSC47M192_TEMP_MIN(2), "temp2_min", SENSORS_SMSC47M192_TEMP(2), - SENSORS_SMSC47M192_TEMP(2), RW }, - NOSYSCTL, VALUE(2), 0 }, - { { SENSORS_SMSC47M192_TEMP_MIN(3), "temp3_min", SENSORS_SMSC47M192_TEMP(3), - SENSORS_SMSC47M192_TEMP(3), RW }, - NOSYSCTL, VALUE(2), 0 }, - { { SENSORS_SMSC47M192_TEMP_MAX(1), "temp1_max", SENSORS_SMSC47M192_TEMP(1), - SENSORS_SMSC47M192_TEMP(1), RW }, - NOSYSCTL, VALUE(1), 0 }, - { { SENSORS_SMSC47M192_TEMP_MAX(2), "temp2_max", SENSORS_SMSC47M192_TEMP(2), - SENSORS_SMSC47M192_TEMP(2), RW }, - NOSYSCTL, VALUE(1), 0 }, - { { SENSORS_SMSC47M192_TEMP_MAX(3), "temp3_max", SENSORS_SMSC47M192_TEMP(3), - SENSORS_SMSC47M192_TEMP(3), RW }, - NOSYSCTL, VALUE(1), 0 }, - { { SENSORS_SMSC47M192_TEMP_ALARM(1), "temp1_alarm", - SENSORS_SMSC47M192_TEMP(1), NOMAP, R }, - NOSYSCTL, VALUE(1), 0 }, - { { SENSORS_SMSC47M192_TEMP_ALARM(2), "temp2_alarm", - SENSORS_SMSC47M192_TEMP(2), NOMAP, R }, - NOSYSCTL, VALUE(1), 0 }, - { { SENSORS_SMSC47M192_TEMP_ALARM(3), "temp3_alarm", - SENSORS_SMSC47M192_TEMP(3), NOMAP, R }, - NOSYSCTL, VALUE(1), 0 }, - { { SENSORS_SMSC47M192_TEMP_FAULT(2), "temp2_fault", - SENSORS_SMSC47M192_TEMP(2), NOMAP, R }, - NOSYSCTL, VALUE(1), 0, "temp2_fault", 0, "temp2_input_fault" }, - { { SENSORS_SMSC47M192_TEMP_FAULT(3), "temp3_fault", - SENSORS_SMSC47M192_TEMP(3), NOMAP, R }, - NOSYSCTL, VALUE(1), 0, "temp3_fault", 0, "temp3_input_fault" }, - { { SENSORS_SMSC47M192_VID, "vid", NOMAP, NOMAP, R }, - NOSYSCTL, VALUE(1), 3 }, - { { SENSORS_SMSC47M192_VRM, "vrm", NOMAP, NOMAP, RW }, - NOSYSCTL, VALUE(1), 1 }, - { { 0 }, 0 } - }; - - -static sensors_chip_feature pc87360_features[] = - { - { { SENSORS_PC87360_FAN1, "fan1", NOMAP, NOMAP, R }, - PC87360_SYSCTL_FAN1, VALUE(2), 0 }, - { { SENSORS_PC87360_FAN2, "fan2", NOMAP, NOMAP, R }, - PC87360_SYSCTL_FAN2, VALUE(2), 0 }, - { { SENSORS_PC87360_FAN3, "fan3", NOMAP, NOMAP, R }, - PC87360_SYSCTL_FAN3, VALUE(2), 0 }, - { { SENSORS_PC87360_FAN1_MIN, "fan1_min", SENSORS_PC87360_FAN1, - SENSORS_PC87360_FAN1, RW }, - PC87360_SYSCTL_FAN1, VALUE(1), 0 }, - { { SENSORS_PC87360_FAN2_MIN, "fan2_min", SENSORS_PC87360_FAN2, - SENSORS_PC87360_FAN2, RW }, - PC87360_SYSCTL_FAN2, VALUE(1), 0 }, - { { SENSORS_PC87360_FAN3_MIN, "fan3_min", SENSORS_PC87360_FAN3, - SENSORS_PC87360_FAN3, RW }, - PC87360_SYSCTL_FAN3, VALUE(1), 0 }, - { { SENSORS_PC87360_FAN1_DIV, "fan1_div", SENSORS_PC87360_FAN1, NOMAP, R }, - PC87360_SYSCTL_FAN_DIV, VALUE(1), 0 }, - { { SENSORS_PC87360_FAN2_DIV, "fan2_div", SENSORS_PC87360_FAN2, NOMAP, R }, - PC87360_SYSCTL_FAN_DIV, VALUE(2), 0 }, - { { SENSORS_PC87360_FAN3_DIV, "fan3_div", SENSORS_PC87360_FAN3, NOMAP, R }, - PC87360_SYSCTL_FAN_DIV, VALUE(3), 0 }, - { { SENSORS_PC87360_FAN1_STATUS, "fan1_status", SENSORS_PC87360_FAN1, NOMAP, - R }, - PC87360_SYSCTL_FAN1_STATUS, VALUE(1), 0 }, - { { SENSORS_PC87360_FAN2_STATUS, "fan2_status", SENSORS_PC87360_FAN2, NOMAP, - R }, - PC87360_SYSCTL_FAN2_STATUS, VALUE(1), 0 }, - { { SENSORS_PC87360_FAN3_STATUS, "fan3_status", SENSORS_PC87360_FAN3, NOMAP, - R }, - PC87360_SYSCTL_FAN3_STATUS, VALUE(1), 0 }, - { { 0 }, 0 } - }; - -static sensors_chip_feature pc87365_features[] = - { - { { SENSORS_PC87360_ALARMS_IN, "alarms_in", NOMAP, NOMAP, R }, - PC87365_SYSCTL_ALARMS, VALUE(1), 0 }, - { { SENSORS_PC87360_ALARMS_TEMP, "alarms_temp", NOMAP, NOMAP, R }, - PC87365_SYSCTL_ALARMS, VALUE(2), 0 }, - { { SENSORS_PC87360_FAN1, "fan1", NOMAP, NOMAP, R }, - PC87360_SYSCTL_FAN1, VALUE(2), 0 }, - { { SENSORS_PC87360_FAN2, "fan2", NOMAP, NOMAP, R }, - PC87360_SYSCTL_FAN2, VALUE(2), 0 }, - { { SENSORS_PC87360_FAN3, "fan3", NOMAP, NOMAP, R }, - PC87360_SYSCTL_FAN3, VALUE(2), 0 }, - { { SENSORS_PC87360_FAN1_MIN, "fan1_min", SENSORS_PC87360_FAN1, - SENSORS_PC87360_FAN1, RW }, - PC87360_SYSCTL_FAN1, VALUE(1), 0 }, - { { SENSORS_PC87360_FAN2_MIN, "fan2_min", SENSORS_PC87360_FAN2, - SENSORS_PC87360_FAN2, RW }, - PC87360_SYSCTL_FAN2, VALUE(1), 0 }, - { { SENSORS_PC87360_FAN3_MIN, "fan3_min", SENSORS_PC87360_FAN3, - SENSORS_PC87360_FAN3, RW }, - PC87360_SYSCTL_FAN3, VALUE(1), 0 }, - { { SENSORS_PC87360_FAN1_DIV, "fan1_div", SENSORS_PC87360_FAN1, NOMAP, R }, - PC87360_SYSCTL_FAN_DIV, VALUE(1), 0 }, - { { SENSORS_PC87360_FAN2_DIV, "fan2_div", SENSORS_PC87360_FAN2, NOMAP, R }, - PC87360_SYSCTL_FAN_DIV, VALUE(2), 0 }, - { { SENSORS_PC87360_FAN3_DIV, "fan3_div", SENSORS_PC87360_FAN3, NOMAP, R }, - PC87360_SYSCTL_FAN_DIV, VALUE(3), 0 }, - { { SENSORS_PC87360_FAN1_STATUS, "fan1_status", SENSORS_PC87360_FAN1, NOMAP, - R }, - PC87360_SYSCTL_FAN1_STATUS, VALUE(1), 0 }, - { { SENSORS_PC87360_FAN2_STATUS, "fan2_status", SENSORS_PC87360_FAN2, NOMAP, - R }, - PC87360_SYSCTL_FAN2_STATUS, VALUE(1), 0 }, - { { SENSORS_PC87360_FAN3_STATUS, "fan3_status", SENSORS_PC87360_FAN3, NOMAP, - R }, - PC87360_SYSCTL_FAN3_STATUS, VALUE(1), 0 }, - { { SENSORS_PC87360_IN0, "in0", NOMAP, NOMAP, R }, - PC87365_SYSCTL_IN0, VALUE(3), 3 }, - { { SENSORS_PC87360_IN1, "in1", NOMAP, NOMAP, R }, - PC87365_SYSCTL_IN1, VALUE(3), 3 }, - { { SENSORS_PC87360_IN2, "in2", NOMAP, NOMAP, R }, - PC87365_SYSCTL_IN2, VALUE(3), 3 }, - { { SENSORS_PC87360_IN3, "in3", NOMAP, NOMAP, R }, - PC87365_SYSCTL_IN3, VALUE(3), 3 }, - { { SENSORS_PC87360_IN4, "in4", NOMAP, NOMAP, R }, - PC87365_SYSCTL_IN4, VALUE(3), 3 }, - { { SENSORS_PC87360_IN5, "in5", NOMAP, NOMAP, R }, - PC87365_SYSCTL_IN5, VALUE(3), 3 }, - { { SENSORS_PC87360_IN6, "in6", NOMAP, NOMAP, R }, - PC87365_SYSCTL_IN6, VALUE(3), 3 }, - { { SENSORS_PC87360_IN7, "in7", NOMAP, NOMAP, R }, - PC87365_SYSCTL_IN7, VALUE(3), 3 }, - { { SENSORS_PC87360_IN8, "in8", NOMAP, NOMAP, R }, - PC87365_SYSCTL_IN8, VALUE(3), 3 }, - { { SENSORS_PC87360_IN9, "in9", NOMAP, NOMAP, R }, - PC87365_SYSCTL_IN9, VALUE(3), 3 }, - { { SENSORS_PC87360_IN10, "in10", NOMAP, NOMAP, R }, - PC87365_SYSCTL_IN10, VALUE(3), 3 }, - { { SENSORS_PC87360_IN0_MIN, "in0_min", SENSORS_PC87360_IN0, - SENSORS_PC87360_IN0, RW }, - PC87365_SYSCTL_IN0, VALUE(1), 3 }, - { { SENSORS_PC87360_IN1_MIN, "in1_min", SENSORS_PC87360_IN1, - SENSORS_PC87360_IN1, RW }, - PC87365_SYSCTL_IN1, VALUE(1), 3 }, - { { SENSORS_PC87360_IN2_MIN, "in2_min", SENSORS_PC87360_IN2, - SENSORS_PC87360_IN2, RW }, - PC87365_SYSCTL_IN2, VALUE(1), 3 }, - { { SENSORS_PC87360_IN3_MIN, "in3_min", SENSORS_PC87360_IN3, - SENSORS_PC87360_IN3, RW }, - PC87365_SYSCTL_IN3, VALUE(1), 3 }, - { { SENSORS_PC87360_IN4_MIN, "in4_min", SENSORS_PC87360_IN4, - SENSORS_PC87360_IN4, RW }, - PC87365_SYSCTL_IN4, VALUE(1), 3 }, - { { SENSORS_PC87360_IN5_MIN, "in5_min", SENSORS_PC87360_IN5, - SENSORS_PC87360_IN5, RW }, - PC87365_SYSCTL_IN5, VALUE(1), 3 }, - { { SENSORS_PC87360_IN6_MIN, "in6_min", SENSORS_PC87360_IN6, - SENSORS_PC87360_IN6, RW }, - PC87365_SYSCTL_IN6, VALUE(1), 3 }, - { { SENSORS_PC87360_IN7_MIN, "in7_min", SENSORS_PC87360_IN7, - SENSORS_PC87360_IN7, RW }, - PC87365_SYSCTL_IN7, VALUE(1), 3 }, - { { SENSORS_PC87360_IN8_MIN, "in8_min", SENSORS_PC87360_IN8, - SENSORS_PC87360_IN8, RW }, - PC87365_SYSCTL_IN8, VALUE(1), 3 }, - { { SENSORS_PC87360_IN9_MIN, "in9_min", SENSORS_PC87360_IN9, - SENSORS_PC87360_IN9, RW }, - PC87365_SYSCTL_IN9, VALUE(1), 3 }, - { { SENSORS_PC87360_IN10_MIN, "in10_min", SENSORS_PC87360_IN10, - SENSORS_PC87360_IN10, RW }, - PC87365_SYSCTL_IN10, VALUE(1), 3 }, - { { SENSORS_PC87360_IN0_MAX, "in0_max", SENSORS_PC87360_IN0, - SENSORS_PC87360_IN0, RW }, - PC87365_SYSCTL_IN0, VALUE(2), 3 }, - { { SENSORS_PC87360_IN1_MAX, "in1_max", SENSORS_PC87360_IN1, - SENSORS_PC87360_IN1, RW }, - PC87365_SYSCTL_IN1, VALUE(2), 3 }, - { { SENSORS_PC87360_IN2_MAX, "in2_max", SENSORS_PC87360_IN2, - SENSORS_PC87360_IN2, RW }, - PC87365_SYSCTL_IN2, VALUE(2), 3 }, - { { SENSORS_PC87360_IN3_MAX, "in3_max", SENSORS_PC87360_IN3, - SENSORS_PC87360_IN3, RW }, - PC87365_SYSCTL_IN3, VALUE(2), 3 }, - { { SENSORS_PC87360_IN4_MAX, "in4_max", SENSORS_PC87360_IN4, - SENSORS_PC87360_IN4, RW }, - PC87365_SYSCTL_IN4, VALUE(2), 3 }, - { { SENSORS_PC87360_IN5_MAX, "in5_max", SENSORS_PC87360_IN5, - SENSORS_PC87360_IN5, RW }, - PC87365_SYSCTL_IN5, VALUE(2), 3 }, - { { SENSORS_PC87360_IN6_MAX, "in6_max", SENSORS_PC87360_IN6, - SENSORS_PC87360_IN6, RW }, - PC87365_SYSCTL_IN6, VALUE(2), 3 }, - { { SENSORS_PC87360_IN7_MAX, "in7_max", SENSORS_PC87360_IN7, - SENSORS_PC87360_IN7, RW }, - PC87365_SYSCTL_IN7, VALUE(2), 3 }, - { { SENSORS_PC87360_IN8_MAX, "in8_max", SENSORS_PC87360_IN8, - SENSORS_PC87360_IN8, RW }, - PC87365_SYSCTL_IN8, VALUE(2), 3 }, - { { SENSORS_PC87360_IN9_MAX, "in9_max", SENSORS_PC87360_IN9, - SENSORS_PC87360_IN9, RW }, - PC87365_SYSCTL_IN9, VALUE(2), 3 }, - { { SENSORS_PC87360_IN10_MAX, "in10_max", SENSORS_PC87360_IN10, - SENSORS_PC87360_IN10, RW }, - PC87365_SYSCTL_IN10, VALUE(2), 3 }, - { { SENSORS_PC87360_IN0_STATUS, "in0_status", SENSORS_PC87360_IN0, NOMAP, R }, - PC87365_SYSCTL_IN0_STATUS, VALUE(1), 0 }, - { { SENSORS_PC87360_IN1_STATUS, "in1_status", SENSORS_PC87360_IN1, NOMAP, R }, - PC87365_SYSCTL_IN1_STATUS, VALUE(1), 0 }, - { { SENSORS_PC87360_IN2_STATUS, "in2_status", SENSORS_PC87360_IN2, NOMAP, R }, - PC87365_SYSCTL_IN2_STATUS, VALUE(1), 0 }, - { { SENSORS_PC87360_IN3_STATUS, "in3_status", SENSORS_PC87360_IN3, NOMAP, R }, - PC87365_SYSCTL_IN3_STATUS, VALUE(1), 0 }, - { { SENSORS_PC87360_IN4_STATUS, "in4_status", SENSORS_PC87360_IN4, NOMAP, R }, - PC87365_SYSCTL_IN4_STATUS, VALUE(1), 0 }, - { { SENSORS_PC87360_IN5_STATUS, "in5_status", SENSORS_PC87360_IN5, NOMAP, R }, - PC87365_SYSCTL_IN5_STATUS, VALUE(1), 0 }, - { { SENSORS_PC87360_IN6_STATUS, "in6_status", SENSORS_PC87360_IN6, NOMAP, R }, - PC87365_SYSCTL_IN6_STATUS, VALUE(1), 0 }, - { { SENSORS_PC87360_IN7_STATUS, "in7_status", SENSORS_PC87360_IN7, NOMAP, R }, - PC87365_SYSCTL_IN7_STATUS, VALUE(1), 0 }, - { { SENSORS_PC87360_IN8_STATUS, "in8_status", SENSORS_PC87360_IN8, NOMAP, R }, - PC87365_SYSCTL_IN8_STATUS, VALUE(1), 0 }, - { { SENSORS_PC87360_IN9_STATUS, "in9_status", SENSORS_PC87360_IN9, NOMAP, R }, - PC87365_SYSCTL_IN0_STATUS, VALUE(1), 0 }, - { { SENSORS_PC87360_IN10_STATUS, "in10_status", SENSORS_PC87360_IN10, NOMAP, - R }, - PC87365_SYSCTL_IN10_STATUS, VALUE(1), 0 }, - { { SENSORS_PC87360_TEMP1, "temp1", NOMAP, NOMAP, R }, - PC87365_SYSCTL_TEMP1, VALUE(4), 0 }, - { { SENSORS_PC87360_TEMP2, "temp2", NOMAP, NOMAP, R }, - PC87365_SYSCTL_TEMP2, VALUE(4), 0 }, - { { SENSORS_PC87360_TEMP3, "temp3", NOMAP, NOMAP, R }, - PC87365_SYSCTL_TEMP3, VALUE(4), 0 }, - { { SENSORS_PC87360_TEMP4, "temp4", NOMAP, NOMAP, R }, - PC87365_SYSCTL_TEMP4, VALUE(4), 3 }, - { { SENSORS_PC87360_TEMP5, "temp5", NOMAP, NOMAP, R }, - PC87365_SYSCTL_TEMP5, VALUE(4), 3 }, - { { SENSORS_PC87360_TEMP6, "temp6", NOMAP, NOMAP, R }, - PC87365_SYSCTL_TEMP6, VALUE(4), 3 }, - { { SENSORS_PC87360_TEMP1_MIN, "temp1_min", SENSORS_PC87360_TEMP1, - SENSORS_PC87360_TEMP1, RW }, - PC87365_SYSCTL_TEMP1, VALUE(2), 0 }, - { { SENSORS_PC87360_TEMP2_MIN, "temp2_min", SENSORS_PC87360_TEMP2, - SENSORS_PC87360_TEMP2, RW }, - PC87365_SYSCTL_TEMP2, VALUE(2), 0 }, - { { SENSORS_PC87360_TEMP3_MIN, "temp3_min", SENSORS_PC87360_TEMP3, - SENSORS_PC87360_TEMP3, RW }, - PC87365_SYSCTL_TEMP3, VALUE(2), 0 }, - { { SENSORS_PC87360_TEMP4_MIN, "temp4_min", SENSORS_PC87360_TEMP4, - SENSORS_PC87360_TEMP4, RW }, - PC87365_SYSCTL_TEMP4, VALUE(2), 3 }, - { { SENSORS_PC87360_TEMP5_MIN, "temp5_min", SENSORS_PC87360_TEMP5, - SENSORS_PC87360_TEMP5, RW }, - PC87365_SYSCTL_TEMP5, VALUE(2), 3 }, - { { SENSORS_PC87360_TEMP6_MIN, "temp6_min", SENSORS_PC87360_TEMP6, - SENSORS_PC87360_TEMP6, RW }, - PC87365_SYSCTL_TEMP6, VALUE(2), 3 }, - { { SENSORS_PC87360_TEMP1_MAX, "temp1_max", SENSORS_PC87360_TEMP1, - SENSORS_PC87360_TEMP1, RW }, - PC87365_SYSCTL_TEMP1, VALUE(1), 0 }, - { { SENSORS_PC87360_TEMP2_MAX, "temp2_max", SENSORS_PC87360_TEMP2, - SENSORS_PC87360_TEMP2, RW }, - PC87365_SYSCTL_TEMP2, VALUE(1), 0 }, - { { SENSORS_PC87360_TEMP3_MAX, "temp3_max", SENSORS_PC87360_TEMP3, - SENSORS_PC87360_TEMP3, RW }, - PC87365_SYSCTL_TEMP3, VALUE(1), 0 }, - { { SENSORS_PC87360_TEMP4_MAX, "temp4_max", SENSORS_PC87360_TEMP4, - SENSORS_PC87360_TEMP4, RW }, - PC87365_SYSCTL_TEMP4, VALUE(1), 3 }, - { { SENSORS_PC87360_TEMP5_MAX, "temp5_max", SENSORS_PC87360_TEMP5, - SENSORS_PC87360_TEMP5, RW }, - PC87365_SYSCTL_TEMP5, VALUE(1), 3 }, - { { SENSORS_PC87360_TEMP6_MAX, "temp6_max", SENSORS_PC87360_TEMP6, - SENSORS_PC87360_TEMP6, RW }, - PC87365_SYSCTL_TEMP6, VALUE(1), 3 }, - { { SENSORS_PC87360_TEMP1_CRIT, "temp1_crit", SENSORS_PC87360_TEMP1, - SENSORS_PC87360_TEMP1, RW }, - PC87365_SYSCTL_TEMP1, VALUE(3), 0 }, - { { SENSORS_PC87360_TEMP2_CRIT, "temp2_crit", SENSORS_PC87360_TEMP2, - SENSORS_PC87360_TEMP2, RW }, - PC87365_SYSCTL_TEMP2, VALUE(3), 0 }, - { { SENSORS_PC87360_TEMP3_CRIT, "temp3_crit", SENSORS_PC87360_TEMP3, - SENSORS_PC87360_TEMP3, RW }, - PC87365_SYSCTL_TEMP3, VALUE(3), 0 }, - { { SENSORS_PC87360_TEMP4_CRIT, "temp4_crit", SENSORS_PC87360_TEMP4, - SENSORS_PC87360_TEMP4, RW }, - PC87365_SYSCTL_TEMP4, VALUE(3), 3 }, - { { SENSORS_PC87360_TEMP5_CRIT, "temp5_crit", SENSORS_PC87360_TEMP5, - SENSORS_PC87360_TEMP5, RW }, - PC87365_SYSCTL_TEMP5, VALUE(3), 3 }, - { { SENSORS_PC87360_TEMP6_CRIT, "temp6_crit", SENSORS_PC87360_TEMP6, - SENSORS_PC87360_TEMP6, RW }, - PC87365_SYSCTL_TEMP6, VALUE(3), 3 }, - { { SENSORS_PC87360_TEMP1_STATUS, "temp1_status", SENSORS_PC87360_TEMP1, - NOMAP, R }, - PC87365_SYSCTL_TEMP1_STATUS, VALUE(1), 0 }, - { { SENSORS_PC87360_TEMP2_STATUS, "temp2_status", SENSORS_PC87360_TEMP2, - NOMAP, R }, - PC87365_SYSCTL_TEMP2_STATUS, VALUE(1), 0 }, - { { SENSORS_PC87360_TEMP3_STATUS, "temp3_status", SENSORS_PC87360_TEMP3, - NOMAP, R }, - PC87365_SYSCTL_TEMP3_STATUS, VALUE(1), 0 }, - { { SENSORS_PC87360_TEMP4_STATUS, "temp4_status", SENSORS_PC87360_TEMP4, - NOMAP, R }, - PC87365_SYSCTL_TEMP4_STATUS, VALUE(1), 0 }, - { { SENSORS_PC87360_TEMP5_STATUS, "temp5_status", SENSORS_PC87360_TEMP5, - NOMAP, R }, - PC87365_SYSCTL_TEMP5_STATUS, VALUE(1), 0 }, - { { SENSORS_PC87360_TEMP6_STATUS, "temp6_status", SENSORS_PC87360_TEMP6, - NOMAP, R }, - PC87365_SYSCTL_TEMP6_STATUS, VALUE(1), 0 }, - { { SENSORS_PC87360_VID, "vid", NOMAP, NOMAP, R }, - PC87365_SYSCTL_VID, VALUE(1), 3 }, - { { SENSORS_PC87360_VRM, "vrm", NOMAP, NOMAP, RW }, - PC87365_SYSCTL_VRM, VALUE(1), 1 }, - { { 0 }, 0 } - }; - -static sensors_chip_feature pc87427_features[] = - { - { { SENSORS_PC87427_FAN(1), "fan1", NOMAP, NOMAP, R }, - NOSYSCTL, VALUE(2), 0 }, - { { SENSORS_PC87427_FAN(2), "fan2", NOMAP, NOMAP, R }, - NOSYSCTL, VALUE(2), 0 }, - { { SENSORS_PC87427_FAN(3), "fan3", NOMAP, NOMAP, R }, - NOSYSCTL, VALUE(2), 0 }, - { { SENSORS_PC87427_FAN(4), "fan4", NOMAP, NOMAP, R }, - NOSYSCTL, VALUE(2), 0 }, - { { SENSORS_PC87427_FAN(5), "fan5", NOMAP, NOMAP, R }, - NOSYSCTL, VALUE(2), 0 }, - { { SENSORS_PC87427_FAN(6), "fan6", NOMAP, NOMAP, R }, - NOSYSCTL, VALUE(2), 0 }, - { { SENSORS_PC87427_FAN(7), "fan7", NOMAP, NOMAP, R }, - NOSYSCTL, VALUE(2), 0 }, - { { SENSORS_PC87427_FAN(8), "fan8", NOMAP, NOMAP, R }, - NOSYSCTL, VALUE(2), 0 }, - { { SENSORS_PC87427_FAN_MIN(1), "fan1_min", SENSORS_PC87427_FAN(1), - SENSORS_PC87427_FAN(1), RW }, - NOSYSCTL, VALUE(1), 0 }, - { { SENSORS_PC87427_FAN_MIN(2), "fan2_min", SENSORS_PC87427_FAN(2), - SENSORS_PC87427_FAN(2), RW }, - NOSYSCTL, VALUE(1), 0 }, - { { SENSORS_PC87427_FAN_MIN(3), "fan3_min", SENSORS_PC87427_FAN(3), - SENSORS_PC87427_FAN(3), RW }, - NOSYSCTL, VALUE(1), 0 }, - { { SENSORS_PC87427_FAN_MIN(4), "fan4_min", SENSORS_PC87427_FAN(4), - SENSORS_PC87427_FAN(4), RW }, - NOSYSCTL, VALUE(1), 0 }, - { { SENSORS_PC87427_FAN_MIN(5), "fan5_min", SENSORS_PC87427_FAN(5), - SENSORS_PC87427_FAN(5), RW }, - NOSYSCTL, VALUE(1), 0 }, - { { SENSORS_PC87427_FAN_MIN(6), "fan6_min", SENSORS_PC87427_FAN(6), - SENSORS_PC87427_FAN(6), RW }, - NOSYSCTL, VALUE(1), 0 }, - { { SENSORS_PC87427_FAN_MIN(7), "fan7_min", SENSORS_PC87427_FAN(7), - SENSORS_PC87427_FAN(7), RW }, - NOSYSCTL, VALUE(1), 0 }, - { { SENSORS_PC87427_FAN_MIN(8), "fan8_min", SENSORS_PC87427_FAN(8), - SENSORS_PC87427_FAN(8), RW }, - NOSYSCTL, VALUE(1), 0 }, - { { SENSORS_PC87427_FAN_ALARM(1), "fan1_alarm", SENSORS_PC87427_FAN(1), - NOMAP, R }, - NOSYSCTL, VALUE(1), 0 }, - { { SENSORS_PC87427_FAN_ALARM(2), "fan2_alarm", SENSORS_PC87427_FAN(2), - NOMAP, R }, - NOSYSCTL, VALUE(1), 0 }, - { { SENSORS_PC87427_FAN_ALARM(3), "fan3_alarm", SENSORS_PC87427_FAN(3), - NOMAP, R }, - NOSYSCTL, VALUE(1), 0 }, - { { SENSORS_PC87427_FAN_ALARM(4), "fan4_alarm", SENSORS_PC87427_FAN(4), - NOMAP, R }, - NOSYSCTL, VALUE(1), 0 }, - { { SENSORS_PC87427_FAN_ALARM(5), "fan5_alarm", SENSORS_PC87427_FAN(5), - NOMAP, R }, - NOSYSCTL, VALUE(1), 0 }, - { { SENSORS_PC87427_FAN_ALARM(6), "fan6_alarm", SENSORS_PC87427_FAN(6), - NOMAP, R }, - NOSYSCTL, VALUE(1), 0 }, - { { SENSORS_PC87427_FAN_ALARM(7), "fan7_alarm", SENSORS_PC87427_FAN(7), - NOMAP, R }, - NOSYSCTL, VALUE(1), 0 }, - { { SENSORS_PC87427_FAN_ALARM(8), "fan8_alarm", SENSORS_PC87427_FAN(8), - NOMAP, R }, - NOSYSCTL, VALUE(1), 0 }, - { { SENSORS_PC87427_FAN_FAULT(1), "fan1_fault", SENSORS_PC87427_FAN(1), - NOMAP, R }, - NOSYSCTL, VALUE(2), 0 }, - { { SENSORS_PC87427_FAN_FAULT(2), "fan2_fault", SENSORS_PC87427_FAN(2), - NOMAP, R }, - NOSYSCTL, VALUE(2), 0 }, - { { SENSORS_PC87427_FAN_FAULT(3), "fan3_fault", SENSORS_PC87427_FAN(3), - NOMAP, R }, - NOSYSCTL, VALUE(2), 0 }, - { { SENSORS_PC87427_FAN_FAULT(4), "fan4_fault", SENSORS_PC87427_FAN(4), - NOMAP, R }, - NOSYSCTL, VALUE(2), 0 }, - { { SENSORS_PC87427_FAN_FAULT(5), "fan5_fault", SENSORS_PC87427_FAN(5), - NOMAP, R }, - NOSYSCTL, VALUE(2), 0 }, - { { SENSORS_PC87427_FAN_FAULT(6), "fan6_fault", SENSORS_PC87427_FAN(6), - NOMAP, R }, - NOSYSCTL, VALUE(2), 0 }, - { { SENSORS_PC87427_FAN_FAULT(7), "fan7_fault", SENSORS_PC87427_FAN(7), - NOMAP, R }, - NOSYSCTL, VALUE(2), 0 }, - { { SENSORS_PC87427_FAN_FAULT(8), "fan8_fault", SENSORS_PC87427_FAN(8), - NOMAP, R }, - NOSYSCTL, VALUE(2), 0 }, - { { 0 }, 0 } - }; - -static sensors_chip_feature lm92_features[] = - { - { { SENSORS_LM92_TEMP, "temp", NOMAP, NOMAP, R }, - LM92_SYSCTL_TEMP, VALUE(1), 4 }, - { { SENSORS_LM92_TEMP_HIGH, "temp_high", SENSORS_LM92_TEMP, - SENSORS_LM92_TEMP, RW }, - LM92_SYSCTL_TEMP, VALUE(2), 4 }, - { { SENSORS_LM92_TEMP_LOW, "temp_low", SENSORS_LM92_TEMP, SENSORS_LM92_TEMP, - RW }, - LM92_SYSCTL_TEMP, VALUE(3), 4 }, - { { SENSORS_LM92_TEMP_CRIT, "temp_crit", SENSORS_LM92_TEMP, - SENSORS_LM92_TEMP, RW }, - LM92_SYSCTL_TEMP, VALUE(4), 4 }, - { { SENSORS_LM92_TEMP_HYST, "temp_hyst", SENSORS_LM92_TEMP, - SENSORS_LM92_TEMP, RW }, - LM92_SYSCTL_TEMP, VALUE(5), 4 , - "temp1_crit_hyst", 3 }, - { { SENSORS_LM92_ALARMS, "alarms", NOMAP, NOMAP, R }, - LM92_SYSCTL_ALARMS, VALUE(1), 0 }, - { { 0 }, 0 } - }; - -static sensors_chip_feature vt8231_features[] = - { - { { SENSORS_VT8231_IN0, "in0", NOMAP, NOMAP, R }, - VT8231_SYSCTL_IN0, VALUE(3), 2 }, - { { SENSORS_VT8231_IN1, "in1", NOMAP, NOMAP, R }, - VT8231_SYSCTL_IN1, VALUE(3), 2 }, - { { SENSORS_VT8231_IN2, "in2", NOMAP, NOMAP, R }, - VT8231_SYSCTL_IN2, VALUE(3), 2 }, - { { SENSORS_VT8231_IN3, "in3", NOMAP, NOMAP, R }, - VT8231_SYSCTL_IN3, VALUE(3), 2 }, - { { SENSORS_VT8231_IN4, "in4", NOMAP, NOMAP, R }, - VT8231_SYSCTL_IN4, VALUE(3), 2 }, - { { SENSORS_VT8231_IN5, "in5", NOMAP, NOMAP, R }, - VT8231_SYSCTL_IN5, VALUE(3), 2 }, - { { SENSORS_VT8231_IN0_MIN, "in0_min", SENSORS_VT8231_IN0, - SENSORS_VT8231_IN0, RW }, - VT8231_SYSCTL_IN0, VALUE(1), 2 }, - { { SENSORS_VT8231_IN1_MIN, "in1_min", SENSORS_VT8231_IN1, - SENSORS_VT8231_IN1, RW }, - VT8231_SYSCTL_IN1, VALUE(1), 2 }, - { { SENSORS_VT8231_IN2_MIN, "in2_min", SENSORS_VT8231_IN2, - SENSORS_VT8231_IN2, RW }, - VT8231_SYSCTL_IN2, VALUE(1), 2 }, - { { SENSORS_VT8231_IN3_MIN, "in3_min", SENSORS_VT8231_IN3, - SENSORS_VT8231_IN3, RW }, - VT8231_SYSCTL_IN3, VALUE(1), 2 }, - { { SENSORS_VT8231_IN4_MIN, "in4_min", SENSORS_VT8231_IN4, - SENSORS_VT8231_IN4, RW }, - VT8231_SYSCTL_IN4, VALUE(1), 2 }, - { { SENSORS_VT8231_IN5_MIN, "in5_min", SENSORS_VT8231_IN5, - SENSORS_VT8231_IN5, RW }, - VT8231_SYSCTL_IN5, VALUE(1), 2 }, - { { SENSORS_VT8231_IN0_MAX, "in0_max", SENSORS_VT8231_IN0, - SENSORS_VT8231_IN0, RW }, - VT8231_SYSCTL_IN0, VALUE(2), 2 }, - { { SENSORS_VT8231_IN1_MAX, "in1_max", SENSORS_VT8231_IN1, - SENSORS_VT8231_IN1, RW }, - VT8231_SYSCTL_IN1, VALUE(2), 2 }, - { { SENSORS_VT8231_IN2_MAX, "in2_max", SENSORS_VT8231_IN2, - SENSORS_VT8231_IN2, RW }, - VT8231_SYSCTL_IN2, VALUE(2), 2 }, - { { SENSORS_VT8231_IN3_MAX, "in3_max", SENSORS_VT8231_IN3, - SENSORS_VT8231_IN3, RW }, - VT8231_SYSCTL_IN3, VALUE(2), 2 }, - { { SENSORS_VT8231_IN4_MAX, "in4_max", SENSORS_VT8231_IN4, - SENSORS_VT8231_IN4, RW }, - VT8231_SYSCTL_IN4, VALUE(2), 2 }, - { { SENSORS_VT8231_IN5_MAX, "in5_max", SENSORS_VT8231_IN5, - SENSORS_VT8231_IN5, RW }, - VT8231_SYSCTL_IN5, VALUE(2), 2 }, - { { SENSORS_VT8231_FAN1, "fan1", NOMAP, NOMAP, R }, - VT8231_SYSCTL_FAN1, VALUE(2), 0 }, - { { SENSORS_VT8231_FAN2, "fan2", NOMAP, NOMAP, R }, - VT8231_SYSCTL_FAN2, VALUE(2), 0 }, - { { SENSORS_VT8231_FAN1_MIN, "fan1_min", SENSORS_VT8231_FAN1, - SENSORS_VT8231_FAN1, RW }, - VT8231_SYSCTL_FAN1, VALUE(1), 0 }, - { { SENSORS_VT8231_FAN2_MIN, "fan2_min", SENSORS_VT8231_FAN2, - SENSORS_VT8231_FAN2, RW }, - VT8231_SYSCTL_FAN2, VALUE(1), 0 }, - { { SENSORS_VT8231_TEMP, "temp1", NOMAP, NOMAP, R }, - VT8231_SYSCTL_TEMP, VALUE(3), 1 }, - { { SENSORS_VT8231_TEMP_HYST, "temp1_hyst", SENSORS_VT8231_TEMP, - SENSORS_VT8231_TEMP, RW }, - VT8231_SYSCTL_TEMP, VALUE(2), 1 }, - { { SENSORS_VT8231_TEMP_OVER, "temp1_over", SENSORS_VT8231_TEMP, - SENSORS_VT8231_TEMP, RW }, - VT8231_SYSCTL_TEMP, VALUE(1), 1 }, - { { SENSORS_VT8231_TEMP2, "temp2", NOMAP, NOMAP, R }, - VT8231_SYSCTL_TEMP2, VALUE(3), 2 }, - { { SENSORS_VT8231_TEMP2_HYST, "temp2_hyst", SENSORS_VT8231_TEMP2, - SENSORS_VT8231_TEMP2, RW }, - VT8231_SYSCTL_TEMP2, VALUE(2), 2 }, - { { SENSORS_VT8231_TEMP2_OVER, "temp2_over", SENSORS_VT8231_TEMP2, - SENSORS_VT8231_TEMP2, RW }, - VT8231_SYSCTL_TEMP2, VALUE(1), 2 }, - { { SENSORS_VT8231_TEMP3, "temp3", NOMAP, NOMAP, R }, - VT8231_SYSCTL_TEMP3, VALUE(3), 2 }, - { { SENSORS_VT8231_TEMP3_HYST, "temp3_hyst", SENSORS_VT8231_TEMP3, - SENSORS_VT8231_TEMP3, RW }, - VT8231_SYSCTL_TEMP3, VALUE(2), 2 }, - { { SENSORS_VT8231_TEMP3_OVER, "temp3_over", SENSORS_VT8231_TEMP3, - SENSORS_VT8231_TEMP3, RW }, - VT8231_SYSCTL_TEMP3, VALUE(1), 2 }, - { { SENSORS_VT8231_TEMP4, "temp4", NOMAP, NOMAP, R }, - VT8231_SYSCTL_TEMP4, VALUE(3), 2 }, - { { SENSORS_VT8231_TEMP4_HYST, "temp4_hyst", SENSORS_VT8231_TEMP4, - SENSORS_VT8231_TEMP4, RW }, - VT8231_SYSCTL_TEMP4, VALUE(2), 2 }, - { { SENSORS_VT8231_TEMP4_OVER, "temp4_over", SENSORS_VT8231_TEMP4, - SENSORS_VT8231_TEMP4, RW }, - VT8231_SYSCTL_TEMP4, VALUE(1), 2 }, - { { SENSORS_VT8231_TEMP5, "temp5", NOMAP, NOMAP, R }, - VT8231_SYSCTL_TEMP5, VALUE(3), 2 }, - { { SENSORS_VT8231_TEMP5_HYST, "temp5_hyst", SENSORS_VT8231_TEMP5, - SENSORS_VT8231_TEMP5, RW }, - VT8231_SYSCTL_TEMP5, VALUE(2), 2 }, - { { SENSORS_VT8231_TEMP5_OVER, "temp5_over", SENSORS_VT8231_TEMP5, - SENSORS_VT8231_TEMP5, RW }, - VT8231_SYSCTL_TEMP5, VALUE(1), 2 }, - { { SENSORS_VT8231_TEMP6, "temp6", NOMAP, NOMAP, R }, - VT8231_SYSCTL_TEMP6, VALUE(3), 2 }, - { { SENSORS_VT8231_TEMP6_HYST, "temp6_hyst", SENSORS_VT8231_TEMP6, - SENSORS_VT8231_TEMP6, RW }, - VT8231_SYSCTL_TEMP6, VALUE(2), 2 }, - { { SENSORS_VT8231_TEMP6_OVER, "temp6_over", SENSORS_VT8231_TEMP6, - SENSORS_VT8231_TEMP6, RW }, - VT8231_SYSCTL_TEMP6, VALUE(1), 2 }, - { { SENSORS_VT8231_FAN1_DIV, "fan1_div", SENSORS_VT8231_FAN1, NOMAP, RW }, - VT8231_SYSCTL_FAN_DIV, VALUE(1), 0 }, - { { SENSORS_VT8231_FAN2_DIV, "fan2_div", SENSORS_VT8231_FAN2, NOMAP, RW }, - VT8231_SYSCTL_FAN_DIV, VALUE(2), 0 }, - { { SENSORS_VT8231_ALARMS, "alarms", NOMAP, NOMAP, R }, - VT8231_SYSCTL_ALARMS, VALUE(1), 0 }, - { { SENSORS_VT8231_VID, "vid", NOMAP, NOMAP, R }, - VT8231_SYSCTL_VID, VALUE(1), 3 }, - { { SENSORS_VT8231_VRM, "vrm", NOMAP, NOMAP, RW }, - VT8231_SYSCTL_VRM, VALUE(1), 1 }, - { { SENSORS_VT8231_UCH, "config", NOMAP, NOMAP, RW }, - VT8231_SYSCTL_UCH, VALUE(1), 0 }, - { { 0 }, 0 } - }; - -static sensors_chip_feature bmc_features[] = - { - { { SENSORS_BMC_IN1, "in1", NOMAP, NOMAP, R }, - BMC_SYSCTL_IN1, VALUE(3), 3 }, - { { SENSORS_BMC_IN1_MIN, "in1_min", SENSORS_BMC_IN1, SENSORS_BMC_IN1, RW }, - BMC_SYSCTL_IN1, VALUE(1), 3 }, - { { SENSORS_BMC_IN1_MAX, "in1_max", SENSORS_BMC_IN1, SENSORS_BMC_IN1, RW }, - BMC_SYSCTL_IN1, VALUE(2), 3 }, - { { SENSORS_BMC_IN1+1, "in2", NOMAP, NOMAP, R }, - BMC_SYSCTL_IN1+1, VALUE(3), 3 }, - { { SENSORS_BMC_IN1_MIN+1, "in2_min", SENSORS_BMC_IN1+1, SENSORS_BMC_IN1+1, - RW }, - BMC_SYSCTL_IN1+1, VALUE(1), 3 }, - { { SENSORS_BMC_IN1_MAX+1, "in2_max", SENSORS_BMC_IN1+1, SENSORS_BMC_IN1+1, - RW }, - BMC_SYSCTL_IN1+1, VALUE(2), 3 }, - { { SENSORS_BMC_IN1+2, "in3", NOMAP, NOMAP, R }, - BMC_SYSCTL_IN1+2, VALUE(3), 3 }, - { { SENSORS_BMC_IN1_MIN+2, "in3_min", SENSORS_BMC_IN1+2, SENSORS_BMC_IN1+2, - RW }, - BMC_SYSCTL_IN1+2, VALUE(1), 3 }, - { { SENSORS_BMC_IN1_MAX+2, "in3_max", SENSORS_BMC_IN1+2, SENSORS_BMC_IN1+2, - RW }, - BMC_SYSCTL_IN1+2, VALUE(2), 3 }, - { { SENSORS_BMC_IN1+3, "in4", NOMAP, NOMAP, R }, - BMC_SYSCTL_IN1+3, VALUE(3), 3 }, - { { SENSORS_BMC_IN1_MIN+3, "in4_min", SENSORS_BMC_IN1+3, SENSORS_BMC_IN1+3, - RW }, - BMC_SYSCTL_IN1+3, VALUE(1), 3 }, - { { SENSORS_BMC_IN1_MAX+3, "in4_max", SENSORS_BMC_IN1+3, SENSORS_BMC_IN1+3, - RW }, - BMC_SYSCTL_IN1+3, VALUE(2), 3 }, - { { SENSORS_BMC_IN1+4, "in5", NOMAP, NOMAP, R }, - BMC_SYSCTL_IN1+4, VALUE(3), 3 }, - { { SENSORS_BMC_IN1_MIN+4, "in5_min", SENSORS_BMC_IN1+4, SENSORS_BMC_IN1+4, - RW }, - BMC_SYSCTL_IN1+4, VALUE(1), 3 }, - { { SENSORS_BMC_IN1_MAX+4, "in5_max", SENSORS_BMC_IN1+4, SENSORS_BMC_IN1+4, - RW }, - BMC_SYSCTL_IN1+4, VALUE(2), 3 }, - { { SENSORS_BMC_IN1+5, "in6", NOMAP, NOMAP, R }, - BMC_SYSCTL_IN1+5, VALUE(3), 3 }, - { { SENSORS_BMC_IN1_MIN+5, "in6_min", SENSORS_BMC_IN1+5, SENSORS_BMC_IN1+5, - RW }, - BMC_SYSCTL_IN1+5, VALUE(1), 3 }, - { { SENSORS_BMC_IN1_MAX+5, "in6_max", SENSORS_BMC_IN1+5, SENSORS_BMC_IN1+5, - RW }, - BMC_SYSCTL_IN1+5, VALUE(2), 3 }, - { { SENSORS_BMC_IN1+6, "in7", NOMAP, NOMAP, R }, - BMC_SYSCTL_IN1+6, VALUE(3), 3 }, - { { SENSORS_BMC_IN1_MIN+6, "in7_min", SENSORS_BMC_IN1+6, SENSORS_BMC_IN1+6, - RW }, - BMC_SYSCTL_IN1+6, VALUE(1), 3 }, - { { SENSORS_BMC_IN1_MAX+6, "in7_max", SENSORS_BMC_IN1+6, SENSORS_BMC_IN1+6, - RW }, - BMC_SYSCTL_IN1+6, VALUE(2), 3 }, - - { { SENSORS_BMC_IN1+7, "in8", NOMAP, NOMAP, R }, - BMC_SYSCTL_IN1+7, VALUE(3), 3 }, - { { SENSORS_BMC_IN1_MIN+7, "in8_min", SENSORS_BMC_IN1+7, SENSORS_BMC_IN1+7, - RW }, - BMC_SYSCTL_IN1+7, VALUE(1), 3 }, - { { SENSORS_BMC_IN1_MAX+7, "in8_max", SENSORS_BMC_IN1+7, SENSORS_BMC_IN1+7, - RW }, - BMC_SYSCTL_IN1+7, VALUE(2), 3 }, - { { SENSORS_BMC_IN1+8, "in9", NOMAP, NOMAP, R }, - BMC_SYSCTL_IN1+8, VALUE(3), 3 }, - { { SENSORS_BMC_IN1_MIN+8, "in9_min", SENSORS_BMC_IN1+8, SENSORS_BMC_IN1+8, - RW }, - BMC_SYSCTL_IN1+8, VALUE(1), 3 }, - { { SENSORS_BMC_IN1_MAX+8, "in9_max", SENSORS_BMC_IN1+8, SENSORS_BMC_IN1+8, - RW }, - BMC_SYSCTL_IN1+8, VALUE(2), 3 }, - { { SENSORS_BMC_IN1+9, "in10", NOMAP, NOMAP, R }, - BMC_SYSCTL_IN1+9, VALUE(3), 3 }, - { { SENSORS_BMC_IN1_MIN+9, "in10_min", SENSORS_BMC_IN1+9, SENSORS_BMC_IN1+9, - RW }, - BMC_SYSCTL_IN1+9, VALUE(1), 3 }, - { { SENSORS_BMC_IN1_MAX+9, "in10_max", SENSORS_BMC_IN1+9, SENSORS_BMC_IN1+9, - RW }, - BMC_SYSCTL_IN1+9, VALUE(2), 3 }, - { { SENSORS_BMC_IN1+10, "in11", NOMAP, NOMAP, R }, - BMC_SYSCTL_IN1+10, VALUE(3), 3 }, - { { SENSORS_BMC_IN1_MIN+10, "in11_min", SENSORS_BMC_IN1+10, - SENSORS_BMC_IN1+10, RW }, - BMC_SYSCTL_IN1+10, VALUE(1), 3 }, - { { SENSORS_BMC_IN1_MAX+10, "in11_max", SENSORS_BMC_IN1+10, - SENSORS_BMC_IN1+10, RW }, - BMC_SYSCTL_IN1+10, VALUE(2), 3 }, - { { SENSORS_BMC_IN1+11, "in12", NOMAP, NOMAP, R }, - BMC_SYSCTL_IN1+11, VALUE(3), 3 }, - { { SENSORS_BMC_IN1_MIN+11, "in12_min", SENSORS_BMC_IN1+11, - SENSORS_BMC_IN1+11, RW }, - BMC_SYSCTL_IN1+11, VALUE(1), 3 }, - { { SENSORS_BMC_IN1_MAX+11, "in12_max", SENSORS_BMC_IN1+11, - SENSORS_BMC_IN1+11, RW }, - BMC_SYSCTL_IN1+11, VALUE(2), 3 }, - { { SENSORS_BMC_IN1+12, "in13", NOMAP, NOMAP, R }, - BMC_SYSCTL_IN1+12, VALUE(3), 3 }, - { { SENSORS_BMC_IN1_MIN+12, "in13_min", SENSORS_BMC_IN1+12, - SENSORS_BMC_IN1+12, RW }, - BMC_SYSCTL_IN1+12, VALUE(1), 3 }, - { { SENSORS_BMC_IN1_MAX+12, "in13_max", SENSORS_BMC_IN1+12, - SENSORS_BMC_IN1+12, RW }, - BMC_SYSCTL_IN1+12, VALUE(2), 3 }, - { { SENSORS_BMC_IN1+13, "in14", NOMAP, NOMAP, R }, - BMC_SYSCTL_IN1+13, VALUE(3), 3 }, - { { SENSORS_BMC_IN1_MIN+13, "in14_min", SENSORS_BMC_IN1+13, - SENSORS_BMC_IN1+13, RW }, - BMC_SYSCTL_IN1+13, VALUE(1), 3 }, - { { SENSORS_BMC_IN1_MAX+13, "in14_max", SENSORS_BMC_IN1+13, - SENSORS_BMC_IN1+13, RW }, - BMC_SYSCTL_IN1+13, VALUE(2), 3 }, - { { SENSORS_BMC_IN1+14, "in15", NOMAP, NOMAP, R }, - BMC_SYSCTL_IN1+14, VALUE(3), 3 }, - { { SENSORS_BMC_IN1_MIN+14, "in15_min", SENSORS_BMC_IN1+14, - SENSORS_BMC_IN1+14, RW }, - BMC_SYSCTL_IN1+14, VALUE(1), 3 }, - { { SENSORS_BMC_IN1_MAX+14, "in15_max", SENSORS_BMC_IN1+14, - SENSORS_BMC_IN1+14, RW }, - BMC_SYSCTL_IN1+14, VALUE(2), 3 }, - { { SENSORS_BMC_IN1+15, "in16", NOMAP, NOMAP, R }, - BMC_SYSCTL_IN1+15, VALUE(3), 3 }, - { { SENSORS_BMC_IN1_MIN+15, "in16_min", SENSORS_BMC_IN1+15, - SENSORS_BMC_IN1+15, RW }, - BMC_SYSCTL_IN1+15, VALUE(1), 3 }, - { { SENSORS_BMC_IN1_MAX+15, "in16_max", SENSORS_BMC_IN1+15, - SENSORS_BMC_IN1+15, RW }, - BMC_SYSCTL_IN1+15, VALUE(2), 3 }, - { { SENSORS_BMC_IN1+16, "in17", NOMAP, NOMAP, R }, - BMC_SYSCTL_IN1+16, VALUE(3), 3 }, - { { SENSORS_BMC_IN1_MIN+16, "in17_min", SENSORS_BMC_IN1+16, - SENSORS_BMC_IN1+16, RW }, - BMC_SYSCTL_IN1+16, VALUE(1), 3 }, - { { SENSORS_BMC_IN1_MAX+16, "in17_max", SENSORS_BMC_IN1+16, - SENSORS_BMC_IN1+16, RW }, - BMC_SYSCTL_IN1+16, VALUE(2), 3 }, - { { SENSORS_BMC_IN1+17, "in18", NOMAP, NOMAP, R }, - BMC_SYSCTL_IN1+17, VALUE(3), 3, }, - { { SENSORS_BMC_IN1_MIN+17, "in18_min", SENSORS_BMC_IN1+17, - SENSORS_BMC_IN1+17, RW }, - BMC_SYSCTL_IN1+17, VALUE(1), 3 }, - { { SENSORS_BMC_IN1_MAX+17, "in18_max", SENSORS_BMC_IN1+17, - SENSORS_BMC_IN1+17, RW }, - BMC_SYSCTL_IN1+17, VALUE(2), 3 }, - { { SENSORS_BMC_IN1+18, "in19", NOMAP, NOMAP, R }, - BMC_SYSCTL_IN1+18, VALUE(3), 3 }, - { { SENSORS_BMC_IN1_MIN+18, "in19_min", SENSORS_BMC_IN1+18, - SENSORS_BMC_IN1+18, RW }, - BMC_SYSCTL_IN1+18, VALUE(1), 3 }, - { { SENSORS_BMC_IN1_MAX+18, "in19_max", SENSORS_BMC_IN1+18, - SENSORS_BMC_IN1+18, RW }, - BMC_SYSCTL_IN1+18, VALUE(2), 3 }, - { { SENSORS_BMC_IN1+19, "in20", NOMAP, NOMAP, R }, - BMC_SYSCTL_IN1+19, VALUE(3), 3 }, - { { SENSORS_BMC_IN1_MIN+19, "in20_min", SENSORS_BMC_IN1+19, - SENSORS_BMC_IN1+19, RW }, - BMC_SYSCTL_IN1+19, VALUE(1), 3 }, - { { SENSORS_BMC_IN1_MAX+19, "in20_max", SENSORS_BMC_IN1+19, - SENSORS_BMC_IN1+19, RW }, - BMC_SYSCTL_IN1+19, VALUE(2), 3 }, - { { SENSORS_BMC_FAN1, "fan1", NOMAP, NOMAP, R }, - BMC_SYSCTL_FAN1, VALUE(2), 0, }, - { { SENSORS_BMC_FAN1+1, "fan2", NOMAP, NOMAP, R }, - BMC_SYSCTL_FAN1+1, VALUE(2), 0, }, - { { SENSORS_BMC_FAN1+2, "fan3", NOMAP, NOMAP, R }, - BMC_SYSCTL_FAN1+2, VALUE(2), 0, }, - { { SENSORS_BMC_FAN1+3, "fan4", NOMAP, NOMAP, R }, - BMC_SYSCTL_FAN1+3, VALUE(2), 0, }, - { { SENSORS_BMC_FAN1+4, "fan5", NOMAP, NOMAP, R }, - BMC_SYSCTL_FAN1+4, VALUE(2), 0, }, - { { SENSORS_BMC_FAN1+5, "fan6", NOMAP, NOMAP, R }, - BMC_SYSCTL_FAN1+5, VALUE(2), 0, }, - { { SENSORS_BMC_FAN1+6, "fan7", NOMAP, NOMAP, R }, - BMC_SYSCTL_FAN1+6, VALUE(2), 0, }, - { { SENSORS_BMC_FAN1+7, "fan8", NOMAP, NOMAP, R }, - BMC_SYSCTL_FAN1+7, VALUE(2), 0, }, - { { SENSORS_BMC_FAN1+8, "fan9", NOMAP, NOMAP, R }, - BMC_SYSCTL_FAN1+8, VALUE(2), 0, }, - { { SENSORS_BMC_FAN1+9, "fan10", NOMAP, NOMAP, R }, - BMC_SYSCTL_FAN1+9, VALUE(2), 0, }, - { { SENSORS_BMC_FAN1_MIN, "fan1_min", SENSORS_BMC_FAN1, SENSORS_BMC_FAN1, RW }, - BMC_SYSCTL_FAN1, VALUE(1), 0 }, - { { SENSORS_BMC_FAN1_MIN+1, "fan2_min", SENSORS_BMC_FAN1+1, - SENSORS_BMC_FAN1+1, RW }, - BMC_SYSCTL_FAN1+1, VALUE(1), 0 }, - { { SENSORS_BMC_FAN1_MIN+2, "fan3_min", SENSORS_BMC_FAN1+2, - SENSORS_BMC_FAN1+2, RW }, - BMC_SYSCTL_FAN1+2, VALUE(1), 0 }, - { { SENSORS_BMC_FAN1_MIN+3, "fan4_min", SENSORS_BMC_FAN1+3, - SENSORS_BMC_FAN1+3, RW }, - BMC_SYSCTL_FAN1+3, VALUE(1), 0 }, - { { SENSORS_BMC_FAN1_MIN+4, "fan5_min", SENSORS_BMC_FAN1+4, - SENSORS_BMC_FAN1+4, RW }, - BMC_SYSCTL_FAN1+4, VALUE(1), 0 }, - { { SENSORS_BMC_FAN1_MIN+5, "fan6_min", SENSORS_BMC_FAN1+5, - SENSORS_BMC_FAN1+5, RW }, - BMC_SYSCTL_FAN1+5, VALUE(1), 0 }, - { { SENSORS_BMC_FAN1_MIN+6, "fan7_min", SENSORS_BMC_FAN1+6, - SENSORS_BMC_FAN1+6, RW }, - BMC_SYSCTL_FAN1+6, VALUE(1), 0 }, - { { SENSORS_BMC_FAN1_MIN+7, "fan8_min", SENSORS_BMC_FAN1+7, - SENSORS_BMC_FAN1+7, RW }, - BMC_SYSCTL_FAN1+7, VALUE(1), 0 }, - { { SENSORS_BMC_FAN1_MIN+8, "fan9_min", SENSORS_BMC_FAN1+8, - SENSORS_BMC_FAN1+8, RW }, - BMC_SYSCTL_FAN1+8, VALUE(1), 0 }, - { { SENSORS_BMC_FAN1_MIN+9, "fan10_min", SENSORS_BMC_FAN1+9, - SENSORS_BMC_FAN1+9, RW }, - BMC_SYSCTL_FAN1+9, VALUE(1), 0 }, - { { SENSORS_BMC_TEMP1, "temp1", NOMAP, NOMAP, R }, - BMC_SYSCTL_TEMP1, VALUE(3), 2 }, - { { SENSORS_BMC_TEMP1_MIN, "temp1_min", SENSORS_BMC_TEMP1, SENSORS_BMC_TEMP1, - RW }, - BMC_SYSCTL_TEMP1, VALUE(2), 2 }, - { { SENSORS_BMC_TEMP1_MAX, "temp1_max", SENSORS_BMC_TEMP1, SENSORS_BMC_TEMP1, - RW }, - BMC_SYSCTL_TEMP1, VALUE(1), 2 }, - { { SENSORS_BMC_TEMP1+1, "temp2", NOMAP, NOMAP, R }, - BMC_SYSCTL_TEMP1+1, VALUE(3), 2 }, - { { SENSORS_BMC_TEMP1_MIN+1, "temp2_min", SENSORS_BMC_TEMP1+1, - SENSORS_BMC_TEMP1+1, RW }, - BMC_SYSCTL_TEMP1+1, VALUE(2), 2 }, - { { SENSORS_BMC_TEMP1_MAX+1, "temp2_max", SENSORS_BMC_TEMP1+1, - SENSORS_BMC_TEMP1+1, RW }, - BMC_SYSCTL_TEMP1+1, VALUE(1), 2 }, - { { SENSORS_BMC_TEMP1+2, "temp3", NOMAP, NOMAP, R }, - BMC_SYSCTL_TEMP1+2, VALUE(3), 2 }, - { { SENSORS_BMC_TEMP1_MIN+2, "temp3_min", SENSORS_BMC_TEMP1+2, - SENSORS_BMC_TEMP1+2, RW }, - BMC_SYSCTL_TEMP1+2, VALUE(2), 2 }, - { { SENSORS_BMC_TEMP1_MAX+2, "temp3_max", SENSORS_BMC_TEMP1+2, - SENSORS_BMC_TEMP1+2, RW }, - BMC_SYSCTL_TEMP1+2, VALUE(1), 2 }, - { { SENSORS_BMC_TEMP1+3, "temp4", NOMAP, NOMAP, R }, - BMC_SYSCTL_TEMP1+3, VALUE(3), 2 }, - { { SENSORS_BMC_TEMP1_MIN+3, "temp4_min", SENSORS_BMC_TEMP1+3, - SENSORS_BMC_TEMP1+3, RW }, - BMC_SYSCTL_TEMP1+3, VALUE(2), 2 }, - { { SENSORS_BMC_TEMP1_MAX+3, "temp4_max", SENSORS_BMC_TEMP1+3, - SENSORS_BMC_TEMP1+3, RW }, - BMC_SYSCTL_TEMP1+3, VALUE(1), 2 }, - { { SENSORS_BMC_TEMP1+4, "temp5", NOMAP, NOMAP, R }, - BMC_SYSCTL_TEMP1+4, VALUE(3), 2 }, - { { SENSORS_BMC_TEMP1_MIN+4, "temp5_min", SENSORS_BMC_TEMP1+4, - SENSORS_BMC_TEMP1+4, RW }, - BMC_SYSCTL_TEMP1+4, VALUE(2), 2 }, - { { SENSORS_BMC_TEMP1_MAX+4, "temp5_max", SENSORS_BMC_TEMP1+4, - SENSORS_BMC_TEMP1+4, RW }, - BMC_SYSCTL_TEMP1+4, VALUE(1), 2 }, - { { SENSORS_BMC_TEMP1+5, "temp6", NOMAP, NOMAP, R }, - BMC_SYSCTL_TEMP1+5, VALUE(3), 2 }, - { { SENSORS_BMC_TEMP1_MIN+5, "temp6_min", SENSORS_BMC_TEMP1+5, - SENSORS_BMC_TEMP1+5, RW }, - BMC_SYSCTL_TEMP1+5, VALUE(2), 2 }, - { { SENSORS_BMC_TEMP1_MAX+5, "temp6_max", SENSORS_BMC_TEMP1+5, - SENSORS_BMC_TEMP1+5, RW }, - BMC_SYSCTL_TEMP1+5, VALUE(1), 2 }, - { { SENSORS_BMC_TEMP1+6, "temp7", NOMAP, NOMAP, R }, - BMC_SYSCTL_TEMP1+6, VALUE(3), 2 }, - { { SENSORS_BMC_TEMP1_MIN+6, "temp7_min", SENSORS_BMC_TEMP1+6, - SENSORS_BMC_TEMP1+6, RW }, - BMC_SYSCTL_TEMP1+6, VALUE(2), 2 }, - { { SENSORS_BMC_TEMP1_MAX+6, "temp7_max", SENSORS_BMC_TEMP1+6, - SENSORS_BMC_TEMP1+6, RW }, - BMC_SYSCTL_TEMP1+6, VALUE(1), 2 }, - { { SENSORS_BMC_TEMP1+7, "temp8", NOMAP, NOMAP, R }, - BMC_SYSCTL_TEMP1+7, VALUE(3), 2 }, - { { SENSORS_BMC_TEMP1_MIN+7, "temp8_min", SENSORS_BMC_TEMP1+7, - SENSORS_BMC_TEMP1+7, RW }, - BMC_SYSCTL_TEMP1+7, VALUE(2), 2 }, - { { SENSORS_BMC_TEMP1_MAX+7, "temp8_max", SENSORS_BMC_TEMP1+7, - SENSORS_BMC_TEMP1+7, RW }, - BMC_SYSCTL_TEMP1+7, VALUE(1), 2 }, - { { SENSORS_BMC_TEMP1+8, "temp9", NOMAP, NOMAP, R }, - BMC_SYSCTL_TEMP1+8, VALUE(3), 2 }, - { { SENSORS_BMC_TEMP1_MIN+8, "temp9_min", SENSORS_BMC_TEMP1+8, - SENSORS_BMC_TEMP1+8, RW }, - BMC_SYSCTL_TEMP1+8, VALUE(2), 2 }, - { { SENSORS_BMC_TEMP1_MAX+8, "temp9_max", SENSORS_BMC_TEMP1+8, - SENSORS_BMC_TEMP1+8, RW }, - BMC_SYSCTL_TEMP1+8, VALUE(1), 2 }, - { { SENSORS_BMC_TEMP1+9, "temp10", NOMAP, NOMAP, R }, - BMC_SYSCTL_TEMP1+9, VALUE(3), 2 }, - { { SENSORS_BMC_TEMP1_MIN+9, "temp10_min", SENSORS_BMC_TEMP1+9, - SENSORS_BMC_TEMP1+9, RW }, - BMC_SYSCTL_TEMP1+9, VALUE(2), 2 }, - { { SENSORS_BMC_TEMP1_MAX+9, "temp10_max", SENSORS_BMC_TEMP1+9, - SENSORS_BMC_TEMP1+9, RW }, - BMC_SYSCTL_TEMP1+9, VALUE(1), 2 }, - { { SENSORS_BMC_ALARMS, "alarms", NOMAP, NOMAP, R }, - BMC_SYSCTL_ALARMS, VALUE(1), 0 }, - { { 0 }, 0 } - }; - -static sensors_chip_feature xeontemp_features[] = - { - { { SENSORS_XEONTEMP_REMOTE_TEMP, "temp", NOMAP, NOMAP, R }, - XEONTEMP_SYSCTL_REMOTE_TEMP, VALUE(3), 0 }, - { { SENSORS_XEONTEMP_REMOTE_TEMP_HYST, "temp_low", - SENSORS_XEONTEMP_REMOTE_TEMP, - SENSORS_XEONTEMP_REMOTE_TEMP, RW }, - XEONTEMP_SYSCTL_REMOTE_TEMP, VALUE(2), - 0 }, - { { SENSORS_XEONTEMP_REMOTE_TEMP_OVER, "temp_over", - SENSORS_XEONTEMP_REMOTE_TEMP, - SENSORS_XEONTEMP_REMOTE_TEMP, RW }, - XEONTEMP_SYSCTL_REMOTE_TEMP, VALUE(1), - 0 }, - { { SENSORS_XEONTEMP_ALARMS, "alarms", NOMAP, NOMAP, R }, - XEONTEMP_SYSCTL_ALARMS, VALUE(1), 0 }, - { { 0 }, 0 } - }; - -static sensors_chip_feature max1619_features[] = - { - { { SENSORS_MAX1619_LOCAL_TEMP, "temp1", NOMAP, NOMAP, R }, - MAX1619_SYSCTL_LOCAL_TEMP, VALUE(1), 0 }, - { { SENSORS_MAX1619_REMOTE_TEMP, "temp2", NOMAP, NOMAP, R }, - MAX1619_SYSCTL_REMOTE_TEMP, VALUE(3), 0 }, - { { SENSORS_MAX1619_REMOTE_LOW, "temp2_min", SENSORS_MAX1619_REMOTE_TEMP, - SENSORS_MAX1619_REMOTE_TEMP, RW }, - MAX1619_SYSCTL_REMOTE_TEMP, VALUE(2), 0 }, - { { SENSORS_MAX1619_REMOTE_HIGH, "temp2_max", SENSORS_MAX1619_REMOTE_TEMP, - SENSORS_MAX1619_REMOTE_TEMP, RW }, - MAX1619_SYSCTL_REMOTE_TEMP, VALUE(1), 0 }, - { { SENSORS_MAX1619_REMOTE_MAX, "temp2_crit", SENSORS_MAX1619_REMOTE_TEMP, - SENSORS_MAX1619_REMOTE_TEMP, RW }, - MAX1619_SYSCTL_REMOTE_CRIT, VALUE(1), 0 }, - { { SENSORS_MAX1619_REMOTE_HYST, "temp2_hyst", SENSORS_MAX1619_REMOTE_TEMP, - SENSORS_MAX1619_REMOTE_TEMP, RW }, - MAX1619_SYSCTL_REMOTE_CRIT, VALUE(2), 0, - "temp2_crit_hyst", 3 }, - { { SENSORS_MAX1619_ALARMS, "alarms", NOMAP, NOMAP, R }, - MAX1619_SYSCTL_ALARMS, VALUE(1), 0 }, - { { 0 }, 0 } - }; - -static sensors_chip_feature max6650_features[] = - { - { { SENSORS_MAX6650_FAN1_TACH, "fan1", NOMAP, NOMAP, R }, - MAX6650_SYSCTL_FAN1, VALUE(1), 0 }, - { { SENSORS_MAX6650_FAN2_TACH, "fan2", NOMAP, NOMAP, R }, - MAX6650_SYSCTL_FAN2, VALUE(1), 0 }, - { { SENSORS_MAX6650_FAN3_TACH, "fan3", NOMAP, NOMAP, R }, - MAX6650_SYSCTL_FAN3, VALUE(1), 0 }, - { { SENSORS_MAX6650_FAN4_TACH, "fan4", NOMAP, NOMAP, R }, - MAX6650_SYSCTL_FAN4, VALUE(1), 0 }, - { { SENSORS_MAX6650_SPEED, "speed", SENSORS_MAX6650_FAN1_TACH, - SENSORS_MAX6650_FAN1_TACH, RW }, - MAX6650_SYSCTL_SPEED, VALUE(1), 0, - "fan1_target", 0 }, - { { 0 }, 0 } - }; - -#define SENSORS_SMSC47B397_TEMP(nr) \ - { { SENSORS_SMSC47B397_TEMP##nr, "temp" #nr, NOMAP, NOMAP, R }, \ - NOSYSCTL, VALUE(1), 0 } - -#define SENSORS_SMSC47B397_FAN(nr) \ - { { SENSORS_SMSC47B397_FAN##nr, "fan" #nr, NOMAP, NOMAP, R }, \ - NOSYSCTL, VALUE(1), 0 } - -static sensors_chip_feature smsc47b397_features[] = -{ - SENSORS_SMSC47B397_TEMP(1), - SENSORS_SMSC47B397_TEMP(2), - SENSORS_SMSC47B397_TEMP(3), - SENSORS_SMSC47B397_TEMP(4), - SENSORS_SMSC47B397_FAN(1), - SENSORS_SMSC47B397_FAN(2), - SENSORS_SMSC47B397_FAN(3), - SENSORS_SMSC47B397_FAN(4), - { { 0 }, 0 } -}; - -static sensors_chip_feature f71805f_features[] = -{ -/* 9 to 11 voltage inputs */ - { { SENSORS_F71805F_IN(0), "in0", NOMAP, NOMAP, R }, - F71805F_SYSCTL_IN0, VALUE(3), 3 }, - { { SENSORS_F71805F_IN(1), "in1", NOMAP, NOMAP, R }, - F71805F_SYSCTL_IN1, VALUE(3), 3 }, - { { SENSORS_F71805F_IN(2), "in2", NOMAP, NOMAP, R }, - F71805F_SYSCTL_IN2, VALUE(3), 3 }, - { { SENSORS_F71805F_IN(3), "in3", NOMAP, NOMAP, R }, - F71805F_SYSCTL_IN3, VALUE(3), 3 }, - { { SENSORS_F71805F_IN(4), "in4", NOMAP, NOMAP, R }, - F71805F_SYSCTL_IN4, VALUE(3), 3 }, - { { SENSORS_F71805F_IN(5), "in5", NOMAP, NOMAP, R }, - F71805F_SYSCTL_IN5, VALUE(3), 3 }, - { { SENSORS_F71805F_IN(6), "in6", NOMAP, NOMAP, R }, - F71805F_SYSCTL_IN6, VALUE(3), 3 }, - { { SENSORS_F71805F_IN(7), "in7", NOMAP, NOMAP, R }, - F71805F_SYSCTL_IN7, VALUE(3), 3 }, - { { SENSORS_F71805F_IN(8), "in8", NOMAP, NOMAP, R }, - F71805F_SYSCTL_IN8, VALUE(3), 3 }, - { { SENSORS_F71805F_IN(9), "in9", NOMAP, NOMAP, R }, - NOSYSCTL, VALUE(3), 3 }, - { { SENSORS_F71805F_IN(10), "in10", NOMAP, NOMAP, R }, - NOSYSCTL, VALUE(3), 3 }, - { { SENSORS_F71805F_IN_MIN(0), "in0_min", SENSORS_F71805F_IN(0), - SENSORS_F71805F_IN(0), RW }, - F71805F_SYSCTL_IN0, VALUE(1), 3 }, - { { SENSORS_F71805F_IN_MIN(1), "in1_min", SENSORS_F71805F_IN(1), - SENSORS_F71805F_IN(1), RW }, - F71805F_SYSCTL_IN1, VALUE(1), 3 }, - { { SENSORS_F71805F_IN_MIN(2), "in2_min", SENSORS_F71805F_IN(2), - SENSORS_F71805F_IN(2), RW }, - F71805F_SYSCTL_IN2, VALUE(1), 3 }, - { { SENSORS_F71805F_IN_MIN(3), "in3_min", SENSORS_F71805F_IN(3), - SENSORS_F71805F_IN(3), RW }, - F71805F_SYSCTL_IN3, VALUE(1), 3 }, - { { SENSORS_F71805F_IN_MIN(4), "in4_min", SENSORS_F71805F_IN(4), - SENSORS_F71805F_IN(4), RW }, - F71805F_SYSCTL_IN4, VALUE(1), 3 }, - { { SENSORS_F71805F_IN_MIN(5), "in5_min", SENSORS_F71805F_IN(5), - SENSORS_F71805F_IN(5), RW }, - F71805F_SYSCTL_IN5, VALUE(1), 3 }, - { { SENSORS_F71805F_IN_MIN(6), "in6_min", SENSORS_F71805F_IN(6), - SENSORS_F71805F_IN(6), RW }, - F71805F_SYSCTL_IN6, VALUE(1), 3 }, - { { SENSORS_F71805F_IN_MIN(7), "in7_min", SENSORS_F71805F_IN(7), - SENSORS_F71805F_IN(7), RW }, - F71805F_SYSCTL_IN7, VALUE(1), 3 }, - { { SENSORS_F71805F_IN_MIN(8), "in8_min", SENSORS_F71805F_IN(8), - SENSORS_F71805F_IN(8), RW }, - F71805F_SYSCTL_IN8, VALUE(1), 3 }, - { { SENSORS_F71805F_IN_MIN(9), "in9_min", SENSORS_F71805F_IN(9), - SENSORS_F71805F_IN(9), RW }, - NOSYSCTL, VALUE(1), 3 }, - { { SENSORS_F71805F_IN_MIN(10), "in10_min", SENSORS_F71805F_IN(10), - SENSORS_F71805F_IN(10), RW }, - NOSYSCTL, VALUE(1), 3 }, - { { SENSORS_F71805F_IN_MAX(0), "in0_max", SENSORS_F71805F_IN(0), - SENSORS_F71805F_IN(0), RW }, - F71805F_SYSCTL_IN0, VALUE(2), 3 }, - { { SENSORS_F71805F_IN_MAX(1), "in1_max", SENSORS_F71805F_IN(1), - SENSORS_F71805F_IN(1), RW }, - F71805F_SYSCTL_IN1, VALUE(2), 3 }, - { { SENSORS_F71805F_IN_MAX(2), "in2_max", SENSORS_F71805F_IN(2), - SENSORS_F71805F_IN(2), RW }, - F71805F_SYSCTL_IN2, VALUE(2), 3 }, - { { SENSORS_F71805F_IN_MAX(3), "in3_max", SENSORS_F71805F_IN(3), - SENSORS_F71805F_IN(3), RW }, - F71805F_SYSCTL_IN3, VALUE(2), 3 }, - { { SENSORS_F71805F_IN_MAX(4), "in4_max", SENSORS_F71805F_IN(4), - SENSORS_F71805F_IN(4), RW }, - F71805F_SYSCTL_IN4, VALUE(2), 3 }, - { { SENSORS_F71805F_IN_MAX(5), "in5_max", SENSORS_F71805F_IN(5), - SENSORS_F71805F_IN(5), RW }, - F71805F_SYSCTL_IN5, VALUE(2), 3 }, - { { SENSORS_F71805F_IN_MAX(6), "in6_max", SENSORS_F71805F_IN(6), - SENSORS_F71805F_IN(6), RW }, - F71805F_SYSCTL_IN6, VALUE(2), 3 }, - { { SENSORS_F71805F_IN_MAX(7), "in7_max", SENSORS_F71805F_IN(7), - SENSORS_F71805F_IN(7), RW }, - F71805F_SYSCTL_IN7, VALUE(2), 3 }, - { { SENSORS_F71805F_IN_MAX(8), "in8_max", SENSORS_F71805F_IN(8), - SENSORS_F71805F_IN(8), RW }, - F71805F_SYSCTL_IN8, VALUE(2), 3 }, - { { SENSORS_F71805F_IN_MAX(9), "in9_max", SENSORS_F71805F_IN(9), - SENSORS_F71805F_IN(9), RW }, - NOSYSCTL, VALUE(2), 3 }, - { { SENSORS_F71805F_IN_MAX(10), "in10_max", SENSORS_F71805F_IN(10), - SENSORS_F71805F_IN(10), RW }, - NOSYSCTL, VALUE(2), 3 }, -/* 3 fan tachometers */ - { { SENSORS_F71805F_FAN(1), "fan1", NOMAP, NOMAP, R }, - F71805F_SYSCTL_FAN1, VALUE(2), 0 }, - { { SENSORS_F71805F_FAN(2), "fan2", NOMAP, NOMAP, R }, - F71805F_SYSCTL_FAN2, VALUE(2), 0 }, - { { SENSORS_F71805F_FAN(3), "fan3", NOMAP, NOMAP, R }, - F71805F_SYSCTL_FAN3, VALUE(2), 0 }, - { { SENSORS_F71805F_FAN_MIN(1), "fan1_min", SENSORS_F71805F_FAN(1), - SENSORS_F71805F_FAN(1), RW }, - F71805F_SYSCTL_FAN1, VALUE(1), 0 }, - { { SENSORS_F71805F_FAN_MIN(2), "fan2_min", SENSORS_F71805F_FAN(2), - SENSORS_F71805F_FAN(2), RW }, - F71805F_SYSCTL_FAN2, VALUE(1), 0 }, - { { SENSORS_F71805F_FAN_MIN(3), "fan3_min", SENSORS_F71805F_FAN(3), - SENSORS_F71805F_FAN(3), RW }, - F71805F_SYSCTL_FAN3, VALUE(1), 0 }, -/* 3 temperature inputs */ - { { SENSORS_F71805F_TEMP(1), "temp1", NOMAP, NOMAP, R }, - F71805F_SYSCTL_TEMP1, VALUE(3), 0 }, - { { SENSORS_F71805F_TEMP(2), "temp2", NOMAP, NOMAP, R }, - F71805F_SYSCTL_TEMP2, VALUE(3), 0 }, - { { SENSORS_F71805F_TEMP(3), "temp3", NOMAP, NOMAP, R }, - F71805F_SYSCTL_TEMP3, VALUE(3), 0 }, - { { SENSORS_F71805F_TEMP_MAX(1), "temp1_max", SENSORS_F71805F_TEMP(1), - SENSORS_F71805F_TEMP(1), RW }, - F71805F_SYSCTL_TEMP1, VALUE(1), 0 }, - { { SENSORS_F71805F_TEMP_MAX(2), "temp2_max", SENSORS_F71805F_TEMP(2), - SENSORS_F71805F_TEMP(2), RW }, - F71805F_SYSCTL_TEMP2, VALUE(1), 0 }, - { { SENSORS_F71805F_TEMP_MAX(3), "temp3_max", SENSORS_F71805F_TEMP(3), - SENSORS_F71805F_TEMP(3), RW }, - F71805F_SYSCTL_TEMP3, VALUE(1), 0 }, - { { SENSORS_F71805F_TEMP_HYST(1), "temp1_hyst", SENSORS_F71805F_TEMP(1), - SENSORS_F71805F_TEMP(1), RW }, - F71805F_SYSCTL_TEMP1, VALUE(2), 0 }, - { { SENSORS_F71805F_TEMP_HYST(2), "temp2_hyst", SENSORS_F71805F_TEMP(2), - SENSORS_F71805F_TEMP(2), RW }, - F71805F_SYSCTL_TEMP2, VALUE(2), 0 }, - { { SENSORS_F71805F_TEMP_HYST(3), "temp3_hyst", SENSORS_F71805F_TEMP(3), - SENSORS_F71805F_TEMP(3), RW }, - F71805F_SYSCTL_TEMP3, VALUE(2), 0 }, - { { SENSORS_F71805F_TEMP_TYPE(1), "sensor1", SENSORS_F71805F_TEMP(1), NOMAP, R }, - F71805F_SYSCTL_SENSOR1, VALUE(1), 0 }, - { { SENSORS_F71805F_TEMP_TYPE(2), "sensor2", SENSORS_F71805F_TEMP(2), NOMAP, R }, - F71805F_SYSCTL_SENSOR2, VALUE(1), 0 }, - { { SENSORS_F71805F_TEMP_TYPE(3), "sensor3", SENSORS_F71805F_TEMP(3), NOMAP, R }, - F71805F_SYSCTL_SENSOR3, VALUE(1), 0 }, -/* 3 alarm bitvectors */ - { { SENSORS_F71805F_ALARMS_IN, "alarms_in", NOMAP, NOMAP, R }, - F71805F_SYSCTL_ALARMS_IN, VALUE(1), 0 }, - { { SENSORS_F71805F_ALARMS_FAN, "alarms_fan", NOMAP, NOMAP, R }, - F71805F_SYSCTL_ALARMS_FAN, VALUE(1), 0 }, - { { SENSORS_F71805F_ALARMS_TEMP, "alarms_temp", NOMAP, NOMAP, R }, - F71805F_SYSCTL_ALARMS_TEMP, VALUE(1), 0 }, - { { 0 }, 0 } -}; - -#define SENSORS_ABITUGURU_IN_FEATURES(nr) \ - { { SENSORS_ABITUGURU_IN(nr), "in" #nr, NOMAP, NOMAP, R }, \ - NOSYSCTL, VALUE(3), 3 }, \ - { { SENSORS_ABITUGURU_IN_MIN(nr), "in" #nr "_min", \ - SENSORS_ABITUGURU_IN(nr), SENSORS_ABITUGURU_IN(nr), RW }, \ - NOSYSCTL, VALUE(1), 3 }, \ - { { SENSORS_ABITUGURU_IN_MIN_ALARM(nr), "in" #nr "_min_alarm", \ - SENSORS_ABITUGURU_IN(nr), NOMAP, R }, \ - NOSYSCTL, VALUE(1), 0 }, \ - { { SENSORS_ABITUGURU_IN_MAX(nr), "in" #nr "_max", \ - SENSORS_ABITUGURU_IN(nr), SENSORS_ABITUGURU_IN(nr), RW }, \ - NOSYSCTL, VALUE(2), 3 }, \ - { { SENSORS_ABITUGURU_IN_MAX_ALARM(nr), "in" #nr "_max_alarm", \ - SENSORS_ABITUGURU_IN(nr), NOMAP, R }, \ - NOSYSCTL, VALUE(2), 0 } - -#define SENSORS_ABITUGURU_TEMP_FEATURES(nr) \ - { { SENSORS_ABITUGURU_TEMP(nr), "temp" #nr, NOMAP, NOMAP, R }, \ - NOSYSCTL, VALUE(3), 3 }, \ - { { SENSORS_ABITUGURU_TEMP_ALARM(nr), "temp" #nr "_alarm", \ - SENSORS_ABITUGURU_TEMP(nr), NOMAP, R }, \ - NOSYSCTL, VALUE(1), 0 }, \ - { { SENSORS_ABITUGURU_TEMP_MAX(nr), "temp" #nr "_max", \ - SENSORS_ABITUGURU_TEMP(nr), SENSORS_ABITUGURU_TEMP(nr), RW }, \ - NOSYSCTL, VALUE(1), 3 }, \ - { { SENSORS_ABITUGURU_TEMP_CRIT(nr), "temp" #nr "_crit", \ - SENSORS_ABITUGURU_TEMP(nr), SENSORS_ABITUGURU_TEMP(nr), RW }, \ - NOSYSCTL, VALUE(2), 3 } - -#define SENSORS_ABITUGURU_FAN_FEATURES(nr) \ - { { SENSORS_ABITUGURU_FAN(nr), "fan" #nr, NOMAP, NOMAP, R }, \ - NOSYSCTL, VALUE(2), 0 }, \ - { { SENSORS_ABITUGURU_FAN_ALARM(nr), "fan" #nr "_alarm", \ - SENSORS_ABITUGURU_FAN(nr), NOMAP, R }, \ - NOSYSCTL, VALUE(1), 0 }, \ - { { SENSORS_ABITUGURU_FAN_MIN(nr), "fan" #nr "_min", \ - SENSORS_ABITUGURU_FAN(nr), SENSORS_ABITUGURU_FAN(nr), RW }, \ - NOSYSCTL, VALUE(1), 0 } - -static sensors_chip_feature abituguru_features[] = -{ - SENSORS_ABITUGURU_IN_FEATURES(0), - SENSORS_ABITUGURU_IN_FEATURES(1), - SENSORS_ABITUGURU_IN_FEATURES(2), - SENSORS_ABITUGURU_IN_FEATURES(3), - SENSORS_ABITUGURU_IN_FEATURES(4), - SENSORS_ABITUGURU_IN_FEATURES(5), - SENSORS_ABITUGURU_IN_FEATURES(6), - SENSORS_ABITUGURU_IN_FEATURES(7), - SENSORS_ABITUGURU_IN_FEATURES(8), - SENSORS_ABITUGURU_IN_FEATURES(9), - SENSORS_ABITUGURU_IN_FEATURES(10), - SENSORS_ABITUGURU_TEMP_FEATURES(1), - SENSORS_ABITUGURU_TEMP_FEATURES(2), - SENSORS_ABITUGURU_TEMP_FEATURES(3), - SENSORS_ABITUGURU_TEMP_FEATURES(4), - SENSORS_ABITUGURU_TEMP_FEATURES(5), - SENSORS_ABITUGURU_TEMP_FEATURES(6), - SENSORS_ABITUGURU_TEMP_FEATURES(7), - SENSORS_ABITUGURU_FAN_FEATURES(1), - SENSORS_ABITUGURU_FAN_FEATURES(2), - SENSORS_ABITUGURU_FAN_FEATURES(3), - SENSORS_ABITUGURU_FAN_FEATURES(4), - SENSORS_ABITUGURU_FAN_FEATURES(5), - SENSORS_ABITUGURU_FAN_FEATURES(6), - { { 0 }, 0 } -}; - -static sensors_chip_feature abituguru3_features[] = -{ - SENSORS_ABITUGURU_IN_FEATURES(0), - SENSORS_ABITUGURU_IN_FEATURES(1), - SENSORS_ABITUGURU_IN_FEATURES(2), - SENSORS_ABITUGURU_IN_FEATURES(3), - SENSORS_ABITUGURU_IN_FEATURES(4), - SENSORS_ABITUGURU_IN_FEATURES(5), - SENSORS_ABITUGURU_IN_FEATURES(6), - SENSORS_ABITUGURU_IN_FEATURES(7), - SENSORS_ABITUGURU_IN_FEATURES(8), - SENSORS_ABITUGURU_IN_FEATURES(9), - SENSORS_ABITUGURU_IN_FEATURES(10), - SENSORS_ABITUGURU_IN_FEATURES(11), - SENSORS_ABITUGURU_IN_FEATURES(12), - SENSORS_ABITUGURU_IN_FEATURES(13), - SENSORS_ABITUGURU_TEMP_FEATURES(1), - SENSORS_ABITUGURU_TEMP_FEATURES(2), - SENSORS_ABITUGURU_TEMP_FEATURES(3), - SENSORS_ABITUGURU_TEMP_FEATURES(4), - SENSORS_ABITUGURU_TEMP_FEATURES(5), - SENSORS_ABITUGURU_TEMP_FEATURES(6), - SENSORS_ABITUGURU_TEMP_FEATURES(7), - SENSORS_ABITUGURU_FAN_FEATURES(1), - SENSORS_ABITUGURU_FAN_FEATURES(2), - SENSORS_ABITUGURU_FAN_FEATURES(3), - SENSORS_ABITUGURU_FAN_FEATURES(4), - SENSORS_ABITUGURU_FAN_FEATURES(5), - SENSORS_ABITUGURU_FAN_FEATURES(6), - SENSORS_ABITUGURU_FAN_FEATURES(7), - SENSORS_ABITUGURU_FAN_FEATURES(8), - { { 0 }, 0 } -}; - - -static sensors_chip_feature k8temp_features[] = - { - { { SENSORS_K8TEMP_TEMP1, "temp1", NOMAP, NOMAP, R }, - NOSYSCTL, VALUE(1), 0 }, - { { SENSORS_K8TEMP_TEMP2, "temp2", NOMAP, NOMAP, R }, - NOSYSCTL, VALUE(1), 0 }, - { { SENSORS_K8TEMP_TEMP3, "temp3", NOMAP, NOMAP, R }, - NOSYSCTL, VALUE(1), 0 }, - { { SENSORS_K8TEMP_TEMP4, "temp4", NOMAP, NOMAP, R }, - NOSYSCTL, VALUE(1), 0 }, - { { 0 }, 0 } - }; - -static sensors_chip_feature coretemp_features[] = - { - { { SENSORS_CORETEMP_TEMP1, "temp1", NOMAP, NOMAP, R }, - NOSYSCTL, VALUE(2), 0 }, - { { SENSORS_CORETEMP_TEMP1_CRIT, "temp1_crit", SENSORS_CORETEMP_TEMP1, - SENSORS_CORETEMP_TEMP1, R }, - NOSYSCTL, VALUE(1), 0 }, - { { SENSORS_CORETEMP_TEMP1_CRIT_ALARM, "temp1_crit_alarm", - SENSORS_CORETEMP_TEMP1, NOMAP, R }, - NOSYSCTL, VALUE(1), 0 }, - { { 0 }, 0 } - }; - -#define SENSORS_DME1737_IN_FEATURES(nr) \ - { { SENSORS_DME1737_IN(nr), "in" #nr, \ - NOMAP, NOMAP, R }, \ - NOSYSCTL, VALUE(3), 3 }, \ - { { SENSORS_DME1737_IN_MIN(nr), "in" #nr "_min", \ - SENSORS_DME1737_IN(nr), SENSORS_DME1737_IN(nr), RW }, \ - NOSYSCTL, VALUE(1), 3 }, \ - { { SENSORS_DME1737_IN_MAX(nr), "in" #nr "_max", \ - SENSORS_DME1737_IN(nr), SENSORS_DME1737_IN(nr), RW }, \ - NOSYSCTL, VALUE(2), 3 }, \ - { { SENSORS_DME1737_IN_ALARM(nr), "in" #nr "_alarm", \ - SENSORS_DME1737_IN(nr), NOMAP, R }, \ - NOSYSCTL, VALUE(1), 0 } - -#define SENSORS_DME1737_TEMP_FEATURES(nr) \ - { { SENSORS_DME1737_TEMP(nr), "temp" #nr, \ - NOMAP, NOMAP, R }, \ - NOSYSCTL, VALUE(3), 3 }, \ - { { SENSORS_DME1737_TEMP_MIN(nr), "temp" #nr "_min", \ - SENSORS_DME1737_TEMP(nr), SENSORS_DME1737_TEMP(nr), RW }, \ - NOSYSCTL, VALUE(2), 3 }, \ - { { SENSORS_DME1737_TEMP_MAX(nr), "temp" #nr "_max", \ - SENSORS_DME1737_TEMP(nr), SENSORS_DME1737_TEMP(nr), RW }, \ - NOSYSCTL, VALUE(1), 3 }, \ - { { SENSORS_DME1737_TEMP_ALARM(nr), "temp" #nr "_alarm", \ - SENSORS_DME1737_TEMP(nr), NOMAP, R }, \ - NOSYSCTL, VALUE(1), 0 }, \ - { { SENSORS_DME1737_TEMP_FAULT(nr), "temp" #nr "_fault", \ - SENSORS_DME1737_TEMP(nr), NOMAP, R }, \ - NOSYSCTL, VALUE(2), 0 } - -#define SENSORS_DME1737_FAN_FEATURES(nr) \ - { { SENSORS_DME1737_FAN(nr), "fan" #nr, \ - NOMAP, NOMAP, R }, \ - NOSYSCTL, VALUE(2), 0 }, \ - { { SENSORS_DME1737_FAN_MIN(nr), "fan" #nr "_min", \ - SENSORS_DME1737_FAN(nr), SENSORS_DME1737_FAN(nr), RW }, \ - NOSYSCTL, VALUE(1), 0 }, \ - { { SENSORS_DME1737_FAN_ALARM(nr), "fan" #nr "_alarm", \ - SENSORS_DME1737_FAN(nr), NOMAP, R }, \ - NOSYSCTL, VALUE(1), 0 } - -#define SENSORS_DME1737_PWM_FEATURES(nr) \ - { { SENSORS_DME1737_PWM(nr), "pwm" #nr, \ - NOMAP, NOMAP, RW }, \ - NOSYSCTL, VALUE(1), 0 }, \ - { { SENSORS_DME1737_PWM_ENABLE(nr), "pwm" #nr "_enable", \ - SENSORS_DME1737_PWM(nr), SENSORS_DME1737_PWM(nr), RW }, \ - NOSYSCTL, VALUE(2), 0 }, \ - { { SENSORS_DME1737_PWM_FREQ(nr), "pwm" #nr "_freq", \ - SENSORS_DME1737_PWM(nr), SENSORS_DME1737_PWM(nr), RW }, \ - NOSYSCTL, VALUE(3), 0 } - -static sensors_chip_feature dme1737_features[] = -{ - SENSORS_DME1737_IN_FEATURES(0), - SENSORS_DME1737_IN_FEATURES(1), - SENSORS_DME1737_IN_FEATURES(2), - SENSORS_DME1737_IN_FEATURES(3), - SENSORS_DME1737_IN_FEATURES(4), - SENSORS_DME1737_IN_FEATURES(5), - SENSORS_DME1737_IN_FEATURES(6), - SENSORS_DME1737_TEMP_FEATURES(1), - SENSORS_DME1737_TEMP_FEATURES(2), - SENSORS_DME1737_TEMP_FEATURES(3), - SENSORS_DME1737_FAN_FEATURES(1), - SENSORS_DME1737_FAN_FEATURES(2), - SENSORS_DME1737_FAN_FEATURES(3), - SENSORS_DME1737_FAN_FEATURES(4), - SENSORS_DME1737_FAN_FEATURES(5), - SENSORS_DME1737_FAN_FEATURES(6), - SENSORS_DME1737_PWM_FEATURES(1), - SENSORS_DME1737_PWM_FEATURES(2), - SENSORS_DME1737_PWM_FEATURES(3), - SENSORS_DME1737_PWM_FEATURES(5), - SENSORS_DME1737_PWM_FEATURES(6), - { { SENSORS_DME1737_VID, "cpu0_vid", NOMAP, NOMAP, R }, - NOSYSCTL, VALUE(1), 3 }, - { { SENSORS_DME1737_VRM, "vrm", NOMAP, NOMAP, RW }, - NOSYSCTL, VALUE(1), 1 }, - { { 0 }, 0 } -}; - -static sensors_chip_feature applesmc_features[] = - { - { { SENSORS_APPLESMC_TEMP(0), "temp1", NOMAP, NOMAP, R }, - NOSYSCTL, VALUE(1), 3 }, - { { SENSORS_APPLESMC_TEMP(1), "temp2", NOMAP, NOMAP, R }, - NOSYSCTL, VALUE(1), 3 }, - { { SENSORS_APPLESMC_TEMP(2), "temp3", NOMAP, NOMAP, R }, - NOSYSCTL, VALUE(1), 3 }, - { { SENSORS_APPLESMC_TEMP(3), "temp4", NOMAP, NOMAP, R }, - NOSYSCTL, VALUE(1), 3 }, - { { SENSORS_APPLESMC_TEMP(4), "temp5", NOMAP, NOMAP, R }, - NOSYSCTL, VALUE(1), 3 }, - { { SENSORS_APPLESMC_TEMP(5), "temp6", NOMAP, NOMAP, R }, - NOSYSCTL, VALUE(1), 3 }, - { { SENSORS_APPLESMC_TEMP(6), "temp7", NOMAP, NOMAP, R }, - NOSYSCTL, VALUE(1), 3 }, - { { SENSORS_APPLESMC_TEMP(7), "temp8", NOMAP, NOMAP, R }, - NOSYSCTL, VALUE(1), 3 }, - { { SENSORS_APPLESMC_TEMP(8), "temp9", NOMAP, NOMAP, R }, - NOSYSCTL, VALUE(1), 3 }, - { { SENSORS_APPLESMC_TEMP(9), "temp10", NOMAP, NOMAP, R }, - NOSYSCTL, VALUE(1), 3 }, - { { SENSORS_APPLESMC_TEMP(10), "temp11", NOMAP, NOMAP, R }, - NOSYSCTL, VALUE(1), 3 }, - { { SENSORS_APPLESMC_TEMP(11), "temp12", NOMAP, NOMAP, R }, - NOSYSCTL, VALUE(1), 3 }, - { { SENSORS_APPLESMC_FAN(0), "fan1", NOMAP, NOMAP, R }, - NOSYSCTL, VALUE(2), 0 }, - { { SENSORS_APPLESMC_FAN(1), "fan2", NOMAP, NOMAP, R }, - NOSYSCTL, VALUE(2), 0 }, - { { SENSORS_APPLESMC_FAN_MIN(0), "fan1_min", SENSORS_APPLESMC_FAN(0), - SENSORS_APPLESMC_FAN(0), R }, NOSYSCTL, VALUE(1), 0 }, - { { SENSORS_APPLESMC_FAN_MIN(1), "fan2_min", SENSORS_APPLESMC_FAN(1), - SENSORS_APPLESMC_FAN(1), R }, NOSYSCTL, VALUE(1), 0 }, - { { SENSORS_APPLESMC_FAN_MAX(0), "fan1_max", SENSORS_APPLESMC_FAN(0), - SENSORS_APPLESMC_FAN(0), R }, NOSYSCTL, VALUE(1), 0 }, - { { SENSORS_APPLESMC_FAN_MAX(1), "fan2_max", SENSORS_APPLESMC_FAN(1), - SENSORS_APPLESMC_FAN(1), R }, NOSYSCTL, VALUE(1), 0 }, - { { SENSORS_APPLESMC_FAN_SAFE(0), "fan1_safe", SENSORS_APPLESMC_FAN(0), - SENSORS_APPLESMC_FAN(0), R }, NOSYSCTL, VALUE(1), 0 }, - { { SENSORS_APPLESMC_FAN_SAFE(1), "fan2_safe", SENSORS_APPLESMC_FAN(1), - SENSORS_APPLESMC_FAN(1), R }, NOSYSCTL, VALUE(1), 0 }, - { { 0 }, 0 } - }; - -#define SENSORS_F71882FG_IN_FEATURES(nr) \ - { { SENSORS_F71882FG_IN(nr), "in" #nr, \ - NOMAP, NOMAP, R }, \ - NOSYSCTL, VALUE(3), 3 } - -#define SENSORS_F71882FG_TEMP_FEATURES(nr) \ - { { SENSORS_F71882FG_TEMP(nr), "temp" #nr, \ - NOMAP, NOMAP, R }, \ - NOSYSCTL, VALUE(3), 3 }, \ - { { SENSORS_F71882FG_TEMP_MAX(nr), "temp" #nr "_max", \ - SENSORS_F71882FG_TEMP(nr), SENSORS_F71882FG_TEMP(nr), RW }, \ - NOSYSCTL, VALUE(1), 3 }, \ - { { SENSORS_F71882FG_TEMP_MAX_HYST(nr), "temp" #nr "_max_hyst", \ - SENSORS_F71882FG_TEMP(nr), SENSORS_F71882FG_TEMP(nr), RW }, \ - NOSYSCTL, VALUE(2), 3 }, \ - { { SENSORS_F71882FG_TEMP_CRIT(nr), "temp" #nr "_crit", \ - SENSORS_F71882FG_TEMP(nr), SENSORS_F71882FG_TEMP(nr), RW }, \ - NOSYSCTL, VALUE(4), 3 }, \ - { { SENSORS_F71882FG_TEMP_CRIT_HYST(nr), "temp" #nr "_crit_hyst", \ - SENSORS_F71882FG_TEMP(nr), SENSORS_F71882FG_TEMP(nr), R }, \ - NOSYSCTL, VALUE(5), 3 }, \ - { { SENSORS_F71882FG_TEMP_ALARM(nr), "temp" #nr "_alarm", \ - SENSORS_F71882FG_TEMP(nr), NOMAP, R }, \ - NOSYSCTL, VALUE(1), 0, "temp" #nr "_max_alarm", 0, \ - "temp" #nr "_alarm" }, \ - { { SENSORS_F71882FG_TEMP_FAULT(nr), "temp" #nr "_fault", \ - SENSORS_F71882FG_TEMP(nr), NOMAP, R }, \ - NOSYSCTL, VALUE(2), 0 }, \ - { { SENSORS_F71882FG_TEMP_TYPE(nr), "temp" #nr "_type", \ - SENSORS_F71882FG_TEMP(nr), NOMAP, R }, \ - NOSYSCTL, VALUE(3), 0 } - -#define SENSORS_F71882FG_FAN_FEATURES(nr) \ - { { SENSORS_F71882FG_FAN(nr), "fan" #nr, \ - NOMAP, NOMAP, R }, \ - NOSYSCTL, VALUE(2), 0 }, \ - { { SENSORS_F71882FG_FAN_ALARM(nr), "fan" #nr "_alarm", \ - SENSORS_F71882FG_FAN(nr), NOMAP, R }, \ - NOSYSCTL, VALUE(1), 0 } - -static sensors_chip_feature f71882fg_features[] = -{ - SENSORS_F71882FG_IN_FEATURES(0), - SENSORS_F71882FG_IN_FEATURES(1), - { { SENSORS_F71882FG_IN_MAX(1), "in1_max", - SENSORS_F71882FG_IN(1), SENSORS_F71882FG_IN(1), RW }, - NOSYSCTL, VALUE(1), 3 }, - { { SENSORS_F71882FG_IN_ALARM(1), "in1_alarm", - SENSORS_F71882FG_IN(1), NOMAP, R }, - NOSYSCTL, VALUE(1), 0 }, - SENSORS_F71882FG_IN_FEATURES(2), - SENSORS_F71882FG_IN_FEATURES(3), - SENSORS_F71882FG_IN_FEATURES(4), - SENSORS_F71882FG_IN_FEATURES(5), - SENSORS_F71882FG_IN_FEATURES(6), - SENSORS_F71882FG_IN_FEATURES(7), - SENSORS_F71882FG_IN_FEATURES(8), - SENSORS_F71882FG_TEMP_FEATURES(1), - SENSORS_F71882FG_TEMP_FEATURES(2), - SENSORS_F71882FG_TEMP_FEATURES(3), - SENSORS_F71882FG_FAN_FEATURES(1), - SENSORS_F71882FG_FAN_FEATURES(2), - SENSORS_F71882FG_FAN_FEATURES(3), - SENSORS_F71882FG_FAN_FEATURES(4), - { { 0 }, 0 } -}; - -#define SENSORS_FSCHMD_IN_FEATURES(nr) \ - { { SENSORS_FSCHMD_IN(nr), "in" #nr, \ - NOMAP, NOMAP, R }, \ - NOSYSCTL, VALUE(1), 3 } - -#define SENSORS_FSCHMD_TEMP_FEATURES(nr) \ - { { SENSORS_FSCHMD_TEMP(nr), "temp" #nr, \ - NOMAP, NOMAP, R }, \ - NOSYSCTL, VALUE(2), 3 }, \ - { { SENSORS_FSCHMD_TEMP_MAX(nr), "temp" #nr "_max", \ - SENSORS_FSCHMD_TEMP(nr), SENSORS_FSCHMD_TEMP(nr), RW }, \ - NOSYSCTL, VALUE(1), 3 }, \ - { { SENSORS_FSCHMD_TEMP_ALARM(nr), "temp" #nr "_alarm", \ - SENSORS_FSCHMD_TEMP(nr), NOMAP, R }, \ - NOSYSCTL, VALUE(1), 0 }, \ - { { SENSORS_FSCHMD_TEMP_FAULT(nr), "temp" #nr "_fault", \ - SENSORS_FSCHMD_TEMP(nr), NOMAP, R }, \ - NOSYSCTL, VALUE(1), 0 } - -#define SENSORS_FSCHMD_FAN_FEATURES(nr) \ - { { SENSORS_FSCHMD_FAN(nr), "fan" #nr, \ - NOMAP, NOMAP, R }, \ - NOSYSCTL, VALUE(1), 0 }, \ - { { SENSORS_FSCHMD_FAN_DIV(nr), "fan" #nr "_div", \ - SENSORS_FSCHMD_FAN(nr), NOMAP, RW }, \ - NOSYSCTL, VALUE(nr), 0 }, \ - { { SENSORS_FSCHMD_FAN_ALARM(nr), "fan" #nr "_alarm", \ - SENSORS_FSCHMD_FAN(nr), NOMAP, R }, \ - NOSYSCTL, VALUE(1), 0 }, \ - { { SENSORS_FSCHMD_FAN_FAULT(nr), "fan" #nr "_fault", \ - SENSORS_FSCHMD_FAN(nr), NOMAP, R }, \ - NOSYSCTL, VALUE(1), 0 } - -static sensors_chip_feature fschmd_features[] = -{ - SENSORS_FSCHMD_IN_FEATURES(0), - SENSORS_FSCHMD_IN_FEATURES(1), - SENSORS_FSCHMD_IN_FEATURES(2), - SENSORS_FSCHMD_TEMP_FEATURES(1), - SENSORS_FSCHMD_TEMP_FEATURES(2), - SENSORS_FSCHMD_TEMP_FEATURES(3), - SENSORS_FSCHMD_TEMP_FEATURES(4), - SENSORS_FSCHMD_TEMP_FEATURES(5), - SENSORS_FSCHMD_FAN_FEATURES(1), - SENSORS_FSCHMD_FAN_FEATURES(2), - SENSORS_FSCHMD_FAN_FEATURES(3), - SENSORS_FSCHMD_FAN_FEATURES(4), - SENSORS_FSCHMD_FAN_FEATURES(5), - { { 0 }, 0 } -}; - -static sensors_chip_feature fschrc_features[] = -{ - SENSORS_FSCHMD_IN_FEATURES(0), - SENSORS_FSCHMD_IN_FEATURES(1), - SENSORS_FSCHMD_IN_FEATURES(2), - SENSORS_FSCHMD_TEMP_FEATURES(1), - SENSORS_FSCHMD_TEMP_FEATURES(2), - SENSORS_FSCHMD_TEMP_FEATURES(3), - SENSORS_FSCHMD_FAN_FEATURES(1), - SENSORS_FSCHMD_FAN_FEATURES(2), - SENSORS_FSCHMD_FAN_FEATURES(3), - SENSORS_FSCHMD_FAN_FEATURES(4), - { { 0 }, 0 } -}; - -sensors_chip_features sensors_chip_features_list[] = -{ - { SENSORS_LM78_PREFIX, lm78_features }, - { SENSORS_LM78J_PREFIX, lm78j_features }, - { SENSORS_LM79_PREFIX, lm79_features }, - { SENSORS_LM75_PREFIX, lm75_features }, - { SENSORS_GL518_PREFIX, gl518_features }, - { SENSORS_GL520_PREFIX, gl520_features }, - { SENSORS_LM80_PREFIX, lm80_features }, - { SENSORS_W83781D_PREFIX, w83781d_features }, - { SENSORS_W83782D_PREFIX, w83782d_features }, - { SENSORS_W83783S_PREFIX, w83783s_features }, - { SENSORS_W83697HF_PREFIX, w83782d_features }, /* same as 782d */ - /* Cheat on 83627HF for now - no separate #defines */ - { SENSORS_W83627HF_PREFIX, w83782d_features }, - /* Cheat on 83627THF for now - no separate #defines */ - { SENSORS_W83627THF_PREFIX, w83782d_features }, - /* Cheat on 83637HF for now - no separate #defines */ - { SENSORS_W83637HF_PREFIX, w83782d_features }, - { SENSORS_W83687THF_PREFIX, w83782d_features }, /* Same as W83627THF */ - { SENSORS_W83791D_PREFIX, w83791d_features }, - { SENSORS_W83792D_PREFIX, w83792d_features }, - { SENSORS_W83793_PREFIX, w83793_features }, - { SENSORS_W83L785TS_PREFIX, w83l785ts_features }, - { SENSORS_W83627EHF_PREFIX, w83627ehf_features }, - { SENSORS_W83627DHG_PREFIX, w83627ehf_features }, /* Similar to W83627EHF but no in9 */ - { SENSORS_AS99127F_PREFIX, as99127f_features }, - { SENSORS_ASB100_PREFIX, asb100_features }, - { SENSORS_ADM9240_PREFIX, adm9240_features }, - /* Cheat on LM81 - same features */ - { SENSORS_LM81_PREFIX, adm9240_features }, - /* Cheat on DS1780 - same features */ - { SENSORS_DS1780_PREFIX, adm9240_features }, - { SENSORS_ADM1021_PREFIX, adm1021_features }, - { SENSORS_MAX1617_PREFIX, max1617_features }, - { SENSORS_MC1066_PREFIX, max1617_features }, - { SENSORS_MAX1617A_PREFIX, max1617a_features }, - /* Cheat on LM84 for now - no separate #defines */ - { SENSORS_LM84_PREFIX, adm1021_features }, - /* Cheat on GL523 for now - no separate #defines */ - { SENSORS_GL523_PREFIX, adm1021_features }, - { SENSORS_ADM1023_PREFIX, adm1023_features }, - /* Cheat on THMC10 for now - no separate #defines */ - { SENSORS_THMC10_PREFIX, adm1021_features }, - { SENSORS_SIS5595_PREFIX, sis5595_features }, - { SENSORS_MAXI_CG_PREFIX, maxi_cg_features }, - { SENSORS_MAXI_CO_PREFIX, maxi_co_features }, - { SENSORS_MAXI_AS_PREFIX, maxi_as_features }, - /* Cheat on NBA for now - no separate #defines */ - { SENSORS_MAXI_NBA_PREFIX, maxi_as_features }, - { SENSORS_THMC50_PREFIX, thmc50_features }, - /* Cheat on ADM1022 for now - no separate #defines */ - { SENSORS_ADM1022_PREFIX, thmc50_features }, - { SENSORS_ADM1025_PREFIX, adm1025_features }, - { SENSORS_NE1619_PREFIX, adm1025_features }, - { SENSORS_ADM1026_PREFIX, adm1026_features }, - { SENSORS_VIA686A_PREFIX, via686a_features }, - { SENSORS_DDCMON_PREFIX, ddcmon_features }, - { SENSORS_EEPROM_PREFIX, eeprom_features }, - { SENSORS_LM87_PREFIX, lm87_features }, - { SENSORS_MTP008_PREFIX, mtp008_features }, - { SENSORS_DS1621_PREFIX, ds1621_features }, - { SENSORS_ADM1024_PREFIX, adm1024_features }, - { SENSORS_IT87_PREFIX, it87_features }, - { SENSORS_IT8712_PREFIX, it87_features }, - { SENSORS_IT8716_PREFIX, it87_features }, - { SENSORS_IT8718_PREFIX, it87_features }, - { SENSORS_IT8720_PREFIX, it87_features }, - { SENSORS_FSCPOS_PREFIX, fscpos_features }, - { SENSORS_FSCSCY_PREFIX, fscscy_features }, - { SENSORS_FSCHER_PREFIX, fscher_features }, - { SENSORS_PCF8591_PREFIX, pcf8591_features }, - { SENSORS_VT1211_PREFIX, vt1211_features }, - { SENSORS_SMSC47M192_PREFIX, smsc47m192_features }, - { SENSORS_SMSC47M1_PREFIX, smsc47m1_features }, - { SENSORS_SMSC47M2_PREFIX, smsc47m2_features }, - { SENSORS_PC87360_PREFIX, pc87360_features }, - { SENSORS_PC87363_PREFIX, pc87360_features }, - { SENSORS_PC87364_PREFIX, pc87360_features }, - { SENSORS_PC87365_PREFIX, pc87365_features }, - { SENSORS_PC87366_PREFIX, pc87365_features }, - { SENSORS_PC87427_PREFIX, pc87427_features }, - { SENSORS_LM92_PREFIX, lm92_features }, - { SENSORS_VT8231_PREFIX, vt8231_features }, - { SENSORS_BMC_PREFIX, bmc_features }, - { SENSORS_LM85_PREFIX, lm85_features }, - { SENSORS_LM85B_PREFIX, lm85_features }, - { SENSORS_LM85C_PREFIX, lm85_features }, - { SENSORS_EMC6D100_PREFIX, lm85_features }, - { SENSORS_EMC6D102_PREFIX, lm85_features }, - { SENSORS_ADM1027_PREFIX, adm1027_features }, - { SENSORS_ADT7463_PREFIX, adm1027_features }, - { SENSORS_LM83_PREFIX, lm83_features }, - { SENSORS_LM90_PREFIX, lm90_features }, - { SENSORS_ADM1032_PREFIX, lm90_features }, - { SENSORS_LM89_PREFIX, lm90_features }, - { SENSORS_LM99_PREFIX, lm90_features }, - { SENSORS_LM86_PREFIX, lm90_features }, - { SENSORS_MAX6657_PREFIX, lm90_features }, - { SENSORS_MAX6658_PREFIX, lm90_features }, - { SENSORS_MAX6659_PREFIX, lm90_features }, - { SENSORS_ADT7461_PREFIX, lm90_features }, - { SENSORS_MAX6680_PREFIX, lm90_features }, - { SENSORS_MAX6681_PREFIX, lm90_features }, - { SENSORS_MAX6646_PREFIX, lm90_features }, - { SENSORS_MAX6647_PREFIX, lm90_features }, - { SENSORS_MAX6649_PREFIX, lm90_features }, - { SENSORS_LM63_PREFIX, lm63_features }, - { SENSORS_MAX1619_PREFIX, max1619_features }, - { SENSORS_XEONTEMP_PREFIX, xeontemp_features }, - { SENSORS_MAX6650_PREFIX, max6650_features }, - { SENSORS_ADM1029_PREFIX, adm1029_features }, - { SENSORS_ADM1030_PREFIX, adm1030_features }, - { SENSORS_ADM1031_PREFIX, adm1031_features }, - { SENSORS_LM93_PREFIX, lm93_features }, - { SENSORS_SMSC47B397_PREFIX, smsc47b397_features }, - { SENSORS_F71805F_PREFIX, f71805f_features }, - { SENSORS_F71872F_PREFIX, f71805f_features }, - { SENSORS_ABITUGURU_PREFIX, abituguru_features }, - { SENSORS_ABITUGURU3_PREFIX, abituguru3_features }, - { SENSORS_K8TEMP_PREFIX, k8temp_features }, - { SENSORS_CORETEMP_PREFIX, coretemp_features }, - { SENSORS_DME1737_PREFIX, dme1737_features }, - { SENSORS_SCH311X_PREFIX, dme1737_features }, - { SENSORS_APPLESMC_PREFIX, applesmc_features }, - { SENSORS_F71882FG_PREFIX, f71882fg_features }, - { SENSORS_FSCHMD_PREFIX, fschmd_features }, - { SENSORS_FSCHRC_PREFIX, fschrc_features }, - { 0 } -}; diff --git a/lib/chips.h b/lib/chips.h deleted file mode 100644 index 519b08da..00000000 --- a/lib/chips.h +++ /dev/null @@ -1,2374 +0,0 @@ -/* - chips.h - Part of libsensors, a Linux library for reading sensor data. - Copyright (c) 1998, 1999 Frodo Looijaard - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -/* This files contains, for each type of chip, the kind of values you can - read and write. The actual value of each define is completely arbitrary, - as long as, for one specific chip, each defined value is unique. I tried - to give similar features similar values, but you can't trust that. - Some entries are very alike (for example the LM78, LM78-J and LM79 - defines). Where documented, you can mix the defines. If chip prefixes - are different, they get their own entry. */ - -/* If you add a chip here, do not forget to add the entry in chips.c too. - Other than that (and a recompile, and a bump up of the library number - for shared libs) nothing should need to be done to support new chips. */ - - -/* LM78 chips */ - -#ifndef LIB_SENSORS_CHIPS_H -#define LIB_SENSORS_CHIPS_H - -#define SENSORS_LM78_PREFIX "lm78" - -#define SENSORS_LM78_IN0 1 /* R */ -#define SENSORS_LM78_IN1 2 /* R */ -#define SENSORS_LM78_IN2 3 /* R */ -#define SENSORS_LM78_IN3 4 /* R */ -#define SENSORS_LM78_IN4 5 /* R */ -#define SENSORS_LM78_IN5 6 /* R */ -#define SENSORS_LM78_IN6 7 /* R */ -#define SENSORS_LM78_IN0_MIN 11 /* RW */ -#define SENSORS_LM78_IN1_MIN 12 /* RW */ -#define SENSORS_LM78_IN2_MIN 13 /* RW */ -#define SENSORS_LM78_IN3_MIN 14 /* RW */ -#define SENSORS_LM78_IN4_MIN 15 /* RW */ -#define SENSORS_LM78_IN5_MIN 16 /* RW */ -#define SENSORS_LM78_IN6_MIN 17 /* RW */ -#define SENSORS_LM78_IN0_MAX 21 /* RW */ -#define SENSORS_LM78_IN1_MAX 22 /* RW */ -#define SENSORS_LM78_IN2_MAX 23 /* RW */ -#define SENSORS_LM78_IN3_MAX 24 /* RW */ -#define SENSORS_LM78_IN4_MAX 25 /* RW */ -#define SENSORS_LM78_IN5_MAX 26 /* RW */ -#define SENSORS_LM78_IN6_MAX 27 /* RW */ -#define SENSORS_LM78_FAN1 31 /* R */ -#define SENSORS_LM78_FAN2 32 /* R */ -#define SENSORS_LM78_FAN3 33 /* R */ -#define SENSORS_LM78_FAN1_MIN 41 /* RW */ -#define SENSORS_LM78_FAN2_MIN 42 /* RW */ -#define SENSORS_LM78_FAN3_MIN 43 /* RW */ -#define SENSORS_LM78_TEMP 51 /* R */ -#define SENSORS_LM78_TEMP_HYST 52 /* RW */ -#define SENSORS_LM78_TEMP_OVER 53 /* RW */ -#define SENSORS_LM78_VID 61 /* R */ -#define SENSORS_LM78_FAN1_DIV 71 /* RW */ -#define SENSORS_LM78_FAN2_DIV 72 /* RW */ -#define SENSORS_LM78_FAN3_DIV 73 /* R (yes, really! */ -#define SENSORS_LM78_ALARMS 81 /* R */ - - -/* LM78-J chips. It is actually safe to use the LM78 defines instead, but it - is better practice to use these. */ - -#define SENSORS_LM78J_PREFIX "lm78-j" - -#define SENSORS_LM78J_IN0 1 /* R */ -#define SENSORS_LM78J_IN1 2 /* R */ -#define SENSORS_LM78J_IN2 3 /* R */ -#define SENSORS_LM78J_IN3 4 /* R */ -#define SENSORS_LM78J_IN4 5 /* R */ -#define SENSORS_LM78J_IN5 6 /* R */ -#define SENSORS_LM78J_IN6 7 /* R */ -#define SENSORS_LM78J_IN0_MIN 11 /* RW */ -#define SENSORS_LM78J_IN1_MIN 12 /* RW */ -#define SENSORS_LM78J_IN2_MIN 13 /* RW */ -#define SENSORS_LM78J_IN3_MIN 14 /* RW */ -#define SENSORS_LM78J_IN4_MIN 15 /* RW */ -#define SENSORS_LM78J_IN5_MIN 16 /* RW */ -#define SENSORS_LM78J_IN6_MIN 17 /* RW */ -#define SENSORS_LM78J_IN0_MAX 21 /* RW */ -#define SENSORS_LM78J_IN1_MAX 22 /* RW */ -#define SENSORS_LM78J_IN2_MAX 23 /* RW */ -#define SENSORS_LM78J_IN3_MAX 24 /* RW */ -#define SENSORS_LM78J_IN4_MAX 25 /* RW */ -#define SENSORS_LM78J_IN5_MAX 26 /* RW */ -#define SENSORS_LM78J_IN6_MAX 27 /* RW */ -#define SENSORS_LM78J_FAN1 31 /* R */ -#define SENSORS_LM78J_FAN2 32 /* R */ -#define SENSORS_LM78J_FAN3 33 /* R */ -#define SENSORS_LM78J_FAN1_MIN 41 /* RW */ -#define SENSORS_LM78J_FAN2_MIN 42 /* RW */ -#define SENSORS_LM78J_FAN3_MIN 43 /* RW */ -#define SENSORS_LM78J_TEMP 51 /* R */ -#define SENSORS_LM78J_TEMP_HYST 52 /* RW */ -#define SENSORS_LM78J_TEMP_OVER 53 /* RW */ -#define SENSORS_LM78J_VID 61 /* R */ -#define SENSORS_LM78J_FAN1_DIV 71 /* RW */ -#define SENSORS_LM78J_FAN2_DIV 72 /* RW */ -#define SENSORS_LM78J_FAN3_DIV 73 /* R (yes, really!) */ -#define SENSORS_LM78J_ALARMS 81 /* R */ - - -/* LM79 chips. It is actually safe to use the LM78 defines instead, but it - is better practice to use these. */ - -#define SENSORS_LM79_PREFIX "lm79" - -#define SENSORS_LM79_IN0 1 /* R */ -#define SENSORS_LM79_IN1 2 /* R */ -#define SENSORS_LM79_IN2 3 /* R */ -#define SENSORS_LM79_IN3 4 /* R */ -#define SENSORS_LM79_IN4 5 /* R */ -#define SENSORS_LM79_IN5 6 /* R */ -#define SENSORS_LM79_IN6 7 /* R */ -#define SENSORS_LM79_IN0_MIN 11 /* RW */ -#define SENSORS_LM79_IN1_MIN 12 /* RW */ -#define SENSORS_LM79_IN2_MIN 13 /* RW */ -#define SENSORS_LM79_IN3_MIN 14 /* RW */ -#define SENSORS_LM79_IN4_MIN 15 /* RW */ -#define SENSORS_LM79_IN5_MIN 16 /* RW */ -#define SENSORS_LM79_IN6_MIN 17 /* RW */ -#define SENSORS_LM79_IN0_MAX 21 /* RW */ -#define SENSORS_LM79_IN1_MAX 22 /* RW */ -#define SENSORS_LM79_IN2_MAX 23 /* RW */ -#define SENSORS_LM79_IN3_MAX 24 /* RW */ -#define SENSORS_LM79_IN4_MAX 25 /* R */ -#define SENSORS_LM79_IN5_MAX 26 /* R */ -#define SENSORS_LM79_IN6_MAX 27 /* R */ -#define SENSORS_LM79_FAN1 31 /* R */ -#define SENSORS_LM79_FAN2 32 /* R */ -#define SENSORS_LM79_FAN3 33 /* R */ -#define SENSORS_LM79_FAN1_MIN 41 /* RW */ -#define SENSORS_LM79_FAN2_MIN 42 /* RW */ -#define SENSORS_LM79_FAN3_MIN 43 /* RW */ -#define SENSORS_LM79_TEMP 51 /* R */ -#define SENSORS_LM79_TEMP_HYST 52 /* RW */ -#define SENSORS_LM79_TEMP_OVER 53 /* RW */ -#define SENSORS_LM79_VID 61 /* R */ -#define SENSORS_LM79_FAN1_DIV 71 /* RW */ -#define SENSORS_LM79_FAN2_DIV 72 /* RW */ -#define SENSORS_LM79_FAN3_DIV 73 /* R (yes, really! */ -#define SENSORS_LM79_ALARMS 81 /* R */ - - -/* LM75 chips. */ - -#define SENSORS_LM75_PREFIX "lm75" - -#define SENSORS_LM75_TEMP 51 /* R */ -#define SENSORS_LM75_TEMP_HYST 52 /* RW */ -#define SENSORS_LM75_TEMP_OVER 53 /* RW */ - -/* ADM1021 chips. */ - -#define SENSORS_ADM1021_PREFIX "adm1021" -/* Cheat on LM84,GL523,THMC10,1023 for now - no separate #defines */ -#define SENSORS_ADM1023_PREFIX "adm1023" -#define SENSORS_LM84_PREFIX "lm84" -#define SENSORS_GL523_PREFIX "gl523" -#define SENSORS_THMC10_PREFIX "thmc10" - -#define SENSORS_ADM1021_TEMP 51 /* R */ -#define SENSORS_ADM1021_TEMP_HYST 52 /* RW */ -#define SENSORS_ADM1021_TEMP_OVER 53 /* RW */ -#define SENSORS_ADM1021_REMOTE_TEMP 54 /* R */ -#define SENSORS_ADM1021_REMOTE_TEMP_HYST 55 /* RW */ -#define SENSORS_ADM1021_REMOTE_TEMP_OVER 56 /* RW */ -#define SENSORS_ADM1021_ALARMS 81 /* R */ -#define SENSORS_ADM1021_DIE_CODE 90 /* R */ - -/* ADM1029 chips */ - -#define SENSORS_ADM1029_PREFIX "adm1029" - -#define SENSORS_ADM1029_TEMP1 51 -#define SENSORS_ADM1029_TEMP1_MAX 52 -#define SENSORS_ADM1029_TEMP1_MIN 53 - -#define SENSORS_ADM1029_TEMP2 61 -#define SENSORS_ADM1029_TEMP2_MAX 62 -#define SENSORS_ADM1029_TEMP2_MIN 63 - -#define SENSORS_ADM1029_TEMP3 71 -#define SENSORS_ADM1029_TEMP3_MAX 72 -#define SENSORS_ADM1029_TEMP3_MIN 73 - -#define SENSORS_ADM1029_FAN1 81 -#define SENSORS_ADM1029_FAN1_MIN 82 -#define SENSORS_ADM1029_FAN1_DIV 83 - -#define SENSORS_ADM1029_FAN2 91 -#define SENSORS_ADM1029_FAN2_MIN 92 -#define SENSORS_ADM1029_FAN2_DIV 93 - - -/* ADM1030 and ADM1031 chips */ - -#define SENSORS_ADM1030_PREFIX "adm1030" -#define SENSORS_ADM1031_PREFIX "adm1031" - -#define SENSORS_ADM1031_TEMP1 51 /* R */ -#define SENSORS_ADM1031_TEMP1_MIN 52 /* RW */ -#define SENSORS_ADM1031_TEMP1_MAX 53 /* RW */ -#define SENSORS_ADM1031_TEMP1_CRIT 54 /* RW */ - -#define SENSORS_ADM1031_TEMP2 61 /* R */ -#define SENSORS_ADM1031_TEMP2_MIN 62 /* RW */ -#define SENSORS_ADM1031_TEMP2_MAX 63 /* RW */ -#define SENSORS_ADM1031_TEMP2_CRIT 64 /* RW */ - -#define SENSORS_ADM1031_TEMP3 71 /* R */ -#define SENSORS_ADM1031_TEMP3_MIN 72 /* RW */ -#define SENSORS_ADM1031_TEMP3_MAX 73 /* RW */ -#define SENSORS_ADM1031_TEMP3_CRIT 74 /* RW */ - - -#define SENSORS_ADM1031_FAN1 80 /* R */ -#define SENSORS_ADM1031_FAN1_MIN 81 /* RW */ -#define SENSORS_ADM1031_FAN1_DIV 82 /* RW */ -#define SENSORS_ADM1031_FAN2 90 /* R */ -#define SENSORS_ADM1031_FAN2_MIN 91 /* RW */ -#define SENSORS_ADM1031_FAN2_DIV 92 /* RW */ - -#define SENSORS_ADM1031_ALARMS 100 /* R */ - - -/* MAX1617 chips. */ - -#define SENSORS_MAX1617_PREFIX "max1617" -#define SENSORS_MC1066_PREFIX "mc1066" - -#define SENSORS_MAX1617_TEMP 51 /* R */ -#define SENSORS_MAX1617_TEMP_HYST 52 /* RW */ -#define SENSORS_MAX1617_TEMP_OVER 53 /* RW */ -#define SENSORS_MAX1617_REMOTE_TEMP 54 /* R */ -#define SENSORS_MAX1617_REMOTE_TEMP_HYST 55 /* RW */ -#define SENSORS_MAX1617_REMOTE_TEMP_OVER 56 /* RW */ -#define SENSORS_MAX1617_ALARMS 81 /* R */ - -/* MAX1617A chips. */ - -#define SENSORS_MAX1617A_PREFIX "max1617a" - -#define SENSORS_MAX1617A_TEMP 51 /* R */ -#define SENSORS_MAX1617A_TEMP_HYST 52 /* RW */ -#define SENSORS_MAX1617A_TEMP_OVER 53 /* RW */ -#define SENSORS_MAX1617A_REMOTE_TEMP 54 /* R */ -#define SENSORS_MAX1617A_REMOTE_TEMP_HYST 55 /* RW */ -#define SENSORS_MAX1617A_REMOTE_TEMP_OVER 56 /* RW */ -#define SENSORS_MAX1617A_ALARMS 81 /* R */ - -/* GL518SM chips */ - -#define SENSORS_GL518_PREFIX "gl518sm" - -#define SENSORS_GL518_VDD 1 /* R */ -#define SENSORS_GL518_VIN1 2 /* R */ -#define SENSORS_GL518_VIN2 3 /* R */ -#define SENSORS_GL518_VIN3 4 /* R */ -#define SENSORS_GL518_VDD_MIN 11 /* RW */ -#define SENSORS_GL518_VIN1_MIN 12 /* RW */ -#define SENSORS_GL518_VIN2_MIN 13 /* RW */ -#define SENSORS_GL518_VIN3_MIN 14 /* RW */ -#define SENSORS_GL518_VDD_MAX 21 /* RW */ -#define SENSORS_GL518_VIN1_MAX 22 /* RW */ -#define SENSORS_GL518_VIN2_MAX 23 /* RW */ -#define SENSORS_GL518_VIN3_MAX 24 /* RW */ -#define SENSORS_GL518_FAN1 31 /* R */ -#define SENSORS_GL518_FAN2 32 /* R */ -#define SENSORS_GL518_FAN1_MIN 41 /* RW */ -#define SENSORS_GL518_FAN2_MIN 42 /* RW */ -#define SENSORS_GL518_TEMP 51 /* R */ -#define SENSORS_GL518_TEMP_HYST 52 /* RW */ -#define SENSORS_GL518_TEMP_OVER 53 /* RW */ -#define SENSORS_GL518_FAN1_DIV 71 /* RW */ -#define SENSORS_GL518_FAN2_DIV 72 /* RW */ -#define SENSORS_GL518_ALARMS 81 /* R */ -#define SENSORS_GL518_BEEP_ENABLE 82 /* RW */ -#define SENSORS_GL518_BEEPS 83 /* RW */ -#define SENSORS_GL518_ITERATE 84 /* RW */ -#define SENSORS_GL518_FAN1OFF 85 /* RW */ -#define SENSORS_GL518_FAN1PIN 86 /* RW */ - -/* GL520SM chips */ - -#define SENSORS_GL520_PREFIX "gl520sm" - -#define SENSORS_GL520_VDD 1 /* R */ -#define SENSORS_GL520_VIN1 2 /* R */ -#define SENSORS_GL520_VIN2 3 /* R */ -#define SENSORS_GL520_VIN3 4 /* R */ -#define SENSORS_GL520_VIN4 5 /* R */ -#define SENSORS_GL520_VDD_MIN 11 /* RW */ -#define SENSORS_GL520_VIN1_MIN 12 /* RW */ -#define SENSORS_GL520_VIN2_MIN 13 /* RW */ -#define SENSORS_GL520_VIN3_MIN 14 /* RW */ -#define SENSORS_GL520_VIN4_MIN 15 /* RW */ -#define SENSORS_GL520_VDD_MAX 21 /* RW */ -#define SENSORS_GL520_VIN1_MAX 22 /* RW */ -#define SENSORS_GL520_VIN2_MAX 23 /* RW */ -#define SENSORS_GL520_VIN3_MAX 24 /* RW */ -#define SENSORS_GL520_VIN4_MAX 25 /* RW */ -#define SENSORS_GL520_FAN1 31 /* R */ -#define SENSORS_GL520_FAN2 32 /* R */ -#define SENSORS_GL520_FAN1_MIN 41 /* RW */ -#define SENSORS_GL520_FAN2_MIN 42 /* RW */ -#define SENSORS_GL520_TEMP1 51 /* R */ -#define SENSORS_GL520_TEMP1_HYST 52 /* RW */ -#define SENSORS_GL520_TEMP1_OVER 53 /* RW */ -#define SENSORS_GL520_TEMP2 54 /* R */ -#define SENSORS_GL520_TEMP2_HYST 55 /* RW */ -#define SENSORS_GL520_TEMP2_OVER 56 /* RW */ -#define SENSORS_GL520_VID 61 /* R */ -#define SENSORS_GL520_FAN1_DIV 71 /* RW */ -#define SENSORS_GL520_FAN2_DIV 72 /* RW */ -#define SENSORS_GL520_ALARMS 81 /* R */ -#define SENSORS_GL520_BEEP_ENABLE 82 /* RW */ -#define SENSORS_GL520_BEEPS 83 /* RW */ -#define SENSORS_GL520_TWOTEMPS 84 /* RW */ -#define SENSORS_GL520_FAN1OFF 85 /* RW */ - -/* LM80 chips */ - -#define SENSORS_LM80_PREFIX "lm80" - -#define SENSORS_LM80_IN0 1 /* R */ -#define SENSORS_LM80_IN1 2 /* R */ -#define SENSORS_LM80_IN2 3 /* R */ -#define SENSORS_LM80_IN3 4 /* R */ -#define SENSORS_LM80_IN4 5 /* R */ -#define SENSORS_LM80_IN5 6 /* R */ -#define SENSORS_LM80_IN6 7 /* R */ -#define SENSORS_LM80_IN0_MIN 11 /* RW */ -#define SENSORS_LM80_IN1_MIN 12 /* RW */ -#define SENSORS_LM80_IN2_MIN 13 /* RW */ -#define SENSORS_LM80_IN3_MIN 14 /* RW */ -#define SENSORS_LM80_IN4_MIN 15 /* RW */ -#define SENSORS_LM80_IN5_MIN 16 /* RW */ -#define SENSORS_LM80_IN6_MIN 17 /* RW */ -#define SENSORS_LM80_IN0_MAX 21 /* RW */ -#define SENSORS_LM80_IN1_MAX 22 /* RW */ -#define SENSORS_LM80_IN2_MAX 23 /* RW */ -#define SENSORS_LM80_IN3_MAX 24 /* RW */ -#define SENSORS_LM80_IN4_MAX 25 /* R */ -#define SENSORS_LM80_IN5_MAX 26 /* R */ -#define SENSORS_LM80_IN6_MAX 27 /* R */ -#define SENSORS_LM80_FAN1 31 /* R */ -#define SENSORS_LM80_FAN2 32 /* R */ -#define SENSORS_LM80_FAN1_MIN 41 /* RW */ -#define SENSORS_LM80_FAN2_MIN 42 /* RW */ -#define SENSORS_LM80_TEMP 51 /* R */ -#define SENSORS_LM80_TEMP_HOT_HYST 52 /* RW */ -#define SENSORS_LM80_TEMP_HOT_MAX 53 /* RW */ -#define SENSORS_LM80_TEMP_OS_HYST 54 /* RW */ -#define SENSORS_LM80_TEMP_OS_MAX 55 /* RW */ -#define SENSORS_LM80_FAN1_DIV 71 /* RW */ -#define SENSORS_LM80_FAN2_DIV 72 /* RW */ -#define SENSORS_LM80_ALARMS 81 /* R */ - -/* LM83 chips */ - -#define SENSORS_LM83_PREFIX "lm83" - -#define SENSORS_LM83_LOCAL_TEMP 51 /* R */ -#define SENSORS_LM83_LOCAL_HIGH 52 /* RW */ -#define SENSORS_LM83_REMOTE1_TEMP 54 /* R */ -#define SENSORS_LM83_REMOTE1_HIGH 55 /* RW */ -#define SENSORS_LM83_REMOTE2_TEMP 57 /* R */ -#define SENSORS_LM83_REMOTE2_HIGH 58 /* RW */ -#define SENSORS_LM83_REMOTE3_TEMP 60 /* R */ -#define SENSORS_LM83_REMOTE3_HIGH 61 /* RW */ -#define SENSORS_LM83_TCRIT 80 /* RW */ -#define SENSORS_LM83_ALARMS 81 /* R */ - -/* LM85 chips */ - -#define SENSORS_LM85_PREFIX "lm85" -#define SENSORS_LM85B_PREFIX "lm85b" -#define SENSORS_LM85C_PREFIX "lm85c" -#define SENSORS_ADM1027_PREFIX "adm1027" -#define SENSORS_ADT7463_PREFIX "adt7463" -#define SENSORS_EMC6D100_PREFIX "emc6d100" -#define SENSORS_EMC6D102_PREFIX "emc6d102" - -#define SENSORS_ADM1027_ALARM_MASK 1 /* RW -- alarm_mask */ -#define SENSORS_ADM1027_FAN1_PPR 2 /* RW -- fan1_ppr */ -#define SENSORS_ADM1027_FAN1_TACH_MODE 3 /* RW -- fan1_tach_mode */ -#define SENSORS_ADM1027_FAN2_PPR 4 /* RW -- fan2_ppr */ -#define SENSORS_ADM1027_FAN2_TACH_MODE 5 /* RW -- fan2_tach_mode */ -#define SENSORS_ADM1027_FAN3_PPR 6 /* RW -- fan3_ppr */ -#define SENSORS_ADM1027_FAN3_TACH_MODE 7 /* RW -- fan3_tach_mode */ -#define SENSORS_ADM1027_FAN4_PPR 8 /* RW -- fan4_ppr */ -#define SENSORS_ADM1027_FAN4_TACH_MODE 9 /* RW -- fan4_tach_mode */ -#define SENSORS_ADM1027_PWM1_SMOOTH 10 /* RW -- pwm1_smooth */ -#define SENSORS_ADM1027_PWM2_SMOOTH 11 /* RW -- pwm2_smooth */ -#define SENSORS_ADM1027_PWM3_SMOOTH 12 /* RW -- pwm3_smooth */ -#define SENSORS_ADM1027_TEMP1_OFFSET 13 /* RW -- temp1_offset */ -#define SENSORS_ADM1027_TEMP2_OFFSET 14 /* RW -- temp2_offset */ -#define SENSORS_ADM1027_TEMP3_OFFSET 15 /* RW -- temp3_offset */ -#define SENSORS_LM85_ALARMS 16 /* R -- alarms */ -#define SENSORS_LM85_VID 17 /* R -- vid */ -#define SENSORS_LM85_VRM 18 /* RW -- vrm */ -#define SENSORS_LM85_FAN1 19 /* R -- fan1 */ -#define SENSORS_LM85_FAN1_MIN 20 /* RW -- fan1_min */ -#define SENSORS_LM85_FAN1_TACH_MODE 21 /* RW -- fan1_tach_mode */ -#define SENSORS_LM85_FAN2 22 /* R -- fan2 */ -#define SENSORS_LM85_FAN2_MIN 23 /* RW -- fan2_min */ -#define SENSORS_LM85_FAN2_TACH_MODE 24 /* RW -- fan2_tach_mode */ -#define SENSORS_LM85_FAN3 25 /* R -- fan3 */ -#define SENSORS_LM85_FAN3_MIN 26 /* RW -- fan3_min */ -#define SENSORS_LM85_FAN3_TACH_MODE 27 /* RW -- fan3_tach_mode */ -#define SENSORS_LM85_FAN4 28 /* R -- fan4 */ -#define SENSORS_LM85_FAN4_MIN 29 /* RW -- fan4_min */ -#define SENSORS_LM85_IN0 30 /* R -- in0 */ -#define SENSORS_LM85_IN0_MAX 31 /* RW -- in0_max */ -#define SENSORS_LM85_IN0_MIN 32 /* RW -- in0_min */ -#define SENSORS_LM85_IN1 33 /* R -- in1 */ -#define SENSORS_LM85_IN1_MAX 34 /* RW -- in1_max */ -#define SENSORS_LM85_IN1_MIN 35 /* RW -- in1_min */ -#define SENSORS_LM85_IN2 36 /* R -- in2 */ -#define SENSORS_LM85_IN2_MAX 37 /* RW -- in2_max */ -#define SENSORS_LM85_IN2_MIN 38 /* RW -- in2_min */ -#define SENSORS_LM85_IN3 39 /* R -- in3 */ -#define SENSORS_LM85_IN3_MAX 40 /* RW -- in3_max */ -#define SENSORS_LM85_IN3_MIN 41 /* RW -- in3_min */ -#define SENSORS_LM85_IN4 42 /* R -- in4 */ -#define SENSORS_LM85_IN4_MAX 43 /* RW -- in4_max */ -#define SENSORS_LM85_IN4_MIN 44 /* RW -- in4_min */ -#define SENSORS_LM85_IN5 45 /* R -- in5 */ -#define SENSORS_LM85_IN5_MAX 46 /* RW -- in5_max */ -#define SENSORS_LM85_IN5_MIN 47 /* RW -- in5_min */ -#define SENSORS_LM85_IN6 48 /* R -- in6 */ -#define SENSORS_LM85_IN6_MAX 49 /* RW -- in6_max */ -#define SENSORS_LM85_IN6_MIN 50 /* RW -- in6_min */ -#define SENSORS_LM85_IN7 51 /* R -- in7 */ -#define SENSORS_LM85_IN7_MAX 52 /* RW -- in7_max */ -#define SENSORS_LM85_IN7_MIN 53 /* RW -- in7_min */ -#define SENSORS_LM85_PWM1 54 /* RW -- pwm1 */ -#define SENSORS_LM85_PWM1_FREQ 55 /* RW -- pwm1_freq */ -#define SENSORS_LM85_PWM1_INVERT 56 /* RW -- pwm1_invert */ -#define SENSORS_LM85_PWM1_MIN 57 /* RW -- pwm1_min */ -#define SENSORS_LM85_PWM1_MIN_CTL 58 /* RW -- pwm1_min_ctl */ -#define SENSORS_LM85_PWM1_SPINUP 59 /* RW -- pwm1_spinup */ -#define SENSORS_LM85_PWM1_SPINUP_CTL 60 /* RW -- pwm1_spinup_ctl */ -#define SENSORS_LM85_PWM1_ZONE 61 /* RW -- pwm1_zone */ -#define SENSORS_LM85_PWM2 62 /* RW -- pwm2 */ -#define SENSORS_LM85_PWM2_FREQ 63 /* RW -- pwm2_freq */ -#define SENSORS_LM85_PWM2_INVERT 64 /* RW -- pwm2_invert */ -#define SENSORS_LM85_PWM2_MIN 65 /* RW -- pwm2_min */ -#define SENSORS_LM85_PWM2_MIN_CTL 66 /* RW -- pwm2_min_ctl */ -#define SENSORS_LM85_PWM2_SPINUP 67 /* RW -- pwm2_spinup */ -#define SENSORS_LM85_PWM2_SPINUP_CTL 68 /* RW -- pwm2_spinup_ctl */ -#define SENSORS_LM85_PWM2_ZONE 69 /* RW -- pwm2_zone */ -#define SENSORS_LM85_PWM3 70 /* RW -- pwm3 */ -#define SENSORS_LM85_PWM3_FREQ 71 /* RW -- pwm3_freq */ -#define SENSORS_LM85_PWM3_INVERT 72 /* RW -- pwm3_invert */ -#define SENSORS_LM85_PWM3_MIN 73 /* RW -- pwm3_min */ -#define SENSORS_LM85_PWM3_MIN_CTL 74 /* RW -- pwm3_min_ctl */ -#define SENSORS_LM85_PWM3_SPINUP 75 /* RW -- pwm3_spinup */ -#define SENSORS_LM85_PWM3_SPINUP_CTL 76 /* RW -- pwm3_spinup_ctl */ -#define SENSORS_LM85_PWM3_ZONE 77 /* RW -- pwm3_zone */ -#define SENSORS_LM85_TEMP1 78 /* R -- temp1 */ -#define SENSORS_LM85_TEMP1_MAX 79 /* RW -- temp1_max */ -#define SENSORS_LM85_TEMP1_MIN 80 /* RW -- temp1_min */ -#define SENSORS_LM85_TEMP2 81 /* R -- temp2 */ -#define SENSORS_LM85_TEMP2_MAX 82 /* RW -- temp2_max */ -#define SENSORS_LM85_TEMP2_MIN 83 /* RW -- temp2_min */ -#define SENSORS_LM85_TEMP3 84 /* R -- temp3 */ -#define SENSORS_LM85_TEMP3_MAX 85 /* RW -- temp3_max */ -#define SENSORS_LM85_TEMP3_MIN 86 /* RW -- temp3_min */ -#define SENSORS_LM85_ZONE1_CRITICAL 87 /* RW -- zone1_critical */ -#define SENSORS_LM85_ZONE1_HYST 88 /* RW -- zone1_hyst */ -#define SENSORS_LM85_ZONE1_LIMIT 89 /* RW -- zone1_limit */ -#define SENSORS_LM85_ZONE1_RANGE 90 /* RW -- zone1_range */ -#define SENSORS_LM85_ZONE1_SMOOTH 91 /* RW -- zone1_smooth */ -#define SENSORS_LM85_ZONE2_CRITICAL 92 /* RW -- zone2_critical */ -#define SENSORS_LM85_ZONE2_HYST 93 /* RW -- zone2_hyst */ -#define SENSORS_LM85_ZONE2_LIMIT 94 /* RW -- zone2_limit */ -#define SENSORS_LM85_ZONE2_RANGE 95 /* RW -- zone2_range */ -#define SENSORS_LM85_ZONE2_SMOOTH 96 /* RW -- zone2_smooth */ -#define SENSORS_LM85_ZONE3_CRITICAL 97 /* RW -- zone3_critical */ -#define SENSORS_LM85_ZONE3_HYST 98 /* RW -- zone3_hyst */ -#define SENSORS_LM85_ZONE3_LIMIT 99 /* RW -- zone3_limit */ -#define SENSORS_LM85_ZONE3_RANGE 100 /* RW -- zone3_range */ -#define SENSORS_LM85_ZONE3_SMOOTH 101 /* RW -- zone3_smooth */ - -/* LM86/LM89/LM90/LM99/ADM1032/MAX6657/MAX6680/ADT7461 chips */ - -#define SENSORS_LM90_PREFIX "lm90" -#define SENSORS_ADM1032_PREFIX "adm1032" -#define SENSORS_LM89_PREFIX "lm89" -#define SENSORS_LM99_PREFIX "lm99" -#define SENSORS_LM86_PREFIX "lm86" -#define SENSORS_MAX6657_PREFIX "max6657" -#define SENSORS_MAX6658_PREFIX "max6658" -#define SENSORS_MAX6659_PREFIX "max6659" -#define SENSORS_ADT7461_PREFIX "adt7461" -#define SENSORS_MAX6680_PREFIX "max6680" -#define SENSORS_MAX6681_PREFIX "max6681" -#define SENSORS_MAX6646_PREFIX "max6646" -#define SENSORS_MAX6647_PREFIX "max6647" -#define SENSORS_MAX6649_PREFIX "max6649" - -#define SENSORS_LM90_LOCAL_TEMP 51 /* R */ -#define SENSORS_LM90_LOCAL_HIGH 52 /* RW */ -#define SENSORS_LM90_LOCAL_LOW 53 /* RW */ -#define SENSORS_LM90_LOCAL_TCRIT 54 /* RW */ -#define SENSORS_LM90_REMOTE_TEMP 57 /* R */ -#define SENSORS_LM90_REMOTE_HIGH 58 /* RW */ -#define SENSORS_LM90_REMOTE_LOW 59 /* RW */ -#define SENSORS_LM90_REMOTE_TCRIT 60 /* RW */ -#define SENSORS_LM90_LOCAL_TCRIT_HYST 79 /* RW */ -#define SENSORS_LM90_REMOTE_TCRIT_HYST 80 /* R, see driver source */ -#define SENSORS_LM90_ALARMS 81 /* R */ - -/* LM63 chips */ - -#define SENSORS_LM63_PREFIX "lm63" - -#define SENSORS_LM63_LOCAL_TEMP 51 /* R */ -#define SENSORS_LM63_LOCAL_HIGH 52 /* RW */ -#define SENSORS_LM63_REMOTE_TEMP 57 /* R */ -#define SENSORS_LM63_REMOTE_HIGH 58 /* RW */ -#define SENSORS_LM63_REMOTE_LOW 59 /* RW */ -#define SENSORS_LM63_REMOTE_TCRIT 60 /* R */ -#define SENSORS_LM63_REMOTE_TCRIT_HYST 80 /* RW */ -#define SENSORS_LM63_ALARMS 81 /* R */ -#define SENSORS_LM63_FAN 84 /* R */ -#define SENSORS_LM63_FAN_LOW 85 /* RW */ -#define SENSORS_LM63_PWM 87 /* RW */ -#define SENSORS_LM63_PWM_ENABLE 88 /* RW */ - -/* Winbond W83781D chips */ - -#define SENSORS_W83781D_PREFIX "w83781d" - -#define SENSORS_W83781D_IN0 1 /* R */ -#define SENSORS_W83781D_IN1 2 /* R */ -#define SENSORS_W83781D_IN2 3 /* R */ -#define SENSORS_W83781D_IN3 4 /* R */ -#define SENSORS_W83781D_IN4 5 /* R */ -#define SENSORS_W83781D_IN5 6 /* R */ -#define SENSORS_W83781D_IN6 7 /* R */ -#define SENSORS_W83781D_IN0_MIN 11 /* RW */ -#define SENSORS_W83781D_IN1_MIN 12 /* RW */ -#define SENSORS_W83781D_IN2_MIN 13 /* RW */ -#define SENSORS_W83781D_IN3_MIN 14 /* RW */ -#define SENSORS_W83781D_IN4_MIN 15 /* RW */ -#define SENSORS_W83781D_IN5_MIN 16 /* RW */ -#define SENSORS_W83781D_IN6_MIN 17 /* RW */ -#define SENSORS_W83781D_IN0_MAX 21 /* RW */ -#define SENSORS_W83781D_IN1_MAX 22 /* RW */ -#define SENSORS_W83781D_IN2_MAX 23 /* RW */ -#define SENSORS_W83781D_IN3_MAX 24 /* RW */ -#define SENSORS_W83781D_IN4_MAX 25 /* RW */ -#define SENSORS_W83781D_IN5_MAX 26 /* RW */ -#define SENSORS_W83781D_IN6_MAX 27 /* RW */ -#define SENSORS_W83781D_FAN1 31 /* R */ -#define SENSORS_W83781D_FAN2 32 /* R */ -#define SENSORS_W83781D_FAN3 33 /* R */ -#define SENSORS_W83781D_FAN1_MIN 41 /* RW */ -#define SENSORS_W83781D_FAN2_MIN 42 /* RW */ -#define SENSORS_W83781D_FAN3_MIN 43 /* RW */ -#define SENSORS_W83781D_TEMP1 51 /* R */ -#define SENSORS_W83781D_TEMP1_HYST 52 /* RW */ -#define SENSORS_W83781D_TEMP1_OVER 53 /* RW */ -#define SENSORS_W83781D_TEMP2 54 /* R */ -#define SENSORS_W83781D_TEMP2_HYST 55 /* RW */ -#define SENSORS_W83781D_TEMP2_OVER 56 /* RW */ -#define SENSORS_W83781D_TEMP3 57 /* R */ -#define SENSORS_W83781D_TEMP3_HYST 58 /* RW */ -#define SENSORS_W83781D_TEMP3_OVER 59 /* RW */ -#define SENSORS_W83781D_VID 61 /* R */ -#define SENSORS_W83781D_VRM 62 /* RW */ -#define SENSORS_W83781D_FAN1_DIV 71 /* RW */ -#define SENSORS_W83781D_FAN2_DIV 72 /* RW */ -#define SENSORS_W83781D_FAN3_DIV 73 /* R (yes, really! */ -#define SENSORS_W83781D_ALARMS 81 /* R */ -#define SENSORS_W83781D_BEEP_ENABLE 82 /* RW */ -#define SENSORS_W83781D_BEEPS 83 /* RW */ -#define SENSORS_W83781D_SENS1 91 /* RW */ -#define SENSORS_W83781D_SENS2 92 /* RW */ -#define SENSORS_W83781D_SENS3 93 /* RW */ - - -/* Winbond W83782D chips */ -/* Cheat on 627HF for now - no separate #defines */ -/* Cheat on 127F for now - no separate #defines */ - -#define SENSORS_W83782D_PREFIX "w83782d" -#define SENSORS_W83627HF_PREFIX "w83627hf" -#define SENSORS_W83627THF_PREFIX "w83627thf" -#define SENSORS_W83637HF_PREFIX "w83637hf" -#define SENSORS_W83687THF_PREFIX "w83687thf" - -#define SENSORS_W83791D_PREFIX "w83791d" - - -#define SENSORS_W83791D_IN0 1 /* R */ -#define SENSORS_W83791D_IN1 2 /* R */ -#define SENSORS_W83791D_IN2 3 /* R */ -#define SENSORS_W83791D_IN3 4 /* R */ -#define SENSORS_W83791D_IN4 5 /* R */ -#define SENSORS_W83791D_IN5 6 /* R */ -#define SENSORS_W83791D_IN6 7 /* R */ -#define SENSORS_W83791D_IN7 8 /* R */ -#define SENSORS_W83791D_IN8 9 /* R */ -#define SENSORS_W83791D_IN9 10 /* R */ - -#define SENSORS_W83791D_IN0_MIN 11 /* RW */ -#define SENSORS_W83791D_IN1_MIN 12 /* RW */ -#define SENSORS_W83791D_IN2_MIN 13 /* RW */ -#define SENSORS_W83791D_IN3_MIN 14 /* RW */ -#define SENSORS_W83791D_IN4_MIN 15 /* RW */ -#define SENSORS_W83791D_IN5_MIN 16 /* RW */ -#define SENSORS_W83791D_IN6_MIN 17 /* RW */ -#define SENSORS_W83791D_IN7_MIN 18 /* RW */ -#define SENSORS_W83791D_IN8_MIN 19 /* RW */ -#define SENSORS_W83791D_IN9_MIN 20 /* RW */ - -#define SENSORS_W83791D_IN0_MAX 21 /* RW */ -#define SENSORS_W83791D_IN1_MAX 22 /* RW */ -#define SENSORS_W83791D_IN2_MAX 23 /* RW */ -#define SENSORS_W83791D_IN3_MAX 24 /* RW */ -#define SENSORS_W83791D_IN4_MAX 25 /* RW */ -#define SENSORS_W83791D_IN5_MAX 26 /* RW */ -#define SENSORS_W83791D_IN6_MAX 27 /* RW */ -#define SENSORS_W83791D_IN7_MAX 28 /* RW */ -#define SENSORS_W83791D_IN8_MAX 29 /* RW */ -#define SENSORS_W83791D_IN9_MAX 30 /* RW */ - -#define SENSORS_W83791D_FAN1 31 /* R */ -#define SENSORS_W83791D_FAN2 32 /* R */ -#define SENSORS_W83791D_FAN3 33 /* R */ -#define SENSORS_W83791D_FAN4 34 /* R */ -#define SENSORS_W83791D_FAN5 35 /* R */ - -#define SENSORS_W83791D_FAN1_MIN 41 /* RW */ -#define SENSORS_W83791D_FAN2_MIN 42 /* RW */ -#define SENSORS_W83791D_FAN3_MIN 43 /* RW */ -#define SENSORS_W83791D_FAN4_MIN 44 /* RW */ -#define SENSORS_W83791D_FAN5_MIN 45 /* RW */ - -#define SENSORS_W83791D_TEMP1 51 /* R */ -#define SENSORS_W83791D_TEMP1_HYST 52 /* RW */ -#define SENSORS_W83791D_TEMP1_OVER 53 /* RW */ -#define SENSORS_W83791D_TEMP2 54 /* R */ -#define SENSORS_W83791D_TEMP2_HYST 55 /* RW */ -#define SENSORS_W83791D_TEMP2_OVER 56 /* RW */ -#define SENSORS_W83791D_TEMP3 57 /* R */ -#define SENSORS_W83791D_TEMP3_HYST 58 /* RW */ -#define SENSORS_W83791D_TEMP3_OVER 59 /* RW */ -#define SENSORS_W83791D_VID 61 /* R */ -#define SENSORS_W83791D_VRM 62 /* RW */ - -#define SENSORS_W83791D_FAN1_DIV 71 /* RW */ -#define SENSORS_W83791D_FAN2_DIV 72 /* RW */ -#define SENSORS_W83791D_FAN3_DIV 73 /* R (yes, really! */ -#define SENSORS_W83791D_FAN4_DIV 74 /* R (yes, really! */ -#define SENSORS_W83791D_FAN5_DIV 75 /* R (yes, really! */ - -#define SENSORS_W83791D_ALARMS 81 /* R */ -#define SENSORS_W83791D_BEEP_ENABLE 82 /* RW */ -#define SENSORS_W83791D_BEEPS 83 /* RW */ -#define SENSORS_W83791D_SENS1 91 /* RW */ -#define SENSORS_W83791D_SENS2 92 /* RW */ -#define SENSORS_W83791D_SENS3 93 /* RW */ - - - -/* Winbond W83792AD/D chip */ -#define SENSORS_W83792D_PREFIX "w83792d" - - -#define SENSORS_W83792D_IN0 1 /* R */ -#define SENSORS_W83792D_IN1 2 /* R */ -#define SENSORS_W83792D_IN2 3 /* R */ -#define SENSORS_W83792D_IN3 4 /* R */ -#define SENSORS_W83792D_IN4 5 /* R */ -#define SENSORS_W83792D_IN5 6 /* R */ -#define SENSORS_W83792D_IN6 7 /* R */ -#define SENSORS_W83792D_IN7 8 /* R */ -#define SENSORS_W83792D_IN8 9 /* R */ -#define SENSORS_W83792D_IN9 10 /* R */ - -#define SENSORS_W83792D_IN0_MIN 11 /* RW */ -#define SENSORS_W83792D_IN1_MIN 12 /* RW */ -#define SENSORS_W83792D_IN2_MIN 13 /* RW */ -#define SENSORS_W83792D_IN3_MIN 14 /* RW */ -#define SENSORS_W83792D_IN4_MIN 15 /* RW */ -#define SENSORS_W83792D_IN5_MIN 16 /* RW */ -#define SENSORS_W83792D_IN6_MIN 17 /* RW */ -#define SENSORS_W83792D_IN7_MIN 18 /* RW */ -#define SENSORS_W83792D_IN8_MIN 19 /* RW */ -#define SENSORS_W83792D_IN9_MIN 20 /* RW */ - -#define SENSORS_W83792D_IN0_MAX 21 /* RW */ -#define SENSORS_W83792D_IN1_MAX 22 /* RW */ -#define SENSORS_W83792D_IN2_MAX 23 /* RW */ -#define SENSORS_W83792D_IN3_MAX 24 /* RW */ -#define SENSORS_W83792D_IN4_MAX 25 /* RW */ -#define SENSORS_W83792D_IN5_MAX 26 /* RW */ -#define SENSORS_W83792D_IN6_MAX 27 /* RW */ -#define SENSORS_W83792D_IN7_MAX 28 /* RW */ -#define SENSORS_W83792D_IN8_MAX 29 /* RW */ -#define SENSORS_W83792D_IN9_MAX 30 /* RW */ - -#define SENSORS_W83792D_FAN1 31 /* R */ -#define SENSORS_W83792D_FAN2 32 /* R */ -#define SENSORS_W83792D_FAN3 33 /* R */ -#define SENSORS_W83792D_FAN4 34 /* R */ -#define SENSORS_W83792D_FAN5 35 /* R */ -#define SENSORS_W83792D_FAN6 36 /* R */ -#define SENSORS_W83792D_FAN7 37 /* R */ - -#define SENSORS_W83792D_FAN1_MIN 41 /* RW */ -#define SENSORS_W83792D_FAN2_MIN 42 /* RW */ -#define SENSORS_W83792D_FAN3_MIN 43 /* RW */ -#define SENSORS_W83792D_FAN4_MIN 44 /* RW */ -#define SENSORS_W83792D_FAN5_MIN 45 /* RW */ -#define SENSORS_W83792D_FAN6_MIN 46 /* RW */ -#define SENSORS_W83792D_FAN7_MIN 47 /* RW */ - -#define SENSORS_W83792D_TEMP1 51 /* R */ -#define SENSORS_W83792D_TEMP1_HYST 52 /* RW */ -#define SENSORS_W83792D_TEMP1_OVER 53 /* RW */ -#define SENSORS_W83792D_TEMP2 54 /* R */ -#define SENSORS_W83792D_TEMP2_HYST 55 /* RW */ -#define SENSORS_W83792D_TEMP2_OVER 56 /* RW */ -#define SENSORS_W83792D_TEMP3 57 /* R */ -#define SENSORS_W83792D_TEMP3_HYST 58 /* RW */ -#define SENSORS_W83792D_TEMP3_OVER 59 /* RW */ -/*#define SENSORS_W83792D_VID 61 */ /* R */ -/*#define SENSORS_W83792D_VRM 62 */ /* RW */ -#define SENSORS_W83792D_CHASSIS 63 /* R */ -#define SENSORS_W83792D_ALARMS 64 /* R */ - -#define SENSORS_W83792D_FAN1_DIV 71 /* RW */ -#define SENSORS_W83792D_FAN2_DIV 72 /* RW */ -#define SENSORS_W83792D_FAN3_DIV 73 /* RW */ -#define SENSORS_W83792D_FAN4_DIV 74 /* RW */ -#define SENSORS_W83792D_FAN5_DIV 75 /* RW */ -#define SENSORS_W83792D_FAN6_DIV 76 /* RW */ -#define SENSORS_W83792D_FAN7_DIV 77 /* RW */ - - -/* Winbond W83793R chip */ -#define SENSORS_W83793_PREFIX "w83793" - -#define SENSORS_W83793_IN(n) (0 + (n)) /* n(0-9) R */ -#define SENSORS_W83793_IN_MIN(n) (20 + (n)) /* n(0-9) RW */ -#define SENSORS_W83793_IN_MAX(n) (40 + (n)) /* n(0-9) RW */ -#define SENSORS_W83793_IN_ALARM(n) (60 + (n)) /* n(0-9) R */ - -#define SENSORS_W83793_FAN(n) (80 + (n)) /* n(1-12) R */ -#define SENSORS_W83793_FAN_MIN(n) (100 + (n)) /* n(1-12) RW */ -#define SENSORS_W83793_FAN_ALARM(n) (120 + (n)) /* n(1-12) R */ - - -#define SENSORS_W83793_TEMP(n) (140 + (n)) /* n(1-6) R */ -#define SENSORS_W83793_TEMP_CRIT(n) (160 + (n)) /* n(1-6) RW */ -#define SENSORS_W83793_TEMP_CRIT_HYST(n) (180 + (n)) /* n(1-6) RW */ -#define SENSORS_W83793_TEMP_ALARM(n) (200 + (n)) /* n(1-6) R */ - -#define SENSORS_W83793_VID0 221 /* R */ -#define SENSORS_W83793_VID1 222 /* R */ -#define SENSORS_W83793_VRM 230 /* RW */ -#define SENSORS_W83793_CHASSIS 240 /* RW */ - - -#define SENSORS_AS99127F_PREFIX "as99127f" - -#define SENSORS_W83782D_IN0 1 /* R */ -#define SENSORS_W83782D_IN1 2 /* R */ -#define SENSORS_W83782D_IN2 3 /* R */ -#define SENSORS_W83782D_IN3 4 /* R */ -#define SENSORS_W83782D_IN4 5 /* R */ -#define SENSORS_W83782D_IN5 6 /* R */ -#define SENSORS_W83782D_IN6 7 /* R */ -#define SENSORS_W83782D_IN7 8 /* R */ -#define SENSORS_W83782D_IN8 9 /* R */ -#define SENSORS_W83782D_IN0_MIN 11 /* RW */ -#define SENSORS_W83782D_IN1_MIN 12 /* RW */ -#define SENSORS_W83782D_IN2_MIN 13 /* RW */ -#define SENSORS_W83782D_IN3_MIN 14 /* RW */ -#define SENSORS_W83782D_IN4_MIN 15 /* RW */ -#define SENSORS_W83782D_IN5_MIN 16 /* RW */ -#define SENSORS_W83782D_IN6_MIN 17 /* RW */ -#define SENSORS_W83782D_IN7_MIN 18 /* RW */ -#define SENSORS_W83782D_IN8_MIN 19 /* RW */ -#define SENSORS_W83782D_IN0_MAX 21 /* RW */ -#define SENSORS_W83782D_IN1_MAX 22 /* RW */ -#define SENSORS_W83782D_IN2_MAX 23 /* RW */ -#define SENSORS_W83782D_IN3_MAX 24 /* RW */ -#define SENSORS_W83782D_IN4_MAX 25 /* RW */ -#define SENSORS_W83782D_IN5_MAX 26 /* RW */ -#define SENSORS_W83782D_IN6_MAX 27 /* RW */ -#define SENSORS_W83782D_IN7_MAX 28 /* RW */ -#define SENSORS_W83782D_IN8_MAX 29 /* RW */ -#define SENSORS_W83782D_FAN1 31 /* R */ -#define SENSORS_W83782D_FAN2 32 /* R */ -#define SENSORS_W83782D_FAN3 33 /* R */ -#define SENSORS_W83782D_FAN1_MIN 41 /* RW */ -#define SENSORS_W83782D_FAN2_MIN 42 /* RW */ -#define SENSORS_W83782D_FAN3_MIN 43 /* RW */ -#define SENSORS_W83782D_TEMP1 51 /* R */ -#define SENSORS_W83782D_TEMP1_HYST 52 /* RW */ -#define SENSORS_W83782D_TEMP1_OVER 53 /* RW */ -#define SENSORS_W83782D_TEMP2 54 /* R */ -#define SENSORS_W83782D_TEMP2_HYST 55 /* RW */ -#define SENSORS_W83782D_TEMP2_OVER 56 /* RW */ -#define SENSORS_W83782D_TEMP3 57 /* R */ -#define SENSORS_W83782D_TEMP3_HYST 58 /* RW */ -#define SENSORS_W83782D_TEMP3_OVER 59 /* RW */ -#define SENSORS_W83782D_VID 61 /* R */ -#define SENSORS_W83782D_VRM 62 /* RW */ -#define SENSORS_W83782D_FAN1_DIV 71 /* RW */ -#define SENSORS_W83782D_FAN2_DIV 72 /* RW */ -#define SENSORS_W83782D_FAN3_DIV 73 /* R (yes, really! */ -#define SENSORS_W83782D_ALARMS 81 /* R */ -#define SENSORS_W83782D_BEEP_ENABLE 82 /* RW */ -#define SENSORS_W83782D_BEEPS 83 /* RW */ -#define SENSORS_W83782D_SENS1 91 /* RW */ -#define SENSORS_W83782D_SENS2 92 /* RW */ -#define SENSORS_W83782D_SENS3 93 /* RW */ - - -/* Winbond W83783S chips */ -/* Cheat on 697HF for now - no separate #defines */ - -#define SENSORS_W83783S_PREFIX "w83783s" -#define SENSORS_W83697HF_PREFIX "w83697hf" - -#define SENSORS_W83783S_IN0 1 /* R */ -#define SENSORS_W83783S_IN1 2 /* R */ -#define SENSORS_W83783S_IN2 3 /* R */ -#define SENSORS_W83783S_IN3 4 /* R */ -#define SENSORS_W83783S_IN4 5 /* R */ -#define SENSORS_W83783S_IN5 6 /* R */ -#define SENSORS_W83783S_IN6 7 /* R */ -#define SENSORS_W83783S_IN0_MIN 11 /* RW */ -#define SENSORS_W83783S_IN1_MIN 12 /* RW */ -#define SENSORS_W83783S_IN2_MIN 13 /* RW */ -#define SENSORS_W83783S_IN3_MIN 14 /* RW */ -#define SENSORS_W83783S_IN4_MIN 15 /* RW */ -#define SENSORS_W83783S_IN5_MIN 16 /* RW */ -#define SENSORS_W83783S_IN6_MIN 17 /* RW */ -#define SENSORS_W83783S_IN0_MAX 21 /* RW */ -#define SENSORS_W83783S_IN1_MAX 22 /* RW */ -#define SENSORS_W83783S_IN2_MAX 23 /* RW */ -#define SENSORS_W83783S_IN3_MAX 24 /* RW */ -#define SENSORS_W83783S_IN4_MAX 25 /* RW */ -#define SENSORS_W83783S_IN5_MAX 26 /* RW */ -#define SENSORS_W83783S_IN6_MAX 27 /* RW */ -#define SENSORS_W83783S_FAN1 31 /* R */ -#define SENSORS_W83783S_FAN2 32 /* R */ -#define SENSORS_W83783S_FAN3 33 /* R */ -#define SENSORS_W83783S_FAN1_MIN 41 /* RW */ -#define SENSORS_W83783S_FAN2_MIN 42 /* RW */ -#define SENSORS_W83783S_FAN3_MIN 43 /* RW */ -#define SENSORS_W83783S_TEMP1 51 /* R */ -#define SENSORS_W83783S_TEMP1_HYST 52 /* RW */ -#define SENSORS_W83783S_TEMP1_OVER 53 /* RW */ -#define SENSORS_W83783S_TEMP2 54 /* R */ -#define SENSORS_W83783S_TEMP2_HYST 55 /* RW */ -#define SENSORS_W83783S_TEMP2_OVER 56 /* RW */ -#define SENSORS_W83783S_VID 61 /* R */ -#define SENSORS_W83783S_VRM 62 /* RW */ -#define SENSORS_W83783S_FAN1_DIV 71 /* RW */ -#define SENSORS_W83783S_FAN2_DIV 72 /* RW */ -#define SENSORS_W83783S_FAN3_DIV 73 /* R (yes, really! */ -#define SENSORS_W83783S_ALARMS 81 /* R */ -#define SENSORS_W83783S_BEEP_ENABLE 82 /* RW */ -#define SENSORS_W83783S_BEEPS 83 /* RW */ -#define SENSORS_W83783S_SENS1 91 /* RW */ -#define SENSORS_W83783S_SENS2 92 /* RW */ - - -/* W83L785TS-S chips */ - -#define SENSORS_W83L785TS_PREFIX "w83l785ts" - -#define SENSORS_W83L785TS_TEMP 51 /* R */ -#define SENSORS_W83L785TS_TEMP_OVER 52 /* R for now */ - - -/* Winbond W83627EHF & W83627DHG Super-I/O chips */ -/* (W83627DHG is similar to W83627EHF but no in9) */ - -#define SENSORS_W83627EHF_PREFIX "w83627ehf" -#define SENSORS_W83627DHG_PREFIX "w83627dhg" - -#define SENSORS_W83627EHF_IN0 1 /* R */ -#define SENSORS_W83627EHF_IN1 2 /* R */ -#define SENSORS_W83627EHF_IN2 3 /* R */ -#define SENSORS_W83627EHF_IN3 4 /* R */ -#define SENSORS_W83627EHF_IN4 5 /* R */ -#define SENSORS_W83627EHF_IN5 6 /* R */ -#define SENSORS_W83627EHF_IN6 7 /* R */ -#define SENSORS_W83627EHF_IN7 8 /* R */ -#define SENSORS_W83627EHF_IN8 9 /* R */ -#define SENSORS_W83627EHF_IN9 10 /* R */ -#define SENSORS_W83627EHF_IN0_ALARM 111 /* R */ -#define SENSORS_W83627EHF_IN1_ALARM 112 /* R */ -#define SENSORS_W83627EHF_IN2_ALARM 113 /* R */ -#define SENSORS_W83627EHF_IN3_ALARM 114 /* R */ -#define SENSORS_W83627EHF_IN4_ALARM 115 /* R */ -#define SENSORS_W83627EHF_IN5_ALARM 116 /* R */ -#define SENSORS_W83627EHF_IN6_ALARM 117 /* R */ -#define SENSORS_W83627EHF_IN7_ALARM 118 /* R */ -#define SENSORS_W83627EHF_IN8_ALARM 119 /* R */ -#define SENSORS_W83627EHF_IN9_ALARM 120 /* R */ -#define SENSORS_W83627EHF_IN0_MIN 11 /* RW */ -#define SENSORS_W83627EHF_IN1_MIN 12 /* RW */ -#define SENSORS_W83627EHF_IN2_MIN 13 /* RW */ -#define SENSORS_W83627EHF_IN3_MIN 14 /* RW */ -#define SENSORS_W83627EHF_IN4_MIN 15 /* RW */ -#define SENSORS_W83627EHF_IN5_MIN 16 /* RW */ -#define SENSORS_W83627EHF_IN6_MIN 17 /* RW */ -#define SENSORS_W83627EHF_IN7_MIN 18 /* RW */ -#define SENSORS_W83627EHF_IN8_MIN 19 /* RW */ -#define SENSORS_W83627EHF_IN9_MIN 20 /* RW */ -#define SENSORS_W83627EHF_IN0_MAX 21 /* RW */ -#define SENSORS_W83627EHF_IN1_MAX 22 /* RW */ -#define SENSORS_W83627EHF_IN2_MAX 23 /* RW */ -#define SENSORS_W83627EHF_IN3_MAX 24 /* RW */ -#define SENSORS_W83627EHF_IN4_MAX 25 /* RW */ -#define SENSORS_W83627EHF_IN5_MAX 26 /* RW */ -#define SENSORS_W83627EHF_IN6_MAX 27 /* RW */ -#define SENSORS_W83627EHF_IN7_MAX 28 /* RW */ -#define SENSORS_W83627EHF_IN8_MAX 29 /* RW */ -#define SENSORS_W83627EHF_IN9_MAX 30 /* RW */ -#define SENSORS_W83627EHF_FAN1 31 /* R */ -#define SENSORS_W83627EHF_FAN2 32 /* R */ -#define SENSORS_W83627EHF_FAN3 33 /* R */ -#define SENSORS_W83627EHF_FAN4 34 /* R */ -#define SENSORS_W83627EHF_FAN5 35 /* R */ -#define SENSORS_W83627EHF_FAN1_ALARM 131 /* R */ -#define SENSORS_W83627EHF_FAN2_ALARM 132 /* R */ -#define SENSORS_W83627EHF_FAN3_ALARM 133 /* R */ -#define SENSORS_W83627EHF_FAN4_ALARM 134 /* R */ -#define SENSORS_W83627EHF_FAN5_ALARM 135 /* R */ -#define SENSORS_W83627EHF_FAN1_MIN 41 /* RW */ -#define SENSORS_W83627EHF_FAN2_MIN 42 /* RW */ -#define SENSORS_W83627EHF_FAN3_MIN 43 /* RW */ -#define SENSORS_W83627EHF_FAN4_MIN 44 /* RW */ -#define SENSORS_W83627EHF_FAN5_MIN 45 /* RW */ -#define SENSORS_W83627EHF_FAN1_DIV 51 /* RW */ -#define SENSORS_W83627EHF_FAN2_DIV 52 /* RW */ -#define SENSORS_W83627EHF_FAN3_DIV 53 /* RW */ -#define SENSORS_W83627EHF_FAN4_DIV 54 /* RW */ -#define SENSORS_W83627EHF_FAN5_DIV 55 /* RW */ -#define SENSORS_W83627EHF_TEMP1 61 /* R */ -#define SENSORS_W83627EHF_TEMP2 62 /* R */ -#define SENSORS_W83627EHF_TEMP3 63 /* R */ -#define SENSORS_W83627EHF_TEMP1_ALARM 161 /* R */ -#define SENSORS_W83627EHF_TEMP2_ALARM 162 /* R */ -#define SENSORS_W83627EHF_TEMP3_ALARM 163 /* R */ -#define SENSORS_W83627EHF_TEMP1_OVER 71 /* RW */ -#define SENSORS_W83627EHF_TEMP2_OVER 72 /* RW */ -#define SENSORS_W83627EHF_TEMP3_OVER 73 /* RW */ -#define SENSORS_W83627EHF_TEMP1_HYST 81 /* RW */ -#define SENSORS_W83627EHF_TEMP2_HYST 82 /* RW */ -#define SENSORS_W83627EHF_TEMP3_HYST 83 /* RW */ -#define SENSORS_W83627EHF_TEMP1_TYPE 91 /* R */ -#define SENSORS_W83627EHF_TEMP2_TYPE 92 /* R */ -#define SENSORS_W83627EHF_TEMP3_TYPE 93 /* R */ -#define SENSORS_W83627EHF_VID 245 /* R */ -#define SENSORS_W83627EHF_VRM 249 /* R */ -#define SENSORS_W83627EHF_ALARMS 250 /* R */ - - -/* Analog Devices ADM9240 chips */ - -#define SENSORS_ADM9240_PREFIX "adm9240" -#define SENSORS_LM81_PREFIX "lm81" -#define SENSORS_DS1780_PREFIX "ds1780" - -/* All three chips have the same features */ -#define SENSORS_ADM9240_IN0 1 /* R */ -#define SENSORS_ADM9240_IN1 2 /* R */ -#define SENSORS_ADM9240_IN2 3 /* R */ -#define SENSORS_ADM9240_IN3 4 /* R */ -#define SENSORS_ADM9240_IN4 5 /* R */ -#define SENSORS_ADM9240_IN5 6 /* R */ -#define SENSORS_ADM9240_IN0_MIN 11 /* RW */ -#define SENSORS_ADM9240_IN1_MIN 12 /* RW */ -#define SENSORS_ADM9240_IN2_MIN 13 /* RW */ -#define SENSORS_ADM9240_IN3_MIN 14 /* RW */ -#define SENSORS_ADM9240_IN4_MIN 15 /* RW */ -#define SENSORS_ADM9240_IN5_MIN 16 /* RW */ -#define SENSORS_ADM9240_IN0_MAX 21 /* RW */ -#define SENSORS_ADM9240_IN1_MAX 22 /* RW */ -#define SENSORS_ADM9240_IN2_MAX 23 /* RW */ -#define SENSORS_ADM9240_IN3_MAX 24 /* RW */ -#define SENSORS_ADM9240_IN4_MAX 25 /* RW */ -#define SENSORS_ADM9240_IN5_MAX 26 /* RW */ -#define SENSORS_ADM9240_FAN1 31 /* R */ -#define SENSORS_ADM9240_FAN2 32 /* R */ -#define SENSORS_ADM9240_FAN1_MIN 41 /* RW */ -#define SENSORS_ADM9240_FAN2_MIN 42 /* RW */ -#define SENSORS_ADM9240_TEMP 51 /* R */ -#define SENSORS_ADM9240_TEMP_HYST 52 /* RW */ -#define SENSORS_ADM9240_TEMP_OVER 53 /* RW */ -#define SENSORS_ADM9240_VID 61 /* R */ -#define SENSORS_ADM9240_FAN1_DIV 71 /* RW */ -#define SENSORS_ADM9240_FAN2_DIV 72 /* RW */ -#define SENSORS_ADM9240_ALARMS 81 /* R */ -#define SENSORS_ADM9240_ANALOG_OUT 82 /* RW */ - - -/* SiS southbridge with integrated lm78 */ - -#define SENSORS_SIS5595_PREFIX "sis5595" - -#define SENSORS_SIS5595_IN0 1 /* R */ -#define SENSORS_SIS5595_IN1 2 /* R */ -#define SENSORS_SIS5595_IN2 3 /* R */ -#define SENSORS_SIS5595_IN3 4 /* R */ -#define SENSORS_SIS5595_IN4 5 /* R */ -#define SENSORS_SIS5595_IN0_MIN 11 /* RW */ -#define SENSORS_SIS5595_IN1_MIN 12 /* RW */ -#define SENSORS_SIS5595_IN2_MIN 13 /* RW */ -#define SENSORS_SIS5595_IN3_MIN 14 /* RW */ -#define SENSORS_SIS5595_IN4_MIN 15 /* RW */ -#define SENSORS_SIS5595_IN0_MAX 21 /* RW */ -#define SENSORS_SIS5595_IN1_MAX 22 /* RW */ -#define SENSORS_SIS5595_IN2_MAX 23 /* RW */ -#define SENSORS_SIS5595_IN3_MAX 24 /* RW */ -#define SENSORS_SIS5595_IN4_MAX 25 /* RW */ -#define SENSORS_SIS5595_FAN1 31 /* R */ -#define SENSORS_SIS5595_FAN2 32 /* R */ -#define SENSORS_SIS5595_FAN1_MIN 41 /* RW */ -#define SENSORS_SIS5595_FAN2_MIN 42 /* RW */ -#define SENSORS_SIS5595_TEMP 51 /* R */ -#define SENSORS_SIS5595_TEMP_HYST 52 /* RW */ -#define SENSORS_SIS5595_TEMP_OVER 53 /* RW */ -#define SENSORS_SIS5595_FAN1_DIV 71 /* RW */ -#define SENSORS_SIS5595_FAN2_DIV 72 /* RW */ -#define SENSORS_SIS5595_ALARMS 81 /* R */ - - -/* HP MaxiLife chips */ - -#define SENSORS_MAXI_CG_PREFIX "maxilife-cg" -#define SENSORS_MAXI_CO_PREFIX "maxilife-co" -#define SENSORS_MAXI_AS_PREFIX "maxilife-as" -#define SENSORS_MAXI_NBA_PREFIX "maxilife-nba" - -#define SENSORS_MAXI_CG_FAN1 1 /* R */ -#define SENSORS_MAXI_CG_FAN2 2 /* R */ -#define SENSORS_MAXI_CG_FAN3 3 /* R */ -#define SENSORS_MAXI_CG_FAN1_MIN 11 /* RW */ -#define SENSORS_MAXI_CG_FAN2_MIN 12 /* RW */ -#define SENSORS_MAXI_CG_FAN3_MIN 13 /* RW */ -#define SENSORS_MAXI_CG_FAN1_DIV 14 /* R */ -#define SENSORS_MAXI_CG_FAN2_DIV 15 /* R */ -#define SENSORS_MAXI_CG_FAN3_DIV 16 /* R */ -#define SENSORS_MAXI_CG_TEMP1 21 /* R */ -#define SENSORS_MAXI_CG_TEMP2 22 /* R */ -#define SENSORS_MAXI_CG_TEMP3 23 /* R */ -#define SENSORS_MAXI_CG_TEMP4 24 /* R */ -#define SENSORS_MAXI_CG_TEMP5 25 /* R */ -#define SENSORS_MAXI_CG_TEMP1_MAX 31 /* R */ -#define SENSORS_MAXI_CG_TEMP2_MAX 32 /* R */ -#define SENSORS_MAXI_CG_TEMP3_MAX 33 /* R */ -#define SENSORS_MAXI_CG_TEMP4_MAX 34 /* R */ -#define SENSORS_MAXI_CG_TEMP5_MAX 35 /* R */ -#define SENSORS_MAXI_CG_TEMP1_HYST 41 /* R */ -#define SENSORS_MAXI_CG_TEMP2_HYST 42 /* R */ -#define SENSORS_MAXI_CG_TEMP3_HYST 43 /* R */ -#define SENSORS_MAXI_CG_TEMP4_HYST 44 /* R */ -#define SENSORS_MAXI_CG_TEMP5_HYST 45 /* R */ -#define SENSORS_MAXI_CG_PLL 51 /* R */ -#define SENSORS_MAXI_CG_PLL_MIN 52 /* RW */ -#define SENSORS_MAXI_CG_PLL_MAX 53 /* RW */ -#define SENSORS_MAXI_CG_VID1 61 /* R */ -#define SENSORS_MAXI_CG_VID2 62 /* R */ -#define SENSORS_MAXI_CG_VID3 63 /* R */ -#define SENSORS_MAXI_CG_VID4 64 /* R */ -#define SENSORS_MAXI_CG_VID1_MIN 71 /* RW */ -#define SENSORS_MAXI_CG_VID2_MIN 72 /* RW */ -#define SENSORS_MAXI_CG_VID3_MIN 73 /* RW */ -#define SENSORS_MAXI_CG_VID4_MIN 74 /* RW */ -#define SENSORS_MAXI_CG_VID1_MAX 81 /* RW */ -#define SENSORS_MAXI_CG_VID2_MAX 82 /* RW */ -#define SENSORS_MAXI_CG_VID3_MAX 83 /* RW */ -#define SENSORS_MAXI_CG_VID4_MAX 84 /* RW */ -#define SENSORS_MAXI_CG_ALARMS 91 /* R */ - -#define SENSORS_MAXI_CO_FAN1 1 /* R */ -#define SENSORS_MAXI_CO_FAN2 2 /* R */ -#define SENSORS_MAXI_CO_FAN3 3 /* R */ -#define SENSORS_MAXI_CO_FAN1_MIN 11 /* RW */ -#define SENSORS_MAXI_CO_FAN2_MIN 12 /* RW */ -#define SENSORS_MAXI_CO_FAN3_MIN 13 /* RW */ -#define SENSORS_MAXI_CO_FAN1_DIV 14 /* R */ -#define SENSORS_MAXI_CO_FAN2_DIV 15 /* R */ -#define SENSORS_MAXI_CO_FAN3_DIV 16 /* R */ -#define SENSORS_MAXI_CO_TEMP1 21 /* R */ -#define SENSORS_MAXI_CO_TEMP2 22 /* R */ -#define SENSORS_MAXI_CO_TEMP3 23 /* R */ -#define SENSORS_MAXI_CO_TEMP4 24 /* R */ -#define SENSORS_MAXI_CO_TEMP5 25 /* R */ -#define SENSORS_MAXI_CO_TEMP1_MAX 31 /* R */ -#define SENSORS_MAXI_CO_TEMP2_MAX 32 /* R */ -#define SENSORS_MAXI_CO_TEMP3_MAX 33 /* R */ -#define SENSORS_MAXI_CO_TEMP4_MAX 34 /* R */ -#define SENSORS_MAXI_CO_TEMP5_MAX 35 /* R */ -#define SENSORS_MAXI_CO_TEMP1_HYST 41 /* R */ -#define SENSORS_MAXI_CO_TEMP2_HYST 42 /* R */ -#define SENSORS_MAXI_CO_TEMP3_HYST 43 /* R */ -#define SENSORS_MAXI_CO_TEMP4_HYST 44 /* R */ -#define SENSORS_MAXI_CO_TEMP5_HYST 45 /* R */ -#define SENSORS_MAXI_CO_PLL 51 /* R */ -#define SENSORS_MAXI_CO_PLL_MIN 52 /* RW */ -#define SENSORS_MAXI_CO_PLL_MAX 53 /* RW */ -#define SENSORS_MAXI_CO_VID1 61 /* R */ -#define SENSORS_MAXI_CO_VID2 62 /* R */ -#define SENSORS_MAXI_CO_VID3 63 /* R */ -#define SENSORS_MAXI_CO_VID4 64 /* R */ -#define SENSORS_MAXI_CO_VID1_MIN 71 /* RW */ -#define SENSORS_MAXI_CO_VID2_MIN 72 /* RW */ -#define SENSORS_MAXI_CO_VID3_MIN 73 /* RW */ -#define SENSORS_MAXI_CO_VID4_MIN 74 /* RW */ -#define SENSORS_MAXI_CO_VID1_MAX 81 /* RW */ -#define SENSORS_MAXI_CO_VID2_MAX 82 /* RW */ -#define SENSORS_MAXI_CO_VID3_MAX 83 /* RW */ -#define SENSORS_MAXI_CO_VID4_MAX 84 /* RW */ -#define SENSORS_MAXI_CO_ALARMS 91 /* R */ - -#define SENSORS_MAXI_AS_FAN1 1 /* R */ -#define SENSORS_MAXI_AS_FAN2 2 /* R */ -#define SENSORS_MAXI_AS_FAN3 3 /* R */ -#define SENSORS_MAXI_AS_FAN1_MIN 11 /* RW */ -#define SENSORS_MAXI_AS_FAN2_MIN 12 /* RW */ -#define SENSORS_MAXI_AS_FAN3_MIN 13 /* RW */ -#define SENSORS_MAXI_AS_FAN1_DIV 14 /* R */ -#define SENSORS_MAXI_AS_FAN2_DIV 15 /* R */ -#define SENSORS_MAXI_AS_FAN3_DIV 16 /* R */ -#define SENSORS_MAXI_AS_TEMP1 21 /* R */ -#define SENSORS_MAXI_AS_TEMP2 22 /* R */ -#define SENSORS_MAXI_AS_TEMP3 23 /* R */ -#define SENSORS_MAXI_AS_TEMP4 24 /* R */ -#define SENSORS_MAXI_AS_TEMP5 25 /* R */ -#define SENSORS_MAXI_AS_TEMP1_MAX 31 /* R */ -#define SENSORS_MAXI_AS_TEMP2_MAX 32 /* R */ -#define SENSORS_MAXI_AS_TEMP3_MAX 33 /* R */ -#define SENSORS_MAXI_AS_TEMP4_MAX 34 /* R */ -#define SENSORS_MAXI_AS_TEMP5_MAX 35 /* R */ -#define SENSORS_MAXI_AS_TEMP1_HYST 41 /* R */ -#define SENSORS_MAXI_AS_TEMP2_HYST 42 /* R */ -#define SENSORS_MAXI_AS_TEMP3_HYST 43 /* R */ -#define SENSORS_MAXI_AS_TEMP4_HYST 44 /* R */ -#define SENSORS_MAXI_AS_TEMP5_HYST 45 /* R */ -#define SENSORS_MAXI_AS_PLL 51 /* R */ -#define SENSORS_MAXI_AS_PLL_MIN 52 /* RW */ -#define SENSORS_MAXI_AS_PLL_MAX 53 /* RW */ -#define SENSORS_MAXI_AS_VID1 61 /* R */ -#define SENSORS_MAXI_AS_VID2 62 /* R */ -#define SENSORS_MAXI_AS_VID3 63 /* R */ -#define SENSORS_MAXI_AS_VID4 64 /* R */ -#define SENSORS_MAXI_AS_VID1_MIN 71 /* RW */ -#define SENSORS_MAXI_AS_VID2_MIN 72 /* RW */ -#define SENSORS_MAXI_AS_VID3_MIN 73 /* RW */ -#define SENSORS_MAXI_AS_VID4_MIN 74 /* RW */ -#define SENSORS_MAXI_AS_VID1_MAX 81 /* RW */ -#define SENSORS_MAXI_AS_VID2_MAX 82 /* RW */ -#define SENSORS_MAXI_AS_VID3_MAX 83 /* RW */ -#define SENSORS_MAXI_AS_VID4_MAX 84 /* RW */ -#define SENSORS_MAXI_AS_ALARMS 91 /* R */ - -/* THMC50/ADM1022 chips */ - -#define SENSORS_THMC50_PREFIX "thmc50" -/* Cheat on ADM1022 for now - no separate #defines */ -#define SENSORS_ADM1022_PREFIX "adm1022" - -#define SENSORS_THMC50_TEMP 51 /* R */ -#define SENSORS_THMC50_TEMP_HYST 52 /* RW */ -#define SENSORS_THMC50_TEMP_OVER 53 /* RW */ -#define SENSORS_THMC50_REMOTE_TEMP 54 /* R */ -#define SENSORS_THMC50_REMOTE_TEMP_HYST 55 /* RW */ -#define SENSORS_THMC50_REMOTE_TEMP_OVER 56 /* RW */ -#define SENSORS_ADM1022_REMOTE_TEMP2 57 /* R */ -#define SENSORS_ADM1022_REMOTE_TEMP2_HYST 58 /* RW */ -#define SENSORS_ADM1022_REMOTE_TEMP2_OVER 59 /* RW */ -#define SENSORS_THMC50_ANALOG_OUT 71 /* RW */ -#define SENSORS_THMC50_INTER 81 /* R */ -#define SENSORS_THMC50_INTER_MASK 82 /* RW */ -#define SENSORS_THMC50_DIE_CODE 90 /* R */ - -/* ADM1025 chip */ - -#define SENSORS_ADM1025_PREFIX "adm1025" -#define SENSORS_NE1619_PREFIX "ne1619" - -#define SENSORS_ADM1025_IN0 1 /* R */ -#define SENSORS_ADM1025_IN1 2 /* R */ -#define SENSORS_ADM1025_IN2 3 /* R */ -#define SENSORS_ADM1025_IN3 4 /* R */ -#define SENSORS_ADM1025_IN4 5 /* R */ -#define SENSORS_ADM1025_IN5 6 /* R */ -#define SENSORS_ADM1025_IN0_MIN 11 /* RW */ -#define SENSORS_ADM1025_IN1_MIN 12 /* RW */ -#define SENSORS_ADM1025_IN2_MIN 13 /* RW */ -#define SENSORS_ADM1025_IN3_MIN 14 /* RW */ -#define SENSORS_ADM1025_IN4_MIN 15 /* RW */ -#define SENSORS_ADM1025_IN5_MIN 16 /* RW */ -#define SENSORS_ADM1025_IN0_MAX 21 /* RW */ -#define SENSORS_ADM1025_IN1_MAX 22 /* RW */ -#define SENSORS_ADM1025_IN2_MAX 23 /* RW */ -#define SENSORS_ADM1025_IN3_MAX 24 /* RW */ -#define SENSORS_ADM1025_IN4_MAX 25 /* RW */ -#define SENSORS_ADM1025_IN5_MAX 26 /* RW */ -#define SENSORS_ADM1025_TEMP1 51 /* R */ -#define SENSORS_ADM1025_TEMP1_LOW 52 /* RW */ -#define SENSORS_ADM1025_TEMP1_HIGH 53 /* RW */ -#define SENSORS_ADM1025_TEMP2 54 /* R */ -#define SENSORS_ADM1025_TEMP2_LOW 55 /* RW */ -#define SENSORS_ADM1025_TEMP2_HIGH 56 /* RW */ -#define SENSORS_ADM1025_VID 61 /* R */ -#define SENSORS_ADM1025_VRM 62 /* R */ -#define SENSORS_ADM1025_ALARMS 81 /* R */ - - -#define SENSORS_ADM1026_PREFIX "adm1026" -/* NOTE: print_adm1026 (sensors) depends on the ordering - * of these entries in each group. For example - * fan#, fan#_div, fan#_min - * temp#, temp#_max, temp#_min, temp#_offset - * and the ordering of the groups - * in0, in1, ... in9, in10, in11 - */ -#define SENSORS_ADM1026_AFC_DAC 1 /* RW -- afc_analog_out */ -#define SENSORS_ADM1026_AFC_PWM 2 /* RW -- afc_pwm */ -#define SENSORS_ADM1026_ALARMS 3 /* R -- alarms */ -#define SENSORS_ADM1026_ALARM_MASK 4 /* R -- alarm_mask */ -#define SENSORS_ADM1026_DAC 5 /* RW -- analog_out */ -#define SENSORS_ADM1026_GPIO 6 /* R -- gpio */ -#define SENSORS_ADM1026_GPIO_MASK 7 /* R -- gpio_mask */ -#define SENSORS_ADM1026_PWM 8 /* RW -- pwm */ -#define SENSORS_ADM1026_VID 9 /* RW -- vid */ -#define SENSORS_ADM1026_VRM 10 /* RW -- vrm */ -#define SENSORS_ADM1026_FAN0 11 /* R -- fan0 */ -#define SENSORS_ADM1026_FAN0_DIV 12 /* RW -- fan0_div */ -#define SENSORS_ADM1026_FAN0_MIN 13 /* RW -- fan0_min */ -#define SENSORS_ADM1026_FAN1 14 /* R -- fan1 */ -#define SENSORS_ADM1026_FAN1_DIV 15 /* RW -- fan1_div */ -#define SENSORS_ADM1026_FAN1_MIN 16 /* RW -- fan1_min */ -#define SENSORS_ADM1026_FAN2 17 /* R -- fan2 */ -#define SENSORS_ADM1026_FAN2_DIV 18 /* RW -- fan2_div */ -#define SENSORS_ADM1026_FAN2_MIN 19 /* RW -- fan2_min */ -#define SENSORS_ADM1026_FAN3 20 /* R -- fan3 */ -#define SENSORS_ADM1026_FAN3_DIV 21 /* RW -- fan3_div */ -#define SENSORS_ADM1026_FAN3_MIN 22 /* RW -- fan3_min */ -#define SENSORS_ADM1026_FAN4 23 /* R -- fan4 */ -#define SENSORS_ADM1026_FAN4_DIV 24 /* RW -- fan4_div */ -#define SENSORS_ADM1026_FAN4_MIN 25 /* RW -- fan4_min */ -#define SENSORS_ADM1026_FAN5 26 /* R -- fan5 */ -#define SENSORS_ADM1026_FAN5_DIV 27 /* RW -- fan5_div */ -#define SENSORS_ADM1026_FAN5_MIN 28 /* RW -- fan5_min */ -#define SENSORS_ADM1026_FAN6 29 /* R -- fan6 */ -#define SENSORS_ADM1026_FAN6_DIV 30 /* RW -- fan6_div */ -#define SENSORS_ADM1026_FAN6_MIN 31 /* RW -- fan6_min */ -#define SENSORS_ADM1026_FAN7 32 /* R -- fan7 */ -#define SENSORS_ADM1026_FAN7_DIV 33 /* RW -- fan7_div */ -#define SENSORS_ADM1026_FAN7_MIN 34 /* RW -- fan7_min */ -#define SENSORS_ADM1026_IN0 35 /* R -- in0 */ -#define SENSORS_ADM1026_IN0_MAX 36 /* RW -- in0_max */ -#define SENSORS_ADM1026_IN0_MIN 37 /* RW -- in0_min */ -#define SENSORS_ADM1026_IN1 38 /* R -- in1 */ -#define SENSORS_ADM1026_IN1_MAX 39 /* RW -- in1_max */ -#define SENSORS_ADM1026_IN1_MIN 40 /* RW -- in1_min */ -#define SENSORS_ADM1026_IN2 41 /* R -- in2 */ -#define SENSORS_ADM1026_IN2_MAX 42 /* RW -- in2_max */ -#define SENSORS_ADM1026_IN2_MIN 43 /* RW -- in2_min */ -#define SENSORS_ADM1026_IN3 44 /* R -- in3 */ -#define SENSORS_ADM1026_IN3_MAX 45 /* RW -- in3_max */ -#define SENSORS_ADM1026_IN3_MIN 46 /* RW -- in3_min */ -#define SENSORS_ADM1026_IN4 47 /* R -- in4 */ -#define SENSORS_ADM1026_IN4_MAX 48 /* RW -- in4_max */ -#define SENSORS_ADM1026_IN4_MIN 49 /* RW -- in4_min */ -#define SENSORS_ADM1026_IN5 50 /* R -- in5 */ -#define SENSORS_ADM1026_IN5_MAX 51 /* RW -- in5_max */ -#define SENSORS_ADM1026_IN5_MIN 52 /* RW -- in5_min */ -#define SENSORS_ADM1026_IN6 53 /* R -- in6 */ -#define SENSORS_ADM1026_IN6_MAX 54 /* RW -- in6_max */ -#define SENSORS_ADM1026_IN6_MIN 55 /* RW -- in6_min */ -#define SENSORS_ADM1026_IN7 56 /* R -- in7 */ -#define SENSORS_ADM1026_IN7_MAX 57 /* RW -- in7_max */ -#define SENSORS_ADM1026_IN7_MIN 58 /* RW -- in7_min */ -#define SENSORS_ADM1026_IN8 59 /* R -- in8 */ -#define SENSORS_ADM1026_IN8_MAX 60 /* RW -- in8_max */ -#define SENSORS_ADM1026_IN8_MIN 61 /* RW -- in8_min */ -#define SENSORS_ADM1026_IN9 62 /* R -- in9 */ -#define SENSORS_ADM1026_IN9_MAX 63 /* RW -- in9_max */ -#define SENSORS_ADM1026_IN9_MIN 64 /* RW -- in9_min */ -#define SENSORS_ADM1026_IN10 65 /* R -- in10 */ -#define SENSORS_ADM1026_IN10_MAX 66 /* RW -- in10_max */ -#define SENSORS_ADM1026_IN10_MIN 67 /* RW -- in10_min */ -#define SENSORS_ADM1026_IN11 68 /* R -- in11 */ -#define SENSORS_ADM1026_IN11_MAX 69 /* RW -- in11_max */ -#define SENSORS_ADM1026_IN11_MIN 70 /* RW -- in11_min */ -#define SENSORS_ADM1026_IN12 71 /* R -- in12 */ -#define SENSORS_ADM1026_IN12_MAX 72 /* RW -- in12_max */ -#define SENSORS_ADM1026_IN12_MIN 73 /* RW -- in12_min */ -#define SENSORS_ADM1026_IN13 74 /* R -- in13 */ -#define SENSORS_ADM1026_IN13_MAX 75 /* RW -- in13_max */ -#define SENSORS_ADM1026_IN13_MIN 76 /* RW -- in13_min */ -#define SENSORS_ADM1026_IN14 77 /* R -- in14 */ -#define SENSORS_ADM1026_IN14_MAX 78 /* RW -- in14_max */ -#define SENSORS_ADM1026_IN14_MIN 79 /* RW -- in14_min */ -#define SENSORS_ADM1026_IN15 80 /* R -- in15 */ -#define SENSORS_ADM1026_IN15_MAX 81 /* RW -- in15_max */ -#define SENSORS_ADM1026_IN15_MIN 82 /* RW -- in15_min */ -#define SENSORS_ADM1026_IN16 83 /* R -- in16 */ -#define SENSORS_ADM1026_IN16_MAX 84 /* RW -- in16_max */ -#define SENSORS_ADM1026_IN16_MIN 85 /* RW -- in16_min */ -#define SENSORS_ADM1026_TEMP1 86 /* R -- temp1 */ -#define SENSORS_ADM1026_TEMP1_MAX 87 /* RW -- temp1_max */ -#define SENSORS_ADM1026_TEMP1_MIN 88 /* RW -- temp1_min */ -#define SENSORS_ADM1026_TEMP1_OFFSET 89 /* RW -- temp1_offset */ -#define SENSORS_ADM1026_TEMP1_THERM 90 /* RW -- temp1_therm */ -#define SENSORS_ADM1026_TEMP1_TMIN 91 /* RW -- temp1_tmin */ -#define SENSORS_ADM1026_TEMP2 92 /* R -- temp2 */ -#define SENSORS_ADM1026_TEMP2_MAX 93 /* RW -- temp2_max */ -#define SENSORS_ADM1026_TEMP2_MIN 94 /* RW -- temp2_min */ -#define SENSORS_ADM1026_TEMP2_OFFSET 95 /* RW -- temp2_offset */ -#define SENSORS_ADM1026_TEMP2_THERM 96 /* RW -- temp2_therm */ -#define SENSORS_ADM1026_TEMP2_TMIN 97 /* RW -- temp2_tmin */ -#define SENSORS_ADM1026_TEMP3 98 /* R -- temp3 */ -#define SENSORS_ADM1026_TEMP3_MAX 99 /* RW -- temp3_max */ -#define SENSORS_ADM1026_TEMP3_MIN 100 /* RW -- temp3_min */ -#define SENSORS_ADM1026_TEMP3_OFFSET 101 /* RW -- temp3_offset */ -#define SENSORS_ADM1026_TEMP3_THERM 102 /* RW -- temp3_therm */ -#define SENSORS_ADM1026_TEMP3_TMIN 103 /* RW -- temp3_tmin */ - - -#define SENSORS_VIA686A_PREFIX "via686a" - -#define SENSORS_VIA686A_IN0 1 /* R */ -#define SENSORS_VIA686A_IN1 2 /* R */ -#define SENSORS_VIA686A_IN2 3 /* R */ -#define SENSORS_VIA686A_IN3 4 /* R */ -#define SENSORS_VIA686A_IN4 5 /* R */ -#define SENSORS_VIA686A_IN0_MIN 11 /* RW */ -#define SENSORS_VIA686A_IN1_MIN 12 /* RW */ -#define SENSORS_VIA686A_IN2_MIN 13 /* RW */ -#define SENSORS_VIA686A_IN3_MIN 14 /* RW */ -#define SENSORS_VIA686A_IN4_MIN 15 /* RW */ -#define SENSORS_VIA686A_IN0_MAX 21 /* RW */ -#define SENSORS_VIA686A_IN1_MAX 22 /* RW */ -#define SENSORS_VIA686A_IN2_MAX 23 /* RW */ -#define SENSORS_VIA686A_IN3_MAX 24 /* RW */ -#define SENSORS_VIA686A_IN4_MAX 25 /* RW */ -#define SENSORS_VIA686A_FAN1 31 /* R */ -#define SENSORS_VIA686A_FAN2 32 /* R */ -#define SENSORS_VIA686A_FAN1_MIN 41 /* RW */ -#define SENSORS_VIA686A_FAN2_MIN 42 /* RW */ -#define SENSORS_VIA686A_TEMP 51 /* R */ -#define SENSORS_VIA686A_TEMP_HYST 52 /* RW */ -#define SENSORS_VIA686A_TEMP_OVER 53 /* RW */ -#define SENSORS_VIA686A_TEMP2 54 /* R */ -#define SENSORS_VIA686A_TEMP2_HYST 55 /* RW */ -#define SENSORS_VIA686A_TEMP2_OVER 56 /* RW */ -#define SENSORS_VIA686A_TEMP3 57 /* R */ -#define SENSORS_VIA686A_TEMP3_HYST 58 /* RW */ -#define SENSORS_VIA686A_TEMP3_OVER 59 /* RW */ -#define SENSORS_VIA686A_FAN1_DIV 71 /* RW */ -#define SENSORS_VIA686A_FAN2_DIV 72 /* RW */ -#define SENSORS_VIA686A_ALARMS 81 /* R */ - - -/* DDC Monitor */ - -#define SENSORS_DDCMON_PREFIX "ddcmon" - -#define SENSORS_DDCMON_MAN_ID 10 -#define SENSORS_DDCMON_PROD_ID 11 -#define SENSORS_DDCMON_YEAR 13 -#define SENSORS_DDCMON_WEEK 14 -#define SENSORS_DDCMON_EDID_VER 15 -#define SENSORS_DDCMON_EDID_REV 16 -#define SENSORS_DDCMON_HORSIZE 21 -#define SENSORS_DDCMON_VERSIZE 22 -#define SENSORS_DDCMON_GAMMA 23 -#define SENSORS_DDCMON_DPMS 24 -#define SENSORS_DDCMON_HORSYNCMIN 31 -#define SENSORS_DDCMON_HORSYNCMAX 32 -#define SENSORS_DDCMON_VERSYNCMIN 33 -#define SENSORS_DDCMON_VERSYNCMAX 34 -#define SENSORS_DDCMON_MAXCLOCK 35 -#define SENSORS_DDCMON_SERIAL 40 -#define SENSORS_DDCMON_TIMINGS 50 -#define SENSORS_DDCMON_TIMING1_HOR 51 -#define SENSORS_DDCMON_TIMING1_VER 52 -#define SENSORS_DDCMON_TIMING1_REF 53 -#define SENSORS_DDCMON_TIMING2_HOR 54 -#define SENSORS_DDCMON_TIMING2_VER 55 -#define SENSORS_DDCMON_TIMING2_REF 56 -#define SENSORS_DDCMON_TIMING3_HOR 57 -#define SENSORS_DDCMON_TIMING3_VER 58 -#define SENSORS_DDCMON_TIMING3_REF 59 -#define SENSORS_DDCMON_TIMING4_HOR 60 -#define SENSORS_DDCMON_TIMING4_VER 61 -#define SENSORS_DDCMON_TIMING4_REF 62 -#define SENSORS_DDCMON_TIMING5_HOR 63 -#define SENSORS_DDCMON_TIMING5_VER 64 -#define SENSORS_DDCMON_TIMING5_REF 65 -#define SENSORS_DDCMON_TIMING6_HOR 66 -#define SENSORS_DDCMON_TIMING6_VER 67 -#define SENSORS_DDCMON_TIMING6_REF 68 -#define SENSORS_DDCMON_TIMING7_HOR 69 -#define SENSORS_DDCMON_TIMING7_VER 70 -#define SENSORS_DDCMON_TIMING7_REF 71 -#define SENSORS_DDCMON_TIMING8_HOR 72 -#define SENSORS_DDCMON_TIMING8_VER 73 -#define SENSORS_DDCMON_TIMING8_REF 74 - -/* EEPROM (SDRAM DIMM) */ - -#define SENSORS_EEPROM_PREFIX "eeprom" - -#define SENSORS_EEPROM_TYPE 10 -#define SENSORS_EEPROM_ROWADDR 12 -#define SENSORS_EEPROM_COLADDR 13 -#define SENSORS_EEPROM_NUMROWS 14 -#define SENSORS_EEPROM_BANKS 15 - -#define SENSORS_EEPROM_VAIO_NAME 128 -/* 129 to 159: reserved, do not use! */ -#define SENSORS_EEPROM_VAIO_SERIAL 160 -/* 161 to 191: reserved, do not use! */ - -#define SENSORS_EEPROM_EDID_HEADER 32 -/* 33 to 39: reserved, do not use! */ - -#define SENSORS_EEPROM_SHUTTLE 40 -/* 41 to 45: reserved, do not use! */ - -/* Analog Devices LM87 chips */ - -#define SENSORS_LM87_PREFIX "lm87" - -#define SENSORS_LM87_IN0 1 /* R */ -#define SENSORS_LM87_IN1 2 /* R */ -#define SENSORS_LM87_IN2 3 /* R */ -#define SENSORS_LM87_IN3 4 /* R */ -#define SENSORS_LM87_IN4 5 /* R */ -#define SENSORS_LM87_IN5 6 /* R */ -#define SENSORS_LM87_AIN1 7 /* R */ -#define SENSORS_LM87_AIN2 8 /* R */ -#define SENSORS_LM87_IN0_MIN 11 /* RW */ -#define SENSORS_LM87_IN1_MIN 12 /* RW */ -#define SENSORS_LM87_IN2_MIN 13 /* RW */ -#define SENSORS_LM87_IN3_MIN 14 /* RW */ -#define SENSORS_LM87_IN4_MIN 15 /* RW */ -#define SENSORS_LM87_IN5_MIN 16 /* RW */ -#define SENSORS_LM87_AIN1_MIN 17 /* RW */ -#define SENSORS_LM87_AIN2_MIN 18 /* RW */ -#define SENSORS_LM87_IN0_MAX 21 /* RW */ -#define SENSORS_LM87_IN1_MAX 22 /* RW */ -#define SENSORS_LM87_IN2_MAX 23 /* RW */ -#define SENSORS_LM87_IN3_MAX 24 /* RW */ -#define SENSORS_LM87_IN4_MAX 25 /* RW */ -#define SENSORS_LM87_IN5_MAX 26 /* RW */ -#define SENSORS_LM87_AIN1_MAX 27 /* RW */ -#define SENSORS_LM87_AIN2_MAX 28 /* RW */ -#define SENSORS_LM87_FAN1 31 /* R */ -#define SENSORS_LM87_FAN2 32 /* R */ -#define SENSORS_LM87_FAN1_MIN 41 /* RW */ -#define SENSORS_LM87_FAN2_MIN 42 /* RW */ -#define SENSORS_LM87_TEMP1 51 /* R */ -#define SENSORS_LM87_TEMP2 52 /* R */ -#define SENSORS_LM87_TEMP3 53 /* R */ -#define SENSORS_LM87_TEMP1_HYST 54 /* RW */ -#define SENSORS_LM87_TEMP1_OVER 55 /* RW */ -#define SENSORS_LM87_TEMP2_HYST 56 /* RW */ -#define SENSORS_LM87_TEMP2_OVER 57 /* RW */ -#define SENSORS_LM87_TEMP3_HYST 58 /* RW */ -#define SENSORS_LM87_TEMP3_OVER 59 /* RW */ -#define SENSORS_LM87_VID 61 /* R */ -#define SENSORS_LM87_VRM 62 /* RW */ -#define SENSORS_LM87_FAN1_DIV 71 /* RW */ -#define SENSORS_LM87_FAN2_DIV 72 /* RW */ -#define SENSORS_LM87_ALARMS 81 /* R */ -#define SENSORS_LM87_ANALOG_OUT 82 /* RW */ - -/* Myson MTP008 chips */ - -#define SENSORS_MTP008_PREFIX "mtp008" - -#define SENSORS_MTP008_IN0 1 /* R */ -#define SENSORS_MTP008_IN1 2 /* R */ -#define SENSORS_MTP008_IN2 3 /* R */ -#define SENSORS_MTP008_IN3 4 /* R */ -#define SENSORS_MTP008_IN4 5 /* R */ -#define SENSORS_MTP008_IN5 6 /* R */ -#define SENSORS_MTP008_IN6 7 /* R */ -#define SENSORS_MTP008_IN0_MIN 11 /* RW */ -#define SENSORS_MTP008_IN1_MIN 12 /* RW */ -#define SENSORS_MTP008_IN2_MIN 13 /* RW */ -#define SENSORS_MTP008_IN3_MIN 14 /* RW */ -#define SENSORS_MTP008_IN4_MIN 15 /* RW */ -#define SENSORS_MTP008_IN5_MIN 16 /* RW */ -#define SENSORS_MTP008_IN6_MIN 17 /* RW */ -#define SENSORS_MTP008_IN0_MAX 21 /* RW */ -#define SENSORS_MTP008_IN1_MAX 22 /* RW */ -#define SENSORS_MTP008_IN2_MAX 23 /* RW */ -#define SENSORS_MTP008_IN3_MAX 24 /* RW */ -#define SENSORS_MTP008_IN4_MAX 25 /* RW */ -#define SENSORS_MTP008_IN5_MAX 26 /* RW */ -#define SENSORS_MTP008_IN6_MAX 27 /* RW */ -#define SENSORS_MTP008_FAN1 31 /* R */ -#define SENSORS_MTP008_FAN2 32 /* R */ -#define SENSORS_MTP008_FAN3 33 /* R */ -#define SENSORS_MTP008_FAN1_MIN 41 /* RW */ -#define SENSORS_MTP008_FAN2_MIN 42 /* RW */ -#define SENSORS_MTP008_FAN3_MIN 43 /* RW */ -#define SENSORS_MTP008_TEMP1 51 /* R */ -#define SENSORS_MTP008_TEMP2 52 /* R */ -#define SENSORS_MTP008_TEMP3 53 /* R */ -#define SENSORS_MTP008_TEMP1_OVER 54 /* RW */ -#define SENSORS_MTP008_TEMP1_HYST 55 /* RW */ -#define SENSORS_MTP008_TEMP2_OVER 56 /* RW */ -#define SENSORS_MTP008_TEMP2_HYST 57 /* RW */ -#define SENSORS_MTP008_TEMP3_OVER 58 /* RW */ -#define SENSORS_MTP008_TEMP3_HYST 59 /* RW */ -#define SENSORS_MTP008_VID 61 /* R */ -#define SENSORS_MTP008_FAN1_DIV 71 /* RW */ -#define SENSORS_MTP008_FAN2_DIV 72 /* RW */ -#define SENSORS_MTP008_FAN3_DIV 73 /* RW */ -#define SENSORS_MTP008_ALARMS 81 /* R */ -#define SENSORS_MTP008_BEEP 82 /* RW */ - -/* DS1621 chips. */ - -#define SENSORS_DS1621_PREFIX "ds1621" - -#define SENSORS_DS1621_TEMP 51 /* R */ -#define SENSORS_DS1621_TEMP_HYST 52 /* RW */ -#define SENSORS_DS1621_TEMP_OVER 53 /* RW */ -#define SENSORS_DS1621_ALARMS 81 /* R */ -#define SENSORS_DS1621_ENABLE 82 /* RW */ -#define SENSORS_DS1621_CONTINUOUS 83 /* RW */ -#define SENSORS_DS1621_POLARITY 84 /* RW */ - -/* ADM1024 chip */ - -#define SENSORS_ADM1024_PREFIX "adm1024" - -#define SENSORS_ADM1024_IN0 1 /* R */ -#define SENSORS_ADM1024_IN1 2 /* R */ -#define SENSORS_ADM1024_IN2 3 /* R */ -#define SENSORS_ADM1024_IN3 4 /* R */ -#define SENSORS_ADM1024_IN4 5 /* R */ -#define SENSORS_ADM1024_IN5 6 /* R */ -#define SENSORS_ADM1024_IN0_MIN 11 /* RW */ -#define SENSORS_ADM1024_IN1_MIN 12 /* RW */ -#define SENSORS_ADM1024_IN2_MIN 13 /* RW */ -#define SENSORS_ADM1024_IN3_MIN 14 /* RW */ -#define SENSORS_ADM1024_IN4_MIN 15 /* RW */ -#define SENSORS_ADM1024_IN5_MIN 16 /* RW */ -#define SENSORS_ADM1024_IN0_MAX 21 /* RW */ -#define SENSORS_ADM1024_IN1_MAX 22 /* RW */ -#define SENSORS_ADM1024_IN2_MAX 23 /* RW */ -#define SENSORS_ADM1024_IN3_MAX 24 /* RW */ -#define SENSORS_ADM1024_IN4_MAX 25 /* RW */ -#define SENSORS_ADM1024_IN5_MAX 26 /* RW */ -#define SENSORS_ADM1024_FAN1 31 /* R */ -#define SENSORS_ADM1024_FAN2 32 /* R */ -#define SENSORS_ADM1024_FAN1_MIN 41 /* RW */ -#define SENSORS_ADM1024_FAN2_MIN 42 /* RW */ -#define SENSORS_ADM1024_TEMP 51 /* R */ -#define SENSORS_ADM1024_TEMP1 52 /* R */ -#define SENSORS_ADM1024_TEMP2 53 /* R */ -#define SENSORS_ADM1024_TEMP_HYST 61 /* RW */ -#define SENSORS_ADM1024_TEMP_OVER 62 /* RW */ -#define SENSORS_ADM1024_TEMP1_HYST 63 /* RW */ -#define SENSORS_ADM1024_TEMP1_OVER 64 /* RW */ -#define SENSORS_ADM1024_TEMP2_HYST 65 /* RW */ -#define SENSORS_ADM1024_TEMP2_OVER 66 /* RW */ -#define SENSORS_ADM1024_VID 71 /* R */ -#define SENSORS_ADM1024_FAN1_DIV 81 /* RW */ -#define SENSORS_ADM1024_FAN2_DIV 82 /* RW */ -#define SENSORS_ADM1024_ALARMS 91 /* R */ -#define SENSORS_ADM1024_ANALOG_OUT 92 /* RW */ - -/* IT87xx chips */ - -#define SENSORS_IT87_PREFIX "it87" -#define SENSORS_IT8712_PREFIX "it8712" -#define SENSORS_IT8716_PREFIX "it8716" -#define SENSORS_IT8718_PREFIX "it8718" -#define SENSORS_IT8720_PREFIX "it8720" - -#define SENSORS_IT87_IN0 1 /* R */ -#define SENSORS_IT87_IN1 2 /* R */ -#define SENSORS_IT87_IN2 3 /* R */ -#define SENSORS_IT87_IN3 4 /* R */ -#define SENSORS_IT87_IN4 5 /* R */ -#define SENSORS_IT87_IN5 6 /* R */ -#define SENSORS_IT87_IN6 7 /* R */ -#define SENSORS_IT87_IN7 8 /* R */ -#define SENSORS_IT87_IN8 9 /* R */ -#define SENSORS_IT87_IN0_MIN 11 /* RW */ -#define SENSORS_IT87_IN1_MIN 12 /* RW */ -#define SENSORS_IT87_IN2_MIN 13 /* RW */ -#define SENSORS_IT87_IN3_MIN 14 /* RW */ -#define SENSORS_IT87_IN4_MIN 15 /* RW */ -#define SENSORS_IT87_IN5_MIN 16 /* RW */ -#define SENSORS_IT87_IN6_MIN 17 /* RW */ -#define SENSORS_IT87_IN7_MIN 18 /* RW */ -#define SENSORS_IT87_IN0_MAX 21 /* RW */ -#define SENSORS_IT87_IN1_MAX 22 /* RW */ -#define SENSORS_IT87_IN2_MAX 23 /* RW */ -#define SENSORS_IT87_IN3_MAX 24 /* RW */ -#define SENSORS_IT87_IN4_MAX 25 /* RW */ -#define SENSORS_IT87_IN5_MAX 26 /* RW */ -#define SENSORS_IT87_IN6_MAX 27 /* RW */ -#define SENSORS_IT87_IN7_MAX 28 /* RW */ -#define SENSORS_IT87_FAN1 31 /* R */ -#define SENSORS_IT87_FAN2 32 /* R */ -#define SENSORS_IT87_FAN3 33 /* R */ -#define SENSORS_IT87_FAN4 34 /* R */ -#define SENSORS_IT87_FAN5 35 /* R */ -#define SENSORS_IT87_FAN1_MIN 41 /* RW */ -#define SENSORS_IT87_FAN2_MIN 42 /* RW */ -#define SENSORS_IT87_FAN3_MIN 43 /* RW */ -#define SENSORS_IT87_FAN4_MIN 44 /* RW */ -#define SENSORS_IT87_FAN5_MIN 45 /* RW */ -#define SENSORS_IT87_TEMP1 51 /* R */ -#define SENSORS_IT87_TEMP2 52 /* R */ -#define SENSORS_IT87_TEMP3 53 /* R */ -#define SENSORS_IT87_TEMP1_LOW 54 /* RW */ -#define SENSORS_IT87_TEMP2_LOW 55 /* RW */ -#define SENSORS_IT87_TEMP3_LOW 56 /* RW */ -#define SENSORS_IT87_TEMP1_HIGH 57 /* RW */ -#define SENSORS_IT87_TEMP2_HIGH 58 /* RW */ -#define SENSORS_IT87_TEMP3_HIGH 59 /* RW */ -#define SENSORS_IT87_VID 61 /* R */ -#define SENSORS_IT87_FAN1_DIV 71 /* RW */ -#define SENSORS_IT87_FAN2_DIV 72 /* RW */ -#define SENSORS_IT87_FAN3_DIV 73 /* R (fan3 different) */ -#define SENSORS_IT87_ALARMS_FAN 81 /* R */ -#define SENSORS_IT87_ALARMS_VIN 82 /* R */ -#define SENSORS_IT87_ALARMS_TEMP 83 /* R */ -#define SENSORS_IT87_ALARMS 84 /* R */ -#define SENSORS_IT87_SENS1 91 /* RW */ -#define SENSORS_IT87_SENS2 92 /* RW */ -#define SENSORS_IT87_SENS3 93 /* RW */ - - -/* fsc poseidon chip */ - -#define SENSORS_FSCPOS_PREFIX "fscpos" - -#define SENSORS_FSCPOS_REV 1 /* R */ -#define SENSORS_FSCPOS_EVENT 2 /* R */ -#define SENSORS_FSCPOS_CONTROL 3 /* RW */ -#define SENSORS_FSCPOS_FAN1 4 /* R */ -#define SENSORS_FSCPOS_FAN2 5 /* R */ -#define SENSORS_FSCPOS_FAN3 6 /* R */ -#define SENSORS_FSCPOS_FAN1_MIN 7 /* RW */ -#define SENSORS_FSCPOS_FAN2_MIN 8 /* RW */ -#define SENSORS_FSCPOS_FAN3_MIN 9 /* RW */ -#define SENSORS_FSCPOS_FAN1_STATE 10 /* RW */ -#define SENSORS_FSCPOS_FAN2_STATE 11 /* RW */ -#define SENSORS_FSCPOS_FAN3_STATE 12 /* RW */ -#define SENSORS_FSCPOS_FAN1_RIPPLE 13 /* RW */ -#define SENSORS_FSCPOS_FAN2_RIPPLE 14 /* RW */ -#define SENSORS_FSCPOS_FAN3_RIPPLE 15 /* RW */ -#define SENSORS_FSCPOS_TEMP1 16 /* R */ -#define SENSORS_FSCPOS_TEMP2 17 /* R */ -#define SENSORS_FSCPOS_TEMP3 18 /* R */ -#define SENSORS_FSCPOS_TEMP1_STATE 19 /* RW */ -#define SENSORS_FSCPOS_TEMP2_STATE 20 /* RW */ -#define SENSORS_FSCPOS_TEMP3_STATE 21 /* RW */ -#define SENSORS_FSCPOS_VOLTAGE1 22 /* R */ -#define SENSORS_FSCPOS_VOLTAGE2 23 /* R */ -#define SENSORS_FSCPOS_VOLTAGE3 24 /* R */ -#define SENSORS_FSCPOS_WDOG_PRESET 25/* RW */ -#define SENSORS_FSCPOS_WDOG_STATE 26/* RW */ -#define SENSORS_FSCPOS_WDOG_CONTROL 27/* RW */ - -/* fsc scylla chip */ - -#define SENSORS_FSCSCY_PREFIX "fscscy" - -#define SENSORS_FSCSCY_REV 1 /* R */ -#define SENSORS_FSCSCY_EVENT 2 /* R */ -#define SENSORS_FSCSCY_CONTROL 3 /* RW */ -#define SENSORS_FSCSCY_FAN1 4 /* R */ -#define SENSORS_FSCSCY_FAN2 5 /* R */ -#define SENSORS_FSCSCY_FAN3 6 /* R */ -#define SENSORS_FSCSCY_FAN4 7 /* R */ -#define SENSORS_FSCSCY_FAN5 8 /* R */ -#define SENSORS_FSCSCY_FAN6 9 /* R */ -#define SENSORS_FSCSCY_FAN1_MIN 10 /* RW */ -#define SENSORS_FSCSCY_FAN2_MIN 11 /* RW */ -#define SENSORS_FSCSCY_FAN3_MIN 12 /* RW */ -#define SENSORS_FSCSCY_FAN4_MIN 13 /* RW */ -#define SENSORS_FSCSCY_FAN5_MIN 14 /* RW */ -#define SENSORS_FSCSCY_FAN6_MIN 15 /* RW */ -#define SENSORS_FSCSCY_FAN1_STATE 16 /* RW */ -#define SENSORS_FSCSCY_FAN2_STATE 17 /* RW */ -#define SENSORS_FSCSCY_FAN3_STATE 18 /* RW */ -#define SENSORS_FSCSCY_FAN4_STATE 19 /* RW */ -#define SENSORS_FSCSCY_FAN5_STATE 20 /* RW */ -#define SENSORS_FSCSCY_FAN6_STATE 21 /* RW */ -#define SENSORS_FSCSCY_FAN1_RIPPLE 22 /* RW */ -#define SENSORS_FSCSCY_FAN2_RIPPLE 23 /* RW */ -#define SENSORS_FSCSCY_FAN3_RIPPLE 24 /* RW */ -#define SENSORS_FSCSCY_FAN4_RIPPLE 25 /* RW */ -#define SENSORS_FSCSCY_FAN5_RIPPLE 26 /* RW */ -#define SENSORS_FSCSCY_FAN6_RIPPLE 27 /* RW */ -#define SENSORS_FSCSCY_TEMP1 28 /* R */ -#define SENSORS_FSCSCY_TEMP2 29 /* R */ -#define SENSORS_FSCSCY_TEMP3 30 /* R */ -#define SENSORS_FSCSCY_TEMP4 31 /* R */ -#define SENSORS_FSCSCY_TEMP1_STATE 32 /* RW */ -#define SENSORS_FSCSCY_TEMP2_STATE 33 /* RW */ -#define SENSORS_FSCSCY_TEMP3_STATE 34 /* RW */ -#define SENSORS_FSCSCY_TEMP4_STATE 35 /* RW */ -#define SENSORS_FSCSCY_TEMP1_LIM 36 /* R */ -#define SENSORS_FSCSCY_TEMP2_LIM 37 /* R */ -#define SENSORS_FSCSCY_TEMP3_LIM 38 /* R */ -#define SENSORS_FSCSCY_TEMP4_LIM 39 /* R */ -#define SENSORS_FSCSCY_TEMP1_MIN 40 /* R */ -#define SENSORS_FSCSCY_TEMP2_MIN 41 /* R */ -#define SENSORS_FSCSCY_TEMP3_MIN 42 /* R */ -#define SENSORS_FSCSCY_TEMP4_MIN 43 /* R */ -#define SENSORS_FSCSCY_TEMP1_MAX 44 /* R */ -#define SENSORS_FSCSCY_TEMP2_MAX 45 /* R */ -#define SENSORS_FSCSCY_TEMP3_MAX 46 /* R */ -#define SENSORS_FSCSCY_TEMP4_MAX 47 /* R */ -#define SENSORS_FSCSCY_VOLTAGE1 48/* R */ -#define SENSORS_FSCSCY_VOLTAGE2 49/* R */ -#define SENSORS_FSCSCY_VOLTAGE3 50/* R */ -#define SENSORS_FSCSCY_WDOG_PRESET 51 /* RW */ -#define SENSORS_FSCSCY_WDOG_STATE 52 /* RW */ -#define SENSORS_FSCSCY_WDOG_CONTROL 52 /* RW */ - -/* fsc hermes chip */ - -#define SENSORS_FSCHER_PREFIX "fscher" - -#define SENSORS_FSCHER_REV 1 /* R */ -#define SENSORS_FSCHER_EVENT 2 /* R */ -#define SENSORS_FSCHER_CONTROL 3 /* RW */ -#define SENSORS_FSCHER_FAN1 4 /* R */ -#define SENSORS_FSCHER_FAN2 5 /* R */ -#define SENSORS_FSCHER_FAN3 6 /* R */ -#define SENSORS_FSCHER_PWM1 7 /* RW */ -#define SENSORS_FSCHER_PWM2 8 /* RW */ -#define SENSORS_FSCHER_PWM3 9 /* RW */ -#define SENSORS_FSCHER_FAN1_STATE 10 /* RW */ -#define SENSORS_FSCHER_FAN2_STATE 11 /* RW */ -#define SENSORS_FSCHER_FAN3_STATE 12 /* RW */ -#define SENSORS_FSCHER_FAN1_RIPPLE 13 /* RW */ -#define SENSORS_FSCHER_FAN2_RIPPLE 14 /* RW */ -#define SENSORS_FSCHER_FAN3_RIPPLE 15 /* RW */ -#define SENSORS_FSCHER_TEMP1 16 /* R */ -#define SENSORS_FSCHER_TEMP2 17 /* R */ -#define SENSORS_FSCHER_TEMP3 18 /* R */ -#define SENSORS_FSCHER_TEMP1_STATE 19 /* RW */ -#define SENSORS_FSCHER_TEMP2_STATE 20 /* RW */ -#define SENSORS_FSCHER_TEMP3_STATE 21 /* RW */ -#define SENSORS_FSCHER_VOLTAGE1 22 /* R */ -#define SENSORS_FSCHER_VOLTAGE2 23 /* R */ -#define SENSORS_FSCHER_VOLTAGE3 24 /* R */ -#define SENSORS_FSCHER_WDOG_PRESET 25/* RW */ -#define SENSORS_FSCHER_WDOG_STATE 26/* RW */ -#define SENSORS_FSCHER_WDOG_CONTROL 27/* RW */ - -/* PCF8591 chip. */ - -#define SENSORS_PCF8591_PREFIX "pcf8591" - -#define SENSORS_PCF8591_AIN_CONF 1 /* RW */ -#define SENSORS_PCF8591_CH0 2 /* R */ -#define SENSORS_PCF8591_CH1 3 /* R */ -#define SENSORS_PCF8591_CH2 4 /* R */ -#define SENSORS_PCF8591_CH3 5 /* R */ -#define SENSORS_PCF8591_AOUT_ENABLE 6 /* RW */ -#define SENSORS_PCF8591_AOUT 7 /* RW */ - - -#define SENSORS_VT1211_PREFIX "vt1211" - -#define SENSORS_VT1211_IN0 1 /* R */ -#define SENSORS_VT1211_IN1 2 /* R */ -#define SENSORS_VT1211_IN2 3 /* R */ -#define SENSORS_VT1211_IN3 4 /* R */ -#define SENSORS_VT1211_IN4 5 /* R */ -#define SENSORS_VT1211_IN5 6 /* R */ -#define SENSORS_VT1211_IN0_MIN 11 /* RW */ -#define SENSORS_VT1211_IN1_MIN 12 /* RW */ -#define SENSORS_VT1211_IN2_MIN 13 /* RW */ -#define SENSORS_VT1211_IN3_MIN 14 /* RW */ -#define SENSORS_VT1211_IN4_MIN 15 /* RW */ -#define SENSORS_VT1211_IN5_MIN 16 /* RW */ -#define SENSORS_VT1211_IN0_MAX 21 /* RW */ -#define SENSORS_VT1211_IN1_MAX 22 /* RW */ -#define SENSORS_VT1211_IN2_MAX 23 /* RW */ -#define SENSORS_VT1211_IN3_MAX 24 /* RW */ -#define SENSORS_VT1211_IN4_MAX 25 /* RW */ -#define SENSORS_VT1211_IN5_MAX 26 /* RW */ -#define SENSORS_VT1211_FAN1 31 /* R */ -#define SENSORS_VT1211_FAN2 32 /* R */ -#define SENSORS_VT1211_FAN1_MIN 41 /* RW */ -#define SENSORS_VT1211_FAN2_MIN 42 /* RW */ -#define SENSORS_VT1211_TEMP1 51 /* R */ -#define SENSORS_VT1211_TEMP1_HYST 52 /* RW */ -#define SENSORS_VT1211_TEMP1_OVER 53 /* RW */ -#define SENSORS_VT1211_TEMP2 54 /* R */ -#define SENSORS_VT1211_TEMP2_HYST 55 /* RW */ -#define SENSORS_VT1211_TEMP2_OVER 56 /* RW */ -#define SENSORS_VT1211_TEMP3 57 /* R */ -#define SENSORS_VT1211_TEMP3_HYST 58 /* RW */ -#define SENSORS_VT1211_TEMP3_OVER 59 /* RW */ -#define SENSORS_VT1211_TEMP4 60 /* R */ -#define SENSORS_VT1211_TEMP4_HYST 61 /* RW */ -#define SENSORS_VT1211_TEMP4_OVER 62 /* RW */ -#define SENSORS_VT1211_TEMP5 63 /* R */ -#define SENSORS_VT1211_TEMP5_HYST 64 /* RW */ -#define SENSORS_VT1211_TEMP5_OVER 65 /* RW */ -#define SENSORS_VT1211_TEMP6 66 /* R */ -#define SENSORS_VT1211_TEMP6_HYST 67 /* RW */ -#define SENSORS_VT1211_TEMP6_OVER 68 /* RW */ -#define SENSORS_VT1211_TEMP7 69 /* R */ -#define SENSORS_VT1211_TEMP7_HYST 70 /* RW */ -#define SENSORS_VT1211_TEMP7_OVER 71 /* RW */ -#define SENSORS_VT1211_FAN1_DIV 75 /* RW */ -#define SENSORS_VT1211_FAN2_DIV 76 /* RW */ -#define SENSORS_VT1211_ALARMS 81 /* R */ -#define SENSORS_VT1211_VID 82 /* R */ -#define SENSORS_VT1211_VRM 83 /* RW */ -#define SENSORS_VT1211_UCH 84 /* RW */ - -#define SENSORS_SMSC47M1_PREFIX "smsc47m1" -#define SENSORS_SMSC47M2_PREFIX "smsc47m2" - -#define SENSORS_SMSC47M1_FAN1 31 /* R */ -#define SENSORS_SMSC47M1_FAN2 32 /* R */ -#define SENSORS_SMSC47M1_FAN3 33 /* R */ -#define SENSORS_SMSC47M1_FAN1_MIN 41 /* RW */ -#define SENSORS_SMSC47M1_FAN2_MIN 42 /* RW */ -#define SENSORS_SMSC47M1_FAN3_MIN 43 /* RW */ -#define SENSORS_SMSC47M1_FAN1_DIV 75 /* RW */ -#define SENSORS_SMSC47M1_FAN2_DIV 76 /* RW */ -#define SENSORS_SMSC47M1_FAN3_DIV 77 /* RW */ -#define SENSORS_SMSC47M1_ALARMS 81 /* R */ - -#define SENSORS_SMSC47M192_PREFIX "smsc47m192" - -#define SENSORS_SMSC47M192_IN(n) (1 + (n)) /* R */ -#define SENSORS_SMSC47M192_IN_MIN(n) (21 + (n)) /* RW */ -#define SENSORS_SMSC47M192_IN_MAX(n) (41 + (n)) /* RW */ -#define SENSORS_SMSC47M192_IN_ALARM(n) (61 + (n)) /* R */ -#define SENSORS_SMSC47M192_TEMP(n) (100 + (n)) /* R */ -#define SENSORS_SMSC47M192_TEMP_MAX(n) (120 + (n)) /* RW */ -#define SENSORS_SMSC47M192_TEMP_MIN(n) (140 + (n)) /* RW */ -#define SENSORS_SMSC47M192_TEMP_OFFSET(n) (160 + (n)) /* RW */ -#define SENSORS_SMSC47M192_TEMP_ALARM(n) (180 + (n)) /* R */ -#define SENSORS_SMSC47M192_TEMP_FAULT(n) (200 + (n)) /* R */ -#define SENSORS_SMSC47M192_VID 301 /* R */ -#define SENSORS_SMSC47M192_VRM 302 /* RW */ - -#define SENSORS_PC87360_PREFIX "pc87360" -#define SENSORS_PC87363_PREFIX "pc87363" -#define SENSORS_PC87364_PREFIX "pc87364" -#define SENSORS_PC87365_PREFIX "pc87365" -#define SENSORS_PC87366_PREFIX "pc87366" - -#define SENSORS_PC87360_ALARMS_IN 10 /* R */ -#define SENSORS_PC87360_ALARMS_TEMP 11 /* R */ - -#define SENSORS_PC87360_FAN1 31 /* R */ -#define SENSORS_PC87360_FAN2 32 /* R */ -#define SENSORS_PC87360_FAN3 33 /* R */ -#define SENSORS_PC87360_FAN1_MIN 41 /* RW */ -#define SENSORS_PC87360_FAN2_MIN 42 /* RW */ -#define SENSORS_PC87360_FAN3_MIN 43 /* RW */ -#define SENSORS_PC87360_FAN1_DIV 71 /* R */ -#define SENSORS_PC87360_FAN2_DIV 72 /* R */ -#define SENSORS_PC87360_FAN3_DIV 73 /* R */ -#define SENSORS_PC87360_FAN1_STATUS 81 /* R */ -#define SENSORS_PC87360_FAN2_STATUS 82 /* R */ -#define SENSORS_PC87360_FAN3_STATUS 83 /* R */ - -#define SENSORS_PC87360_IN0 90 /* R */ -#define SENSORS_PC87360_IN1 91 /* R */ -#define SENSORS_PC87360_IN2 92 /* R */ -#define SENSORS_PC87360_IN3 93 /* R */ -#define SENSORS_PC87360_IN4 94 /* R */ -#define SENSORS_PC87360_IN5 95 /* R */ -#define SENSORS_PC87360_IN6 96 /* R */ -#define SENSORS_PC87360_IN7 97 /* R */ -#define SENSORS_PC87360_IN8 98 /* R */ -#define SENSORS_PC87360_IN9 99 /* R */ -#define SENSORS_PC87360_IN10 100 /* R */ -#define SENSORS_PC87360_IN0_MIN 110 /* RW */ -#define SENSORS_PC87360_IN1_MIN 111 /* RW */ -#define SENSORS_PC87360_IN2_MIN 112 /* RW */ -#define SENSORS_PC87360_IN3_MIN 113 /* RW */ -#define SENSORS_PC87360_IN4_MIN 114 /* RW */ -#define SENSORS_PC87360_IN5_MIN 115 /* RW */ -#define SENSORS_PC87360_IN6_MIN 116 /* RW */ -#define SENSORS_PC87360_IN7_MIN 117 /* RW */ -#define SENSORS_PC87360_IN8_MIN 118 /* RW */ -#define SENSORS_PC87360_IN9_MIN 119 /* RW */ -#define SENSORS_PC87360_IN10_MIN 120 /* RW */ -#define SENSORS_PC87360_IN0_MAX 130 /* RW */ -#define SENSORS_PC87360_IN1_MAX 131 /* RW */ -#define SENSORS_PC87360_IN2_MAX 132 /* RW */ -#define SENSORS_PC87360_IN3_MAX 133 /* RW */ -#define SENSORS_PC87360_IN4_MAX 134 /* RW */ -#define SENSORS_PC87360_IN5_MAX 135 /* RW */ -#define SENSORS_PC87360_IN6_MAX 136 /* RW */ -#define SENSORS_PC87360_IN7_MAX 137 /* RW */ -#define SENSORS_PC87360_IN8_MAX 138 /* RW */ -#define SENSORS_PC87360_IN9_MAX 139 /* RW */ -#define SENSORS_PC87360_IN10_MAX 140 /* RW */ -#define SENSORS_PC87360_IN0_STATUS 150 /* R */ -#define SENSORS_PC87360_IN1_STATUS 151 /* R */ -#define SENSORS_PC87360_IN2_STATUS 152 /* R */ -#define SENSORS_PC87360_IN3_STATUS 153 /* R */ -#define SENSORS_PC87360_IN4_STATUS 154 /* R */ -#define SENSORS_PC87360_IN5_STATUS 155 /* R */ -#define SENSORS_PC87360_IN6_STATUS 156 /* R */ -#define SENSORS_PC87360_IN7_STATUS 157 /* R */ -#define SENSORS_PC87360_IN8_STATUS 158 /* R */ -#define SENSORS_PC87360_IN9_STATUS 159 /* R */ -#define SENSORS_PC87360_IN10_STATUS 160 /* R */ - -#define SENSORS_PC87360_TEMP1 171 /* R */ -#define SENSORS_PC87360_TEMP2 172 /* R */ -#define SENSORS_PC87360_TEMP3 173 /* R */ -#define SENSORS_PC87360_TEMP4 174 /* R */ -#define SENSORS_PC87360_TEMP5 175 /* R */ -#define SENSORS_PC87360_TEMP6 176 /* R */ -#define SENSORS_PC87360_TEMP1_MIN 181 /* RW */ -#define SENSORS_PC87360_TEMP2_MIN 182 /* RW */ -#define SENSORS_PC87360_TEMP3_MIN 183 /* RW */ -#define SENSORS_PC87360_TEMP4_MIN 184 /* RW */ -#define SENSORS_PC87360_TEMP5_MIN 185 /* RW */ -#define SENSORS_PC87360_TEMP6_MIN 186 /* RW */ -#define SENSORS_PC87360_TEMP1_MAX 191 /* RW */ -#define SENSORS_PC87360_TEMP2_MAX 192 /* RW */ -#define SENSORS_PC87360_TEMP3_MAX 193 /* RW */ -#define SENSORS_PC87360_TEMP4_MAX 194 /* RW */ -#define SENSORS_PC87360_TEMP5_MAX 195 /* RW */ -#define SENSORS_PC87360_TEMP6_MAX 196 /* RW */ -#define SENSORS_PC87360_TEMP1_CRIT 201 /* RW */ -#define SENSORS_PC87360_TEMP2_CRIT 202 /* RW */ -#define SENSORS_PC87360_TEMP3_CRIT 203 /* RW */ -#define SENSORS_PC87360_TEMP4_CRIT 204 /* RW */ -#define SENSORS_PC87360_TEMP5_CRIT 205 /* RW */ -#define SENSORS_PC87360_TEMP6_CRIT 206 /* RW */ -#define SENSORS_PC87360_TEMP1_STATUS 211 /* R */ -#define SENSORS_PC87360_TEMP2_STATUS 212 /* R */ -#define SENSORS_PC87360_TEMP3_STATUS 213 /* R */ -#define SENSORS_PC87360_TEMP4_STATUS 214 /* R */ -#define SENSORS_PC87360_TEMP5_STATUS 215 /* R */ -#define SENSORS_PC87360_TEMP6_STATUS 216 /* R */ - -#define SENSORS_PC87360_VID 240 /* R */ -#define SENSORS_PC87360_VRM 241 /* RW */ - -#define SENSORS_PC87427_PREFIX "pc87427" - -/* fan n from 1 to 8 */ -#define SENSORS_PC87427_FAN(n) (n) /* R */ -#define SENSORS_PC87427_FAN_MIN(n) (16 + (n)) /* RW */ -#define SENSORS_PC87427_FAN_ALARM(n) (32 + (n)) /* R */ -#define SENSORS_PC87427_FAN_FAULT(n) (48 + (n)) /* R */ - -#define SENSORS_LM92_PREFIX "lm92" - -#define SENSORS_LM92_TEMP_HIGH 1 /* RW */ -#define SENSORS_LM92_TEMP_LOW 2 /* RW */ -#define SENSORS_LM92_TEMP_CRIT 3 /* RW */ -#define SENSORS_LM92_TEMP_HYST 4 /* RW */ -#define SENSORS_LM92_TEMP 5 /* R */ -#define SENSORS_LM92_ALARMS 6 /* R */ - -#define SENSORS_VT8231_PREFIX "vt8231" - -#define SENSORS_VT8231_IN0 1 /* R */ -#define SENSORS_VT8231_IN1 2 /* R */ -#define SENSORS_VT8231_IN2 3 /* R */ -#define SENSORS_VT8231_IN3 4 /* R */ -#define SENSORS_VT8231_IN4 5 /* R */ -#define SENSORS_VT8231_IN5 6 /* R */ -#define SENSORS_VT8231_IN0_MIN 11 /* RW */ -#define SENSORS_VT8231_IN1_MIN 12 /* RW */ -#define SENSORS_VT8231_IN2_MIN 13 /* RW */ -#define SENSORS_VT8231_IN3_MIN 14 /* RW */ -#define SENSORS_VT8231_IN4_MIN 15 /* RW */ -#define SENSORS_VT8231_IN5_MIN 16 /* RW */ -#define SENSORS_VT8231_IN0_MAX 21 /* RW */ -#define SENSORS_VT8231_IN1_MAX 22 /* RW */ -#define SENSORS_VT8231_IN2_MAX 23 /* RW */ -#define SENSORS_VT8231_IN3_MAX 24 /* RW */ -#define SENSORS_VT8231_IN4_MAX 25 /* RW */ -#define SENSORS_VT8231_IN5_MAX 26 /* RW */ -#define SENSORS_VT8231_FAN1 31 /* R */ -#define SENSORS_VT8231_FAN2 32 /* R */ -#define SENSORS_VT8231_FAN1_MIN 41 /* RW */ -#define SENSORS_VT8231_FAN2_MIN 42 /* RW */ -#define SENSORS_VT8231_TEMP 51 /* R */ -#define SENSORS_VT8231_TEMP_HYST 52 /* RW */ -#define SENSORS_VT8231_TEMP_OVER 53 /* RW */ -#define SENSORS_VT8231_TEMP2 54 /* R */ -#define SENSORS_VT8231_TEMP2_HYST 55 /* RW */ -#define SENSORS_VT8231_TEMP2_OVER 56 /* RW */ -#define SENSORS_VT8231_TEMP3 57 /* R */ -#define SENSORS_VT8231_TEMP3_HYST 58 /* RW */ -#define SENSORS_VT8231_TEMP3_OVER 59 /* RW */ -#define SENSORS_VT8231_TEMP4 60 /* R */ -#define SENSORS_VT8231_TEMP4_HYST 61 /* RW */ -#define SENSORS_VT8231_TEMP4_OVER 62 /* RW */ -#define SENSORS_VT8231_TEMP5 63 /* R */ -#define SENSORS_VT8231_TEMP5_HYST 64 /* RW */ -#define SENSORS_VT8231_TEMP5_OVER 65 /* RW */ -#define SENSORS_VT8231_TEMP6 66 /* R */ -#define SENSORS_VT8231_TEMP6_HYST 67 /* RW */ -#define SENSORS_VT8231_TEMP6_OVER 68 /* RW */ -#define SENSORS_VT8231_FAN1_DIV 75 /* RW */ -#define SENSORS_VT8231_FAN2_DIV 76 /* RW */ -#define SENSORS_VT8231_ALARMS 81 /* R */ -#define SENSORS_VT8231_VID 82 /* R */ -#define SENSORS_VT8231_VRM 83 /* RW */ -#define SENSORS_VT8231_UCH 84 /* RW */ - -#define SENSORS_BMC_PREFIX "bmc" - -/* quantity of each sensor is unknown, so just define the - first one of each and keep them 100 apart. */ -#define SENSORS_BMC_ALARMS 1 /* R */ -#define SENSORS_BMC_IN1 101 /* R */ -#define SENSORS_BMC_IN1_MIN 201 /* RW */ -#define SENSORS_BMC_IN1_MAX 301 /* RW */ -#define SENSORS_BMC_FAN1 1001 /* R */ -#define SENSORS_BMC_FAN1_MIN 1101 /* RW */ -#define SENSORS_BMC_TEMP1 2001 /* R */ -#define SENSORS_BMC_TEMP1_MIN 2101 /* RW */ -#define SENSORS_BMC_TEMP1_MAX 2201 /* RW */ -#define SENSORS_BMC_CURR1 3001 /* R */ -#define SENSORS_BMC_CURR1_MIN 3101 /* RW */ -#define SENSORS_BMC_CURR1_MAX 3201 /* RW */ - -#define SENSORS_LM93_PREFIX "lm93" - -#define SENSORS_LM93_IN1 1011 -#define SENSORS_LM93_IN1_MIN 1012 -#define SENSORS_LM93_IN1_MAX 1013 -#define SENSORS_LM93_IN2 1021 -#define SENSORS_LM93_IN2_MIN 1022 -#define SENSORS_LM93_IN2_MAX 1023 -#define SENSORS_LM93_IN3 1031 -#define SENSORS_LM93_IN3_MIN 1032 -#define SENSORS_LM93_IN3_MAX 1033 -#define SENSORS_LM93_IN4 1041 -#define SENSORS_LM93_IN4_MIN 1042 -#define SENSORS_LM93_IN4_MAX 1043 -#define SENSORS_LM93_IN5 1051 -#define SENSORS_LM93_IN5_MIN 1052 -#define SENSORS_LM93_IN5_MAX 1053 -#define SENSORS_LM93_IN6 1061 -#define SENSORS_LM93_IN6_MIN 1062 -#define SENSORS_LM93_IN6_MAX 1063 -#define SENSORS_LM93_IN7 1071 -#define SENSORS_LM93_IN7_MIN 1072 -#define SENSORS_LM93_IN7_MAX 1073 -#define SENSORS_LM93_IN8 1081 -#define SENSORS_LM93_IN8_MIN 1082 -#define SENSORS_LM93_IN8_MAX 1083 -#define SENSORS_LM93_IN9 1091 -#define SENSORS_LM93_IN9_MIN 1092 -#define SENSORS_LM93_IN9_MAX 1093 -#define SENSORS_LM93_IN10 1101 -#define SENSORS_LM93_IN10_MIN 1102 -#define SENSORS_LM93_IN10_MAX 1103 -#define SENSORS_LM93_IN11 1111 -#define SENSORS_LM93_IN11_MIN 1112 -#define SENSORS_LM93_IN11_MAX 1113 -#define SENSORS_LM93_IN12 1121 -#define SENSORS_LM93_IN12_MIN 1122 -#define SENSORS_LM93_IN12_MAX 1123 -#define SENSORS_LM93_IN13 1131 -#define SENSORS_LM93_IN13_MIN 1132 -#define SENSORS_LM93_IN13_MAX 1133 -#define SENSORS_LM93_IN14 1141 -#define SENSORS_LM93_IN14_MIN 1142 -#define SENSORS_LM93_IN14_MAX 1143 -#define SENSORS_LM93_IN15 1151 -#define SENSORS_LM93_IN15_MIN 1152 -#define SENSORS_LM93_IN15_MAX 1153 -#define SENSORS_LM93_IN16 1161 -#define SENSORS_LM93_IN16_MIN 1162 -#define SENSORS_LM93_IN16_MAX 1163 -#define SENSORS_LM93_TEMP1 2011 -#define SENSORS_LM93_TEMP1_MIN 2012 -#define SENSORS_LM93_TEMP1_MAX 2013 -#define SENSORS_LM93_TEMP2 2021 -#define SENSORS_LM93_TEMP2_MIN 2022 -#define SENSORS_LM93_TEMP2_MAX 2023 -#define SENSORS_LM93_TEMP3 2031 -#define SENSORS_LM93_TEMP3_MIN 2032 -#define SENSORS_LM93_TEMP3_MAX 2033 -#define SENSORS_LM93_FAN1 3011 -#define SENSORS_LM93_FAN1_MIN 3012 -#define SENSORS_LM93_FAN2 3021 -#define SENSORS_LM93_FAN2_MIN 3022 -#define SENSORS_LM93_FAN3 3031 -#define SENSORS_LM93_FAN3_MIN 3032 -#define SENSORS_LM93_FAN4 3041 -#define SENSORS_LM93_FAN4_MIN 3042 -#define SENSORS_LM93_VID1 4001 -#define SENSORS_LM93_VID2 4002 -#define SENSORS_LM93_ALARMS 5001 - -#define SENSORS_ASB100_PREFIX "asb100" - -#define SENSORS_ASB100_IN0 0x01 /* R */ -#define SENSORS_ASB100_IN1 0x02 /* R */ -#define SENSORS_ASB100_IN2 0x03 /* R */ -#define SENSORS_ASB100_IN3 0x04 /* R */ -#define SENSORS_ASB100_IN4 0x05 /* R */ -#define SENSORS_ASB100_IN5 0x06 /* R */ -#define SENSORS_ASB100_IN6 0x07 /* R */ -#define SENSORS_ASB100_IN0_MIN 0x11 /* RW */ -#define SENSORS_ASB100_IN1_MIN 0x12 /* RW */ -#define SENSORS_ASB100_IN2_MIN 0x13 /* RW */ -#define SENSORS_ASB100_IN3_MIN 0x14 /* RW */ -#define SENSORS_ASB100_IN4_MIN 0x15 /* RW */ -#define SENSORS_ASB100_IN5_MIN 0x16 /* RW */ -#define SENSORS_ASB100_IN6_MIN 0x17 /* RW */ -#define SENSORS_ASB100_IN0_MAX 0x21 /* RW */ -#define SENSORS_ASB100_IN1_MAX 0x22 /* RW */ -#define SENSORS_ASB100_IN2_MAX 0x23 /* RW */ -#define SENSORS_ASB100_IN3_MAX 0x24 /* RW */ -#define SENSORS_ASB100_IN4_MAX 0x25 /* RW */ -#define SENSORS_ASB100_IN5_MAX 0x26 /* RW */ -#define SENSORS_ASB100_IN6_MAX 0x27 /* RW */ -#define SENSORS_ASB100_FAN1 0x31 /* R */ -#define SENSORS_ASB100_FAN2 0x32 /* R */ -#define SENSORS_ASB100_FAN3 0x33 /* R */ -#define SENSORS_ASB100_FAN1_MIN 0x41 /* RW */ -#define SENSORS_ASB100_FAN2_MIN 0x42 /* RW */ -#define SENSORS_ASB100_FAN3_MIN 0x43 /* RW */ -#define SENSORS_ASB100_TEMP1 0x51 /* R */ -#define SENSORS_ASB100_TEMP1_HYST 0x52 /* RW */ -#define SENSORS_ASB100_TEMP1_OVER 0x53 /* RW */ -#define SENSORS_ASB100_TEMP2 0x54 /* R */ -#define SENSORS_ASB100_TEMP2_HYST 0x55 /* RW */ -#define SENSORS_ASB100_TEMP2_OVER 0x56 /* RW */ -#define SENSORS_ASB100_TEMP3 0x57 /* R */ -#define SENSORS_ASB100_TEMP3_HYST 0x58 /* RW */ -#define SENSORS_ASB100_TEMP3_OVER 0x59 /* RW */ -#define SENSORS_ASB100_TEMP4 0x5a /* R */ -#define SENSORS_ASB100_TEMP4_HYST 0x5b /* RW */ -#define SENSORS_ASB100_TEMP4_OVER 0x5c /* RW */ -#define SENSORS_ASB100_VID 0x61 /* R */ -#define SENSORS_ASB100_VRM 0x62 /* RW */ -#define SENSORS_ASB100_FAN1_DIV 0x71 /* RW */ -#define SENSORS_ASB100_FAN2_DIV 0x72 /* RW */ -#define SENSORS_ASB100_FAN3_DIV 0x73 /* RW */ -#define SENSORS_ASB100_ALARMS 0x81 /* R */ -#define SENSORS_ASB100_BEEP_ENABLE 0x82 /* RW */ -#define SENSORS_ASB100_BEEPS 0x83 /* RW */ - -#define SENSORS_XEONTEMP_PREFIX "xeontemp" - -#define SENSORS_XEONTEMP_REMOTE_TEMP 54 /* R */ -#define SENSORS_XEONTEMP_REMOTE_TEMP_HYST 55 /* RW */ -#define SENSORS_XEONTEMP_REMOTE_TEMP_OVER 56 /* RW */ -#define SENSORS_XEONTEMP_ALARMS 81 /* R */ - -/* MAX1619 chip */ - -#define SENSORS_MAX1619_PREFIX "max1619" - -#define SENSORS_MAX1619_LOCAL_TEMP 51 /* R */ -#define SENSORS_MAX1619_REMOTE_TEMP 52 /* R */ -#define SENSORS_MAX1619_REMOTE_LOW 53 /* RW */ -#define SENSORS_MAX1619_REMOTE_HIGH 54 /* RW */ -#define SENSORS_MAX1619_REMOTE_MAX 55 /* RW */ -#define SENSORS_MAX1619_REMOTE_HYST 56 /* RW */ -#define SENSORS_MAX1619_ALARMS 81 /* R */ - -/* MAX6650 / 1 chips */ - -#define SENSORS_MAX6650_PREFIX "max6650" - -#define SENSORS_MAX6650_FAN1_TACH 1 /* R */ -#define SENSORS_MAX6650_FAN2_TACH 2 /* R */ -#define SENSORS_MAX6650_FAN3_TACH 3 /* R */ -#define SENSORS_MAX6650_FAN4_TACH 4 /* R */ -#define SENSORS_MAX6650_SPEED 5 /* RW */ - -/* SMSC47B397-NC chip */ -#define SENSORS_SMSC47B397_PREFIX "smsc47b397" - -#define SENSORS_SMSC47B397_TEMP1 0x01 /* R */ -#define SENSORS_SMSC47B397_TEMP2 0x02 /* R */ -#define SENSORS_SMSC47B397_TEMP3 0x03 /* R */ -#define SENSORS_SMSC47B397_TEMP4 0x04 /* R */ -#define SENSORS_SMSC47B397_FAN1 0x11 /* R */ -#define SENSORS_SMSC47B397_FAN2 0x12 /* R */ -#define SENSORS_SMSC47B397_FAN3 0x13 /* R */ -#define SENSORS_SMSC47B397_FAN4 0x14 /* R */ - -/* Fintek F71805F/FG and F71872F/FG chips */ -#define SENSORS_F71805F_PREFIX "f71805f" -#define SENSORS_F71872F_PREFIX "f71872f" - -/* in n from 0 to 10 */ -#define SENSORS_F71805F_IN(n) (1 + (n)) -#define SENSORS_F71805F_IN_MIN(n) (16 + (n)) -#define SENSORS_F71805F_IN_MAX(n) (31 + (n)) -/* fan n from 1 to 3 */ -#define SENSORS_F71805F_FAN(n) (50 + (n)) -#define SENSORS_F71805F_FAN_MIN(n) (60 + (n)) -/* temp n from 1 to 3 */ -#define SENSORS_F71805F_TEMP(n) (80 + (n)) -#define SENSORS_F71805F_TEMP_MAX(n) (90 + (n)) -#define SENSORS_F71805F_TEMP_HYST(n) (100 + (n)) -#define SENSORS_F71805F_TEMP_TYPE(n) (110 + (n)) -/* alarms */ -#define SENSORS_F71805F_ALARMS_IN 200 -#define SENSORS_F71805F_ALARMS_FAN 201 -#define SENSORS_F71805F_ALARMS_TEMP 202 - -/* Abit uGuru chips */ -#define SENSORS_ABITUGURU_PREFIX "abituguru" -#define SENSORS_ABITUGURU3_PREFIX "abituguru3" - -/* in n from 0 to 10 */ -#define SENSORS_ABITUGURU_IN(n) (0x01 + (n)) /* R */ -#define SENSORS_ABITUGURU_IN_MIN(n) (0x11 + (n)) /* RW */ -#define SENSORS_ABITUGURU_IN_MIN_ALARM(n) (0x21 + (n)) /* R */ -#define SENSORS_ABITUGURU_IN_MAX(n) (0x31 + (n)) /* RW */ -#define SENSORS_ABITUGURU_IN_MAX_ALARM(n) (0x41 + (n)) /* R */ -/* temp n from 1 to 7 */ -#define SENSORS_ABITUGURU_TEMP(n) (0x50 + (n)) /* R */ -#define SENSORS_ABITUGURU_TEMP_ALARM(n) (0x60 + (n)) /* R */ -#define SENSORS_ABITUGURU_TEMP_MAX(n) (0x70 + (n)) /* RW */ -#define SENSORS_ABITUGURU_TEMP_CRIT(n) (0x80 + (n)) /* RW */ -/* fan n from 1 to 6 */ -#define SENSORS_ABITUGURU_FAN(n) (0x90 + (n)) /* R */ -#define SENSORS_ABITUGURU_FAN_ALARM(n) (0xA0 + (n)) /* R */ -#define SENSORS_ABITUGURU_FAN_MIN(n) (0xB0 + (n)) /* RW */ - -/* K8TEMP */ -#define SENSORS_K8TEMP_PREFIX "k8temp" -#define SENSORS_K8TEMP_TEMP1 0x01 /* R */ -#define SENSORS_K8TEMP_TEMP2 0x02 /* R */ -#define SENSORS_K8TEMP_TEMP3 0x03 /* R */ -#define SENSORS_K8TEMP_TEMP4 0x04 /* R */ - -/* coretemp */ - -#define SENSORS_CORETEMP_PREFIX "coretemp" -#define SENSORS_CORETEMP_TEMP1 0x01 /* R */ -#define SENSORS_CORETEMP_TEMP1_CRIT 0x02 /* R */ -#define SENSORS_CORETEMP_TEMP1_CRIT_ALARM 0x03 /* R */ - -/* DME1737 chips */ - -#define SENSORS_DME1737_PREFIX "dme1737" -#define SENSORS_SCH311X_PREFIX "sch311x" - -/* in n from 0 to 6 */ -#define SENSORS_DME1737_IN(n) (0x01 + (n)) /* R */ -#define SENSORS_DME1737_IN_MIN(n) (0x11 + (n)) /* RW */ -#define SENSORS_DME1737_IN_MAX(n) (0x21 + (n)) /* RW */ -#define SENSORS_DME1737_IN_ALARM(n) (0x31 + (n)) /* R */ - -/* temp n from 1 to 3*/ -#define SENSORS_DME1737_TEMP(n) (0x41 + (n)) /* R */ -#define SENSORS_DME1737_TEMP_MIN(n) (0x51 + (n)) /* RW */ -#define SENSORS_DME1737_TEMP_MAX(n) (0x61 + (n)) /* RW */ -#define SENSORS_DME1737_TEMP_ALARM(n) (0x71 + (n)) /* R */ -#define SENSORS_DME1737_TEMP_FAULT(n) (0x81 + (n)) /* R */ - -/* fan n from 1 to 6 */ -#define SENSORS_DME1737_FAN(n) (0x91 + (n)) /* R */ -#define SENSORS_DME1737_FAN_MIN(n) (0xa1 + (n)) /* RW */ -#define SENSORS_DME1737_FAN_ALARM(n) (0xb1 + (n)) /* R */ - -/* pwm n from 1 to 3 and 5 to 6 */ -#define SENSORS_DME1737_PWM(n) (0xc1 + (n)) /* RW */ -#define SENSORS_DME1737_PWM_ENABLE(n) (0xd1 + (n)) /* RW */ -#define SENSORS_DME1737_PWM_FREQ(n) (0xe1 + (n)) /* RW */ - -#define SENSORS_DME1737_VID (0xf0) /* R */ -#define SENSORS_DME1737_VRM (0xf1) /* RW */ - -/* applesmc */ - -#define SENSORS_APPLESMC_PREFIX "applesmc" - -/* temp n from 0 to 11 */ -#define SENSORS_APPLESMC_TEMP(n) (0x01 + (n)) /* R */ - -/* fan n from 0 to 1 */ -#define SENSORS_APPLESMC_FAN(n) (0x21 + (n)) /* R */ -#define SENSORS_APPLESMC_FAN_MIN(n) (0x41 + (n)) /* R */ -#define SENSORS_APPLESMC_FAN_MAX(n) (0x61 + (n)) /* R */ -#define SENSORS_APPLESMC_FAN_SAFE(n) (0x81 + (n)) /* R */ - -/* Fintek F71882FG and F71883FG chips */ -#define SENSORS_F71882FG_PREFIX "f71882fg" - -/* in n from 0 to 8 */ -#define SENSORS_F71882FG_IN(n) (1 + (n)) -#define SENSORS_F71882FG_IN_MAX(n) (16 + (n)) -#define SENSORS_F71882FG_IN_ALARM(n) (31 + (n)) -/* fan n from 1 to 4 */ -#define SENSORS_F71882FG_FAN(n) (50 + (n)) -#define SENSORS_F71882FG_FAN_ALARM(n) (60 + (n)) -/* temp n from 1 to 3 */ -#define SENSORS_F71882FG_TEMP(n) (80 + (n)) -#define SENSORS_F71882FG_TEMP_MAX(n) (90 + (n)) -#define SENSORS_F71882FG_TEMP_MAX_HYST(n) (100 + (n)) -#define SENSORS_F71882FG_TEMP_CRIT(n) (110 + (n)) -#define SENSORS_F71882FG_TEMP_CRIT_HYST(n) (120 + (n)) -#define SENSORS_F71882FG_TEMP_ALARM(n) (130 + (n)) -#define SENSORS_F71882FG_TEMP_FAULT(n) (140 + (n)) -#define SENSORS_F71882FG_TEMP_TYPE(n) (150 + (n)) - -/* Fujitsu Siemens Computers Heimdal and Heracles */ -#define SENSORS_FSCHMD_PREFIX "fschmd" -#define SENSORS_FSCHRC_PREFIX "fschrc" - -/* Note, we start with feature numbers of 60+ to not have any overlapping - features with the old FSCPOS, FSCSCY and FSCHER feature lists, as the - FSCHMD feature defines for features only exported by the new FSCHMD driver - are reused in the feature lists of the FSCPOS, FSCSCY and FSCHER */ - -/* in n from 0 to 3 */ -#define SENSORS_FSCHMD_IN(n) (60 + (n)) -/* fan n from 1 to 5 (4 for the hrc) */ -#define SENSORS_FSCHMD_FAN(n) (70 + (n)) -#define SENSORS_FSCHMD_FAN_DIV(n) (80 + (n)) -#define SENSORS_FSCHMD_FAN_ALARM(n) (90 + (n)) -#define SENSORS_FSCHMD_FAN_FAULT(n) (100 + (n)) -/* temp n from 1 to 5 (3 for the hrc) */ -#define SENSORS_FSCHMD_TEMP(n) (110 + (n)) -#define SENSORS_FSCHMD_TEMP_MAX(n) (120 + (n)) -#define SENSORS_FSCHMD_TEMP_ALARM(n) (130 + (n)) -#define SENSORS_FSCHMD_TEMP_FAULT(n) (140 + (n)) - -#endif /* def LIB_SENSORS_CHIPS_H */ diff --git a/lib/conf-lex.l b/lib/conf-lex.l index 4c77e202..afacefa7 100644 --- a/lib/conf-lex.l +++ b/lib/conf-lex.l @@ -15,7 +15,8 @@ You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + MA 02110-1301 USA. */ #include @@ -74,10 +75,6 @@ FLOAT [[:digit:]]*\.?[[:digit:]]+ NUM 0|([1-9][[:digit:]]*) - /* Only number between 1 and 255, octally represented. */ - -OCTESC (1[0-7]{0,2})|([2-7][0-7]?)|(0[1-7][0-7]?)|(00[1-7]) - %% @@ -311,26 +308,12 @@ ignore{BLANK}* { \\t buffer_add_char("\t"); \\v buffer_add_char("\v"); - /* We can't support \0, this would cause havoc! */ - -\\{OCTESC} { - int res; - sscanf(sensors_yytext+1,"%o",&res); - buffer_add_char(&res); - } - /* Other escapes: just copy the character behind the slash */ \\. { buffer_add_char(&sensors_yytext[1]); } - /* This prevents backing up; it is otherwise purely redundant */ - -\\00 { - buffer_add_char("00"); - } - /* Anything else (including a bare '\' which may be followed by EOF) */ \\ | diff --git a/lib/conf-parse.y b/lib/conf-parse.y index 84eaee2e..47fea254 100644 --- a/lib/conf-parse.y +++ b/lib/conf-parse.y @@ -15,7 +15,8 @@ You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + MA 02110-1301 USA. */ #define YYERROR_VERBOSE @@ -81,7 +82,7 @@ static sensors_chip *current_chip = NULL; void *nothing; sensors_chip_name_list chips; sensors_expr *expr; - int bus; + sensors_bus_id bus; sensors_chip_name chip; int line; } @@ -105,9 +106,8 @@ static sensors_chip *current_chip = NULL; %type chip_name_list %type expression -%type i2cbus_name +%type bus_id %type adapter_name -%type algorithm_name %type function_name %type string %type chip_name @@ -121,7 +121,6 @@ input: /* empty */ ; line: bus_statement EOL - | busalgo_statement EOL | label_statement EOL | set_statement EOL | chip_statement EOL @@ -130,26 +129,15 @@ line: bus_statement EOL | error EOL ; -bus_statement: BUS i2cbus_name adapter_name +bus_statement: BUS bus_id adapter_name { sensors_bus new_el; new_el.lineno = $1; - new_el.number = $2; + new_el.bus = $2; new_el.adapter = $3; bus_add_el(&new_el); } ; -/* for compatibility, deprecated */ -busalgo_statement: BUS i2cbus_name adapter_name algorithm_name - { sensors_bus new_el; - new_el.lineno = $1; - new_el.number = $2; - new_el.adapter = $3; - free($4); - bus_add_el(&new_el); - } -; - label_statement: LABEL function_name string { sensors_label new_el; if (!current_chip) { @@ -307,24 +295,18 @@ expression: FLOAT } ; -i2cbus_name: NAME - { int res = sensors_parse_i2cbus_name($1,&$$); +bus_id: NAME + { int res = sensors_parse_bus_id($1,&$$); free($1); if (res) { - sensors_yyerror("Parse error in i2c bus name"); + sensors_yyerror("Parse error in bus id"); YYERROR; } } ; adapter_name: NAME - { sensors_strip_of_spaces($1); - $$ = $1; } -; - -algorithm_name: NAME - { sensors_strip_of_spaces($1); - $$ = $1; } + { $$ = $1; } ; function_name: NAME diff --git a/lib/conf.h b/lib/conf.h index 3fa07504..24cb9b8a 100644 --- a/lib/conf.h +++ b/lib/conf.h @@ -14,19 +14,20 @@ You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + MA 02110-1301 USA. */ #ifndef LIB_SENSORS_CONF_H #define LIB_SENSORS_CONF_H /* This is defined in conf-lex.l */ -extern int sensors_yylex(void); +int sensors_yylex(void); extern char sensors_lex_error[]; extern int sensors_yylineno; extern FILE *sensors_yyin; /* This is defined in conf-parse.y */ -extern int sensors_yyparse(void); +int sensors_yyparse(void); #endif /* LIB_SENSORS_CONF_H */ diff --git a/lib/data.c b/lib/data.c index bfe0847a..df58242d 100644 --- a/lib/data.c +++ b/lib/data.c @@ -1,6 +1,7 @@ /* data.c - Part of libsensors, a Linux library for reading sensor data. Copyright (c) 1998, 1999 Frodo Looijaard + Copyright (C) 2007 Jean Delvare This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -14,19 +15,23 @@ You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + MA 02110-1301 USA. */ +/* this define needed for strndup() */ +#define _GNU_SOURCE + #include #include +#include "access.h" #include "error.h" #include "data.h" #include "sensors.h" #include "../version.h" const char *libsensors_version = LM_VERSION; -const char *libsensors_date = LM_DATE; sensors_chip *sensors_config_chips = NULL; int sensors_config_chips_count = 0; @@ -36,7 +41,7 @@ sensors_bus *sensors_config_busses = NULL; int sensors_config_busses_count = 0; int sensors_config_busses_max = 0; -sensors_proc_chips_entry *sensors_proc_chips = NULL; +sensors_chip_features *sensors_proc_chips = NULL; int sensors_proc_chips_count = 0; int sensors_proc_chips_max = 0; @@ -44,10 +49,8 @@ sensors_bus *sensors_proc_bus = NULL; int sensors_proc_bus_count = 0; int sensors_proc_bus_max = 0; -static int sensors_substitute_chip(sensors_chip_name *name,int lineno); - -/* Wow, this must be one of the ugliest functions I have ever written. - The idea is that it parses a chip name. These are valid names: +/* + Parse a chip name to the internal representation. These are valid names: lm78-i2c-10-5e *-i2c-10-5e lm78-i2c-10-* *-i2c-10-* @@ -56,225 +59,192 @@ static int sensors_substitute_chip(sensors_chip_name *name,int lineno); lm78-isa-10dd *-isa-10dd lm78-isa-* *-isa-* lm78-* *-* - * - Here 'lm78' can be any prefix. To complicate matters, such a prefix - can also contain dashes (like lm78-j, for example!). 'i2c' and 'isa' are + + Here 'lm78' can be any prefix. 'i2c' and 'isa' are literal strings, just like all dashes '-' and wildcards '*'. '10' can be any decimal i2c bus number. '5e' can be any hexadecimal i2c device address, and '10dd' any hexadecimal isa address. - If '*' is used in prefixes, together with dashes, ambiguous parses are - introduced. In that case, the prefix is kept as small as possible. - The 'prefix' part in the result is freshly allocated. All old contents of res is overwritten. res itself is not allocated. In case of an error return (ie. != 0), res is undefined, but all allocations are undone. - - Don't tell me there are bugs in here, because I'll start screaming :-) */ -int sensors_parse_chip_name(const char *orig_name, sensors_chip_name *res) +int sensors_parse_chip_name(const char *name, sensors_chip_name *res) { - char *part2, *part3, *part4; - char *name = strdup(orig_name); - int i; + char *dash; - /* Play it safe */ - res->busname = NULL; + /* First, the prefix. It's either "*" or a real chip name. */ + if (!strncmp(name, "*-", 2)) { + res->prefix = SENSORS_CHIP_NAME_PREFIX_ANY; + name += 2; + } else { + if (!(dash = strchr(name, '-'))) + return -SENSORS_ERR_CHIP_NAME; + res->prefix = strndup(name, dash - name); + if (!res->prefix) + sensors_fatal_error("sensors_parse_chip_name", + "Allocating name prefix"); + name = dash + 1; + } - if (! name) - sensors_fatal_error("sensors_parse_chip_name","Allocating new name"); - /* First split name in upto four pieces. */ - if ((part4 = strrchr(name,'-'))) - *part4++ = '\0'; - if ((part3 = strrchr(name,'-'))) - *part3++ = '\0'; - if ((part2 = strrchr(name,'-'))) - *part2++ = '\0'; + /* Then we have either a sole "*" (all chips with this name) or a bus + type and an address. */ + if (!strcmp(name, "*")) { + res->bus.type = SENSORS_BUS_TYPE_ANY; + res->bus.nr = SENSORS_BUS_NR_ANY; + res->addr = SENSORS_CHIP_NAME_ADDR_ANY; + return 0; + } - /* No dashes found? */ - if (! part4) { - if (!strcmp(name,"*")) { - res->prefix = SENSORS_CHIP_NAME_PREFIX_ANY; - res->bus = SENSORS_CHIP_NAME_BUS_ANY; - res->addr = SENSORS_CHIP_NAME_ADDR_ANY; - goto SUCCES; - } else - goto ERROR; - } + if (!(dash = strchr(name, '-'))) + goto ERROR; + if (!strncmp(name, "i2c", dash - name)) + res->bus.type = SENSORS_BUS_TYPE_I2C; + else if (!strncmp(name, "isa", dash - name)) + res->bus.type = SENSORS_BUS_TYPE_ISA; + else if (!strncmp(name, "pci", dash - name)) + res->bus.type = SENSORS_BUS_TYPE_PCI; + else if (!strncmp(name, "spi", dash - name)) + res->bus.type = SENSORS_BUS_TYPE_SPI; + else if (!strncmp(name, "virtual", dash - name)) + res->bus.type = SENSORS_BUS_TYPE_VIRTUAL; + else if (!strncmp(name, "acpi", dash - name)) + res->bus.type = SENSORS_BUS_TYPE_ACPI; + else + goto ERROR; + name = dash + 1; - /* At least one dash found. Now part4 is either '*', or an address */ - if (!strcmp(part4,"*")) - res->addr = SENSORS_CHIP_NAME_ADDR_ANY; - else { - if ((strlen(part4) > 4) || (strlen(part4) == 0)) - goto ERROR; - res->addr = 0; - for (i = 0; ; i++) { - switch (part4[i]) { - case '0': case '1': case '2': case '3': case '4': - case '5': case '6': case '7': case '8': case '9': - res->addr = res->addr * 16 + part4[i] - '0'; - break; - case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': - res->addr = res->addr * 16 + part4[i] - 'a' + 10; - break; - case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': - res->addr = res->addr * 16 + part4[i] - 'A' + 10; - break; - case 0: - goto DONE; - default: - goto ERROR; - } - } -DONE:; - } + /* Some bus types (i2c, spi) have an additional bus number. + For these, the next part is either a "*" (any bus of that type) + or a decimal number. */ + switch (res->bus.type) { + case SENSORS_BUS_TYPE_I2C: + case SENSORS_BUS_TYPE_SPI: + if (!strncmp(name, "*-", 2)) { + res->bus.nr = SENSORS_BUS_NR_ANY; + name += 2; + break; + } - /* OK. So let's look at part3. It must either be the number of the - i2c bus (and then part2 *must* be "i2c"), or it must be "isa", - or, if part4 was "*", it belongs to 'prefix'. Or no second dash - was found at all, of course. */ - if (! part3) { - if (res->addr == SENSORS_CHIP_NAME_ADDR_ANY) { - res->bus = SENSORS_CHIP_NAME_BUS_ANY; - } else - goto ERROR; - } else if (!strcmp(part3,"isa")) { - res->bus = SENSORS_CHIP_NAME_BUS_ISA; - if (part2) - *(part2-1) = '-'; - } else if (!strcmp(part3,"pci")) { - res->bus = SENSORS_CHIP_NAME_BUS_PCI; - if (part2) - *(part2-1) = '-'; - } else if (part2 && !strcmp(part2,"i2c") && !strcmp(part3,"*")) - res->bus = SENSORS_CHIP_NAME_BUS_ANY_I2C; - else if (part2 && !strcmp(part2,"i2c")) { - if ((strlen(part3) > 3) || (strlen(part3) == 0)) - goto ERROR; - res->bus = 0; - for (i = 0; ; i++) { - switch (part3[i]) { - case '0': case '1': case '2': case '3': case '4': - case '5': case '6': case '7': case '8': case '9': - res->bus = res->bus * 10 + part3[i] - '0'; - break; - case 0: - goto DONE2; - default: - goto ERROR; - } - } -DONE2:; - } else if (res->addr == SENSORS_CHIP_NAME_ADDR_ANY) { - res->bus = SENSORS_CHIP_NAME_BUS_ANY; - if (part2) - *(part2-1) = '-'; - *(part3-1) = '-'; - } else if(part3 && part4) { - res->bus = SENSORS_CHIP_NAME_BUS_DUMMY; - if (! (res->busname = strdup(part3))) - sensors_fatal_error("sensors_parse_chip_name","Allocating new busname"); - } else - goto ERROR; + res->bus.nr = strtoul(name, &dash, 10); + if (*name == '\0' || *dash != '-' || res->bus.nr < 0) + goto ERROR; + name = dash + 1; + break; + default: + res->bus.nr = SENSORS_BUS_NR_ANY; + } - if (!strcmp(name,"*")) - res->prefix = SENSORS_CHIP_NAME_PREFIX_ANY; - else if (! (res->prefix = strdup(name))) - sensors_fatal_error("sensors_parse_chip_name", "Allocating name prefix"); - goto SUCCES; + /* Last part is the chip address, or "*" for any address. */ + if (!strcmp(name, "*")) { + res->addr = SENSORS_CHIP_NAME_ADDR_ANY; + } else { + res->addr = strtoul(name, &dash, 16); + if (*name == '\0' || *dash != '\0' || res->addr < 0) + goto ERROR; + } -SUCCES: - free(name); - return 0; + return 0; ERROR: - free(name); - return -SENSORS_ERR_CHIP_NAME; + free(res->prefix); + return -SENSORS_ERR_CHIP_NAME; } -int sensors_parse_i2cbus_name(const char *name, int *res) +int sensors_snprintf_chip_name(char *str, size_t size, + const sensors_chip_name *chip) { - int i; + if (sensors_chip_name_has_wildcards(chip)) + return -SENSORS_ERR_WILDCARDS; - if (! strcmp(name,"isa")) { - *res = SENSORS_CHIP_NAME_BUS_ISA; - return 0; - } - if (strncmp(name,"i2c-",4)) { - *res = SENSORS_CHIP_NAME_BUS_DUMMY; - return 0; - } - name += 4; - if ((strlen(name) > 3) || (strlen(name) == 0)) - return -SENSORS_ERR_BUS_NAME; - *res = 0; - for (i = 0; ; i++) { - switch (name[i]) { - case '0': case '1': case '2': case '3': case '4': - case '5': case '6': case '7': case '8': case '9': - *res = *res * 10 + name[i] - '0'; - break; - case 0: - return 0; - default: - return -SENSORS_ERR_BUS_NAME; - } - } + switch (chip->bus.type) { + case SENSORS_BUS_TYPE_ISA: + return snprintf(str, size, "%s-isa-%04x", chip->prefix, + chip->addr); + case SENSORS_BUS_TYPE_PCI: + return snprintf(str, size, "%s-pci-%04x", chip->prefix, + chip->addr); + case SENSORS_BUS_TYPE_I2C: + return snprintf(str, size, "%s-i2c-%hd-%02x", chip->prefix, + chip->bus.nr, chip->addr); + case SENSORS_BUS_TYPE_SPI: + return snprintf(str, size, "%s-spi-%hd-%x", chip->prefix, + chip->bus.nr, chip->addr); + case SENSORS_BUS_TYPE_VIRTUAL: + return snprintf(str, size, "%s-virtual-%x", chip->prefix, + chip->addr); + case SENSORS_BUS_TYPE_ACPI: + return snprintf(str, size, "%s-acpi-%x", chip->prefix, + chip->addr); + } + + return -SENSORS_ERR_CHIP_NAME; } - -#define SENSORS_CHIP_NAME_BUS_IGNORE -42 - -int sensors_substitute_chip(sensors_chip_name *name,int lineno) +int sensors_parse_bus_id(const char *name, sensors_bus_id *bus) { - int i,j; - for (i = 0; i < sensors_config_busses_count; i++) - if (sensors_config_busses[i].number == name->bus) - break; + char *endptr; - if (i == sensors_config_busses_count) { - sensors_parse_error("Undeclared i2c bus referenced",lineno); - name->bus = SENSORS_CHIP_NAME_BUS_IGNORE; - return -SENSORS_ERR_BUS_NAME; - } - - /* We used to compare both the adapter and the algorithm names for - bus matching, but Linux 2.6 has no more names for algorithms, and - it was redundant anyway. So we now only rely on the adapter name. */ - for (j = 0; j < sensors_proc_bus_count; j++) { - if (!strcmp(sensors_config_busses[i].adapter, - sensors_proc_bus[j].adapter)) { - name->bus = sensors_proc_bus[j].number; - return 0; - } - } - - /* We did not find a matching bus name, simply ignore this chip - config entry. */ - name->bus = SENSORS_CHIP_NAME_BUS_IGNORE; - return 0; + if (strncmp(name, "i2c-", 4)) { + return -SENSORS_ERR_BUS_NAME; + } + name += 4; + bus->type = SENSORS_BUS_TYPE_I2C; + bus->nr = strtoul(name, &endptr, 10); + if (*name == '\0' || *endptr != '\0' || bus->nr < 0) + return -SENSORS_ERR_BUS_NAME; + return 0; } +static int sensors_substitute_chip(sensors_chip_name *name, int lineno) +{ + int i, j; + for (i = 0; i < sensors_config_busses_count; i++) + if (sensors_config_busses[i].bus.type == name->bus.type && + sensors_config_busses[i].bus.nr == name->bus.nr) + break; + + if (i == sensors_config_busses_count) { + sensors_parse_error("Undeclared bus id referenced", lineno); + name->bus.nr = SENSORS_BUS_NR_IGNORE; + return -SENSORS_ERR_BUS_NAME; + } + + /* Compare the adapter names */ + for (j = 0; j < sensors_proc_bus_count; j++) { + if (!strcmp(sensors_config_busses[i].adapter, + sensors_proc_bus[j].adapter)) { + name->bus.nr = sensors_proc_bus[j].bus.nr; + return 0; + } + } + + /* We did not find a matching bus name, simply ignore this chip + config entry. */ + name->bus.nr = SENSORS_BUS_NR_IGNORE; + return 0; +} int sensors_substitute_busses(void) { - int err,i,j,lineno; - sensors_chip_name_list *chips; - int res=0; + int err, i, j, lineno; + sensors_chip_name_list *chips; + int res = 0; - for(i = 0; i < sensors_config_chips_count; i++) { - lineno = sensors_config_chips[i].lineno; - chips = &sensors_config_chips[i].chips; - for(j = 0; j < chips->fits_count; j++) - if ((chips->fits[j].bus != SENSORS_CHIP_NAME_BUS_ISA) && - (chips->fits[j].bus != SENSORS_CHIP_NAME_BUS_PCI) && - (chips->fits[j].bus != SENSORS_CHIP_NAME_BUS_DUMMY) && - (chips->fits[j].bus != SENSORS_CHIP_NAME_BUS_ANY) && - (chips->fits[j].bus != SENSORS_CHIP_NAME_BUS_ANY_I2C)) - if ((err = sensors_substitute_chip(chips->fits+j, lineno))) - res = err; - } - return res; + for (i = 0; i < sensors_config_chips_count; i++) { + lineno = sensors_config_chips[i].lineno; + chips = &sensors_config_chips[i].chips; + for (j = 0; j < chips->fits_count; j++) { + /* We can only substitute if a specific bus number + is given. */ + if (chips->fits[j].bus.nr == SENSORS_BUS_NR_ANY) + continue; + + err = sensors_substitute_chip(&chips->fits[j], lineno); + if (err) + res = err; + } + } + return res; } diff --git a/lib/data.h b/lib/data.h index 8cb0ba73..401bf125 100644 --- a/lib/data.h +++ b/lib/data.h @@ -1,6 +1,7 @@ /* data.h - Part of libsensors, a Linux library for reading sensor data. Copyright (c) 1998, 1999 Frodo Looijaard + Copyright (C) 2007 Jean Delvare This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -14,7 +15,8 @@ You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + MA 02110-1301 USA. */ #ifndef LIB_SENSORS_DATA_H @@ -27,142 +29,107 @@ data. */ /* Kinds of expression operators recognized */ -typedef enum sensors_operation { - sensors_add, sensors_sub, sensors_multiply, sensors_divide, - sensors_negate, sensors_exp, sensors_log } sensors_operation; +typedef enum sensors_operation { + sensors_add, sensors_sub, sensors_multiply, sensors_divide, + sensors_negate, sensors_exp, sensors_log, +} sensors_operation; /* An expression can have several forms */ typedef enum sensors_expr_kind { - sensors_kind_val, sensors_kind_source, sensors_kind_var, - sensors_kind_sub } sensors_expr_kind; + sensors_kind_val, sensors_kind_source, sensors_kind_var, + sensors_kind_sub +} sensors_expr_kind; /* An expression. It is either a floating point value, a variable name, an operation on subexpressions, or the special value 'sub' } */ struct sensors_expr; typedef struct sensors_subexpr { - sensors_operation op; - struct sensors_expr *sub1; - struct sensors_expr *sub2; + sensors_operation op; + struct sensors_expr *sub1; + struct sensors_expr *sub2; } sensors_subexpr; typedef struct sensors_expr { - sensors_expr_kind kind; - union { - double val; - char *var; - sensors_subexpr subexpr; - } data; + sensors_expr_kind kind; + union { + double val; + char *var; + sensors_subexpr subexpr; + } data; } sensors_expr; /* Config file label declaration: a feature name, combined with the label value */ typedef struct sensors_label { - char *name; - char *value; - int lineno; + char *name; + char *value; + int lineno; } sensors_label; -/* Config file set declaration: a feature name, combined with an expression */ +/* Config file set declaration: a subfeature name, combined with an + expression */ typedef struct sensors_set { - char *name; - sensors_expr *value; - int lineno; + char *name; + sensors_expr *value; + int lineno; } sensors_set; -/* Config file compute declaration: a feature name, combined with two +/* Config file compute declaration: a feature name, combined with two expressions */ typedef struct sensors_compute { - char *name; - sensors_expr *from_proc; - sensors_expr *to_proc; - int lineno; + char *name; + sensors_expr *from_proc; + sensors_expr *to_proc; + int lineno; } sensors_compute; /* Config file ignore declaration: a feature name */ typedef struct sensors_ignore { - char *name; - int lineno; + char *name; + int lineno; } sensors_ignore; /* A list of chip names, used to represent a config file chips declaration */ typedef struct sensors_chip_name_list { - sensors_chip_name *fits; - int fits_count; - int fits_max; + sensors_chip_name *fits; + int fits_count; + int fits_max; } sensors_chip_name_list; /* A config file chip block */ typedef struct sensors_chip { - sensors_chip_name_list chips; - sensors_label *labels; - int labels_count; - int labels_max; - sensors_set *sets; - int sets_count; - int sets_max; - sensors_compute *computes; - int computes_count; - int computes_max; - sensors_ignore *ignores; - int ignores_count; - int ignores_max; - int lineno; + sensors_chip_name_list chips; + sensors_label *labels; + int labels_count; + int labels_max; + sensors_set *sets; + int sets_count; + int sets_max; + sensors_compute *computes; + int computes_count; + int computes_max; + sensors_ignore *ignores; + int ignores_count; + int ignores_max; + int lineno; } sensors_chip; -/* Config file bus declaration: the i2c bus number, combined with adapter +/* Config file bus declaration: the bus type and number, combined with adapter name */ typedef struct sensors_bus { - int number; - char *adapter; - int lineno; + char *adapter; + sensors_bus_id bus; + int lineno; } sensors_bus; -/* /proc/sys/dev/sensors/chips line representation */ -typedef struct sensors_proc_chips_entry { - int sysctl; - sensors_chip_name name; -} sensors_proc_chips_entry; - -/* Internal data about a single chip feature. - name is the string name used to refer to this feature (both in config - files and through user functions); - number is the internal feature number, used in many functions to refer - to this feature - logical_mapping is either SENSORS_NO_MAPPING if this is feature is the - main element of category; or it is the number of a feature with which - this feature is logically grouped (a group could be fan, fan_max and - fan_div) - compute_mapping is like logical_mapping, only it refers to another - feature whose compute line will be inherited (a group could be fan and - fan_max, but not fan_div) - mode is SENSORS_MODE_NO_RW, SENSORS_MODE_R, SENSORS_MODE_W or - SENSORS_MODE_RW, for unaccessible, readable, writable, and both readable - and writable. - sysctl is the SYSCTL id of the file the value can be found in. - offset is the (byte) offset of the place this feature can be found. - scaling is the number of decimal points to scale by. - This scaling is performed on the raw sysctl value, NOT the value - seen in /proc. Therefore the scaling value must be the same as - the value returned in nrels_mag by the SENSORS_PROC_REAL_INFO - operation in the chip drivers. - Divide the read value by 10**scaling to get the real value. - Scaling can be positive or negative but negative values aren't - very useful because the driver can scale that direction itself. */ -typedef struct sensors_chip_feature { - sensors_feature_data data; - int sysctl; - int offset; - int scaling; - const char *sysname; - int sysscaling; - const char *altsysname; -} sensors_chip_feature; - -/* Internal data about all features of a type of chip */ +/* Internal data about all features and subfeatures of a chip */ typedef struct sensors_chip_features { - const char *prefix; - struct sensors_chip_feature *feature; + struct sensors_chip_name chip; + struct sensors_feature *feature; + struct sensors_subfeature *subfeature; + int feature_count; + int subfeature_count; } sensors_chip_features; extern sensors_chip *sensors_config_chips; @@ -173,13 +140,13 @@ extern sensors_bus *sensors_config_busses; extern int sensors_config_busses_count; extern int sensors_config_busses_max; -extern sensors_proc_chips_entry *sensors_proc_chips; +extern sensors_chip_features *sensors_proc_chips; extern int sensors_proc_chips_count; extern int sensors_proc_chips_max; #define sensors_add_proc_chips(el) sensors_add_array_el( \ (el), &sensors_proc_chips, &sensors_proc_chips_count,\ - &sensors_proc_chips_max, sizeof(struct sensors_proc_chips_entry)) + &sensors_proc_chips_max, sizeof(struct sensors_chip_features)) extern sensors_bus *sensors_proc_bus; extern int sensors_proc_bus_count; @@ -189,6 +156,13 @@ extern int sensors_proc_bus_max; (el), &sensors_proc_bus, &sensors_proc_bus_count,\ &sensors_proc_bus_max, sizeof(struct sensors_bus)) -extern sensors_chip_features sensors_chip_features_list[]; +/* Substitute configuration bus numbers with real-world /proc bus numbers + in the chips lists */ +int sensors_substitute_busses(void); + + +/* Parse a bus id into its components. Returns 0 on succes, a value from + error.h on failure. */ +int sensors_parse_bus_id(const char *name, sensors_bus_id *bus); #endif /* def LIB_SENSORS_DATA_H */ diff --git a/lib/error.c b/lib/error.c index e1435243..7472c59b 100644 --- a/lib/error.c +++ b/lib/error.c @@ -1,6 +1,7 @@ /* error.c - Part of libsensors, a Linux library for reading sensor data. Copyright (c) 1998, 1999 Frodo Looijaard + Copyright (C) 2007, 2008 Jean Delvare This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -14,53 +15,54 @@ You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + MA 02110-1301 USA. */ #include #include #include "error.h" +#include "general.h" static void sensors_default_parse_error(const char *err, int lineno); -static void sensors_default_fatal_error(const char *proc,const char *err); +static void sensors_default_fatal_error(const char *proc, const char *err); -void (*sensors_parse_error) (const char *err, int lineno) = - sensors_default_parse_error; -void (*sensors_fatal_error) (const char *proc, const char *err) = - sensors_default_fatal_error; +void (*sensors_parse_error) (const char *err, int lineno) = + sensors_default_parse_error; +void (*sensors_fatal_error) (const char *proc, const char *err) = + sensors_default_fatal_error; -static const char *errorlist[] = - { /* Unknown error */ "sensors_strerror: Unknown error!", - /* SENSORS_ERR_WILDCARDS */ "Wildcard found in chip name", - /* SENSORS_ERR_NO_ENTRY */ "No such feature known", - /* SENSORS_ERR_ACCESS */ "Can't read or write", - /* SENSORS_ERR_PROC */ "Can't access procfs/sysfs file", - /* SENSORS_ERR_DIV_ZERO */ "Divide by zero", - /* SENSORS_ERR_CHIP_NAME */ "Can't parse chip name", - /* SENSORS_ERR_BUS_NAME */ "Can't parse bus name", - /* SENSORS_ERR_PARSE */ "General parse error", - /* SENSORS_ERR_ACCESS_W */ "Can't write", - /* SENSORS_ERR_ACCESS_R */ "Can't read" - }; - -#define ERROR_LIST_LEN (sizeof(errorlist) / sizeof(char *)) +static const char *errorlist[] = { + /* Invalid error code */ NULL, + /* SENSORS_ERR_WILDCARDS */ "Wildcard found in chip name", + /* SENSORS_ERR_NO_ENTRY */ "No such subfeature known", + /* SENSORS_ERR_ACCESS_R */ "Can't read", + /* SENSORS_ERR_KERNEL */ "Kernel interface error", + /* SENSORS_ERR_DIV_ZERO */ "Divide by zero", + /* SENSORS_ERR_CHIP_NAME */ "Can't parse chip name", + /* SENSORS_ERR_BUS_NAME */ "Can't parse bus name", + /* SENSORS_ERR_PARSE */ "General parse error", + /* SENSORS_ERR_ACCESS_W */ "Can't write", + /* SENSORS_ERR_IO */ "I/O error", + /* SENSORS_ERR_RECURSION */ "Evaluation recurses too deep", +}; const char *sensors_strerror(int errnum) { - if (errnum < 0) - errnum = -errnum; - if (errnum >= ERROR_LIST_LEN) - errnum = 0; - return errorlist[errnum]; -} + if (errnum < 0) + errnum = -errnum; + if (errnum >= ARRAY_SIZE(errorlist)) + errnum = 0; + return errorlist[errnum]; +} void sensors_default_parse_error(const char *err, int lineno) { - fprintf(stderr,"Error: Line %d: %s\n",lineno,err); + fprintf(stderr, "Error: Line %d: %s\n", lineno, err); } void sensors_default_fatal_error(const char *proc, const char *err) { - fprintf(stderr,"Fatal error in `%s': %s\n",proc,err); - exit(1); + fprintf(stderr, "Fatal error in `%s': %s\n", proc, err); + exit(1); } diff --git a/lib/error.h b/lib/error.h index 9ff72ffb..74a71732 100644 --- a/lib/error.h +++ b/lib/error.h @@ -1,6 +1,7 @@ /* error.h - Part of libsensors, a Linux library for reading sensor data. Copyright (c) 1998, 1999 Frodo Looijaard + Copyright (C) 2007, 2008 Jean Delvare This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -14,22 +15,24 @@ You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + MA 02110-1301 USA. */ #ifndef LIB_SENSORS_ERROR_H #define LIB_SENSORS_ERROR_H -#define SENSORS_ERR_WILDCARDS 1 /* Wildcard found in chip name */ -#define SENSORS_ERR_NO_ENTRY 2 /* No such feature known */ -#define SENSORS_ERR_ACCESS 3 /* Can't read or write */ -#define SENSORS_ERR_PROC 4 /* Can't access /proc file */ -#define SENSORS_ERR_DIV_ZERO 5 /* Divide by zero */ -#define SENSORS_ERR_CHIP_NAME 6 /* Can't parse chip name */ -#define SENSORS_ERR_BUS_NAME 7 /* Can't parse bus name */ -#define SENSORS_ERR_PARSE 8 /* General parse error */ -#define SENSORS_ERR_ACCESS_W 9 /* Can't write */ -#define SENSORS_ERR_ACCESS_R 10 /* Can't read */ +#define SENSORS_ERR_WILDCARDS 1 /* Wildcard found in chip name */ +#define SENSORS_ERR_NO_ENTRY 2 /* No such subfeature known */ +#define SENSORS_ERR_ACCESS_R 3 /* Can't read */ +#define SENSORS_ERR_KERNEL 4 /* Kernel interface error */ +#define SENSORS_ERR_DIV_ZERO 5 /* Divide by zero */ +#define SENSORS_ERR_CHIP_NAME 6 /* Can't parse chip name */ +#define SENSORS_ERR_BUS_NAME 7 /* Can't parse bus name */ +#define SENSORS_ERR_PARSE 8 /* General parse error */ +#define SENSORS_ERR_ACCESS_W 9 /* Can't write */ +#define SENSORS_ERR_IO 10 /* I/O error */ +#define SENSORS_ERR_RECURSION 11 /* Evaluation recurses too deep */ #ifdef __cplusplus extern "C" { @@ -39,7 +42,7 @@ extern "C" { /* This function returns a pointer to a string which describes the error. errnum may be negative (the corresponding positive error is returned). You may not modify the result! */ -extern const char *sensors_strerror(int errnum); +const char *sensors_strerror(int errnum); /* This function is called when a parse error is detected. Give it a new value, and your own function is called instead of the default (which diff --git a/lib/general.c b/lib/general.c index 9374b58c..ef05f0d1 100644 --- a/lib/general.c +++ b/lib/general.c @@ -14,7 +14,8 @@ You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + MA 02110-1301 USA. */ #include "error.h" @@ -29,62 +30,57 @@ void sensors_malloc_array(void *list, int *num_el, int *max_el, int el_size) { - void **my_list = (void **)list; + void **my_list = (void **)list; - *my_list = malloc(el_size*A_BUNCH); - if (! *my_list) - sensors_fatal_error("sensors_malloc_array","Allocating new elements"); - *max_el = A_BUNCH; - *num_el = 0; + *my_list = malloc(el_size*A_BUNCH); + if (! *my_list) + sensors_fatal_error("sensors_malloc_array", + "Allocating new elements"); + *max_el = A_BUNCH; + *num_el = 0; } void sensors_free_array(void *list, int *num_el, int *max_el) { - void **my_list = (void **)list; + void **my_list = (void **)list; - free(*my_list); - *my_list = NULL; - *num_el = 0; - *max_el = 0; + free(*my_list); + *my_list = NULL; + *num_el = 0; + *max_el = 0; } void sensors_add_array_el(const void *el, void *list, int *num_el, - int *max_el, int el_size) + int *max_el, int el_size) { - int new_max_el; - void **my_list = (void *)list; - if (*num_el + 1 > *max_el) { - new_max_el = *max_el + A_BUNCH; - *my_list = realloc(*my_list,new_max_el * el_size); - if (! *my_list) - sensors_fatal_error("sensors_add_array_el","Allocating new elements"); - *max_el = new_max_el; - } - memcpy(((char *) *my_list) + *num_el * el_size, el, el_size); - (*num_el) ++; + int new_max_el; + void **my_list = (void *)list; + if (*num_el + 1 > *max_el) { + new_max_el = *max_el + A_BUNCH; + *my_list = realloc(*my_list, new_max_el * el_size); + if (! *my_list) + sensors_fatal_error("sensors_add_array_el", + "Allocating new elements"); + *max_el = new_max_el; + } + memcpy(((char *) *my_list) + *num_el * el_size, el, el_size); + (*num_el) ++; } -void sensors_add_array_els(const void *els, int nr_els, void *list, - int *num_el, int *max_el, int el_size) +void sensors_add_array_els(const void *els, int nr_els, void *list, + int *num_el, int *max_el, int el_size) { - int new_max_el; - void **my_list = (void *)list; - if (*num_el + nr_els > *max_el) { - new_max_el = (*max_el + nr_els + A_BUNCH); - new_max_el -= new_max_el % A_BUNCH; - *my_list = realloc(*my_list,new_max_el * el_size); - if (! *my_list) - sensors_fatal_error("sensors_add_array_els","Allocating new elements"); - *max_el = new_max_el; - } - memcpy(((char *)*my_list) + *num_el * el_size, els, el_size * nr_els); - *num_el += nr_els; -} - -/* Strip a string of all terminating spaces */ -void sensors_strip_of_spaces(char *name) -{ - int i; - for (i = strlen(name)-1; (i>=0) && (name[i] == ' '); i--); - name[i+1] = '\0'; + int new_max_el; + void **my_list = (void *)list; + if (*num_el + nr_els > *max_el) { + new_max_el = (*max_el + nr_els + A_BUNCH); + new_max_el -= new_max_el % A_BUNCH; + *my_list = realloc(*my_list, new_max_el * el_size); + if (! *my_list) + sensors_fatal_error("sensors_add_array_els", + "Allocating new elements"); + *max_el = new_max_el; + } + memcpy(((char *)*my_list) + *num_el * el_size, els, el_size * nr_els); + *num_el += nr_els; } diff --git a/lib/general.h b/lib/general.h index 1bb308ac..7a9fbace 100644 --- a/lib/general.h +++ b/lib/general.h @@ -14,7 +14,8 @@ You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + MA 02110-1301 USA. */ #ifndef LIB_SENSORS_GENERAL @@ -25,15 +26,14 @@ made between the current number of elements and the maximum number. You can only add elements at the end. Primitive, but very useful for internal use. */ -extern void sensors_malloc_array(void *list, int *num_el, int *max_el, - int el_size); -extern void sensors_free_array(void *list, int *num_el, int *max_el); -extern void sensors_add_array_el(const void *el, void *list, int *num_el, - int *max_el, int el_size); -extern void sensors_add_array_els(const void *els, int nr_els, void *list, - int *num_el, int *max_el, int el_size); +void sensors_malloc_array(void *list, int *num_el, int *max_el, + int el_size); +void sensors_free_array(void *list, int *num_el, int *max_el); +void sensors_add_array_el(const void *el, void *list, int *num_el, + int *max_el, int el_size); +void sensors_add_array_els(const void *els, int nr_els, void *list, + int *num_el, int *max_el, int el_size); -/* Strip a string of all terminating spaces */ -extern void sensors_strip_of_spaces(char *name); +#define ARRAY_SIZE(arr) (int)(sizeof(arr) / sizeof((arr)[0])) #endif /* LIB_SENSORS_GENERAL */ diff --git a/lib/init.c b/lib/init.c index 158f0b1a..7c8b55d8 100644 --- a/lib/init.c +++ b/lib/init.c @@ -1,6 +1,7 @@ /* init.c - Part of libsensors, a Linux library for reading sensor data. Copyright (c) 1998, 1999 Frodo Looijaard + Copyright (C) 2007 Jean Delvare This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -14,16 +15,17 @@ You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + MA 02110-1301 USA. */ #include #include #include #include +#include #include "sensors.h" #include "data.h" -#include "proc.h" #include "error.h" #include "access.h" #include "conf.h" @@ -31,170 +33,192 @@ #include "scanner.h" #include "init.h" -static void free_proc_chips_entry(sensors_proc_chips_entry entry); -static void free_chip_name(sensors_chip_name name); -static void free_bus(sensors_bus bus); -static void free_chip(sensors_chip chip); -static void free_label(sensors_label label); -static void free_set(sensors_set set); -static void free_compute(sensors_compute compute); -static void free_ignore(sensors_ignore ignore); +#define DEFAULT_CONFIG_FILE ETCDIR "/sensors3.conf" +#define ALT_CONFIG_FILE ETCDIR "/sensors.conf" /* Wrapper around sensors_yyparse(), which clears the locale so that the decimal numbers are always parsed properly. */ static int sensors_parse(void) { - int res; - char *locale; + int res; + char *locale; - /* Remember the current locale and clear it */ - locale = setlocale(LC_ALL, NULL); - if (locale) { - locale = strdup(locale); - setlocale(LC_ALL, "C"); - } + /* Remember the current locale and clear it */ + locale = setlocale(LC_ALL, NULL); + if (locale) { + locale = strdup(locale); + setlocale(LC_ALL, "C"); + } - res = sensors_yyparse(); + res = sensors_yyparse(); - /* Restore the old locale */ - if (locale) { - setlocale(LC_ALL, locale); - free(locale); - } + /* Restore the old locale */ + if (locale) { + setlocale(LC_ALL, locale); + free(locale); + } - return res; + return res; } int sensors_init(FILE *input) { - int res; - sensors_cleanup(); - if (sensors_init_sysfs()) { - if ((res = sensors_read_sysfs_bus()) || (res = sensors_read_sysfs_chips())) - return res; - } else { - if ((res = sensors_read_proc_bus()) || (res = sensors_read_proc_chips())) - return res; - } - if ((res = sensors_scanner_init(input))) - return -SENSORS_ERR_PARSE; - if ((res = sensors_parse())) - return -SENSORS_ERR_PARSE; - if ((res = sensors_substitute_busses())) - return res; - return 0; + int res; + + if (!sensors_init_sysfs()) + return -SENSORS_ERR_KERNEL; + if ((res = sensors_read_sysfs_bus()) || + (res = sensors_read_sysfs_chips())) + goto exit_cleanup; + + res = -SENSORS_ERR_PARSE; + if (input) { + if (sensors_scanner_init(input) || + sensors_parse()) + goto exit_cleanup; + } else { + /* No configuration provided, use default */ + input = fopen(DEFAULT_CONFIG_FILE, "r"); + if (!input && errno == ENOENT) + input = fopen(ALT_CONFIG_FILE, "r"); + if (input) { + if (sensors_scanner_init(input) || + sensors_parse()) { + fclose(input); + goto exit_cleanup; + } + fclose(input); + } + } + + if ((res = sensors_substitute_busses())) + goto exit_cleanup; + return 0; + +exit_cleanup: + sensors_cleanup(); + return res; } -void sensors_cleanup(void) +static void free_chip_name(sensors_chip_name *name) { - int i; - - sensors_scanner_exit(); - - for (i = 0; i < sensors_proc_chips_count; i++) - free_proc_chips_entry(sensors_proc_chips[i]); - free(sensors_proc_chips); - sensors_proc_chips = NULL; - sensors_proc_chips_count = sensors_proc_chips_max = 0; - - for (i = 0; i < sensors_config_busses_count; i++) - free_bus(sensors_config_busses[i]); - free(sensors_config_busses); - sensors_config_busses = NULL; - sensors_config_busses_count = sensors_config_busses_max = 0; - - for (i = 0; i < sensors_config_chips_count; i++) - free_chip(sensors_config_chips[i]); - free(sensors_config_chips); - sensors_config_chips = NULL; - sensors_config_chips_count = sensors_config_chips_max = 0; - - for (i = 0; i < sensors_proc_bus_count; i++) - free_bus(sensors_proc_bus[i]); - free(sensors_proc_bus); - sensors_proc_bus = NULL; - sensors_proc_bus_count = sensors_proc_bus_max = 0; + free(name->prefix); + free(name->path); } -void free_proc_chips_entry(sensors_proc_chips_entry entry) +static void free_chip_features(sensors_chip_features *features) { - free_chip_name(entry.name); + int i; + + for (i = 0; i < features->subfeature_count; i++) + free(features->subfeature[i].name); + free(features->subfeature); + for (i = 0; i < features->feature_count; i++) + free(features->feature[i].name); + free(features->feature); } -void free_chip_name(sensors_chip_name name) +static void free_bus(sensors_bus *bus) { - free(name.prefix); - free(name.busname); + free(bus->adapter); } -void free_bus(sensors_bus bus) +static void free_label(sensors_label *label) { - free(bus.adapter); -} - -void free_chip(sensors_chip chip) -{ - int i; - - for (i = 0; i < chip.chips.fits_count; i++) - free_chip_name(chip.chips.fits[i]); - free(chip.chips.fits); - chip.chips.fits_count = chip.chips.fits_max = 0; - - for (i = 0; i < chip.labels_count; i++) - free_label(chip.labels[i]); - free(chip.labels); - chip.labels_count = chip.labels_max = 0; - - for (i = 0; i < chip.sets_count; i++) - free_set(chip.sets[i]); - free(chip.sets); - chip.sets_count = chip.sets_max = 0; - - for (i = 0; i < chip.computes_count; i++) - free_compute(chip.computes[i]); - free(chip.computes); - chip.computes_count = chip.computes_max = 0; - - for (i = 0; i < chip.ignores_count; i++) - free_ignore(chip.ignores[i]); - free(chip.ignores); - chip.ignores_count = chip.ignores_max = 0; -} - -void free_label(sensors_label label) -{ - free(label.name); - free(label.value); -} - -void free_set(sensors_set set) -{ - free(set.name); - sensors_free_expr(set.value); -} - -void free_compute(sensors_compute compute) -{ - free(compute.name); - sensors_free_expr(compute.from_proc); - sensors_free_expr(compute.to_proc); -} - -void free_ignore(sensors_ignore ignore) -{ - free(ignore.name); + free(label->name); + free(label->value); } void sensors_free_expr(sensors_expr *expr) { - if ((expr->kind) == sensors_kind_var) - free(expr->data.var); - else if ((expr->kind) == sensors_kind_sub) { - if (expr->data.subexpr.sub1) - sensors_free_expr(expr->data.subexpr.sub1); - if (expr->data.subexpr.sub2) - sensors_free_expr(expr->data.subexpr.sub2); - } - free(expr); + if (expr->kind == sensors_kind_var) + free(expr->data.var); + else if (expr->kind == sensors_kind_sub) { + if (expr->data.subexpr.sub1) + sensors_free_expr(expr->data.subexpr.sub1); + if (expr->data.subexpr.sub2) + sensors_free_expr(expr->data.subexpr.sub2); + } + free(expr); +} + +static void free_set(sensors_set *set) +{ + free(set->name); + sensors_free_expr(set->value); +} + +static void free_compute(sensors_compute *compute) +{ + free(compute->name); + sensors_free_expr(compute->from_proc); + sensors_free_expr(compute->to_proc); +} + +static void free_ignore(sensors_ignore *ignore) +{ + free(ignore->name); +} + +static void free_chip(sensors_chip *chip) +{ + int i; + + for (i = 0; i < chip->chips.fits_count; i++) + free_chip_name(&chip->chips.fits[i]); + free(chip->chips.fits); + chip->chips.fits_count = chip->chips.fits_max = 0; + + for (i = 0; i < chip->labels_count; i++) + free_label(&chip->labels[i]); + free(chip->labels); + chip->labels_count = chip->labels_max = 0; + + for (i = 0; i < chip->sets_count; i++) + free_set(&chip->sets[i]); + free(chip->sets); + chip->sets_count = chip->sets_max = 0; + + for (i = 0; i < chip->computes_count; i++) + free_compute(&chip->computes[i]); + free(chip->computes); + chip->computes_count = chip->computes_max = 0; + + for (i = 0; i < chip->ignores_count; i++) + free_ignore(&chip->ignores[i]); + free(chip->ignores); + chip->ignores_count = chip->ignores_max = 0; +} + +void sensors_cleanup(void) +{ + int i; + + sensors_scanner_exit(); + + for (i = 0; i < sensors_proc_chips_count; i++) { + free_chip_name(&sensors_proc_chips[i].chip); + free_chip_features(&sensors_proc_chips[i]); + } + free(sensors_proc_chips); + sensors_proc_chips = NULL; + sensors_proc_chips_count = sensors_proc_chips_max = 0; + + for (i = 0; i < sensors_config_busses_count; i++) + free_bus(&sensors_config_busses[i]); + free(sensors_config_busses); + sensors_config_busses = NULL; + sensors_config_busses_count = sensors_config_busses_max = 0; + + for (i = 0; i < sensors_config_chips_count; i++) + free_chip(&sensors_config_chips[i]); + free(sensors_config_chips); + sensors_config_chips = NULL; + sensors_config_chips_count = sensors_config_chips_max = 0; + + for (i = 0; i < sensors_proc_bus_count; i++) + free_bus(&sensors_proc_bus[i]); + free(sensors_proc_bus); + sensors_proc_bus = NULL; + sensors_proc_bus_count = sensors_proc_bus_max = 0; } diff --git a/lib/init.h b/lib/init.h index ae0476a7..a86983ad 100644 --- a/lib/init.h +++ b/lib/init.h @@ -14,7 +14,8 @@ You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + MA 02110-1301 USA. */ #ifndef LIB_SENSORS_INIT_H diff --git a/lib/libsensors.3 b/lib/libsensors.3 index 4ec46a40..ebe33a96 100644 --- a/lib/libsensors.3 +++ b/lib/libsensors.3 @@ -24,7 +24,7 @@ .\" .\" References consulted: .\" libsensors source code -.TH libsensors 3 "October 2006" "" "Linux Programmer's Manual" +.TH libsensors 3 "October 2007" "lm-sensors 3" "Linux Programmer's Manual" .SH NAME libsensors \- publicly accessible functions provided by the sensors library .SH SYNOPSIS @@ -35,26 +35,30 @@ libsensors \- publicly accessible functions provided by the sensors library .B void sensors_cleanup(void); .B int sensors_parse_chip_name(const char *orig_name, \fBsensors_chip_name *res);\fP -.B int sensors_match_chip(sensors_chip_name chip1, - \fBsensors_chip_name chip2);\fP -.B int sensors_chip_name_has_wildcards(sensors_chip_name chip); .B const char *sensors_get_adapter_name(int bus_nr); -.B int sensors_get_label(sensors_chip_name name, int feature, - \fBchar **result);\fP -.B int sensors_get_feature(sensors_chip_name name, int feature, - \fBdouble *result);\fP -.B int sensors_set_feature(sensors_chip_name name, int feature, - \fBdouble value);\fP -.B int sensors_do_chip_sets(sensors_chip_name name); -.B extern int sensors_do_all_sets(void); -.B const sensors_chip_name *sensors_get_detected_chips(int *nr); -.B const sensors_feature_data *sensors_get_all_features - \fB(sensors_chip_name name, int *nr1,int *nr2);\fP +.B char *sensors_get_label(const sensors_chip_name *name, const sensors_feature *feature);\fP +.B int sensors_get_value(const sensors_chip_name *name, int subfeat_nr, + \fBdouble *value);\fP +.B int sensors_set_value(const sensors_chip_name *name, int subfeat_nr, + \fBdouble value);\fP +.B int sensors_do_chip_sets(const sensors_chip_name *name); +.B const sensors_chip_name *sensors_get_detected_chips(const sensors_chip_name + \fB*match, int *nr);\fP +.B const sensors_feature *sensors_get_features(const sensors_chip_name *name, int *nr);\fP +.B const sensors_subfeature *sensors_get_all_subfeatures(const sensors_chip_name *name, const sensors_feature *feature, int *nr);\fP +.B const sensors_subfeature *sensors_get_subfeature(const sensors_chip_name *name, const sensors_feature *feature, sensors_subfeature_type type);\fP +.B const char *libsensors_version; .fi .SH DESCRIPTION .B int sensors_init(FILE *input); .br -(Re)load the configuration file and the detected chips list. If this returns a value unequal to zero, you are in trouble; you can not assume anything will be initialized properly. +Load the configuration file and the detected chips list. If this returns a +value unequal to zero, you are in trouble; you can not assume anything will +be initialized properly. If you want to reload the configuration file, call +sensors_cleanup() below before calling sensors_init() again. + +If FILE is NULL, the default configuration file is used (see the FILES +section below). Most applications will want to do that. .B void sensors_cleanup(void); .br @@ -66,83 +70,117 @@ Clean-up function: You can't access anything after this, until the next sensors_ .br Parse a chip name to the internal representation. Return 0 on succes, <0 on error. -\fBint sensors_match_chip(sensors_chip_name chip1, - sensors_chip_name chip2);\fP -.br -Compare two chips name descriptions, to see whether they could match. Return 0 if it does not match, return 1 if it does match. - -\fBint sensors_chip_name_has_wildcards - (sensors_chip_name chip);\fP -.br -Check whether the chip name is an 'absolute' name, which can only match one chip, or whether it has wildcards. Returns 0 if it is absolute, 1 if there are wildcards. - .B const char *sensors_get_adapter_name(int bus_nr); .br This function returns the adapter name of a bus number, as used within the sensors_chip_name structure. If it could not be found, it returns NULL. -.B const char *sensors_get_algorithm_name(int bus_nr); +\fBchar *sensors_get_label(const sensors_chip_name *name, const sensors_feature *feature);\fP .br -This function used to return the algorithm name of a bus number. -It is now deprecated and returns an arbitrary string. It will be dropped -in a later version of the library so you should stop using it. +Look up the label which belongs to this chip. Note that chip should not +contain wildcard values! The returned string is newly allocated (free it +yourself). On failure, NULL is returned. +If no label exists for this feature, its name is returned itself. -\fBint sensors_get_label(sensors_chip_name name, int feature, - char **result);\fP +\fBint sensors_get_value(const sensors_chip_name *name, int subfeat_nr, double *value);\fP .br -Look up the label which belongs to this chip. Note that chip should not contain wildcard values! *result is newly allocated (free it yourself). This function will return 0 on success, and <0 on failure. +Read the value of a subfeature of a certain chip. Note that chip should not +contain wildcard values! This function will return 0 on success, and <0 on +failure. -\fBint sensors_get_feature(sensors_chip_name name, - int feature, double *result);\fP +\fBint sensors_set_value(const sensors_chip_name *name, int subfeat_nr, double value);\fP .br -Read the value of a feature of a certain chip. Note that chip should not contain wildcard values! This function will return 0 on success, and <0 on failure. +Set the value of a subfeature of a certain chip. Note that chip should not +contain wildcard values! This function will return 0 on success, and <0 on +failure. -\fBint sensors_set_feature(sensors_chip_name name, - int feature, double value);\fP -.br -Set the value of a feature of a certain chip. Note that chip should not contain wildcard values! This function will return 0 on success, and <0 on failure. - -.B int sensors_do_chip_sets(sensors_chip_name name); +.B int sensors_do_chip_sets(const sensors_chip_name *name); .br Execute all set statements for this particular chip. The chip may contain wildcards! This function will return 0 on success, and <0 on failure. -.B int sensors_do_all_sets(void); +\fBconst sensors_chip_name *sensors_get_detected_chips(const sensors_chip_name + *match, int *nr);\fP .br -Execute all set statements for all detected chips. This is the same as calling sensors_do_chip_sets with an all wildcards chip name +This function returns all detected chips that match a given chip name, +one by one. If no chip name is provided, all detected chips are returned. +To start at the beginning of the list, use 0 for nr; NULL is returned if +we are at the end of the list. Do not try to change these chip names, as +they point to internal structures! -\fBconst sensors_chip_name *sensors_get_detected_chips - (int *nr);\fP +This structure contains information related to a given feature of a +specific chip. .br -This function returns all detected chips, one by one. To start at the beginning of the list, use 0 for nr; NULL is returned if we are at the end of the list. Do not try to change these chip names, as they point to internal structures! Do not use nr for anything else. - -This structure is used when you want to get all features of a specific chip. -.br -\fBtypedef struct sensors_feature_data { -.br - int number; +\fBtypedef struct sensors_feature { .br const char *name; +.br + int number; +.br + sensors_feature_type type; +.br +} sensors_feature;\fP +.br +There are other member not documented here, which are only meant for libsensors +internal use. + +This structure contains information related to a given subfeature of a +specific chip feature. +.br +\fBtypedef struct sensors_subfeature { +.br + const char *name; +.br + int number; +.br + sensors_subfeature_type type; .br int mapping; .br - int unused; + unsigned int flags; .br - int mode; +} sensors_subfeature;\fP .br -} sensors_feature_data;\fP -.br -The mode field can be one of: -.br -SENSORS_MODE_NO_RW, SENSORS_MODE_R, SENSORS_MODE_W or SENSORS_MODE_RW. +The flags field is a bitfield, its value is a combination of +SENSORS_MODE_R (readable), SENSORS_MODE_W (writable) and SENSORS_COMPUTE_MAPPING +(affected by the computation rules of the main feature). -\fBconst sensors_feature_data *sensors_get_all_features - (sensors_chip_name name, int *nr1,int *nr2);\fP +\fBconst sensors_feature *sensors_get_features(const sensors_chip_name *name, int *nr);\fP .br -This returns all features of a specific chip. They are returned in bunches: everything with the same mapping is returned just after each other, with the master feature in front (that feature does not map to itself, but has SENSORS_NO_MAPPING as mapping field). nr1 and nr2 are two internally used variables. Set both to zero to start again at the begin of the list. If no more features are found NULL is returned. Do not try to change the returned structure; you will corrupt internal data structures. +This returns all main features of a specific chip. nr is an internally +used variable. Set it to zero to start at the begin of the list. If no +more features are found NULL is returned. +Do not try to change the returned structure; you will corrupt internal +data structures. +\fBconst sensors_subfeature *sensors_get_all_subfeatures(const sensors_chip_name *name, const sensors_feature *feature, int *nr);\fP +.br +This returns all subfeatures of a given main feature. nr is an internally +used variable. Set it to zero to start at the begin of the list. If no +more subfeatures are found NULL is returned. +Do not try to change the returned structure; you will corrupt internal +data structures. + +\fBconst sensors_subfeature *sensors_get_subfeature(const sensors_chip_name *name, const sensors_feature *feature, sensors_subfeature_type type);\fP +.br +This returns the subfeature of the given type for a given main feature, +if it exists, NULL otherwise. +Do not try to change the returned structure; you will corrupt internal +data structures. + +\fBconst char *libsensors_version;\fP +.br +A string representing the version of libsensors. + +.SH FILES +.I /etc/sensors3.conf +.br +.I /etc/sensors.conf +.RS +The system-wide +.BR libsensors (3) +configuration file. /etc/sensors3.conf is tried first, and if it doesn't exist, +/etc/sensors.conf is used instead. -.SH "CONFORMING TO" -lm_sensors-2.x .SH SEE ALSO sensors.conf(5) diff --git a/lib/proc.c b/lib/proc.c deleted file mode 100644 index 3eab99cc..00000000 --- a/lib/proc.c +++ /dev/null @@ -1,463 +0,0 @@ -/* - proc.c - Part of libsensors, a Linux library for reading sensor data. - Copyright (c) 1998, 1999 Frodo Looijaard - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#include -#include -#include -#include -#include -#include -#include -#include - -#include "kernel/include/sensors.h" -#include "data.h" -#include "error.h" -#include "access.h" -#include "proc.h" -#include "general.h" -#include "sysfs.h" - -/* OK, this proves one thing: if there are too many chips detected, we get in - trouble. The limit is around 4096/sizeof(struct sensors_chip_data), which - works out to about 100 entries right now. That seems sensible enough, - but if we ever get at the point where more chips can be detected, we must - enlarge buf, and check that sysctl can handle larger buffers. */ - -#define BUF_LEN 4096 - -static char buf[BUF_LEN]; - -static int getsysname(const sensors_chip_feature *feature, char *sysname, - int *sysmag, char *altsysname); - -/* This reads /proc/sys/dev/sensors/chips into memory */ -int sensors_read_proc_chips(void) -{ - int res; - - int name[3] = { CTL_DEV, DEV_SENSORS, SENSORS_CHIPS }; - size_t buflen = BUF_LEN; - char *bufptr = buf; - sensors_proc_chips_entry entry; - int lineno; - - if (sysctl(name, 3, bufptr, &buflen, NULL, 0)) - return -SENSORS_ERR_PROC; - - lineno = 1; - while (buflen >= sizeof(struct i2c_chips_data)) { - if ((res = - sensors_parse_chip_name(((struct i2c_chips_data *) bufptr)->name, - &entry.name))) { - sensors_parse_error("Parsing /proc/sys/dev/sensors/chips",lineno); - return res; - } - entry.sysctl = ((struct i2c_chips_data *) bufptr)->sysctl_id; - sensors_add_proc_chips(&entry); - bufptr += sizeof(struct i2c_chips_data); - buflen -= sizeof(struct i2c_chips_data); - lineno++; - } - return 0; -} - -int sensors_read_proc_bus(void) -{ - FILE *f; - char line[255]; - char *border; - sensors_bus entry; - int lineno; - - f = fopen("/proc/bus/i2c","r"); - if (!f) - return -SENSORS_ERR_PROC; - lineno=1; - while (fgets(line,255,f)) { - if (strlen(line) > 0) - line[strlen(line)-1] = '\0'; - if (! (border = strrchr(line,'\t'))) - goto ERROR; - /* Skip algorithm name */ - *border='\0'; - if (! (border = strrchr(line,'\t'))) - goto ERROR; - if (! (entry.adapter = strdup(border + 1))) - goto FAT_ERROR; - *border='\0'; - if (! (border = strrchr(line,'\t'))) - goto ERROR; - *border='\0'; - if (strncmp(line,"i2c-",4)) - goto ERROR; - if (sensors_parse_i2cbus_name(line,&entry.number)) - goto ERROR; - sensors_strip_of_spaces(entry.adapter); - sensors_add_proc_bus(&entry); - lineno++; - } - fclose(f); - return 0; -FAT_ERROR: - sensors_fatal_error("sensors_read_proc_bus","Allocating entry"); -ERROR: - sensors_parse_error("Parsing /proc/bus/i2c",lineno); - fclose(f); - return -SENSORS_ERR_PROC; -} - - -/* This returns the first detected chip which matches the name */ -static int sensors_get_chip_id(sensors_chip_name name) -{ - int i; - for (i = 0; i < sensors_proc_chips_count; i++) - if (sensors_match_chip(name, sensors_proc_chips[i].name)) - return sensors_proc_chips[i].sysctl; - return -SENSORS_ERR_NO_ENTRY; -} - -/* This reads a feature /proc or /sys file. - Sysfs uses a one-value-per file system... -*/ -int sensors_read_proc(sensors_chip_name name, int feature, double *value) -{ - int sysctl_name[4] = { CTL_DEV, DEV_SENSORS }; - const sensors_chip_feature *the_feature; - size_t buflen = BUF_LEN; - int mag; - - if (!sensors_found_sysfs) - if ((sysctl_name[2] = sensors_get_chip_id(name)) < 0) - return sysctl_name[2]; - if (! (the_feature = sensors_lookup_feature_nr(name.prefix,feature))) - return -SENSORS_ERR_NO_ENTRY; - if (sensors_found_sysfs) { - char n[NAME_MAX], altn[NAME_MAX]; - FILE *f; - strcpy(n, name.busname); - strcat(n, "/"); - strcpy(altn, n); - /* use strrchr to append sysname to n */ - getsysname(the_feature, strrchr(n, '\0'), &mag, strrchr(altn, '\0')); - if ((f = fopen(n, "r")) != NULL - || (f = fopen(altn, "r")) != NULL) { - int res = fscanf(f, "%lf", value); - fclose(f); - if (res != 1) - return -SENSORS_ERR_PROC; - for (; mag > 0; mag --) - *value /= 10.0; - } else - return -SENSORS_ERR_PROC; - } else { - sysctl_name[3] = the_feature->sysctl; - if (sysctl(sysctl_name, 4, buf, &buflen, NULL, 0)) - return -SENSORS_ERR_PROC; - *value = *((long *) (buf + the_feature->offset)); - for (mag = the_feature->scaling; mag > 0; mag --) - *value /= 10.0; - for (; mag < 0; mag ++) - *value *= 10.0; - } - return 0; -} - -int sensors_write_proc(sensors_chip_name name, int feature, double value) -{ - int sysctl_name[4] = { CTL_DEV, DEV_SENSORS }; - const sensors_chip_feature *the_feature; - size_t buflen = BUF_LEN; - int mag; - - if (!sensors_found_sysfs) - if ((sysctl_name[2] = sensors_get_chip_id(name)) < 0) - return sysctl_name[2]; - if (! (the_feature = sensors_lookup_feature_nr(name.prefix,feature))) - return -SENSORS_ERR_NO_ENTRY; - if (sensors_found_sysfs) { - char n[NAME_MAX], altn[NAME_MAX]; - FILE *f; - strcpy(n, name.busname); - strcat(n, "/"); - strcpy(altn, n); - /* use strrchr to append sysname to n */ - getsysname(the_feature, strrchr(n, '\0'), &mag, strrchr(altn, '\0')); - if ((f = fopen(n, "w")) != NULL - || (f = fopen(altn, "w")) != NULL) { - for (; mag > 0; mag --) - value *= 10.0; - fprintf(f, "%d", (int) value); - fclose(f); - } else - return -SENSORS_ERR_PROC; - } else { - sysctl_name[3] = the_feature->sysctl; - if (sysctl(sysctl_name, 4, buf, &buflen, NULL, 0)) - return -SENSORS_ERR_PROC; - /* The following line is known to solve random problems, still it - can't be considered a definitive solution... - if (sysctl_name[0] != CTL_DEV) { sysctl_name[0] = CTL_DEV ; } */ - for (mag = the_feature->scaling; mag > 0; mag --) - value *= 10.0; - for (; mag < 0; mag ++) - value /= 10.0; - * ((long *) (buf + the_feature->offset)) = (long) value; - buflen = the_feature->offset + sizeof(long); -#ifdef DEBUG - /* The following get* calls don't do anything, they are here - for debugging purposes only. Strace will show the - returned values. */ - getuid(); geteuid(); - getgid(); getegid(); -#endif - if (sysctl(sysctl_name, 4, NULL, 0, buf, buflen)) - return -SENSORS_ERR_PROC; - } - return 0; -} - -#define CURRMAG 3 -#define FANMAG 0 -#define INMAG 3 -#define TEMPMAG 3 - -/* The following are used in getsysname() below */ -struct match { - const char * name, * sysname; - const int sysmag; - const char * altsysname; -}; - -static const struct match matches[] = { - { "beeps", "beep_mask", 0 }, - { "pwm", "pwm1", 0, "fan1_pwm" }, - { "vid", "cpu0_vid", INMAG, "in0_ref" }, - { "remote_temp", "temp2_input", TEMPMAG }, - { "remote_temp_hyst", "temp2_max_hyst", TEMPMAG }, - { "remote_temp_low", "temp2_min", TEMPMAG }, - { "remote_temp_over", "temp2_max", TEMPMAG }, - { "temp", "temp1_input", TEMPMAG }, - { "temp_hyst", "temp1_max_hyst", TEMPMAG }, - { "temp_low", "temp1_min", TEMPMAG }, - { "temp_over", "temp1_max", TEMPMAG }, - { "temp_high", "temp1_max", TEMPMAG }, - { "temp_crit", "temp1_crit", TEMPMAG }, - { NULL, NULL } -}; - -/* - Returns the sysfs name and magnitude for a given feature. - First looks for a sysfs name and magnitude in the feature structure. - These should be added in chips.c for all non-standard feature names. - If that fails, converts common /proc feature names - to their sysfs equivalent, and uses common sysfs magnitude. - Common magnitudes are #defined above. - Common conversions are as follows: - fan%d_min -> fan%d_min (for magnitude) - fan%d_state -> fan%d_status (for old fscxxx drv) - fan%d_ripple -> fan%d_div (for old fscxxx drv, alt. name) - fan%d -> fan%d_input - pwm%d -> fan%d_pwm (alt. name) - pwm%d_enable -> fan%d_pwm_enable (alt. name) - in%d_max -> in%d_max (for magnitude) - in%d_min -> in%d_min (for magnitude) - in%d -> in%d_input - vin%d_max -> in%d_max - vin%d_min -> in%d_min - vin%d -> in%d_input - temp%d_over -> temp%d_max - temp%d_hyst -> temp%d_max_hyst - temp%d_max -> temp%d_max (for magnitude) - temp%d_high -> temp%d_max - temp%d_min -> temp%d_min (for magnitude) - temp%d_low -> temp%d_min - temp%d_crit -> temp%d_crit (for magnitude) - temp%d_state -> temp%d_status (for old fscxxx drv) - temp%d_offset -> temp%d_offset (for magnitude) - temp%d -> temp%d_input - sensor%d -> temp%d_type - AND all conversions listed in the matches[] structure above. - - If that fails, returns old /proc feature name and magnitude. - - References: doc/developers/proc in the lm_sensors package; - Documentation/hwmon/sysfs-interface in the kernel -*/ -static int getsysname(const sensors_chip_feature *feature, char *sysname, - int *sysmag, char *altsysname) -{ - const char * name = feature->data.name; - char last; - char check; /* used to verify end of string */ - int num; - const struct match *m; - -/* default to a non-existent alternate name (should rarely be tried) */ - strcpy(altsysname, "_"); - -/* use override in feature structure if present */ - if(feature->sysname != NULL) { - strcpy(sysname, feature->sysname); - if(feature->sysscaling) - *sysmag = feature->sysscaling; - else - *sysmag = feature->scaling; - if(feature->altsysname != NULL) - strcpy(altsysname, feature->altsysname); - return 0; - } - -/* check for constant mappings */ - for(m = matches; m->name != NULL; m++) { - if(!strcmp(m->name, name)) { - strcpy(sysname, m->sysname); - if (m->altsysname != NULL) - strcpy(altsysname, m->altsysname); - *sysmag = m->sysmag; - return 0; - } - } - -/* convert common /proc names to common sysfs names */ - if(sscanf(name, "fan%d_mi%c%c", &num, &last, &check) == 2 && last == 'n') { - strcpy(sysname, name); - *sysmag = FANMAG; - return 0; - } - if(sscanf(name, "fan%d_stat%c%c", &num, &last, &check) == 2 && last == 'e') { - sprintf(sysname, "fan%d_status", num); - *sysmag = 0; - return 0; - } - if(sscanf(name, "fan%d_rippl%c%c", &num, &last, &check) == 2 && last == 'e') { - strcpy(sysname, name); - sprintf(altsysname, "fan%d_div", num); - *sysmag = 0; - return 0; - } - if(sscanf(name, "fan%d%c", &num, &check) == 1) { - sprintf(sysname, "fan%d_input", num); - *sysmag = FANMAG; - return 0; - } - if(sscanf(name, "pwm%d%c", &num, &check) == 1) { - strcpy(sysname, name); - *sysmag = 0; - sprintf(altsysname, "fan%d_pwm", num); - return 0; - } - if(sscanf(name, "pwm%d_enabl%c%c", &num, &last, &check) == 2 && last == 'e') { - strcpy(sysname, name); - *sysmag = 0; - sprintf(altsysname, "fan%d_pwm_enable", num); - return 0; - } - - if((sscanf(name, "in%d_mi%c%c", &num, &last, &check) == 2 && last == 'n') - || (sscanf(name, "in%d_ma%c%c", &num, &last, &check) == 2 && last == 'x')) { - strcpy(sysname, name); - *sysmag = INMAG; - return 0; - } - if((sscanf(name, "in%d%c", &num, &check) == 1) - || (sscanf(name, "vin%d%c", &num, &check) == 1)) { - sprintf(sysname, "in%d_input", num); - *sysmag = INMAG; - return 0; - } - if(sscanf(name, "vin%d_mi%c%c", &num, &last, &check) == 2 && last == 'n') { - sprintf(sysname, "in%d_min", num); - *sysmag = INMAG; - return 0; - } - if(sscanf(name, "vin%d_ma%c%c", &num, &last, &check) == 2 && last == 'x') { - sprintf(sysname, "in%d_max", num); - *sysmag = INMAG; - return 0; - } - - if(sscanf(name, "temp%d_hys%c%c", &num, &last, &check) == 2 && last == 't') { - sprintf(sysname, "temp%d_max_hyst", num); - *sysmag = TEMPMAG; - return 0; - } - if((sscanf(name, "temp%d_ove%c%c", &num, &last, &check) == 2 && last == 'r') - || (sscanf(name, "temp%d_ma%c%c", &num, &last, &check) == 2 && last == 'x') - || (sscanf(name, "temp%d_hig%c%c", &num, &last, &check) == 2 && last == 'h')) { - sprintf(sysname, "temp%d_max", num); - *sysmag = TEMPMAG; - return 0; - } - if((sscanf(name, "temp%d_mi%c%c", &num, &last, &check) == 2 && last == 'n') - || (sscanf(name, "temp%d_lo%c%c", &num, &last, &check) == 2 && last == 'w')) { - sprintf(sysname, "temp%d_min", num); - *sysmag = TEMPMAG; - return 0; - } - if(sscanf(name, "temp%d_cri%c%c", &num, &last, &check) == 2 && last == 't') { - sprintf(sysname, "temp%d_crit", num); - *sysmag = TEMPMAG; - return 0; - } - if(sscanf(name, "temp%d_stat%c%c", &num, &last, &check) == 2 && last == 'e') { - sprintf(sysname, "temp%d_status", num); - *sysmag = 0; - return 0; - } - if(sscanf(name, "temp%d_offse%c%c", &num, &last, &check) == 2 && last == 't') { - sprintf(sysname, "temp%d_offset", num); - *sysmag = TEMPMAG; - return 0; - } - if(sscanf(name, "temp%d%c", &num, &check) == 1) { - sprintf(sysname, "temp%d_input", num); - *sysmag = TEMPMAG; - return 0; - } - if(sscanf(name, "sensor%d%c", &num, &check) == 1) { - sprintf(sysname, "temp%d_type", num); - *sysmag = 0; - return 0; - } - -/* bmcsensors only, not yet in kernel */ -/* - if((sscanf(name, "curr%d_mi%c%c", &num, &last, &check) == 2 && last == 'n') - || (sscanf(name, "curr%d_ma%c%c", &num, &last, &check) == 2 && last == 'x')) { - strcpy(sysname, name); - *sysmag = CURRMAG; - return 0; - } - if(sscanf(name, "curr%d%c", &num, &check) == 1) { - sprintf(sysname, "curr%d_input", num); - *sysmag = CURRMAG; - return 0; - } -*/ - -/* give up, use old name (probably won't work though...) */ -/* known to be the same: - "alarms", "beep_enable", "vrm", "fan%d_div" -*/ - strcpy(sysname, name); - *sysmag = feature->scaling; - return 0; -} diff --git a/lib/proc.h b/lib/proc.h deleted file mode 100644 index 05638b58..00000000 --- a/lib/proc.h +++ /dev/null @@ -1,37 +0,0 @@ -/* - proc.h - Part of libsensors, a Linux library for reading sensor data. - Copyright (c) 1998, 1999 Frodo Looijaard - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#ifndef SENSORS_LIB_PROC_H -#define SENSORS_LIB_PROC_H - -/* Read /proc/sys/dev/sensors/chips */ -extern int sensors_read_proc_chips(void); - -/* Read /proc/bus/i2c */ -extern int sensors_read_proc_bus(void); - -/* Read a value out of a /proc file */ -extern int sensors_read_proc(sensors_chip_name name, int feature, - double *value); - -/* Write a value to a /proc file */ -extern int sensors_write_proc(sensors_chip_name name, int feature, - double value); - -#endif diff --git a/lib/scanner.h b/lib/scanner.h index d8e9a413..d67abc48 100644 --- a/lib/scanner.h +++ b/lib/scanner.h @@ -14,14 +14,15 @@ You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + MA 02110-1301 USA. */ #ifndef LIB_SENSORS_SCANNER_H #define LIB_SENSORS_SCANNER_H -extern int sensors_scanner_init(FILE *input); -extern void sensors_scanner_exit(void); +int sensors_scanner_init(FILE *input); +void sensors_scanner_exit(void); #endif diff --git a/lib/sensors.conf.5 b/lib/sensors.conf.5 index b81612f1..8db4b152 100644 --- a/lib/sensors.conf.5 +++ b/lib/sensors.conf.5 @@ -1,5 +1,6 @@ -.\" Copyright 1998, 1999 Adrian Baugh and -.\" Frodo Looijaard +.\" Copyright (C) 1998, 1999 Adrian Baugh and +.\" Frodo Looijaard +.\" Copyright (C) 2008 Jean Delvare .\" .\" Permission is granted to make and distribute verbatim copies of this .\" manual provided the copyright notice and this permission notice are @@ -8,22 +9,19 @@ .\" Permission is granted to copy and distribute modified versions of this .\" manual under the conditions for verbatim copying, provided that the .\" entire resulting derived work is distributed under the terms of a -.\" permission notice identical to this one -.\" +.\" permission notice identical to this one. +.\" .\" Since the Linux kernel and libraries are constantly changing, this .\" manual page may be incorrect or out-of-date. The author(s) assume no .\" responsibility for errors or omissions, or for damages resulting from -.\" the use of the information contained herein. The author(s) may not -.\" have taken the same level of care in the production of this manual, -.\" which is licensed free of charge, as they might when working -.\" professionally. -.\" +.\" the use of the information contained herein. +.\" .\" Formatted or processed versions of this manual, if unaccompanied by .\" the source, must acknowledge the copyright and authors of this work. .\" .\" References consulted: .\" sensors.conf.eg by Frodo Looijaard -.TH sensors.conf 5 "April 2007" "" "Linux User's Manual" +.TH sensors.conf 5 "December 2008" "lm-sensors 3" "Linux User's Manual" .SH NAME sensors.conf \- libsensors configuration file @@ -31,9 +29,413 @@ sensors.conf \- libsensors configuration file sensors.conf describes how libsensors, and so all programs using it, should translate the raw readings from the kernel modules to real\-world values. +.SH SEMANTICS + +On a given system, there may be one or more hardware monitoring chips. +Each chip may have several features. For example, the LM78 monitors 7 +voltage inputs, 3 fans and one temperature. Feature names are +standardized. Typical feature names are in0, in1, in2... for voltage +inputs, fan1, fan2, fan3... for fans and temp1, temp2, temp3... for +temperature inputs. + +Each feature may in turn have one or more sub\-features, each +representing an attribute of the feature: input value, low limit, high +limit, alarm, etc. Sub\-feature names are standardized as well. For +example, the first voltage input (in0) would typically have +sub\-features in0_input (measured value), in0_min (low limit), in0_max +(high limit) and in0_alarm (alarm flag). Which sub\-features are +actually present depend on the exact chip type. + +The +.I sensors.conf +configuration file will let you configure each chip, feature and +sub\-feature in a way that makes sense for your system. + +The rest of this section describes the meaning of each configuration +statement. + +.SS CHIP STATEMENT + +A +.I chip +statement selects for which chips all following +.IR compute , +.IR label , +.I ignore +and +.I set +statements are meant. A chip +selection remains valid until the next +.I chip +statement. Example: + +.RS +chip "lm78\-*" "lm79\-*" +.RE + +If a chip matches at least one of the chip descriptions, the following +configuration lines are examined for it, otherwise they are ignored. + +A chip description is built from several elements, separated by +dashes. The first element is the chip type, the second element is +the name of the bus, and the third element is the hexadecimal address +of the chip. Such chip descriptions are printed by sensors(1) as the +first line for every chip. + +The name of the bus is either +.IR isa , +.IR pci , +.IR virtual , +.I spi-* +or +.I i2c-N +with +.I N +being a bus number as bound with a +.I bus +statement. This list isn't necessarily exhaustive as support for other +bus types may be added in the future. + +You may substitute the wildcard operator +.I * +for every element. Note however that it wouldn't make any sense to specify +the address without the bus type, so the address part is plain omitted +when the bus type isn't specified. +Here is how you would express the following matches: + +.TS +l l. +LM78 chip at address 0x2d on I2C bus 1 lm78\-i2c\-1\-2d +LM78 chip at address 0x2d on any I2C bus lm78\-i2c\-*\-2d +LM78 chip at address 0x290 on the ISA bus lm78\-isa\-0290 +Any LM78 chip on I2C bus 1 lm78\-i2c\-1\-* +Any LM78 on any I2C bus lm78\-i2c\-*\-* +Any LM78 chip on the ISA bus lm78\-isa\-* +Any LM78 chip lm78\-* +Any chip at address 0x2d on I2C bus 1 *\-i2c\-1\-2d +Any chip at address 0x290 on the ISA bus *\-isa\-0290 +.TE + +If several chip statements match a specific chip, they are all considered. + +.SS LABEL STATEMENT + +A +.I label +statement describes how a feature should be called. Features without a +.I label +statement are just called by their feature name. Applications can use this +to label the readings they present. Example: + +.RS +label in3 "+5V" +.RE + +The first argument is the feature name. The second argument is the feature +description. + +.SS IGNORE STATEMENT + +An +.I ignore +statement is a hint that a specific feature should be ignored - probably +because it returns bogus values (for example, because a fan or temperature +sensor is not connected). Example: + +.RS +ignore fan1 +.RE + +The only argument is the feature name. Please note that this does not disable +anything in the actual sensor chip; it simply hides the feature in question +from libsensors users. + +.SS COMPUTE STATEMENT + +A +.I compute +statement describes how a feature's raw value should be translated to a +real\-world value, and how a real\-world value should be translated back +to a raw value again. This is most useful for voltage sensors, because +in general sensor chips have a limited range and voltages outside this +range must be divided (using resistors) before they can be monitored. +Example: + +.RS +compute in3 ((6.8/10)+1)*@, @/((6.8/10)+1) +.RE + +The example above expresses the fact that the voltage input is divided +using two resistors of values 6.8 Ohm and 10 Ohm, respectively. See the +.B VOLTAGE COMPUTATION DETAILS +section below for details. + +The first argument is the feature name. The second argument is an expression +which specifies how a raw value must be translated to a real\-world value; +`@' stands here for the raw value. This is the formula which will be applied +when reading values from the chip. The third argument is an expression that +specifies how a real\-world value should be translated back to a raw value; +`@' stands here for the real\-world value. This is the formula which will be +applied when writing values to the chip. The two formulas are obviously +related, and are separated by a comma. + +A +.I compute +statement applies to all sub\-features of the target feature for which +it makes sense. For example, the above example would affect sub\-features +in3_min and in3_max (which are voltage values) but not in3_alarm +(which is a boolean flag.) + +The following operators are supported in +.I compute +statements: +.RS ++ \- * / ( ) ^ ` +.RE +^x means exp(x) and `x means ln(x). + +You may use the name of sub\-features in these expressions; current readings +are substituted. You should be careful though to avoid circular references. + +If at any moment a translation between a raw and a real\-world value is +called for, but no +.I compute +statement applies, a one\-on\-one translation is used instead. + +.SS SET STATEMENT + +A +.I set +statement is used to write a sub\-feature value to the chip. Of course not +all sub\-feature values can be set that way, in particular input values +and alarm flags can not. Valid sub\-features are usually min/max limits. +Example: + +.RS +set in3_min 5 * 0.95 +.RE +.RS +set in3_max 5 * 1.05 +.RE + +The example above basically configures the chip to allow a 5% deviance +for the +5V power input. + +The first argument is the feature name. The second argument is an expression +which determines the written value. If there is an applying +.I compute +statement, this value is fed to its third argument to translate it to a +raw value. + +You may use the name of sub\-features in these expressions; current readings +are substituted. You should be careful though to avoid circular references. + +Please note that +.I set +statements are only executed by sensors(1) when you use the +.B \-s +option. Typical graphical sensors applications do not care about these +statements at all. + +.SS BUS STATEMENT + +A +.I bus +statement binds the description of an I2C or SMBus adapter to a bus number. +This makes it possible to refer to an adapter in the configuration file, +independent of the actual correspondence of bus numbers and actual +adapters (which may change from moment to moment). Example: + +.RS +bus "i2c\-0" "SMBus PIIX4 adapter at e800" +.RE + +The first argument is the bus number. It is the literal text +.IR i2c\- , +followed by a number. As there is a dash in this argument, it must +always be quoted. + +The second argument is the adapter name, it must match exactly the +adapter name as it appears in +.IR /sys/class/i2c\-adapter/i2c\-*/name . +It should always be quoted as well as it will most certainly contain +spaces or dashes. + +The +.I bus +statements may be scattered randomly throughout the configuration file; +there is no need to place the bus line before the place where its binding +is referred to. Still, as a matter of good style, we suggest you place +all +.I bus +statements together at the top of your configuration file. + +Running +.B sensors --bus-list +will generate these lines for you. + +.SS STATEMENT ORDER + +Statements can go in any order, however it is recommended to put +`set fanX_div' statements before `set fanX_min' statements, in case +a driver doesn't preserve the fanX_min setting when the fanX_div +value is changed. Even if the driver does, it's still better to put +the statements in this order to avoid accuracy loss. + +.SH VOLTAGE COMPUTATION DETAILS + +Most voltage sensors in sensor chips have a range of 0 to 4.08 V. +This is generally sufficient for the +3.3V and CPU supply voltages, so +the sensor chip reading is the actual voltage. + +Other supply voltages must be scaled with an external resistor network. +The driver reports the value at the chip's pin (0 \- 4.08 V), and the +userspace application must convert this raw value to an actual voltage. +The +.I compute +statements provide this facility. + +Unfortunately the resistor values vary among motherboard types. +Therefore you have to figure out the correct resistor values for your +own motherboard. + +For positive voltages (typically +5V and +12V), two resistors are used, +with the following formula: + R1 = R2 * (Vs/Vin \- 1) + +where: + R1 and R2 are the resistor values + Vs is the actual voltage being monitored + Vin is the voltage at the pin + +This leads to the following compute formula: + compute inX @*((R1/R2)+1), @/(((R1/R2)+1) + +Real\-world formula for +5V and +12V would look like: + compute in3 @*((6.8/10)+1), @/((6.8/10)+1) + compute in4 @*((28/10)+1), @/((28/10)+1) + +For negative voltages (typically \-5V and \-12V), two resistors are used +as well, but different boards use different strategies to bring the +voltage value into the 0 \- 4.08 V range. Some use an inverting +amplifier, others use a positive reference voltage. This leads to +different computation formulas. Note that most users won't have to care +because most modern motherboards make little use of \-12V and no use of +\-5V so they do not bother monitoring these voltage inputs. + +Real\-world examples for the inverting amplifier case: + compute in5 \-@*(240/60), \-@/(240/60) + compute in6 \-@*(100/60), \-@/(100/60) + +Real\-world examples for the positive voltage reference case: + compute in5 @*(1+232/56) \- 4.096*232/56, (@ + 4.096*232/56)/(1+232/56) + compute in6 @*(1+120/56) \- 4.096*120/56, (@ + 4.096*120/56)/(1+120/56) + +Many recent monitoring chips have a 0 \- 2.04 V range, so scaling resistors +are even more needed, and resistor values are different. + +There are also a few chips out there which have internal scaling +resistors, meaning that their value is known and doesn't change from +one motherboard to the next. For these chips, the driver usually +handles the scaling so it is transparent to the user and no +.I compute +statements are needed. + +.SH TEMPERATURE CONFIGURATION + +On top of the usual features, temperatures can have two specific +sub\-features: temperature sensor type (tempX_type) and hysteresis +values (tempX_max_hyst and tempX_crit_hyst). + +.SS THERMAL SENSOR TYPES + +Available thermal sensor types: +.TS +r l. +1 PII/Celeron Diode +2 3904 transistor +3 thermal diode +4 thermistor +5 AMD AMDSI +6 Intel PECI +.TE + +For example, to set temp1 to thermistor type, use: + +.RS +set temp1_type 4 +.RE + +Only certain chips support thermal sensor type change, and even these +usually only support some of the types above. Please refer to the +specific driver documentation to find out which types are supported +by your chip. + +In theory, the BIOS should have configured the sensor types correctly, +so you shouldn't have to touch them, but sometimes it isn't the case. + +.SS THERMAL HYSTERESIS MECHANISM + +Many monitoring chips do not handle the high and critical temperature +limits as simple limits. Instead, they have two values for each +limit, one which triggers an alarm when the temperature rises and another +one which clears the alarm when the temperature falls. The latter is +typically a few degrees below the former. This mechanism is known as +hysteresis. + +The reason for implementing things that way is that high temperature +alarms typically trigger an action to attempt to cool the system down, +either by scaling down the CPU frequency, or by kicking in an extra +fan. This should normally let the temperature fall in a timely manner. +If this was clearing the alarm immediately, then the system would be +back to its original state where the temperature rises and the alarm +would immediately trigger again, causing an undesirable tight fan on, +fan off loop. The hysteresis mechanism ensures that the system is +really cool before the fan stops, so that it will not have to kick in +again immediately. + +So, in addition to tempX_max, many chips have a tempX_max_hyst +sub-feature. Likewise, tempX_crit often comes with tempX_max_crit. +Example: + +.RS +set temp1_max 60 +.RE +.RS +set temp1_max_hyst 56 +.RE + +The hysteresis mechanism can be disabled by giving both limits the same +value. + +.SH BEEPS + +Some chips support alarms with beep warnings. When an alarm is triggered +you can be warned by a beeping signal through your computer speaker. On +top of per\-feature beep flags, there is usually a master beep control +switch to enable or disable beeping globally. Enable beeping using: + +.RS +set beep_enable 1 +.RE + +or disable it using: + +.RS +set beep_enable 0 +.RE + +.SH WHICH STATEMENT APPLIES + +If more than one statement of the same kind applies at a certain moment, +the last one in the configuration file is used. So usually, you should +put more general +.I chip +statements at the top, so you can overrule them below. + .SH SYNTAX Comments are introduced by hash marks. A comment continues to the end of the -line. Empty lines, and lines containing only whitespace or comments are +line. Empty lines, and lines containing only whitespace or comments are ignored. Other lines have one of the below forms. There must be whitespace between each element, but the amount of whitespace is unimportant. A line may be continued on the next line by ending it with a backslash; this does @@ -43,31 +445,31 @@ or .BR NUMBER . .RS -bus +bus .B NAME NAME NAME .sp 0 -chip +chip .B NAME\-LIST .sp 0 -label +label .B NAME NAME .sp 0 -compute -.B NAME EXPR -, +compute +.B NAME EXPR +, .B EXPR .sp 0 ignore .B NAME .sp 0 -set +set .B NAME EXPR .RE .sp A .B NAME is a string. If it only contains letters, digits and underscores, it does not -have to quoted; in all other cases, you should use double quotes around it. +have to be quoted; in all other cases, you must use double quotes around it. Within quotes, you can use the normal escape\-codes from C. A @@ -87,27 +489,33 @@ is of one of the below forms: .sp 0 @ .sp 0 -.B EXPR +.B EXPR + .B EXPR .sp 0 -.B EXPR -\- +.B EXPR +\- .B EXPR .sp 0 -.B EXPR -* +.B EXPR +* .B EXPR .sp 0 -.B EXPR -/ +.B EXPR +/ .B EXPR .sp 0 -\- +\- .B EXPR .sp 0 -( -.B EXPR +^ +.B EXPR +.sp 0 +` +.B EXPR +.sp 0 +( +.B EXPR ) .RE @@ -116,299 +524,16 @@ A is a floating\-point number. `10', `10.4' and `.4' are examples of valid floating\-point numbers; `10.' or `10E4' are not valid. -.SH SEMANTICS - -This section describes the meaning of each statement. Each statement is -accompanied by an example line. Please ignore line wrap\-arounds. - -.SS BUS STATEMENT - +.SH FILES +.I /etc/sensors3.conf +.br +.I /etc/sensors.conf .RS -bus "i2c\-0" "SMBus PIIX4 adapter at e800" -.RE +The system-wide +.BR libsensors (3) +configuration file. /etc/sensors3.conf is tried first, and if it doesn't exist, +/etc/sensors.conf is used instead. -A -.I bus -statement binds the description of an I2C or SMBus adapter to a bus number. -This makes it possible to refer to an adapter in the configuration file, -independent of the actual correspondence of bus numbers and actual -adapters (which may change from moment to moment). - -The first argument is the bus number. It is the literal text -.IR i2c\- , -followed by a number. As there is a dash in this argument, it must -always be quoted. - -The second argument is the adapter name, it must match exactly the -adapter name as it appears in -.I /proc/bus/i2c -(2.4 kernel) -or -.I /sys/class/i2c-adapter/i2c-*/device/name -(2.6 kernel). -It should always be quoted as well as it will most certainly contain -spaces or dashes. - -There used to be a third argument, the algorithm name. For compatibility -reasons, the parser still accepts this third argument, but ignores it. - -The -.I bus -statements may be scattered randomly throughout the configuration file; -there is no need to place the bus line before the place where its binding -is referred to. Still, as a matter of good style, we suggest you place -all -.I bus -statements together at the top of your configuration file. - -The program -.I prog/config/grab_busses.sh -in the source distribution can help you generate these lines. - -.SS CHIP STATEMENT - -.RS -chip "lm78\-*" "lm79\-*" -.RE - -The -.I chip -statement selects for which chips all following configuration -statements are meant. The chip selection remains valid until the next -.I chip -statement. It does not influence the operation of a -.I bus -statement. - -If a chip matches at least one of the chip descriptions, all following -configuration lines are examined for it. If it matches none of the -chip descriptions, every -.RI non\- bus -statement is ignored upto the next -.I chip -statement. - -A chip description is built from a couple of elements, separated by -dashes. To complicate matters, sometimes an element can also contain -dashes. This complicates the parsing algorithm, but is not too confusing -for humans (we hope!). - -The first element is the name of the chip type. Sometimes a single driver -implements several chip types, with several names. The driver documentation -should tell you. You may substitute the wildcard operator -.I * -for this element. - -The second element is the name of the bus. This is either -.IR isa , -.I pci -or -.IR i2c-N , -with -.I N -being any number as bound with a -.I bus -statement. You may substitute the wildcard operator -.I * -for this element, or only for the number of the I2C bus -(which means 'any I2C bus'). - -The third element is the hexadecimal address of the chip. The valid range -depends on the bus type. You may substitute -the wildcard operator -.I * -for this element. - -There are some folding rules for wildcards to make things easier for humans -to read. Also, you can't specify the address if you wildcard the complete -second element. The following are all valid chip type specification based -on -.I lm78\-i2c\-1\-2d -or -.IR lm78\-isa\-0290 : - -.RS -lm78\-i2c\-1\-2d -.sp 0 -lm78\-i2c\-1\-* -.sp 0 -lm78\-i2c\-*\-2d -.sp 0 -lm78\-i2c\-*\-* -.sp 0 -lm78\-isa\-0290 -.sp 0 -lm78\-isa\-* -.sp 0 -lm78\-* -.sp 0 -*\-i2c\-1\-2d -.sp 0 -*\-i2c\-1\-* -.sp 0 -*\-i2c\-*\-2d -.sp 0 -*\-i2c-*\-* -.sp 0 -*\-isa\-0290 -.sp 0 -*\-isa\-* -.sp 0 -*\-* -.sp 0 -* -.RE - -.SS COMPUTE STATEMENT -.RS -compute in3 ((6.8/10)+1)*@ , @/((6.8/10)+1) -.RE - -The -.I compute -statement describes how you should translate a feature's raw value to a -real\-world value, and how you should translate it back to a raw value again. - -The first argument is the feature name, which may be the name of a feature -class (see below). The second is an expression which specifies how a -raw value must be translated to a real\-world value; `@' stands here for -the raw value. The third is an expression that specifies how a real\-world -value should be translated back to a raw value; `@' stands here for the -real\-world value. - -You may use the name of other features in these expressions; you should be -careful though to avoid circular references, as this may hang the expression -evaluator. - -If at any moment a translation between a raw and a real\-world value is -called for, but no -.I compute -statement applies, a one\-on\-one translation is used instead. - -The comma is an unfortunate necessity to stop the statement from becoming -ambiguous. - -.SS IGNORE STATEMENT -.RS -ignore fan1 -.RE - -The -.I ignore -statement is a hint that a specific feature should be ignored - probably -because it returns bogus values (for example, because a fan or temperature -sensor is not connected). - -The only argument is the feature name, which may be a feature class; -in that case the label class is used (see below). - -.SS LABEL STATEMENT -.RS -label in3 "+5V" -.RE - -The -.I label -statement describes how a feature should be called. Features without a -.I label -statement are just called by their feature name. Applications can use this -to label the readings they present (but they don't have to). - -The first argument is the feature name, which may be a feature class (see -below). The second argument is the feature description. - -.SS SET STATEMENT -.RS -set in3_min 5 * 0.95 -.RE - -The -.I set -statement gives an initial value for a feature. Not each feature can be -given a sensible initial value; valid features are usually min/max limits. - -The first argument is the feature name. The second argument is an expression -which determines the initial value. If there is an applying -.I compute -statement, this value is fed to its third argument to translate it to a -raw value. - -You may use the name of other features in these expressions; current readings -are substituted. You should be careful though to avoid circular references, -as this may hang the expression evaluator. Also, you can't be sure in which -order -.I set -statements are evaluated, so this can lead to nasty surprises. - -.SH FEATURE CLASSES - -There are two kinds of classes, here called -.I compute -and -.I label -classes, after the statements for which they are defined. Classes are -defined over features: the kind of values that can be read from or set -for a specific kind of chip. - -Each class has a class name, which is usually the same as its most -prominent feature. A -.I label -or -.I compute -statement for the class name feature forces the same settings for all other -class members. A specific statement for a class member feature always -overrides the general class setting, though. This means that you can't -override the class name feature explicitly. - -A simple example will explain this better. The -.I fan1 -label class of the -.I lm78 -chip contains three members: -.I fan1 -itself, -.I fan1_min -and -.IR fan1_div . -The last feature sets the number by which readings are divided (to give the -fan less resolution, but a larger field of operation). The following -line will set the name of all these features to describe the fan: -.RS -label fan1 "Processor 1 FAN" -.RE -Now we happen to know that, due to the type of fan we use, all readings -are always off by a factor of two (some fans only return one 'tick' each -rotation, others return two): -.RS -compute fan1 @/2 , @*2 -.RE -It will be clear that this should be done for the -.I fan1_min -feature too, but not for the -.I fan1_div -feature! Fortunately, the -.I fan1 -compute class contains -.IR fan1_min , -but not -.IR fan1_div , -so this works out right. - -.SH WHICH STATEMENT APPLIES - -If more than one statement of the same kind applies at a certain moment, -the last one in the configuration file is used. So usually, you should -put more general -.I chip -statements at the top, so you can overrule them below. - -There is one exception to this rule: if a statement only applies because -the feature is in the same class as the feature the statement contains, -and there is anywhere else a statement for this specific class member, -that one takes always precedence. - -.SH "CONFORMING TO" -lm_sensors-2.x .SH SEE ALSO libsensors(3) diff --git a/lib/sensors.h b/lib/sensors.h index 67ba7fda..04236abe 100644 --- a/lib/sensors.h +++ b/lib/sensors.h @@ -1,6 +1,7 @@ /* sensors.h - Part of libsensors, a Linux library for reading sensor data. Copyright (c) 1998, 1999 Frodo Looijaard + Copyright (C) 2007 Jean Delvare This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -14,13 +15,15 @@ You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + MA 02110-1301 USA. */ #ifndef LIB_SENSORS_SENSORS_H #define LIB_SENSORS_SENSORS_H #include +#include /* Publicly accessible library functions */ @@ -28,129 +31,228 @@ when the API + ABI breaks), the third digit is incremented to track small API additions like new flags / enum values. The second digit is for tracking larger additions like new methods. */ -#define SENSORS_API_VERSION 0x300 +#define SENSORS_API_VERSION 0x402 -#define SENSORS_CHIP_NAME_PREFIX_ANY NULL -#define SENSORS_CHIP_NAME_BUS_ISA -1 -#define SENSORS_CHIP_NAME_BUS_ANY -2 -#define SENSORS_CHIP_NAME_BUS_ANY_I2C -3 -#define SENSORS_CHIP_NAME_BUS_DUMMY -4 -#define SENSORS_CHIP_NAME_BUS_PCI -5 -#define SENSORS_CHIP_NAME_ADDR_ANY -1 +#define SENSORS_CHIP_NAME_PREFIX_ANY NULL +#define SENSORS_CHIP_NAME_ADDR_ANY (-1) + +#define SENSORS_BUS_TYPE_ANY (-1) +#define SENSORS_BUS_TYPE_I2C 0 +#define SENSORS_BUS_TYPE_ISA 1 +#define SENSORS_BUS_TYPE_PCI 2 +#define SENSORS_BUS_TYPE_SPI 3 +#define SENSORS_BUS_TYPE_VIRTUAL 4 +#define SENSORS_BUS_TYPE_ACPI 5 +#define SENSORS_BUS_NR_ANY (-1) +#define SENSORS_BUS_NR_IGNORE (-2) #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ +extern const char *libsensors_version; + +typedef struct sensors_bus_id { + short type; + short nr; +} sensors_bus_id; + /* A chip name is encoded in this structure */ typedef struct sensors_chip_name { - char *prefix; - int bus; - int addr; - char *busname; /* if dummy */ + char *prefix; + sensors_bus_id bus; + int addr; + char *path; } sensors_chip_name; -/* (Re)load the configuration file and the detected chips list. If this - returns a value unequal to zero, you are in trouble; you can not - assume anything will be initialized properly. */ -extern int sensors_init(FILE *input); +/* Load the configuration file and the detected chips list. If this + returns a value unequal to zero, you are in trouble; you can not + assume anything will be initialized properly. If you want to + reload the configuration file, call sensors_cleanup() below before + calling sensors_init() again. */ +int sensors_init(FILE *input); /* Clean-up function: You can't access anything after this, until the next sensors_init() call! */ -extern void sensors_cleanup(void); +void sensors_cleanup(void); /* Parse a chip name to the internal representation. Return 0 on success, <0 on error. */ -extern int sensors_parse_chip_name(const char *orig_name, - sensors_chip_name *res); +int sensors_parse_chip_name(const char *orig_name, sensors_chip_name *res); -/* Compare two chips name descriptions, to see whether they could match. - Return 0 if it does not match, return 1 if it does match. */ -extern int sensors_match_chip(sensors_chip_name chip1, - sensors_chip_name chip2); +/* Print a chip name from its internal representation. Note that chip should + not contain wildcard values! Return the number of characters printed on + success (same as snprintf), <0 on error. */ +int sensors_snprintf_chip_name(char *str, size_t size, + const sensors_chip_name *chip); -/* Check whether the chip name is an 'absolute' name, which can only match - one chip, or whether it has wildcards. Returns 0 if it is absolute, 1 - if there are wildcards. */ -extern int sensors_chip_name_has_wildcards(sensors_chip_name chip); - -/* This function returns the adapter name of a bus number, +/* This function returns the adapter name of a bus, as used within the sensors_chip_name structure. If it could not be found, it returns NULL */ -extern const char *sensors_get_adapter_name(int bus_nr); +const char *sensors_get_adapter_name(const sensors_bus_id *bus); -/* This function is deprecated and will be dropped soon. */ -extern const char *sensors_get_algorithm_name(int bus_nr); +typedef struct sensors_feature sensors_feature; -/* Look up the label which belongs to this chip. Note that chip should not - contain wildcard values! *result is newly allocated (free it yourself). - This function will return 0 on success, and <0 on failure. +/* Look up the label for a given feature. Note that chip should not + contain wildcard values! The returned string is newly allocated (free it + yourself). On failure, NULL is returned. If no label exists for this feature, its name is returned itself. */ -extern int sensors_get_label(sensors_chip_name name, int feature, - char **result); +char *sensors_get_label(const sensors_chip_name *name, + const sensors_feature *feature); -/* Looks up whether a feature should be ignored. Returns <0 on failure, - 0 if it should be ignored, 1 if it is valid. This function takes - logical mappings into account. */ -extern int sensors_get_ignored(sensors_chip_name name, int feature); - -/* Read the value of a feature of a certain chip. Note that chip should not +/* Read the value of a subfeature of a certain chip. Note that chip should not contain wildcard values! This function will return 0 on success, and <0 on failure. */ -extern int sensors_get_feature(sensors_chip_name name, int feature, - double *result); +int sensors_get_value(const sensors_chip_name *name, int subfeat_nr, + double *value); -/* Set the value of a feature of a certain chip. Note that chip should not +/* Set the value of a subfeature of a certain chip. Note that chip should not contain wildcard values! This function will return 0 on success, and <0 on failure. */ -extern int sensors_set_feature(sensors_chip_name name, int feature, - double value); +int sensors_set_value(const sensors_chip_name *name, int subfeat_nr, + double value); /* Execute all set statements for this particular chip. The chip may contain wildcards! This function will return 0 on success, and <0 on failure. */ -extern int sensors_do_chip_sets(sensors_chip_name name); +int sensors_do_chip_sets(const sensors_chip_name *name); -/* Execute all set statements for all detected chips. This is the same as - calling sensors_do_chip_sets with an all wildcards chip name */ -extern int sensors_do_all_sets(void); +/* This function returns all detected chips that match a given chip name, + one by one. If no chip name is provided, all detected chips are returned. + To start at the beginning of the list, use 0 for nr; NULL is returned if + we are at the end of the list. Do not try to change these chip names, as + they point to internal structures! */ +const sensors_chip_name *sensors_get_detected_chips(const sensors_chip_name + *match, int *nr); -/* This function returns all detected chips, one by one. To start at the - beginning of the list, use 0 for nr; NULL is returned if we are - at the end of the list. Do not try to change these chip names, as - they point to internal structures! Do not use nr for anything else. */ -extern const sensors_chip_name *sensors_get_detected_chips(int *nr); +/* These defines are used in the flags field of sensors_subfeature */ +#define SENSORS_MODE_R 1 +#define SENSORS_MODE_W 2 +#define SENSORS_COMPUTE_MAPPING 4 +typedef enum sensors_feature_type { + SENSORS_FEATURE_IN = 0x00, + SENSORS_FEATURE_FAN = 0x01, + SENSORS_FEATURE_TEMP = 0x02, + SENSORS_FEATURE_POWER = 0x03, + SENSORS_FEATURE_ENERGY = 0x04, + SENSORS_FEATURE_CURR = 0x05, + SENSORS_FEATURE_VID = 0x10, + SENSORS_FEATURE_BEEP_ENABLE = 0x18, + SENSORS_FEATURE_UNKNOWN = INT_MAX, +} sensors_feature_type; -/* These defines are used in the mode field of sensors_feature_data */ -#define SENSORS_MODE_NO_RW 0 -#define SENSORS_MODE_R 1 -#define SENSORS_MODE_W 2 -#define SENSORS_MODE_RW 3 +/* All the sensor types (in, fan, temp, vid) are a multiple of 0x100 apart, + and sensor subfeatures which have no compute mapping have bit 7 set. */ +typedef enum sensors_subfeature_type { + SENSORS_SUBFEATURE_IN_INPUT = SENSORS_FEATURE_IN << 8, + SENSORS_SUBFEATURE_IN_MIN, + SENSORS_SUBFEATURE_IN_MAX, + SENSORS_SUBFEATURE_IN_ALARM = (SENSORS_FEATURE_IN << 8) | 0x80, + SENSORS_SUBFEATURE_IN_MIN_ALARM, + SENSORS_SUBFEATURE_IN_MAX_ALARM, + SENSORS_SUBFEATURE_IN_BEEP, -/* This define is used in the mapping field of sensors_feature_data if no - mapping is available */ -#define SENSORS_NO_MAPPING -1 + SENSORS_SUBFEATURE_FAN_INPUT = SENSORS_FEATURE_FAN << 8, + SENSORS_SUBFEATURE_FAN_MIN, + SENSORS_SUBFEATURE_FAN_ALARM = (SENSORS_FEATURE_FAN << 8) | 0x80, + SENSORS_SUBFEATURE_FAN_FAULT, + SENSORS_SUBFEATURE_FAN_DIV, + SENSORS_SUBFEATURE_FAN_BEEP, -/* This structure is used when you want to get all features of a specific - chip. */ -typedef struct sensors_feature_data { - int number; - const char *name; - int mapping; - int compute_mapping; - int mode; -} sensors_feature_data; + SENSORS_SUBFEATURE_TEMP_INPUT = SENSORS_FEATURE_TEMP << 8, + SENSORS_SUBFEATURE_TEMP_MAX, + SENSORS_SUBFEATURE_TEMP_MAX_HYST, + SENSORS_SUBFEATURE_TEMP_MIN, + SENSORS_SUBFEATURE_TEMP_CRIT, + SENSORS_SUBFEATURE_TEMP_CRIT_HYST, + SENSORS_SUBFEATURE_TEMP_ALARM = (SENSORS_FEATURE_TEMP << 8) | 0x80, + SENSORS_SUBFEATURE_TEMP_MAX_ALARM, + SENSORS_SUBFEATURE_TEMP_MIN_ALARM, + SENSORS_SUBFEATURE_TEMP_CRIT_ALARM, + SENSORS_SUBFEATURE_TEMP_FAULT, + SENSORS_SUBFEATURE_TEMP_TYPE, + SENSORS_SUBFEATURE_TEMP_OFFSET, + SENSORS_SUBFEATURE_TEMP_BEEP, -/* This returns all features of a specific chip. They are returned in - bunches: everything with the same mapping is returned just after each - other, with the master feature in front (that feature does not map to - itself, but has SENSORS_NO_MAPPING as mapping field). nr1 and nr2 are - two internally used variables. Set both to zero to start again at the - begin of the list. If no more features are found NULL is returned. + SENSORS_SUBFEATURE_POWER_AVERAGE = SENSORS_FEATURE_POWER << 8, + SENSORS_SUBFEATURE_POWER_AVERAGE_HIGHEST, + SENSORS_SUBFEATURE_POWER_AVERAGE_LOWEST, + SENSORS_SUBFEATURE_POWER_INPUT, + SENSORS_SUBFEATURE_POWER_INPUT_HIGHEST, + SENSORS_SUBFEATURE_POWER_INPUT_LOWEST, + SENSORS_SUBFEATURE_POWER_AVERAGE_INTERVAL = (SENSORS_FEATURE_POWER << 8) | 0x80, + + SENSORS_SUBFEATURE_ENERGY_INPUT = SENSORS_FEATURE_ENERGY << 8, + + SENSORS_SUBFEATURE_CURR_INPUT = SENSORS_FEATURE_CURR << 8, + SENSORS_SUBFEATURE_CURR_MIN, + SENSORS_SUBFEATURE_CURR_MAX, + SENSORS_SUBFEATURE_CURR_ALARM = (SENSORS_FEATURE_CURR << 8) | 0x80, + SENSORS_SUBFEATURE_CURR_MIN_ALARM, + SENSORS_SUBFEATURE_CURR_MAX_ALARM, + SENSORS_SUBFEATURE_CURR_BEEP, + + SENSORS_SUBFEATURE_VID = SENSORS_FEATURE_VID << 8, + + SENSORS_SUBFEATURE_BEEP_ENABLE = SENSORS_FEATURE_BEEP_ENABLE << 8, + + SENSORS_SUBFEATURE_UNKNOWN = INT_MAX, +} sensors_subfeature_type; + +/* Data about a single chip feature (or category leader) */ +struct sensors_feature { + char *name; + int number; + sensors_feature_type type; + /* Members below are for libsensors internal use only */ + int first_subfeature; + int padding1; +}; + +/* Data about a single chip subfeature: + name is the string name used to refer to this subfeature (in config files) + number is the internal subfeature number, used in many functions to refer + to this subfeature + type is the subfeature type + mapping is the number of a main feature this subfeature belongs to + (for example subfeatures fan1_input, fan1_min, fan1_div and fan1_alarm + are mapped to main feature fan1) + flags is a bitfield, its value is a combination of SENSORS_MODE_R (readable), + SENSORS_MODE_W (writable) and SENSORS_COMPUTE_MAPPING (affected by the + computation rules of the main feature) */ +typedef struct sensors_subfeature { + char *name; + int number; + sensors_subfeature_type type; + int mapping; + unsigned int flags; +} sensors_subfeature; + +/* This returns all main features of a specific chip. nr is an internally + used variable. Set it to zero to start at the begin of the list. If no + more features are found NULL is returned. Do not try to change the returned structure; you will corrupt internal data structures. */ -extern const sensors_feature_data *sensors_get_all_features - (sensors_chip_name name, int *nr1,int *nr2); +const sensors_feature * +sensors_get_features(const sensors_chip_name *name, int *nr); + +/* This returns all subfeatures of a given main feature. nr is an internally + used variable. Set it to zero to start at the begin of the list. If no + more features are found NULL is returned. + Do not try to change the returned structure; you will corrupt internal + data structures. */ +const sensors_subfeature * +sensors_get_all_subfeatures(const sensors_chip_name *name, + const sensors_feature *feature, int *nr); + +/* This returns the subfeature of the given type for a given main feature, + if it exists, NULL otherwise. + Do not try to change the returned structure; you will corrupt internal + data structures. */ +const sensors_subfeature * +sensors_get_subfeature(const sensors_chip_name *name, + const sensors_feature *feature, + sensors_subfeature_type type); #ifdef __cplusplus } diff --git a/lib/sysfs.c b/lib/sysfs.c index 19f542e0..7f805a80 100644 --- a/lib/sysfs.c +++ b/lib/sysfs.c @@ -1,6 +1,7 @@ /* sysfs.c - Part of libsensors, a library for reading Linux sensor data Copyright (c) 2005 Mark M. Hoffman + Copyright (C) 2007-2008 Jean Delvare This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -14,7 +15,8 @@ You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + MA 02110-1301 USA. */ /* this define needed for strndup() */ @@ -27,225 +29,765 @@ #include #include #include -#include +#include #include "data.h" #include "error.h" #include "access.h" #include "general.h" #include "sysfs.h" -int sensors_found_sysfs = 0; + +/****************************************************************************/ + +#define ATTR_MAX 128 + +/* + * Read an attribute from sysfs + * Returns a pointer to a freshly allocated string; free it yourself. + * If the file doesn't exist or can't be read, NULL is returned. + */ +static char *sysfs_read_attr(const char *device, const char *attr) +{ + char path[NAME_MAX]; + char buf[ATTR_MAX], *p; + FILE *f; + + snprintf(path, NAME_MAX, "%s/%s", device, attr); + + if (!(f = fopen(path, "r"))) + return NULL; + p = fgets(buf, ATTR_MAX, f); + fclose(f); + if (!p) + return NULL; + + /* Last byte is a '\n'; chop that off */ + p = strndup(buf, strlen(buf) - 1); + if (!p) + sensors_fatal_error(__func__, "Out of memory"); + return p; +} + +/* + * Call an arbitrary function for each class device of the given class + * Returns 0 on success (all calls returned 0), a positive errno for + * local errors, or a negative error value if any call fails. + */ +static int sysfs_foreach_classdev(const char *class_name, + int (*func)(const char *, const char *)) +{ + char path[NAME_MAX]; + int path_off, ret; + DIR *dir; + struct dirent *ent; + + path_off = snprintf(path, NAME_MAX, "%s/class/%s", + sensors_sysfs_mount, class_name); + if (!(dir = opendir(path))) + return errno; + + ret = 0; + while (!ret && (ent = readdir(dir))) { + if (ent->d_name[0] == '.') /* skip hidden entries */ + continue; + + snprintf(path + path_off, NAME_MAX - path_off, "/%s", + ent->d_name); + ret = func(path, ent->d_name); + } + + closedir(dir); + return ret; +} + +/* + * Call an arbitrary function for each device of the given bus type + * Returns 0 on success (all calls returned 0), a positive errno for + * local errors, or a negative error value if any call fails. + */ +static int sysfs_foreach_busdev(const char *bus_type, + int (*func)(const char *, const char *)) +{ + char path[NAME_MAX]; + int path_off, ret; + DIR *dir; + struct dirent *ent; + + path_off = snprintf(path, NAME_MAX, "%s/bus/%s/devices", + sensors_sysfs_mount, bus_type); + if (!(dir = opendir(path))) + return errno; + + ret = 0; + while (!ret && (ent = readdir(dir))) { + if (ent->d_name[0] == '.') /* skip hidden entries */ + continue; + + snprintf(path + path_off, NAME_MAX - path_off, "/%s", + ent->d_name); + ret = func(path, ent->d_name); + } + + closedir(dir); + return ret; +} + +/****************************************************************************/ char sensors_sysfs_mount[NAME_MAX]; +#define MAX_SENSORS_PER_TYPE 20 +#define MAX_SUBFEATURES 8 +#define MAX_SENSOR_TYPES 6 +/* Room for all 5 types (in, fan, temp, power, energy) with all their + subfeatures + VID + misc features */ +#define ALL_POSSIBLE_SUBFEATURES \ + (MAX_SENSORS_PER_TYPE * MAX_SUBFEATURES * \ + MAX_SENSOR_TYPES * 2 + \ + MAX_SENSORS_PER_TYPE + 1) + +static +int get_type_scaling(sensors_subfeature_type type) +{ + /* Multipliers for subfeatures */ + switch (type & 0xFF80) { + case SENSORS_SUBFEATURE_IN_INPUT: + case SENSORS_SUBFEATURE_TEMP_INPUT: + case SENSORS_SUBFEATURE_CURR_INPUT: + return 1000; + case SENSORS_SUBFEATURE_FAN_INPUT: + return 1; + case SENSORS_SUBFEATURE_POWER_AVERAGE: + case SENSORS_SUBFEATURE_ENERGY_INPUT: + return 1000000; + } + + /* Multipliers for second class subfeatures + that need their own multiplier */ + switch (type) { + case SENSORS_SUBFEATURE_POWER_AVERAGE_INTERVAL: + case SENSORS_SUBFEATURE_VID: + case SENSORS_SUBFEATURE_TEMP_OFFSET: + return 1000; + default: + return 1; + } +} + +static +char *get_feature_name(sensors_feature_type ftype, char *sfname) +{ + char *name, *underscore; + + switch (ftype) { + case SENSORS_FEATURE_IN: + case SENSORS_FEATURE_FAN: + case SENSORS_FEATURE_TEMP: + case SENSORS_FEATURE_POWER: + case SENSORS_FEATURE_ENERGY: + case SENSORS_FEATURE_CURR: + underscore = strchr(sfname, '_'); + name = strndup(sfname, underscore - sfname); + break; + default: + name = strdup(sfname); + } + + return name; +} + +/* Static mappings for use by sensors_subfeature_get_type() */ +struct subfeature_type_match +{ + const char *name; + sensors_subfeature_type type; +}; + +struct feature_type_match +{ + const char *name; + const struct subfeature_type_match *submatches; +}; + +static const struct subfeature_type_match temp_matches[] = { + { "input", SENSORS_SUBFEATURE_TEMP_INPUT }, + { "max", SENSORS_SUBFEATURE_TEMP_MAX }, + { "max_hyst", SENSORS_SUBFEATURE_TEMP_MAX_HYST }, + { "min", SENSORS_SUBFEATURE_TEMP_MIN }, + { "crit", SENSORS_SUBFEATURE_TEMP_CRIT }, + { "crit_hyst", SENSORS_SUBFEATURE_TEMP_CRIT_HYST }, + { "alarm", SENSORS_SUBFEATURE_TEMP_ALARM }, + { "min_alarm", SENSORS_SUBFEATURE_TEMP_MIN_ALARM }, + { "max_alarm", SENSORS_SUBFEATURE_TEMP_MAX_ALARM }, + { "crit_alarm", SENSORS_SUBFEATURE_TEMP_CRIT_ALARM }, + { "fault", SENSORS_SUBFEATURE_TEMP_FAULT }, + { "type", SENSORS_SUBFEATURE_TEMP_TYPE }, + { "offset", SENSORS_SUBFEATURE_TEMP_OFFSET }, + { NULL, 0 } +}; + +static const struct subfeature_type_match in_matches[] = { + { "input", SENSORS_SUBFEATURE_IN_INPUT }, + { "min", SENSORS_SUBFEATURE_IN_MIN }, + { "max", SENSORS_SUBFEATURE_IN_MAX }, + { "alarm", SENSORS_SUBFEATURE_IN_ALARM }, + { "min_alarm", SENSORS_SUBFEATURE_IN_MIN_ALARM }, + { "max_alarm", SENSORS_SUBFEATURE_IN_MAX_ALARM }, + { NULL, 0 } +}; + +static const struct subfeature_type_match fan_matches[] = { + { "input", SENSORS_SUBFEATURE_FAN_INPUT }, + { "min", SENSORS_SUBFEATURE_FAN_MIN }, + { "div", SENSORS_SUBFEATURE_FAN_DIV }, + { "alarm", SENSORS_SUBFEATURE_FAN_ALARM }, + { "fault", SENSORS_SUBFEATURE_FAN_FAULT }, + { NULL, 0 } +}; + +static const struct subfeature_type_match power_matches[] = { + { "average", SENSORS_SUBFEATURE_POWER_AVERAGE }, + { "average_highest", SENSORS_SUBFEATURE_POWER_AVERAGE_HIGHEST }, + { "average_lowest", SENSORS_SUBFEATURE_POWER_AVERAGE_LOWEST }, + { "input", SENSORS_SUBFEATURE_POWER_INPUT }, + { "input_highest", SENSORS_SUBFEATURE_POWER_INPUT_HIGHEST }, + { "input_lowest", SENSORS_SUBFEATURE_POWER_INPUT_LOWEST }, + { "average_interval", SENSORS_SUBFEATURE_POWER_AVERAGE_INTERVAL }, + { NULL, 0 } +}; + +static const struct subfeature_type_match energy_matches[] = { + { "input", SENSORS_SUBFEATURE_ENERGY_INPUT }, + { NULL, 0 } +}; + +static const struct subfeature_type_match curr_matches[] = { + { "input", SENSORS_SUBFEATURE_CURR_INPUT }, + { "min", SENSORS_SUBFEATURE_CURR_MIN }, + { "max", SENSORS_SUBFEATURE_CURR_MAX }, + { "alarm", SENSORS_SUBFEATURE_CURR_ALARM }, + { "min_alarm", SENSORS_SUBFEATURE_CURR_MIN_ALARM }, + { "max_alarm", SENSORS_SUBFEATURE_CURR_MAX_ALARM }, + { NULL, 0 } +}; + +static const struct subfeature_type_match cpu_matches[] = { + { "vid", SENSORS_SUBFEATURE_VID }, + { NULL, 0 } +}; + +static struct feature_type_match matches[] = { + { "temp%d%c", temp_matches }, + { "in%d%c", in_matches }, + { "fan%d%c", fan_matches }, + { "cpu%d%c", cpu_matches }, + { "power%d%c", power_matches }, + { "curr%d%c", curr_matches }, + { "energy%d%c", energy_matches }, +}; + +/* Return the subfeature type and channel number based on the subfeature + name */ +static +sensors_subfeature_type sensors_subfeature_get_type(const char *name, int *nr) +{ + char c; + int i, count; + const struct subfeature_type_match *submatches; + + /* Special case */ + if (!strcmp(name, "beep_enable")) { + *nr = 0; + return SENSORS_SUBFEATURE_BEEP_ENABLE; + } + + for (i = 0; i < ARRAY_SIZE(matches); i++) + if ((count = sscanf(name, matches[i].name, nr, &c))) + break; + + if (i == ARRAY_SIZE(matches) || count != 2 || c != '_') + return SENSORS_SUBFEATURE_UNKNOWN; /* no match */ + + submatches = matches[i].submatches; + name = strchr(name + 3, '_') + 1; + for (i = 0; submatches[i].name != NULL; i++) + if (!strcmp(name, submatches[i].name)) + return submatches[i].type; + + return SENSORS_SUBFEATURE_UNKNOWN; +} + +static int sensors_get_attr_mode(const char *device, const char *attr) +{ + char path[NAME_MAX]; + struct stat st; + int mode = 0; + + snprintf(path, NAME_MAX, "%s/%s", device, attr); + if (!stat(path, &st)) { + if (st.st_mode & S_IRUSR) + mode |= SENSORS_MODE_R; + if (st.st_mode & S_IWUSR) + mode |= SENSORS_MODE_W; + } + return mode; +} + +static int sensors_read_dynamic_chip(sensors_chip_features *chip, + const char *dev_path) +{ + int i, fnum = 0, sfnum = 0, prev_slot; + DIR *dir; + struct dirent *ent; + sensors_subfeature *all_subfeatures; + sensors_subfeature *dyn_subfeatures; + sensors_feature *dyn_features; + sensors_feature_type ftype; + sensors_subfeature_type sftype; + + if (!(dir = opendir(dev_path))) + return -errno; + + /* We use a large sparse table at first to store all found + subfeatures, so that we can store them sorted at type and index + and then later create a dense sorted table. */ + all_subfeatures = calloc(ALL_POSSIBLE_SUBFEATURES, + sizeof(sensors_subfeature)); + if (!all_subfeatures) + sensors_fatal_error(__func__, "Out of memory"); + + while ((ent = readdir(dir))) { + char *name = ent->d_name; + int nr; + + if (ent->d_name[0] == '.') + continue; + + sftype = sensors_subfeature_get_type(name, &nr); + if (sftype == SENSORS_SUBFEATURE_UNKNOWN) + continue; + + /* Adjust the channel number */ + switch (sftype & 0xFF00) { + case SENSORS_SUBFEATURE_FAN_INPUT: + case SENSORS_SUBFEATURE_TEMP_INPUT: + case SENSORS_SUBFEATURE_POWER_AVERAGE: + case SENSORS_SUBFEATURE_ENERGY_INPUT: + case SENSORS_SUBFEATURE_CURR_INPUT: + nr--; + break; + } + + if (nr < 0 || nr >= MAX_SENSORS_PER_TYPE) { + /* More sensors of one type than MAX_SENSORS_PER_TYPE, + we have to ignore it */ +#ifdef DEBUG + sensors_fatal_error(__func__, + "Increase MAX_SENSORS_PER_TYPE!"); +#endif + continue; + } + + /* "calculate" a place to store the subfeature in our sparse, + sorted table */ + switch (sftype) { + case SENSORS_SUBFEATURE_VID: + i = nr + MAX_SENSORS_PER_TYPE * MAX_SUBFEATURES * + MAX_SENSOR_TYPES * 2; + break; + case SENSORS_SUBFEATURE_BEEP_ENABLE: + i = MAX_SENSORS_PER_TYPE * MAX_SUBFEATURES * + MAX_SENSOR_TYPES * 2 + MAX_SENSORS_PER_TYPE; + break; + default: + i = (sftype >> 8) * MAX_SENSORS_PER_TYPE * + MAX_SUBFEATURES * 2 + nr * MAX_SUBFEATURES * 2 + + ((sftype & 0x80) >> 7) * MAX_SUBFEATURES + + (sftype & 0x7F); + } + + if (all_subfeatures[i].name) { +#ifdef DEBUG + sensors_fatal_error(__func__, "Duplicate subfeature"); +#endif + continue; + } + + /* fill in the subfeature members */ + all_subfeatures[i].type = sftype; + all_subfeatures[i].name = strdup(name); + if (!(sftype & 0x80)) + all_subfeatures[i].flags |= SENSORS_COMPUTE_MAPPING; + all_subfeatures[i].flags |= sensors_get_attr_mode(dev_path, name); + + sfnum++; + } + closedir(dir); + + if (!sfnum) { /* No subfeature */ + chip->subfeature = NULL; + goto exit_free; + } + + /* How many main features? */ + prev_slot = -1; + for (i = 0; i < ALL_POSSIBLE_SUBFEATURES; i++) { + if (!all_subfeatures[i].name) + continue; + + if (i >= MAX_SENSORS_PER_TYPE * MAX_SUBFEATURES * + MAX_SENSOR_TYPES * 2 || + i / (MAX_SUBFEATURES * 2) != prev_slot) { + fnum++; + prev_slot = i / (MAX_SUBFEATURES * 2); + } + } + + dyn_subfeatures = calloc(sfnum, sizeof(sensors_subfeature)); + dyn_features = calloc(fnum, sizeof(sensors_feature)); + if (!dyn_subfeatures || !dyn_features) + sensors_fatal_error(__func__, "Out of memory"); + + /* Copy from the sparse array to the compact array */ + sfnum = 0; + fnum = -1; + prev_slot = -1; + for (i = 0; i < ALL_POSSIBLE_SUBFEATURES; i++) { + if (!all_subfeatures[i].name) + continue; + + /* New main feature? */ + if (i >= MAX_SENSORS_PER_TYPE * MAX_SUBFEATURES * + MAX_SENSOR_TYPES * 2 || + i / (MAX_SUBFEATURES * 2) != prev_slot) { + ftype = all_subfeatures[i].type >> 8; + fnum++; + prev_slot = i / (MAX_SUBFEATURES * 2); + + dyn_features[fnum].name = get_feature_name(ftype, + all_subfeatures[i].name); + dyn_features[fnum].number = fnum; + dyn_features[fnum].first_subfeature = sfnum; + dyn_features[fnum].type = ftype; + } + + dyn_subfeatures[sfnum] = all_subfeatures[i]; + dyn_subfeatures[sfnum].number = sfnum; + /* Back to the feature */ + dyn_subfeatures[sfnum].mapping = fnum; + + sfnum++; + } + + chip->subfeature = dyn_subfeatures; + chip->subfeature_count = sfnum; + chip->feature = dyn_features; + chip->feature_count = ++fnum; + +exit_free: + free(all_subfeatures); + return 0; +} + /* returns !0 if sysfs filesystem was found, 0 otherwise */ int sensors_init_sysfs(void) { struct stat statbuf; - /* libsysfs will return success even if sysfs is not mounted, - so we have to double-check */ - if (sysfs_get_mnt_path(sensors_sysfs_mount, NAME_MAX) == 0 - && stat(sensors_sysfs_mount, &statbuf) == 0 - && statbuf.st_nlink > 2) - sensors_found_sysfs = 1; + snprintf(sensors_sysfs_mount, NAME_MAX, "%s", "/sys"); + if (stat(sensors_sysfs_mount, &statbuf) < 0 + || statbuf.st_nlink <= 2) /* Empty directory */ + return 0; - return sensors_found_sysfs; + return 1; } -/* returns: 0 if successful, !0 otherwise */ -static int sensors_read_one_sysfs_chip(struct sysfs_device *dev) +/* returns: number of devices added (0 or 1) if successful, <0 otherwise */ +static int sensors_read_one_sysfs_chip(const char *dev_path, + const char *dev_name, + const char *hwmon_path) { int domain, bus, slot, fn; - struct sysfs_attribute *attr, *bus_attr; - char bus_path[SYSFS_PATH_MAX]; - sensors_proc_chips_entry entry; - int err = -SENSORS_ERR_PARSE; + int err = -SENSORS_ERR_KERNEL; + char *bus_attr; + char bus_path[NAME_MAX]; + char linkpath[NAME_MAX]; + char subsys_path[NAME_MAX], *subsys; + int sub_len; + sensors_chip_features entry; /* ignore any device without name attribute */ - if (!(attr = sysfs_get_device_attr(dev, "name"))) + if (!(entry.chip.prefix = sysfs_read_attr(hwmon_path, "name"))) return 0; - /* ignore subclients */ - if (attr->len >= 11 && !strcmp(attr->value + attr->len - 11, - " subclient\n")) - return 0; + entry.chip.path = strdup(hwmon_path); + if (!entry.chip.path) + sensors_fatal_error(__func__, "Out of memory"); - /* also ignore eeproms */ - if (!strcmp(attr->value, "eeprom\n")) - return 0; + if (dev_path == NULL) { + /* Virtual device */ + entry.chip.bus.type = SENSORS_BUS_TYPE_VIRTUAL; + entry.chip.bus.nr = 0; + /* For now we assume that virtual devices are unique */ + entry.chip.addr = 0; + goto done; + } - /* NB: attr->value[attr->len-1] == '\n'; chop that off */ - entry.name.prefix = strndup(attr->value, attr->len - 1); - if (!entry.name.prefix) - sensors_fatal_error(__FUNCTION__, "out of memory"); + /* Find bus type */ + snprintf(linkpath, NAME_MAX, "%s/subsystem", dev_path); + sub_len = readlink(linkpath, subsys_path, NAME_MAX - 1); + if (sub_len < 0 && errno == ENOENT) { + /* Fallback to "bus" link for kernels <= 2.6.17 */ + snprintf(linkpath, NAME_MAX, "%s/bus", dev_path); + sub_len = readlink(linkpath, subsys_path, NAME_MAX - 1); + } + if (sub_len < 0) { + /* Older kernels (<= 2.6.11) have neither the subsystem + symlink nor the bus symlink */ + if (errno == ENOENT) + subsys = NULL; + else + goto exit_free; + } else { + subsys_path[sub_len] = '\0'; + subsys = strrchr(subsys_path, '/') + 1; + } - entry.name.busname = strdup(dev->path); - if (!entry.name.busname) - sensors_fatal_error(__FUNCTION__, "out of memory"); - - if (sscanf(dev->name, "%d-%x", &entry.name.bus, &entry.name.addr) == 2) { + if ((!subsys || !strcmp(subsys, "i2c")) && + sscanf(dev_name, "%hd-%x", &entry.chip.bus.nr, + &entry.chip.addr) == 2) { /* find out if legacy ISA or not */ - if (entry.name.bus == 9191) - entry.name.bus = SENSORS_CHIP_NAME_BUS_ISA; - else { + if (entry.chip.bus.nr == 9191) { + entry.chip.bus.type = SENSORS_BUS_TYPE_ISA; + entry.chip.bus.nr = 0; + } else { + entry.chip.bus.type = SENSORS_BUS_TYPE_I2C; snprintf(bus_path, sizeof(bus_path), - "%s/class/i2c-adapter/i2c-%d/device/name", - sensors_sysfs_mount, entry.name.bus); + "%s/class/i2c-adapter/i2c-%d/device", + sensors_sysfs_mount, entry.chip.bus.nr); - if ((bus_attr = sysfs_open_attribute(bus_path))) { - if (sysfs_read_attribute(bus_attr)) { - sysfs_close_attribute(bus_attr); - goto exit_free; + if ((bus_attr = sysfs_read_attr(bus_path, "name"))) { + if (!strncmp(bus_attr, "ISA ", 4)) { + entry.chip.bus.type = SENSORS_BUS_TYPE_ISA; + entry.chip.bus.nr = 0; } - if (bus_attr->value - && !strncmp(bus_attr->value, "ISA ", 4)) - entry.name.bus = SENSORS_CHIP_NAME_BUS_ISA; - - sysfs_close_attribute(bus_attr); + free(bus_attr); } } - } else if (sscanf(dev->name, "%*[a-z0-9_].%d", &entry.name.addr) == 1) { - /* must be new ISA (platform driver) */ - entry.name.bus = SENSORS_CHIP_NAME_BUS_ISA; - } else if (sscanf(dev->name, "%x:%x:%x.%x", &domain, &bus, &slot, &fn) == 4) { + } else + if ((!subsys || !strcmp(subsys, "spi")) && + sscanf(dev_name, "spi%hd.%d", &entry.chip.bus.nr, + &entry.chip.addr) == 2) { + /* SPI */ + entry.chip.bus.type = SENSORS_BUS_TYPE_SPI; + } else + if ((!subsys || !strcmp(subsys, "pci")) && + sscanf(dev_name, "%x:%x:%x.%x", &domain, &bus, &slot, &fn) == 4) { /* PCI */ - entry.name.addr = (domain << 16) + (bus << 8) + (slot << 3) + fn; - entry.name.bus = SENSORS_CHIP_NAME_BUS_PCI; + entry.chip.addr = (domain << 16) + (bus << 8) + (slot << 3) + fn; + entry.chip.bus.type = SENSORS_BUS_TYPE_PCI; + entry.chip.bus.nr = 0; + } else + if ((!subsys || !strcmp(subsys, "platform") || + !strcmp(subsys, "of_platform"))) { + /* must be new ISA (platform driver) */ + if (sscanf(dev_name, "%*[a-z0-9_].%d", &entry.chip.addr) != 1) + entry.chip.addr = 0; + entry.chip.bus.type = SENSORS_BUS_TYPE_ISA; + entry.chip.bus.nr = 0; + } else if (subsys && !strcmp(subsys, "acpi")) { + entry.chip.bus.type = SENSORS_BUS_TYPE_ACPI; + /* For now we assume that acpi devices are unique */ + entry.chip.bus.nr = 0; + entry.chip.addr = 0; } else { - /* Ignore unknown devices */ + /* Ignore unknown device */ err = 0; goto exit_free; } +done: + if (sensors_read_dynamic_chip(&entry, hwmon_path) < 0) + goto exit_free; + if (!entry.subfeature) { /* No subfeature, discard chip */ + err = 0; + goto exit_free; + } sensors_add_proc_chips(&entry); - return 0; + return 1; exit_free: - free(entry.name.prefix); - free(entry.name.busname); + free(entry.chip.prefix); + free(entry.chip.path); return err; } +static int sensors_add_hwmon_device_compat(const char *path, + const char *dev_name) +{ + int err; + + err = sensors_read_one_sysfs_chip(path, dev_name, path); + if (err < 0) + return err; + return 0; +} + /* returns 0 if successful, !0 otherwise */ static int sensors_read_sysfs_chips_compat(void) { - struct sysfs_bus *bus; - struct dlist *devs; - struct sysfs_device *dev; - int ret = 0; + int ret; - if (!(bus = sysfs_open_bus("i2c"))) { - if (errno && errno != ENOENT) - ret = -SENSORS_ERR_PROC; - goto exit0; + ret = sysfs_foreach_busdev("i2c", sensors_add_hwmon_device_compat); + if (ret && ret != ENOENT) + return -SENSORS_ERR_KERNEL; + + return 0; +} + +static int sensors_add_hwmon_device(const char *path, const char *classdev) +{ + char linkpath[NAME_MAX]; + char device[NAME_MAX], *device_p; + int dev_len, err; + (void)classdev; /* hide warning */ + + snprintf(linkpath, NAME_MAX, "%s/device", path); + dev_len = readlink(linkpath, device, NAME_MAX - 1); + if (dev_len < 0) { + /* No device link? Treat as virtual */ + err = sensors_read_one_sysfs_chip(NULL, NULL, path); + } else { + device[dev_len] = '\0'; + device_p = strrchr(device, '/') + 1; + + /* The attributes we want might be those of the hwmon class + device, or those of the device itself. */ + err = sensors_read_one_sysfs_chip(linkpath, device_p, path); + if (err == 0) + err = sensors_read_one_sysfs_chip(linkpath, device_p, + linkpath); } - - if (!(devs = sysfs_get_bus_devices(bus))) { - if (errno && errno != ENOENT) - ret = -SENSORS_ERR_PROC; - goto exit1; - } - - dlist_for_each_data(devs, dev, struct sysfs_device) - if ((ret = sensors_read_one_sysfs_chip(dev))) - goto exit1; - -exit1: - /* this frees bus and devs */ - sysfs_close_bus(bus); - -exit0: - return ret; + if (err < 0) + return err; + return 0; } /* returns 0 if successful, !0 otherwise */ int sensors_read_sysfs_chips(void) { - struct sysfs_class *cls; - struct dlist *clsdevs; - struct sysfs_class_device *clsdev; - int ret = 0; + int ret; - if (!(cls = sysfs_open_class("hwmon"))) { + ret = sysfs_foreach_classdev("hwmon", sensors_add_hwmon_device); + if (ret == ENOENT) { /* compatibility function for kernel 2.6.n where n <= 13 */ return sensors_read_sysfs_chips_compat(); } - if (!(clsdevs = sysfs_get_class_devices(cls))) { - if (errno && errno != ENOENT) - ret = -SENSORS_ERR_PROC; - goto exit; - } - - dlist_for_each_data(clsdevs, clsdev, struct sysfs_class_device) { - struct sysfs_device *dev; - if (!(dev = sysfs_get_classdev_device(clsdev))) - continue; - if ((ret = sensors_read_one_sysfs_chip(dev))) - goto exit; - } - -exit: - /* this frees cls and clsdevs */ - sysfs_close_class(cls); + if (ret > 0) + ret = -SENSORS_ERR_KERNEL; return ret; } +/* returns 0 if successful, !0 otherwise */ +static int sensors_add_i2c_bus(const char *path, const char *classdev) +{ + sensors_bus entry; + + if (sscanf(classdev, "i2c-%hd", &entry.bus.nr) != 1 || + entry.bus.nr == 9191) /* legacy ISA */ + return 0; + entry.bus.type = SENSORS_BUS_TYPE_I2C; + + /* Get the adapter name from the classdev "name" attribute + * (Linux 2.6.20 and later). If it fails, fall back to + * the device "name" attribute (for older kernels). */ + entry.adapter = sysfs_read_attr(path, "name"); + if (!entry.adapter) + entry.adapter = sysfs_read_attr(path, "device/name"); + if (entry.adapter) + sensors_add_proc_bus(&entry); + + return 0; +} + /* returns 0 if successful, !0 otherwise */ int sensors_read_sysfs_bus(void) { - struct sysfs_class *cls; - struct dlist *clsdevs; - struct sysfs_class_device *clsdev; - sensors_bus entry; - int ret = 0; + int ret; - if (!(cls = sysfs_open_class("i2c-adapter"))) { - if (errno && errno != ENOENT) - ret = -SENSORS_ERR_PROC; - goto exit0; - } + ret = sysfs_foreach_classdev("i2c-adapter", sensors_add_i2c_bus); + if (ret && ret != ENOENT) + return -SENSORS_ERR_KERNEL; - if (!(clsdevs = sysfs_get_class_devices(cls))) { - if (errno && errno != ENOENT) - ret = -SENSORS_ERR_PROC; - goto exit1; - } - - dlist_for_each_data(clsdevs, clsdev, struct sysfs_class_device) { - struct sysfs_device *dev; - struct sysfs_attribute *attr; - - /* Get the adapter name from the classdev "name" attribute - * (Linux 2.6.20 and later). If it fails, fall back to - * the device "name" attribute (for older kernels). */ - if (!(attr = sysfs_get_classdev_attr(clsdev, "name")) - && !((dev = sysfs_get_classdev_device(clsdev)) && - (attr = sysfs_get_device_attr(dev, "name")))) - continue; - - /* NB: attr->value[attr->len-1] == '\n'; chop that off */ - entry.adapter = strndup(attr->value, attr->len - 1); - if (!entry.adapter) - sensors_fatal_error(__FUNCTION__, "out of memory"); - - if (!strncmp(entry.adapter, "ISA ", 4)) { - entry.number = SENSORS_CHIP_NAME_BUS_ISA; - } else if (sscanf(clsdev->name, "i2c-%d", &entry.number) != 1) { - entry.number = SENSORS_CHIP_NAME_BUS_DUMMY; - } - - sensors_add_proc_bus(&entry); - } - -exit1: - /* this frees *cls _and_ *clsdevs */ - sysfs_close_class(cls); - -exit0: - return ret; + return 0; } +int sensors_read_sysfs_attr(const sensors_chip_name *name, + const sensors_subfeature *subfeature, + double *value) +{ + char n[NAME_MAX]; + FILE *f; + + snprintf(n, NAME_MAX, "%s/%s", name->path, subfeature->name); + if ((f = fopen(n, "r"))) { + int res, err = 0; + + errno = 0; + res = fscanf(f, "%lf", value); + if (res == EOF && errno == EIO) + err = -SENSORS_ERR_IO; + else if (res != 1) + err = -SENSORS_ERR_ACCESS_R; + res = fclose(f); + if (err) + return err; + + if (res == EOF) { + if (errno == EIO) + return -SENSORS_ERR_IO; + else + return -SENSORS_ERR_ACCESS_R; + } + *value /= get_type_scaling(subfeature->type); + } else + return -SENSORS_ERR_KERNEL; + + return 0; +} + +int sensors_write_sysfs_attr(const sensors_chip_name *name, + const sensors_subfeature *subfeature, + double value) +{ + char n[NAME_MAX]; + FILE *f; + + snprintf(n, NAME_MAX, "%s/%s", name->path, subfeature->name); + if ((f = fopen(n, "w"))) { + int res, err = 0; + + value *= get_type_scaling(subfeature->type); + res = fprintf(f, "%d", (int) value); + if (res == -EIO) + err = -SENSORS_ERR_IO; + else if (res < 0) + err = -SENSORS_ERR_ACCESS_W; + res = fclose(f); + if (err) + return err; + + if (res == EOF) { + if (errno == EIO) + return -SENSORS_ERR_IO; + else + return -SENSORS_ERR_ACCESS_W; + } + } else + return -SENSORS_ERR_KERNEL; + + return 0; +} diff --git a/lib/sysfs.h b/lib/sysfs.h index 351524d2..ae52abed 100644 --- a/lib/sysfs.h +++ b/lib/sysfs.h @@ -1,6 +1,7 @@ /* sysfs.h - part of libsensors, a library for reading Linux sensor data - Copyright (C) Mark M. Hoffman + Copyright (C) Mark M. Hoffman + Copyright (C) 2007 Jean Delvare This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -14,30 +15,29 @@ You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + MA 02110-1301 USA. */ #ifndef SENSORS_LIB_SYSFS_H #define SENSORS_LIB_SYSFS_H -#ifdef SYSFS_SUPPORT -extern int sensors_found_sysfs; - extern char sensors_sysfs_mount[]; -extern int sensors_init_sysfs(void); +int sensors_init_sysfs(void); -extern int sensors_read_sysfs_chips(void); +int sensors_read_sysfs_chips(void); -extern int sensors_read_sysfs_bus(void); +int sensors_read_sysfs_bus(void); -#else +/* Read a value out of a sysfs attribute file */ +int sensors_read_sysfs_attr(const sensors_chip_name *name, + const sensors_subfeature *subfeature, + double *value); -#define sensors_found_sysfs 0 -#define sensors_init_sysfs() 0 -#define sensors_read_sysfs_chips() (-1) -#define sensors_read_sysfs_bus() (-1) - -#endif +/* Write a value to a sysfs attribute file */ +int sensors_write_sysfs_attr(const sensors_chip_name *name, + const sensors_subfeature *subfeature, + double value); #endif /* !SENSORS_LIB_SYSFS_H */ diff --git a/lib/test/Module.mk b/lib/test/Module.mk index b9991def..2a9f6edc 100644 --- a/lib/test/Module.mk +++ b/lib/test/Module.mk @@ -4,8 +4,6 @@ LIB_TEST_DIR := lib/test LIB_TEST_TARGETS := $(LIB_TEST_DIR)/test-scanner LIB_TEST_SOURCES := $(LIB_TEST_DIR)/test-scanner.c -LIBICONV := $(shell if /sbin/ldconfig -p | grep -q libiconv\\.so ; then echo \-liconv; else echo; fi) - LIB_TEST_SCANNER_OBJS := \ $(LIB_TEST_DIR)/test-scanner.ro \ $(LIB_DIR)/conf-lex.ao \ @@ -13,7 +11,7 @@ LIB_TEST_SCANNER_OBJS := \ $(LIB_DIR)/general.ao $(LIB_TEST_DIR)/test-scanner: $(LIB_TEST_SCANNER_OBJS) - $(CC) $(EXLDFLAGS) -o $@ $(LIB_TEST_SCANNER_OBJS) $(LIBICONV) -Llib + $(CC) $(EXLDFLAGS) -o $@ $(LIB_TEST_SCANNER_OBJS) -Llib all-lib-test: $(LIB_TEST_TARGETS) user :: all-lib-test diff --git a/lib/test/test-scanner.c b/lib/test/test-scanner.c index 3d6ac545..e0abcee8 100644 --- a/lib/test/test-scanner.c +++ b/lib/test/test-scanner.c @@ -13,7 +13,8 @@ You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + MA 02110-1301 USA. */ #include diff --git a/lib/test/test-scanner.pl b/lib/test/test-scanner.pl index da6d6489..6d163a8e 100755 --- a/lib/test/test-scanner.pl +++ b/lib/test/test-scanner.pl @@ -14,7 +14,8 @@ # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software -# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, +# MA 02110-1301 USA. # require 5.004; diff --git a/mkpatch/Config.in b/mkpatch/Config.in deleted file mode 100644 index 3f11a043..00000000 --- a/mkpatch/Config.in +++ /dev/null @@ -1,69 +0,0 @@ -# -# Sensor device configuration -# All depend on CONFIG_I2C_PROC. -# ISA-only devices depend on CONFIG_I2C_ISA also. -# - -if [ "$CONFIG_I2C" = "m" -o "$CONFIG_I2C" = "y" ] ; then -if [ "$CONFIG_I2C_PROC" = "m" -o "$CONFIG_I2C_PROC" = "y" ] ; then - mainmenu_option next_comment - comment 'Hardware sensors support' - - dep_mbool 'Hardware sensors support' CONFIG_SENSORS $CONFIG_I2C $CONFIG_I2C_PROC - - if [ "$CONFIG_SENSORS" != "n" ]; then - dep_tristate ' Analog Devices ADM1021 and compatibles' CONFIG_SENSORS_ADM1021 $CONFIG_I2C $CONFIG_I2C_PROC - dep_tristate ' Analog Devices ADM1024' CONFIG_SENSORS_ADM1024 $CONFIG_I2C $CONFIG_I2C_PROC - dep_tristate ' Analog Devices ADM1025' CONFIG_SENSORS_ADM1025 $CONFIG_I2C $CONFIG_I2C_PROC - dep_tristate ' Analog Devices ADM1026' CONFIG_SENSORS_ADM1026 $CONFIG_I2C $CONFIG_I2C_PROC - dep_tristate ' Analog Devices ADM1030, ADM1031' CONFIG_SENSORS_ADM1031 $CONFIG_I2C $CONFIG_I2C_PROC - dep_tristate ' Analog Devices ADM9240 and compatibles' CONFIG_SENSORS_ADM9240 $CONFIG_I2C $CONFIG_I2C_PROC - dep_tristate ' Asus ASB100' CONFIG_SENSORS_ASB100 $CONFIG_I2C $CONFIG_I2C_PROC - dep_tristate ' Dallas DS1621 and DS1625' CONFIG_SENSORS_DS1621 $CONFIG_I2C $CONFIG_I2C_PROC - dep_tristate ' Fintek F71805F' CONFIG_SENSORS_F71805F $CONFIG_I2C $CONFIG_I2C_PROC - dep_tristate ' Fujitsu-Siemens Hermes' CONFIG_SENSORS_FSCHER $CONFIG_I2C $CONFIG_I2C_PROC - dep_tristate ' Fujitsu-Siemens Poseidon' CONFIG_SENSORS_FSCPOS $CONFIG_I2C $CONFIG_I2C_PROC - dep_tristate ' Fujitsu-Siemens Scylla' CONFIG_SENSORS_FSCSCY $CONFIG_I2C $CONFIG_I2C_PROC - dep_tristate ' Genesys Logic GL518SM' CONFIG_SENSORS_GL518SM $CONFIG_I2C $CONFIG_I2C_PROC - dep_tristate ' Genesys Logic GL520SM' CONFIG_SENSORS_GL520SM $CONFIG_I2C $CONFIG_I2C_PROC - dep_tristate ' HP Maxilife' CONFIG_SENSORS_MAXILIFE $CONFIG_I2C $CONFIG_I2C_PROC - dep_tristate ' Intel Xeon Thermal Sensor' CONFIG_SENSORS_XEONTEMP $CONFIG_I2C $CONFIG_I2C_PROC - dep_tristate ' ITE 8705/8712, SiS950' CONFIG_SENSORS_IT87 $CONFIG_I2C $CONFIG_I2C_PROC - dep_tristate ' Maxim MAX1619' CONFIG_SENSORS_MAX1619 $CONFIG_I2C $CONFIG_I2C_PROC - dep_tristate ' Maxim MAX6650, MAX6651' CONFIG_SENSORS_MAX6650 $CONFIG_I2C $CONFIG_I2C_PROC - dep_tristate ' Myson MTP008' CONFIG_SENSORS_MTP008 $CONFIG_I2C $CONFIG_I2C_PROC - dep_tristate ' National Semiconductor LM63' CONFIG_SENSORS_LM63 $CONFIG_I2C $CONFIG_I2C_PROC - dep_tristate ' National Semiconductor LM75 and compatibles' CONFIG_SENSORS_LM75 $CONFIG_I2C $CONFIG_I2C_PROC - dep_tristate ' National Semiconductor LM78' CONFIG_SENSORS_LM78 $CONFIG_I2C $CONFIG_I2C_PROC - dep_tristate ' National Semiconductor LM80' CONFIG_SENSORS_LM80 $CONFIG_I2C $CONFIG_I2C_PROC - dep_tristate ' National Semiconductor LM83 and compatibles' CONFIG_SENSORS_LM83 $CONFIG_I2C $CONFIG_I2C_PROC - dep_tristate ' National Semiconductor LM85, Analog Devices ADM1027' CONFIG_SENSORS_LM85 $CONFIG_I2C $CONFIG_I2C_PROC - dep_tristate ' National Semiconductor LM87' CONFIG_SENSORS_LM87 $CONFIG_I2C $CONFIG_I2C_PROC - dep_tristate ' National Semiconductor LM90 and compatibles' CONFIG_SENSORS_LM90 $CONFIG_I2C $CONFIG_I2C_PROC - dep_tristate ' National Semiconductor LM92' CONFIG_SENSORS_LM92 $CONFIG_I2C $CONFIG_I2C_PROC - dep_tristate ' National Semiconductor LM93' CONFIG_SENSORS_LM93 $CONFIG_I2C $CONFIG_I2C_PROC - dep_tristate ' National Semiconductor PC8736x Sensors' CONFIG_SENSORS_PC87360 $CONFIG_I2C $CONFIG_I2C_PROC - dep_tristate ' Silicon Integrated Systems Corp. SiS5595' CONFIG_SENSORS_SIS5595 $CONFIG_I2C $CONFIG_I2C_PROC $CONFIG_I2C_ISA - dep_tristate ' SMSC47M1xx Integrated Sensors' CONFIG_SENSORS_SMSC47M1 $CONFIG_I2C $CONFIG_I2C_PROC $CONFIG_I2C_ISA - dep_tristate ' Texas Instruments THMC50 and compatibles' CONFIG_SENSORS_THMC50 $CONFIG_I2C $CONFIG_I2C_PROC - dep_tristate ' VIA 686a Integrated Hardware Monitor' CONFIG_SENSORS_VIA686A $CONFIG_I2C $CONFIG_I2C_PROC $CONFIG_I2C_ISA - dep_tristate ' VIA VT1211 Integrated Sensors' CONFIG_SENSORS_VT1211 $CONFIG_I2C $CONFIG_I2C_PROC $CONFIG_I2C_ISA - dep_tristate ' VIA VT8231 Integrated Sensors' CONFIG_SENSORS_VT8231 $CONFIG_I2C $CONFIG_I2C_PROC $CONFIG_I2C_ISA - dep_tristate ' Winbond W83781D, W83782D, W83783S, W83627HF, Asus AS99127F' CONFIG_SENSORS_W83781D $CONFIG_I2C $CONFIG_I2C_PROC - dep_tristate ' Winbond W83792D' CONFIG_SENSORS_W83792D $CONFIG_I2C $CONFIG_I2C_PROC - dep_tristate ' Winbond W83627HF, W83627THF, W83637HF, W83687THF, W83697HF' CONFIG_SENSORS_W83627HF $CONFIG_I2C $CONFIG_I2C_PROC $CONFIG_I2C_ISA - dep_tristate ' Winbond W83L785TS-S' CONFIG_SENSORS_W83L785TS $CONFIG_I2C $CONFIG_I2C_PROC - bool 'Other I2C devices' CONFIG_SENSORS_OTHER - if [ "$CONFIG_SENSORS_OTHER" = "y" ] ; then - dep_tristate ' Brooktree BT869 Video Modulator' CONFIG_SENSORS_BT869 $CONFIG_I2C $CONFIG_I2C_PROC - dep_tristate ' DDC Monitor EDID EEPROM' CONFIG_SENSORS_DDCMON $CONFIG_I2C $CONFIG_I2C_PROC - dep_tristate ' EEprom (DIMM) reader ' CONFIG_SENSORS_EEPROM $CONFIG_I2C $CONFIG_I2C_PROC - dep_tristate ' Matrix-Orbital LCD Displays' CONFIG_SENSORS_MATORB $CONFIG_I2C $CONFIG_I2C_PROC - dep_tristate ' Philips PCF8574 Parallel I/O' CONFIG_SENSORS_PCF8574 $CONFIG_I2C $CONFIG_I2C_PROC - dep_tristate ' Philips PCF8591 D/A and A/D' CONFIG_SENSORS_PCF8591 $CONFIG_I2C $CONFIG_I2C_PROC - fi - fi - endmenu -fi -fi - diff --git a/mkpatch/FILES b/mkpatch/FILES deleted file mode 100644 index 1d06b242..00000000 --- a/mkpatch/FILES +++ /dev/null @@ -1,73 +0,0 @@ -kernel/busses/i2c-ali1535.c drivers/i2c/i2c-ali1535.c -kernel/busses/i2c-ali15x3.c drivers/i2c/i2c-ali15x3.c -kernel/busses/i2c-ali1563.c drivers/i2c/i2c-ali1563.c -kernel/busses/i2c-amd756.c drivers/i2c/i2c-amd756.c -kernel/busses/i2c-amd756-s4882.c drivers/i2c/i2c-amd756-s4882.c -kernel/busses/i2c-amd8111.c drivers/i2c/i2c-amd8111.c -kernel/busses/i2c-hydra.c drivers/i2c/i2c-hydra.c -kernel/busses/i2c-i801.c drivers/i2c/i2c-i801.c -kernel/busses/i2c-i810.c drivers/i2c/i2c-i810.c -kernel/busses/i2c-isa.c drivers/i2c/i2c-isa.c -kernel/busses/i2c-nforce2.c drivers/i2c/i2c-nforce2.c -kernel/busses/i2c-piix4.c drivers/i2c/i2c-piix4.c -kernel/busses/i2c-savage4.c drivers/i2c/i2c-savage4.c -kernel/busses/i2c-sis5595.c drivers/i2c/i2c-sis5595.c -kernel/busses/i2c-tsunami.c drivers/i2c/i2c-tsunami.c -kernel/busses/i2c-via.c drivers/i2c/i2c-via.c -kernel/busses/i2c-viapro.c drivers/i2c/i2c-viapro.c -kernel/busses/i2c-voodoo3.c drivers/i2c/i2c-voodoo3.c -kernel/busses/i2c-sis630.c drivers/i2c/i2c-sis630.c -kernel/busses/i2c-sis645.c drivers/i2c/i2c-sis645.c -kernel/chips/adm1021.c drivers/sensors/adm1021.c -kernel/chips/adm1024.c drivers/sensors/adm1024.c -kernel/chips/adm1025.c drivers/sensors/adm1025.c -kernel/chips/adm1026.c drivers/sensors/adm1026.c -kernel/chips/adm1031.c drivers/sensors/adm1031.c -kernel/chips/adm9240.c drivers/sensors/adm9240.c -kernel/chips/asb100.c drivers/sensors/asb100.c -kernel/chips/bt869.c drivers/sensors/bt869.c -kernel/chips/ddcmon.c drivers/sensors/ddcmon.c -kernel/chips/ds1621.c drivers/sensors/ds1621.c -kernel/chips/eeprom.c drivers/sensors/eeprom.c -kernel/chips/f71805f.c drivers/sensors/f71805f.c -kernel/chips/fscher.c drivers/sensors/fscher.c -kernel/chips/fscpos.c drivers/sensors/fscpos.c -kernel/chips/fscscy.c drivers/sensors/fscscy.c -kernel/chips/gl518sm.c drivers/sensors/gl518sm.c -kernel/chips/gl520sm.c drivers/sensors/gl520sm.c -kernel/chips/it87.c drivers/sensors/it87.c -kernel/chips/lm63.c drivers/sensors/lm63.c -kernel/chips/lm75.h drivers/sensors/lm75.h -kernel/chips/lm75.c drivers/sensors/lm75.c -kernel/chips/lm78.c drivers/sensors/lm78.c -kernel/chips/lm80.c drivers/sensors/lm80.c -kernel/chips/lm83.c drivers/sensors/lm83.c -kernel/chips/lm85.c drivers/sensors/lm85.c -kernel/chips/lm87.c drivers/sensors/lm87.c -kernel/chips/lm90.c drivers/sensors/lm90.c -kernel/chips/lm92.c drivers/sensors/lm92.c -kernel/chips/lm93.c drivers/sensors/lm93.c -kernel/chips/lm93.h drivers/sensors/lm93.h -kernel/chips/matorb.c drivers/sensors/matorb.c -kernel/chips/max1619.c drivers/sensors/max1619.c -kernel/chips/max6650.c drivers/sensors/max6650.c -kernel/chips/maxilife.c drivers/sensors/maxilife.c -kernel/chips/mtp008.c drivers/sensors/mtp008.c -kernel/chips/pc87360.c drivers/sensors/pc87360.c -kernel/chips/pcf8574.c drivers/sensors/pcf8574.c -kernel/chips/pcf8591.c drivers/sensors/pcf8591.c -kernel/chips/sis5595.c drivers/sensors/sis5595.c -kernel/chips/smsc47m1.c drivers/sensors/smsc47m1.c -kernel/chips/thmc50.c drivers/sensors/thmc50.c -kernel/chips/via686a.c drivers/sensors/via686a.c -kernel/chips/vt1211.c drivers/sensors/vt1211.c -kernel/chips/vt8231.c drivers/sensors/vt8231.c -kernel/chips/w83781d.c drivers/sensors/w83781d.c -kernel/chips/w83792d.c drivers/sensors/w83792d.c -kernel/chips/w83627hf.c drivers/sensors/w83627hf.c -kernel/chips/w83627ehf.c drivers/sensors/w83627ehf.c -kernel/chips/w83l785ts.c drivers/sensors/w83l785ts.c -kernel/chips/xeontemp.c drivers/sensors/xeontemp.c -kernel/include/sensors_compat.h include/linux/sensors_compat.h -kernel/include/sensors_vid.h include/linux/sensors_vid.h -mkpatch/Config.in drivers/sensors/Config.in diff --git a/mkpatch/INCLUDES b/mkpatch/INCLUDES deleted file mode 100644 index 81932f14..00000000 --- a/mkpatch/INCLUDES +++ /dev/null @@ -1,2 +0,0 @@ -"sensors_compat.h" -"sensors_vid.h" diff --git a/mkpatch/Module.mk b/mkpatch/Module.mk deleted file mode 100644 index 3b3cc8e8..00000000 --- a/mkpatch/Module.mk +++ /dev/null @@ -1,26 +0,0 @@ -# Module.mk - Makefile for a Linux module for reading sensor data. -# Copyright (c) 1998, 1999 Frodo Looijaard -# -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - -# Note that MODULE_DIR (the directory in which this file resides) is a -# 'simply expanded variable'. That means that its value is substituted -# verbatim in the rules, until it is redefined. -MODULE_DIR := mkpatch -MKPATCHDIR := $(MODULE_DIR) - -clean-mkpatch: - $(RM) $(MKPATCHDIR)/.temp -clean :: clean-mkpatch diff --git a/mkpatch/mkpatch.pl b/mkpatch/mkpatch.pl deleted file mode 100755 index 2a1d0a3c..00000000 --- a/mkpatch/mkpatch.pl +++ /dev/null @@ -1,1353 +0,0 @@ -#!/usr/bin/perl -w - -# mkpatch - Create patches against the Linux kernel -# Copyright (C) 1999 Frodo Looijaard -# Copyright (C) 2005-2007 Jean Delvare -# -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - -use strict; - -use vars qw($temp); -$temp = "mkpatch/.temp"; - -# Generate a diff between the old kernel file and the new lm_sensors file. We -# arrange the headers to tell us the old tree was under directory -# `linux-old', and the new tree under `linux'. -# $_[0]: sensors package root (like /tmp/sensors) -# $_[1]: Linux kernel tree (like /usr/src/linux) -# $_[2]: Name of the kernel file -# $_[3]: Name of the patched file -sub print_diff -{ - my ($package_root,$kernel_root,$kernel_file,$package_file) = @_; - my ($diff_command,$package_mtime,$kernel_mtime); - - $diff_command = "diff -u"; - if ( -e "$kernel_root/$kernel_file") { - $diff_command .= " $kernel_root/$kernel_file"; - $kernel_mtime = (stat("$kernel_root/$kernel_file"))[9]; - } else { - $diff_command .= " /dev/null"; - $kernel_mtime = 0; - } - if ( -e "$package_root/$package_file") { - $diff_command .= " $package_root/$package_file"; - $package_mtime = (stat("$package_root/$package_file"))[9]; - } else { - $diff_command .= " /dev/null"; - $package_mtime = 0; - } - open INPUT, "$diff_command|" or die "Can't execute `$diff_command'"; - if () { - ; - print "--- linux-old/$kernel_file\t".gmtime($kernel_mtime)."\n". - "+++ linux/$kernel_file\t".gmtime($package_mtime)."\n"; - - print while ; - } - close INPUT; -} - -# This generates diffs for kernel file Documentation/Configure.help. This -# file contains the help texts that can be displayed during `make *config' -# for the kernel. -# The new texts are put at the end of the file, or just before the -# lm_sensors texts. -# Of course, care is taken old lines are removed. -# $_[0]: i2c package root (like /tmp/i2c) -# $_[1]: Linux kernel tree (like /usr/src/linux) -sub gen_Documentation_Configure_help -{ - my ($package_root,$kernel_root) = @_; - my $kernel_file = "Documentation/Configure.help"; - my $package_file = $temp; - - open INPUT,"$kernel_root/$kernel_file" - or die "Can't open `$kernel_root/$kernel_file'"; - open OUTPUT,">$package_root/$package_file" - or die "Can't open $package_root/$package_file"; - MAIN: while() { - if (m@I2C mainboard interfaces@ or - m@Acer Labs ALI 1535@ or - m@Acer Labs ALI 1533 and 1543C@ or - m@Acer Labs ALI 1563@ or - m@AMD 756/766/768/8111@ or - m@SMBus multiplexing on the Tyan S4882@ or - m@AMD 8111 SMBus 2.0@ or - m@Apple Hydra Mac I/O@ or - m@Intel I801@ or - m@Intel I810/I815 based Mainboard@ or - m@Intel 82371AB PIIX4\(E\)@ or - m@Nvidia Nforce2@ or - m@Silicon Integrated Systems Corp. SiS5595 based Mainboard@ or - m@VIA Technologies, Inc. VT82C586B@ or - m@VIA Technologies, Inc. VT82C596, 596B, 686A/B, 8233@ or - m@3DFX Banshee / Voodoo3@ or - m@DEC Tsunami 21272@ or - m@Pseudo ISA adapter \(for hardware sensors modules\)@ or - m@Analog Devices ADM1021 and compatibles@ or - m@Analog Devices ADM1024@ or - m@Analog Devices ADM1025@ or - m@Analog Devices ADM1026@ or - m@Analog Devices ADM1030, ADM1031@ or - m@Analog Devices ADM9240 and compatibles@ or - m@Asus ASB100@ or - m@Dallas DS1621 and DS1625@ or - m@Fintek F71805F@ or - m@Fujitsu-Siemens Hermes@ or - m@Fujitsu-Siemens Poseidon@ or - m@Fujitsu-Siemens Scylla@ or - m@Genesys Logic GL518SM@ or - m@Genesys Logic GL520SM@ or - m@HP Maxilife@ or - m@Intel Xeon Thermal Sensor@ or - m@ITE 8705, 8712, Sis950@ or - m@Maxim MAX1619@ or - m@Maxim MAX6650, MAX6651@ or - m@Myson MTP008@ or - m@National Semiconductor LM63@ or - m@National Semiconductor LM75 and compatibles@ or - m@National Semiconductor LM78@ or - m@National Semiconductor LM80@ or - m@National Semiconductor LM83@ or - m@National Semiconductor LM85@ or - m@National Semiconductor LM87@ or - m@National Semiconductor LM90@ or - m@National Semiconductor LM92@ or - m@National Semiconductor LM93@ or - m@National Semiconductor PC8736x@ or - m@Silicon Integrated Systems Corp. SiS5595 Sensor@ or - m@Texas Instruments THMC50 / Analog Devices ADM1022@ or - m@Via VT82C686A/B@ or - m@Winbond W83781D, W83782D, W83783S@ or - m@Winbond W83792D@ or - m@Winbond W83627HF, W83627THF@ or - m@Winbond W83627EHF/EHG@ or - m@Winbond W83L785TS-S@ or - m@EEprom \(DIMM\) reader@) { - $_ = ; - $_ = ; - $_ = while not m@^\S@ and not eof(INPUT); - redo MAIN; - } - if (eof(INPUT)) { - print OUTPUT <<'EOF' -I2C mainboard interfaces -CONFIG_I2C_MAINBOARD - Many modern mainboards have some kind of I2C interface integrated. This - is often in the form of a SMBus, or System Management Bus, which is - basically the same as I2C but which uses only a subset of the I2C - protocol. - - You will also want the latest user-space utilities: you can find them - in the lm_sensors package, which you can download at - http://www.lm-sensors.org/ - -Acer Labs ALI 1535 -CONFIG_I2C_ALI1535 - If you say yes to this option, support will be included for the Acer - Labs ALI 1535 mainboard I2C interface. This can also be - built as a module. - -Acer Labs ALI 1533 and 1543C -CONFIG_I2C_ALI15X3 - If you say yes to this option, support will be included for the Acer - Labs ALI 1533 and 1543C mainboard I2C interfaces. This can also be - built as a module which can be inserted and removed while the kernel - is running. - -Acer Labs ALI 1563 -CONFIG_I2C_ALI1563 - If you say yes to this option, support will be included for the Acer - Labs ALI M1563 mainboard SMBus interface. This can also be built as a - module. - -AMD 756/766/768/8111 and nVidia nForce -CONFIG_I2C_AMD756 - If you say yes to this option, support will be included for the AMD - 756/766/768/8111 and nVidia nForce mainboard I2C interfaces. This can - also be built as a module which can be inserted and removed while the - kernel is running. - -SMBus multiplexing on the Tyan S4882 -CONFIG_I2C_AMD756_S4882 - Enabling this option will add specific SMBus support for the Tyan - S4882 motherboard. On this 4-CPU board, the SMBus is multiplexed - over 8 different channels, where the various memory module EEPROMs - and temperature sensors live. Saying yes here will give you access - to these in addition to the trunk. - -AMD 8111 SMBus 2.0 -CONFIG_I2C_AMD8111 - If you say yes to this option, support will be included for the AMD - 8111 mainboard SMBus 2.0 interface. This can also be - built as a module which can be inserted and removed while the kernel - is running. - -Apple Hydra Mac I/O -CONFIG_I2C_HYDRA - If you say yes to this option, support will be included for the - Hydra mainboard I2C interface. This can also be built as a module - which can be inserted and removed while the kernel is running. - -Intel I801 -CONFIG_I2C_I801 - If you say yes to this option, support will be included for the - Intel I801 mainboard I2C interfaces. "I810" mainboard sensor chips are - generally located on the I801's I2C bus. This can also be - built as a module which can be inserted and removed while the kernel - is running. - -Intel I810/I815 based Mainboard -CONFIG_I2C_I810 - If you say yes to this option, support will be included for the - Intel I810/I810E/I815/I845G mainboard I2C interfaces. The I2C busses - of these chips are generally used only for video devices. For "810" - mainboard sensor chips, use the I801 I2C driver instead. - - This can also be built as a module which can be inserted and removed - while the kernel is running. - -Intel 82371AB PIIX4(E), ServerWorks OSB4, CSB5, CSB6, HT-1000 -CONFIG_I2C_PIIX4 - If you say yes to this option, support will be included for the - Intel PIIX4, PIIX4E, 443MX, Serverworks OSB4, CSB5, CSB6 and - HT-1000, ATI IXP200, IXP300, IXP400, SB600, SB700 and SB800, and - SMSC Victory66 mainboard SMBus interfaces. - - This can also be built as a module which can be inserted and removed - while the kernel is running. - -Nvidia Nforce2/3/4 based Mainboard -CONFIG_I2C_NFORCE2 - If you say yes to this option, support will be included for the - Nvidia Nforce2, Nforce3 and Nforce4 families of mainboard SMBus - interfaces. - - This can also be built as a module which can be inserted and removed - while the kernel is running. - -Silicon Integrated Systems Corp. SiS5595 based Mainboard -CONFIG_I2C_SIS5595 - If you say yes to this option, support will be included for the - SiS5595 mainboard I2C interfaces. For integrated sensors on the - Sis5595, use CONFIG_SENSORS_SIS5595. This can also be - built as a module which can be inserted and removed while the kernel - is running. - -Silicon Integrated Systems Corp. SiS630/730 based Mainboard -CONFIG_I2C_SIS630 - If you say yes to this option, support will be included for the SiS 630 - and 730 mainboard I2C interfaces. This can also be built as a module - which can be inserted and removed while the kernel is running. - -Silicon Integrated Systems Corp. SiS645/961,645DX/961,735 based Mainboard -CONFIG_I2C_SIS645 - If you say yes to this option, support will be included for the SiS 645/961, - 645DX/961 and 735 mainboard I2C interfaces. This can also be built as a module - which can be inserted and removed while the kernel is running. - -VIA Technologies, Inc. VT82C586B -CONFIG_I2C_VIA - If you say yes to this option, support will be included for the VIA - Technologies I2C adapter found on some motherboards. This can also - be built as a module which can be inserted and removed while the - kernel is running. - -VIA Technologies, Inc. VT82C596/82C686/82xx and CX700/VX800/VX820 -CONFIG_I2C_VIAPRO - If you say yes to this option, support will be included for the VIA - Technologies I2C adapter on these chips. For integrated sensors on the - Via 686A/B, use CONFIG_SENSORS_VIA686A. This can also be - be built as a module which can be inserted and removed while the - kernel is running. - -3DFX Banshee / Voodoo3 -CONFIG_I2C_VOODOO3 - If you say yes to this option, support will be included for the - 3DFX Banshee and Voodoo3 I2C interfaces. The I2C busses on the these - chips are generally used only for video devices. - This can also be - built as a module which can be inserted and removed while the kernel - is running. - -DEC Tsunami 21272 -CONFIG_I2C_TSUNAMI - If you say yes to this option, support will be included for the DEC - Tsunami chipset I2C adapter. Requires the Alpha architecture; - do not enable otherwise. This can also be built as a module which - can be inserted and removed while the kernel is running. - -Pseudo ISA adapter (for hardware sensors modules) -CONFIG_I2C_ISA - This provides support for accessing some hardware sensor chips over - the ISA bus rather than the I2C or SMBus. If you want to do this, - say yes here. This feature can also be built as a module which can - be inserted and removed while the kernel is running. - - You will also need the latest user-space utilities: you can find them - in the lm_sensors package, which you can download at - http://www.lm-sensors.org/ - -Analog Devices ADM1021 and compatibles -CONFIG_SENSORS_ADM1021 - If you say yes here you get support for Analog Devices ADM1021 - and ADM1023 sensor chips and clones: Maxim MAX1617 and MAX1617A, - Genesys Logic GL523SM, National Semi LM84, TI THMC10 and Onsemi - MC1066. This can also be built as a module which can be inserted - and removed while the kernel is running. - - You will also need the latest user-space utilities: you can find them - in the lm_sensors package, which you can download at - http://www.lm-sensors.org/ - -Analog Devices ADM1024 -CONFIG_SENSORS_ADM1024 - If you say yes here you get support for Analog Devices ADM1024 sensor - chips. This can also be built as a module. - - You will also need the latest user-space utilities: you can find them - in the lm_sensors package, which you can download at - http://www.lm-sensors.org/ - -Analog Devices ADM1025 -CONFIG_SENSORS_ADM1025 - If you say yes here you get support for Analog Devices ADM1025 sensor - chips. This can also be built as a module which can be inserted and - removed while the kernel is running. - - You will also need the latest user-space utilities: you can find them - in the lm_sensors package, which you can download at - http://www.lm-sensors.org/ - -Analog Devices ADM1026 -CONFIG_SENSORS_ADM1026 - If you say yes here you get support for Analog Devices ADM1026 sensor - chips. This can also be built as a module which can be inserted and - removed while the kernel is running. - - You will also need the latest user-space utilities: you can find them - in the lm_sensors package, which you can download at - http://www.lm-sensors.org/ - -Analog Devices ADM1030, ADM1031 -CONFIG_SENSORS_ADM1031 - If you say yes here you get support for Analog Devices ADM1030 and - ADM1031 sensor chips. This can also be built as a module which can - be inserted and removed while the kernel is running. - - You will also need the latest user-space utilities: you can find them - in the lm_sensors package, which you can download at - http://www.lm-sensors.org/ - -Analog Devices ADM9240 and compatibles -CONFIG_SENSORS_ADM9240 - If you say yes here you get support for Analog Devices ADM9240 - sensor chips and clones: the Dallas Semiconductor DS1780 and - the National Semiconductor LM81. This can also be built as a - module which can be inserted and removed while the kernel is - running. - - You will also need the latest user-space utilities: you can find them - in the lm_sensors package, which you can download at - http://www.lm-sensors.org/ - -Asus ASB100 -CONFIG_SENSORS_ASB100 - If you say yes here you get support for the Asus ASB100 (aka - "Bach") sensor chip. This can also be built as a module. - - You will also need the latest user-space utilities: you can find - them in the lm_sensors package, which you can download at - http://www.lm-sensors.org/ - -Dallas DS1621 and DS1625 -CONFIG_SENSORS_DS1621 - If you say yes here you get support for the Dallas DS1621 and DS1625x - sensor chips. This can also be built as a module. - - You will also need the latest user-space utilities: you can find them - in the lm_sensors package, which you can download at - http://www.lm-sensors.org/ - -Fintek F71805F -CONFIG_SENSORS_F71805F - If you say yes here you get support for the hardware monitoring - features of the Fintek F71805F/FG Super-I/O chip. This can also be - built as a module. - - You will also need the latest user-space utilities: you can find them - in the lm_sensors package, which you can download at - http://www.lm-sensors.org/ - -Fujitsu-Siemens Hermes -CONFIG_SENSORS_FSCHER - If you say yes here you get support for the Fujitsu-Siemens Hermes - sensor chip. This can also be built as a module. - - You will also need the latest user-space utilities: you can find them - in the lm_sensors package, which you can download at - http://www.lm-sensors.org/ - -Fujitsu-Siemens Poseidon -CONFIG_SENSORS_FSCPOS - If you say yes here you get support for the Fujitsu-Siemens Poseidon - sensor chip. This can also be built as a module. - - You will also need the latest user-space utilities: you can find them - in the lm_sensors package, which you can download at - http://www.lm-sensors.org/ - -Fujitsu-Siemens Scylla -CONFIG_SENSORS_FSCSCY - If you say yes here you get support for the Fujitsu-Siemens Scylla - sensor chip. This can also be built as a module. This driver may/should - also work with the following Fujitsu-Siemens chips: "Poseidon", - "Poseidon II" and "Hydra". You may have to force loading of the module - for motherboards in these cases. Be careful - those motherboards have - not been tested with this driver. - - You will also need the latest user-space utilities: you can find them - in the lm_sensors package, which you can download at - http://www.lm-sensors.org/ - -Genesys Logic GL518SM -CONFIG_SENSORS_GL518SM - If you say yes here you get support for Genesys Logic GL518SM sensor - chips. This can also be built as a module which can be inserted and - removed while the kernel is running. - - You will also need the latest user-space utilities: you can find them - in the lm_sensors package, which you can download at - http://www.lm-sensors.org/ - -Genesys Logic GL520SM -CONFIG_SENSORS_GL520SM - If you say yes here you get support for Genesys Logic GL518SM sensor - chips. This can also be built as a module which can be inserted and - removed while the kernel is running. - - You will also need the latest user-space utilities: you can find them - in the lm_sensors package, which you can download at - http://www.lm-sensors.org/ - -HP Maxilife -CONFIG_SENSORS_MAXILIFE - If you say yes here you get support for the HP Maxilife - sensor chip. This can also be built as a module. - - You will also need the latest user-space utilities: you can find them - in the lm_sensors package, which you can download at - http://www.lm-sensors.org/ - -Intel Xeon Thermal Sensor -CONFIG_SENSORS_XEONTEMP - If you say yes here you get support for the Intel Xeon processor - built-in thermal sensor. This can also be built as a module which - can be inserted and removed while the kernel is running. - - You will also need the latest user-space utilities: you can find them - in the lm_sensors package, which you can download at - http://www.lm-sensors.org/ - -ITE 8705, 8712, Sis950 -CONFIG_SENSORS_IT87 - If you say yes here you get support for the ITE 8705 and 8712 and - SiS950 sensor chips. This can also be built as a module. - - You will also need the latest user-space utilities: you can find them - in the lm_sensors package, which you can download at - http://www.lm-sensors.org/ - -Maxim MAX1619 -CONFIG_SENSORS_MAX1619 - If you say yes here you get support for the Maxim MAX1619 sensor - chips. This can also be built as a module. - - You will also need the latest user-space utilities: you can find them - in the lm_sensors package, which you can download at - http://www.lm-sensors.org/ - -Maxim MAX6650, MAX6651 -CONFIG_SENSORS_MAX6650 - If you say yes here you get support for the Maxim MAX6650 and - MAX6651 sensor chips. This can also be built as a module. - - You will also need the latest user-space utilities: you can find them - in the lm_sensors package, which you can download at - http://www.lm-sensors.org/ - -Myson MTP008 -CONFIG_SENSORS_MTP008 - If you say yes here you get support for the Myson MTP008 - sensor chip. This can also be built as a module. - - You will also need the latest user-space utilities: you can find them - in the lm_sensors package, which you can download at - http://www.lm-sensors.org/ - -National Semiconductor LM63 -CONFIG_SENSORS_LM63 - If you say yes here you get support for National Semiconductor LM63 - sensor chips. This can also be built as a module which can be inserted - and removed while the kernel is running. - - You will also need the latest user-space utilities: you can find them - in the lm_sensors package, which you can download at - http://www.lm-sensors.org/ - -National Semiconductor LM75 and compatibles -CONFIG_SENSORS_LM75 - If you say yes here you get support for National Semiconductor LM75 - sensor chips and clones: Dallas Semiconductor DS75 and DS1775 (in - 9-bit precision mode), and TelCom (now Microchip) TCN75. This can - also be built as a module which can be inserted and removed while - the kernel is running. - - You will also need the latest user-space utilities: you can find them - in the lm_sensors package, which you can download at - http://www.lm-sensors.org/ - -National Semiconductor LM78 -CONFIG_SENSORS_LM78 - If you say yes here you get support for National Semiconductor LM78 - sensor chips family: the LM78-J and LM79. Many clone chips will - also work at least somewhat with this driver. This can also be built - as a module which can be inserted and removed while the kernel is - running. - - You will also need the latest user-space utilities: you can find them - in the lm_sensors package, which you can download at - http://www.lm-sensors.org/ - -National Semiconductor LM80 -CONFIG_SENSORS_LM80 - If you say yes here you get support for National Semiconductor LM80 - sensor chips. This can also be built as a module which can be - inserted and removed while the kernel is running. - - You will also need the latest user-space utilities: you can find them - in the lm_sensors package, which you can download at - http://www.lm-sensors.org/ - -National Semiconductor LM83 and compatibles -CONFIG_SENSORS_LM83 - If you say yes here you get support for the National Semiconductor - LM82 and LM83 sensor chips. This can also be built as a module. - - You will also need the latest user-space utilities: you can find - them in the lm_sensors package, which you can download at - http://www.lm-sensors.org/ - -National Semiconductor LM85 -CONFIG_SENSORS_LM85 - If you say yes here you get support for National Semiconductor LM85 - sensor chips and compatibles. Compatible chips include the Analog - Devices ADM1027 and ADT7463 and SMSC EMC6D100 and EMC6D101. This - can also be built as a module which can be inserted and removed - while the kernel is running. - - You will also need the latest user-space utilities: you can find them - in the lm_sensors package, which you can download at - http://www.lm-sensors.org/ - -National Semiconductor LM87 -CONFIG_SENSORS_LM87 - If you say yes here you get support for National Semiconductor LM87 - sensor chips. This can also be built as a module which can be - inserted and removed while the kernel is running. - - You will also need the latest user-space utilities: you can find them - in the lm_sensors package, which you can download at - http://www.lm-sensors.org/ - -National Semiconductor LM90 -CONFIG_SENSORS_LM90 - If you say yes here you get support for the National Semiconductor - LM90, LM89 and LM99, Analog Devices ADM1032 and ADT7461, and Maxim - MAX6657 and MAX6658 sensor chips. This can also be built as a module. - - You will also need the latest user-space utilities: you can find - them in the lm_sensors package, which you can download at - http://www.lm-sensors.org/ - -National Semiconductor LM92 -CONFIG_SENSORS_LM92 - If you say yes here you get support for National Semiconductor LM92 - sensor chips. This can also be built as a module which can be - inserted and removed while the kernel is running. - - You will also need the latest user-space utilities: you can find them - in the lm_sensors package, which you can download at - http://www.lm-sensors.org/ - -National Semiconductor LM93 -CONFIG_SENSORS_LM93 - If you say yes here you get support for National Semiconductor LM93 - sensor chips. This can also be built as a module which can be inserted - and removed while the kernel is running. - - You will also need the latest user-space utilities: you can find them - in the lm_sensors package, which you can download at - http://www.lm-sensors.org/ - -National Semiconductor PC8736x Sensors -CONFIG_SENSORS_PC87360 - If you say yes here you get support for the integrated hardware - monitoring in the National Semicoductor PC87360, PC87363, PC87364, - PC87365 and PC87366 Super I/O chips. This can also be built as a - module which can be inserted and removed while the kernel is - running. - - You will also need the latest user-space utilities: you can find them - in the lm_sensors package, which you can download at - http://www.lm-sensors.org/ - -Philips PCF8574 -CONFIG_SENSORS_PCF8574 - If you say yes here you get support for the Philips PCF8574 - I2C 8-bit Parallel I/O device. - This can also be built as a module which can be - inserted and removed while the kernel is running. - - You will also need the latest user-space utilities: you can find them - in the lm_sensors package, which you can download at - http://www.lm-sensors.org/ - -Philips PCF8591 -CONFIG_SENSORS_PCF8591 - If you say yes here you get support for the Philips PCF8591 - I2C Quad D/A + Single A/D I/O device. - This can also be built as a module which can be - inserted and removed while the kernel is running. - - You will also need the latest user-space utilities: you can find them - in the lm_sensors package, which you can download at - http://www.lm-sensors.org/ - -Silicon Integrated Systems Corp. SiS5595 Sensor -CONFIG_SENSORS_SIS5595 - If you say yes here you get support for the integrated sensors in - SiS5595 South Bridges. This can also be built as a module - which can be inserted and removed while the kernel is running. - - You will also need the latest user-space utilities: you can find them - in the lm_sensors package, which you can download at - http://www.lm-sensors.org/ - -SMSC47M1xx Super I/O Fan Support -CONFIG_SENSORS_SMSC47M1 - If you say yes here you get support for the integrated fan - monitoring and control in the SMSC 47M1xx Super I/O chips. - This can also be built as a module - which can be inserted and removed while the kernel is running. - - You will also need the latest user-space utilities: you can find them - in the lm_sensors package, which you can download at - http://www.lm-sensors.org/ - -Texas Instruments THMC50 / Analog Devices ADM1022 -CONFIG_SENSORS_THMC50 - If you say yes here you get support for Texas Instruments THMC50 - sensor chips and clones: the Analog Devices ADM1022. - This can also be built as a module which - can be inserted and removed while the kernel is running. - - You will also need the latest user-space utilities: you can find them - in the lm_sensors package, which you can download at - http://www.lm-sensors.org/ - -Via VT82C686A/B -CONFIG_SENSORS_VIA686A - If you say yes here you get support for the integrated sensors in - Via 686A/B South Bridges. This can also be built as a module - which can be inserted and removed while the kernel is running. - - You will also need the latest user-space utilities: you can find them - in the lm_sensors package, which you can download at - http://www.lm-sensors.org/ - -Via VT1211 Sensors -CONFIG_SENSORS_VT1211 - If you say yes here you get support for the integrated sensors in - the Via VT1211 Super I/O device. This can also be built as a module - which can be inserted and removed while the kernel is running. - - You will also need the latest user-space utilities: you can find them - in the lm_sensors package, which you can download at - http://www.lm-sensors.org/ - -Via VT8231 Sensors -CONFIG_SENSORS_VT8231 - If you say yes here you get support for the integrated sensors in - the Via VT8231 device. This can also be built as a module - which can be inserted and removed while the kernel is running. - - You will also need the latest user-space utilities: you can find them - in the lm_sensors package, which you can download at - http://www.lm-sensors.org/ - -Winbond W83781D, W83782D, W83783S, W83627HF, AS99127F -CONFIG_SENSORS_W83781D - If you say yes here you get support for the Winbond W8378x series - of sensor chips: the W83781D, W83782D, W83783S and W83627HF, - and the similar Asus AS99127F. This can also be built as a module - which can be inserted and removed while the kernel is running. - - You will also need the latest user-space utilities: you can find them - in the lm_sensors package, which you can download at - http://www.lm-sensors.org/ - -Winbond W83792D -CONFIG_SENSORS_W83792D - If you say yes here you get support for the Winbond W83792D - sensor chips. - - You will also need the latest user-space utilities: you can find them - in the lm_sensors package, which you can download at - http://www.lm-sensors.org/ - -Winbond W83627HF, W83627THF, W83637HF, W83687THF, W83697HF -CONFIG_SENSORS_W83627HF - If you say yes here you get support for the Winbond W836x7 series - of sensor chips: the W83627HF, W83627THF, W83637HF, W83687THF and - W83697HF. This can also be built as a module which can be inserted - and removed while the kernel is running. - - You will also need the latest user-space utilities: you can find - them in the lm_sensors package, which you can download at - http://www.lm-sensors.org/ - -Winbond W83627EHF/EHG -CONFIG_SENSORS_W83627EHF - If you say yes here you get support for the Winbond W83627EHF/EHG - sensor chips. This can also be built as a module which can be - inserted and removed while the kernel is running. - - You will also need the latest user-space utilities: you can find - them in the lm_sensors package, which you can download at - http://www.lm-sensors.org/ - -Winbond W83L785TS-S -CONFIG_SENSORS_W83L785TS - If you say yes here you get support for the Winbond W83L785TS-S - sensor chip. This can also be built as a module. - - You will also need the latest user-space utilities: you can find - them in the lm_sensors package, which you can download at - http://www.lm-sensors.org/ - -EEprom (DIMM) reader -CONFIG_SENSORS_EEPROM - If you say yes here you get read-only access to the EEPROM data - available on modern memory DIMMs, and which could theoretically - also be available on other devices. This can also be built as a - module which can be inserted and removed while the kernel is - running. - - You will also need the latest user-space utilities: you can find them - in the lm_sensors package, which you can download at - http://www.lm-sensors.org/ - -EOF - } - print OUTPUT; - } - close INPUT; - close OUTPUT; - print_diff $package_root,$kernel_root,$kernel_file,$package_file; -} - - -# This generates diffs for the main Linux Makefile. -# Three lines which add drivers/sensors/sensors.a to the DRIVERS list are -# put just before the place where the architecture Makefile is included. -# Of course, care is taken old lines are removed. -# $_[0]: sensors package root (like /tmp/sensors) -# $_[1]: Linux kernel tree (like /usr/src/linux) -sub gen_Makefile -{ - my ($package_root,$kernel_root) = @_; - my $kernel_file = "Makefile"; - my $package_file = $temp; - my $type = 0; - my $pr1 = 0; - - open INPUT,"$kernel_root/$kernel_file" - or die "Can't open `$kernel_root/$kernel_file'"; - open OUTPUT,">$package_root/$package_file" - or die "Can't open $package_root/$package_file"; - `grep -q -s 'i2c\.o' "$kernel_root/$kernel_file"`; - $type = 2 if ! $?; - MAIN: while() { - $type = 1 if !$type and (m@^DRIVERS-\$@); - if (m@DRIVERS-\$\(CONFIG_SENSORS\)@) { - $_ = ; - redo MAIN; - } elsif (m@CONFIG_SENSORS@) { - $_ = while not m@endif@; - $_ = ; - $_ = if m@^$@; - redo MAIN; - } - if ($type == 1 and m@^DRIVERS \+= \$\(DRIVERS-y\)@) { - print OUTPUT <<'EOF'; -DRIVERS-$(CONFIG_SENSORS) += drivers/sensors/sensors.a -EOF - $pr1 = 1; - } - if ($type == 2 and m@^DRIVERS .*= \$\(DRIVERS-y\)@) { - print OUTPUT <<'EOF'; -DRIVERS-$(CONFIG_SENSORS) += drivers/sensors/sensor.o -EOF - $pr1 = 1; - } - if ($type == 0 and m@include arch/\$\(ARCH\)/Makefile@) { - print OUTPUT <<'EOF'; -ifeq ($(CONFIG_SENSORS),y) -DRIVERS := $(DRIVERS) drivers/sensors/sensors.a -endif - -EOF - $pr1 = 1; - } - print OUTPUT; - } - close INPUT; - close OUTPUT; - die "Automatic patch generation for main `Makefile' failed.\n". - "See our home page http://www.lm-sensors.org/ for assistance!" if $pr1 == 0; - print_diff $package_root,$kernel_root,$kernel_file,$package_file; -} - -# This generates diffs for drivers/Makefile -# First, `sensors' is added to the ALL_SUB_DIRS list. Next, a couple of lines -# to add sensors to the SUB_DIRS and/or MOD_SUB_DIRS lists is put right before -# Rules.make is included. -# Of course, care is taken old lines are removed. -# $_[0]: sensors package root (like /tmp/sensors) -# $_[1]: Linux kernel tree (like /usr/src/linux) -sub gen_drivers_Makefile -{ - my ($package_root,$kernel_root) = @_; - my $kernel_file = "drivers/Makefile"; - my $package_file = $temp; - my $sensors_present; - my $pr1 = 0; - my $pr2 = 0; - my $new_style = 0; - - open INPUT,"$kernel_root/$kernel_file" - or die "Can't open `$kernel_root/$kernel_file'"; - open OUTPUT,">$package_root/$package_file" - or die "Can't open $package_root/$package_file"; - MAIN: while() { - if (m@^mod-subdirs\s*:=@) { - $new_style = 1; - } - if ((! $new_style and m@^ALL_SUB_DIRS\s*:=@) or m@^mod-subdirs\s*:=@) { - $pr1 = 1; - $sensors_present = 0; - while (m@\\$@) { - $sensors_present = 1 if m@sensors@; - print OUTPUT; - $_ = ; - } - $sensors_present = 1 if m@sensors@; - s@$@ sensors@ if (not $sensors_present); - print OUTPUT; - $_ = ; - redo MAIN; - } - if (m@^ifeq.*CONFIG_SENSORS@) { - $_ = while not m@^endif@; - $_ = ; - $_ = if m@^$@; - redo MAIN; - } - if (m@^subdir.*CONFIG_SENSORS@) { - $_ = ; - redo MAIN; - } - if (!$pr2 and (m@^include \$\(TOPDIR\)/Rules.make$@ or m@^subdir-\$\(CONFIG_ACPI@)) { - $pr2 = 1; - if ($new_style) { - print OUTPUT <<'EOF'; -subdir-$(CONFIG_SENSORS) += sensors -EOF - } else { - print OUTPUT <<'EOF'; -ifeq ($(CONFIG_SENSORS),y) -SUB_DIRS += sensors -MOD_SUB_DIRS += sensors -else - ifeq ($(CONFIG_SENSORS),m) - MOD_SUB_DIRS += sensors - endif -endif - -EOF - } - } - print OUTPUT; - } - close INPUT; - close OUTPUT; - die "Automatic patch generation for `drivers/Makefile' failed.\n". - "See our home page http://www.lm-sensors.org/ for assistance!" if $pr1 == 0 or $pr2 == 0; - print_diff $package_root,$kernel_root,$kernel_file,$package_file; -} - -# This generates diffs for drivers/char/Config.in -# It adds a line just before CONFIG_APM or main_menu_option lines to include -# the sensors Config.in. -# Of course, care is taken old lines are removed. -# $_[0]: sensors package root (like /tmp/sensors) -# $_[1]: Linux kernel tree (like /usr/src/linux) -sub gen_drivers_char_Config_in -{ - my ($package_root,$kernel_root) = @_; - my $kernel_file = "drivers/char/Config.in"; - my $package_file = $temp; - my $pr1 = 0; - - open INPUT,"$kernel_root/$kernel_file" - or die "Can't open `$kernel_root/$kernel_file'"; - open OUTPUT,">$package_root/$package_file" - or die "Can't open $package_root/$package_file"; - MAIN: while() { - if (m@source drivers/i2c/Config.in@) { - $pr1 = 1; - print OUTPUT; - print OUTPUT "\nsource drivers/sensors/Config.in\n"; - $_ = ; - redo MAIN; - } - if (m@sensors@) { - $_ = ; - $_ = if m@^$@; - redo MAIN; - } - print OUTPUT; - } - close INPUT; - close OUTPUT; - die "Automatic patch generation for `drivers/char/Config.in' failed.\n". - "See our home page http://www.lm-sensors.org/ for assistance!" if $pr1 == 0; - print_diff $package_root,$kernel_root,$kernel_file,$package_file; -} - -# This generates diffs for drivers/i2c/Config.in -# Several adapter drivers that are included in the lm_sensors package are -# added at the first and onlu sensors marker. -# Of course, care is taken old lines are removed. -# $_[0]: sensors package root (like /tmp/sensors) -# $_[1]: Linux kernel tree (like /usr/src/linux) -sub gen_drivers_i2c_Config_in -{ - my ($package_root,$kernel_root) = @_; - my $kernel_file = "drivers/i2c/Config.in"; - my $package_file = "$temp"; - my $pr1 = 0; - - open INPUT,"$kernel_root/$kernel_file" - or die "Can't open `$kernel_root/$kernel_file'"; - open OUTPUT,">$package_root/$package_file" - or die "Can't open $package_root/$package_file"; - while() { - if (m@sensors code starts here@) { - $pr1++; - print OUTPUT; - while () { - last if m@sensors code ends here@; - } - print OUTPUT << 'EOF'; - bool 'I2C mainboard interfaces' CONFIG_I2C_MAINBOARD - if [ "$CONFIG_I2C_MAINBOARD" = "y" ]; then - dep_tristate ' Acer Labs ALI 1535' CONFIG_I2C_ALI1535 $CONFIG_I2C - dep_tristate ' Acer Labs ALI 1533 and 1543C' CONFIG_I2C_ALI15X3 $CONFIG_I2C - dep_tristate ' Acer Labs ALI 1563' CONFIG_I2C_ALI1563 $CONFIG_I2C - dep_tristate ' Apple Hydra Mac I/O' CONFIG_I2C_HYDRA $CONFIG_I2C_ALGOBIT - dep_tristate ' AMD 756/766/768/8111 and nVidia nForce' CONFIG_I2C_AMD756 $CONFIG_I2C - if [ "$CONFIG_I2C_AMD756" != "n" ]; then - dep_tristate ' SMBus multiplexing on the Tyan S4882' CONFIG_I2C_AMD756_S4882 $CONFIG_I2C_AMD756 - fi - dep_tristate ' AMD 8111 SMBus 2.0' CONFIG_I2C_AMD8111 $CONFIG_I2C - if [ "$CONFIG_ALPHA" = "y" ]; then - dep_tristate ' DEC Tsunami I2C interface' CONFIG_I2C_TSUNAMI $CONFIG_I2C_ALGOBIT - fi - dep_tristate ' Intel 82801 (ICH) and ESB' CONFIG_I2C_I801 $CONFIG_I2C - dep_tristate ' Intel i810AA/AB/E and i815' CONFIG_I2C_I810 $CONFIG_I2C_ALGOBIT - dep_tristate ' Intel 82371AB PIIX4(E), 443MX, ServerWorks OSB4/CSB5, SMSC Victory66' CONFIG_I2C_PIIX4 $CONFIG_I2C - dep_tristate ' Nvidia Nforce2/3/4' CONFIG_I2C_NFORCE2 $CONFIG_I2C - dep_tristate ' SiS 5595' CONFIG_I2C_SIS5595 $CONFIG_I2C - dep_tristate ' SiS 630/730' CONFIG_I2C_SIS630 $CONFIG_I2C - dep_tristate ' SiS 645/961,645DX/961,735' CONFIG_I2C_SIS645 $CONFIG_I2C $CONFIG_HOTPLUG - dep_tristate ' Savage 4' CONFIG_I2C_SAVAGE4 $CONFIG_I2C_ALGOBIT - dep_tristate ' VIA Technologies, Inc. VT82C586B' CONFIG_I2C_VIA $CONFIG_I2C_ALGOBIT - dep_tristate ' VIA Technologies, Inc. VT82C596/82C686/82xx and CX700/VX800/VX820' CONFIG_I2C_VIAPRO $CONFIG_I2C - dep_tristate ' Voodoo3 I2C interface' CONFIG_I2C_VOODOO3 $CONFIG_I2C_ALGOBIT - dep_tristate ' Pseudo ISA adapter (for some hardware sensors)' CONFIG_I2C_ISA $CONFIG_I2C - fi - -EOF - } - print OUTPUT; - } - close INPUT; - close OUTPUT; - die "Automatic patch generation for `drivers/i2c/Config.in' failed.\n". - "See our home page http://www.lm-sensors.org/ for assistance!" if $pr1 != 1; - print_diff $package_root,$kernel_root,$kernel_file,$package_file; -} - -sub gen_drivers_sensors_Makefile -{ - my ($package_root,$kernel_root) = @_; - my $kernel_file = "drivers/sensors/Makefile"; - my $package_file = $temp; - - open OUTPUT,">$package_root/$package_file" - or die "Can't open $package_root/$package_file"; - print OUTPUT <<'EOF'; -# -# Makefile for the kernel hardware sensors drivers. -# - -MOD_LIST_NAME := SENSORS_MODULES -O_TARGET := sensor.o - -obj-$(CONFIG_SENSORS_ADM1021) += adm1021.o -obj-$(CONFIG_SENSORS_ADM1024) += adm1024.o -obj-$(CONFIG_SENSORS_ADM1025) += adm1025.o -obj-$(CONFIG_SENSORS_ADM1026) += adm1026.o -obj-$(CONFIG_SENSORS_ADM1031) += adm1031.o -obj-$(CONFIG_SENSORS_ADM9240) += adm9240.o -obj-$(CONFIG_SENSORS_ASB100) += asb100.o -obj-$(CONFIG_SENSORS_BT869) += bt869.o -obj-$(CONFIG_SENSORS_DDCMON) += ddcmon.o -obj-$(CONFIG_SENSORS_DS1621) += ds1621.o -obj-$(CONFIG_SENSORS_EEPROM) += eeprom.o -obj-$(CONFIG_SENSORS_F71805F) += f71805f.o -obj-$(CONFIG_SENSORS_FSCHER) += fscher.o -obj-$(CONFIG_SENSORS_FSCPOS) += fscpos.o -obj-$(CONFIG_SENSORS_FSCSCY) += fscscy.o -obj-$(CONFIG_SENSORS_GL518SM) += gl518sm.o -obj-$(CONFIG_SENSORS_GL520SM) += gl520sm.o -obj-$(CONFIG_SENSORS_IT87) += it87.o -obj-$(CONFIG_SENSORS_LM63) += lm63.o -obj-$(CONFIG_SENSORS_LM75) += lm75.o -obj-$(CONFIG_SENSORS_LM78) += lm78.o -obj-$(CONFIG_SENSORS_LM80) += lm80.o -obj-$(CONFIG_SENSORS_LM83) += lm83.o -obj-$(CONFIG_SENSORS_LM85) += lm85.o -obj-$(CONFIG_SENSORS_LM87) += lm87.o -obj-$(CONFIG_SENSORS_LM90) += lm90.o -obj-$(CONFIG_SENSORS_LM92) += lm92.o -obj-$(CONFIG_SENSORS_LM93) += lm93.o -obj-$(CONFIG_SENSORS_MAX1619) += max1619.o -obj-$(CONFIG_SENSORS_MAX6650) += max6650.o -obj-$(CONFIG_SENSORS_MAXILIFE) += maxilife.o -obj-$(CONFIG_SENSORS_MTP008) += mtp008.o -obj-$(CONFIG_SENSORS_PC87360) += pc87360.o -obj-$(CONFIG_SENSORS_PCF8574) += pcf8574.o -obj-$(CONFIG_SENSORS_PCF8591) += pcf8591.o -obj-$(CONFIG_SENSORS_SIS5595) += sis5595.o -obj-$(CONFIG_SENSORS_SMSC47M1) += smsc47m1.o -obj-$(CONFIG_SENSORS_THMC50) += thmc50.o -obj-$(CONFIG_SENSORS_VIA686A) += via686a.o -obj-$(CONFIG_SENSORS_VT1211) += vt1211.o -obj-$(CONFIG_SENSORS_VT8231) += vt8231.o -obj-$(CONFIG_SENSORS_W83781D) += w83781d.o -obj-$(CONFIG_SENSORS_W83792D) += w83792d.o -obj-$(CONFIG_SENSORS_W83627HF) += w83627hf.o -obj-$(CONFIG_SENSORS_W83627EHF) += w83627ehf.o -obj-$(CONFIG_SENSORS_W83L785TS) += w83l785ts.o -obj-$(CONFIG_SENSORS_XEONTEMP) += xeontemp.o - -include $(TOPDIR)/Rules.make - -EOF - close OUTPUT; - print_diff $package_root,$kernel_root,$kernel_file,$package_file; -} - -# This generates diffs for drivers/i2c/Makefile. -# Lines to add correct files to M_OBJS and/or L_OBJS are added just before -# Rules.make is included -# Of course, care is taken old lines are removed. -# $_[0]: sensors package root (like /tmp/sensors) -# $_[1]: Linux kernel tree (like /usr/src/linux) -sub gen_drivers_i2c_Makefile -{ - my ($package_root,$kernel_root) = @_; - my $kernel_file = "drivers/i2c/Makefile"; - my $package_file = $temp; - my $pr1 = 0; - - open INPUT,"$kernel_root/$kernel_file" - or die "Can't open `$kernel_root/$kernel_file'"; - open OUTPUT,">$package_root/$package_file" - or die "Can't open $package_root/$package_file"; - while() { - if (m@sensors code starts here@) { - $pr1 ++; - print OUTPUT; - while () { - last if m@sensors code ends here@; - } - print OUTPUT <<'EOF'; -export-objs += i2c-amd756.o - -obj-$(CONFIG_I2C_ALI1535) += i2c-ali1535.o -obj-$(CONFIG_I2C_ALI15X3) += i2c-ali15x3.o -obj-$(CONFIG_I2C_ALI1563) += i2c-ali1563.o -obj-$(CONFIG_I2C_AMD756) += i2c-amd756.o -obj-$(CONFIG_I2C_AMD756_S4882) += i2c-amd756-s4882.o -obj-$(CONFIG_I2C_AMD8111) += i2c-amd8111.o -obj-$(CONFIG_I2C_HYDRA) += i2c-hydra.o -obj-$(CONFIG_I2C_I801) += i2c-i801.o -obj-$(CONFIG_I2C_I810) += i2c-i810.o -obj-$(CONFIG_I2C_ISA) += i2c-isa.o -obj-$(CONFIG_I2C_NFORCE2) += i2c-nforce2.o -obj-$(CONFIG_I2C_PIIX4) += i2c-piix4.o -obj-$(CONFIG_I2C_SIS5595) += i2c-sis5595.o -obj-$(CONFIG_I2C_SIS630) += i2c-sis630.o -obj-$(CONFIG_I2C_SIS645) += i2c-sis645.o -obj-$(CONFIG_I2C_SAVAGE4) += i2c-savage4.o -obj-$(CONFIG_I2C_TSUNAMI) += i2c-tsunami.o -obj-$(CONFIG_I2C_VIA) += i2c-via.o -obj-$(CONFIG_I2C_VIAPRO) += i2c-viapro.o -obj-$(CONFIG_I2C_VOODOO3) += i2c-voodoo3.o -EOF - } - print OUTPUT; - } - close INPUT; - close OUTPUT; - die "Automatic patch generation for `drivers/i2c/Makefile' failed.\n". - "See our home page http://www.lm-sensors.org/ for assistance!" if $pr1 != 1; - print_diff $package_root,$kernel_root,$kernel_file,$package_file; -} - -# Generate the diffs for the list of MAINTAINERS -# $_[0]: i2c package root (like /tmp/i2c) -# $_[1]: Linux kernel tree (like /usr/src/linux) -sub gen_MAINTAINERS -{ - my ($package_root,$kernel_root) = @_; - my $kernel_file = "MAINTAINERS"; - my $package_file = $temp; - my $done = 0; - - open INPUT,"$kernel_root/$kernel_file" - or die "Can't open `$kernel_root/$kernel_file'"; - open OUTPUT,">$package_root/$package_file" - or die "Can't open $package_root/$package_file"; - MAIN: while() { - if (m@SENSORS DRIVERS@) { - $_= while not m@^$@; - $_=; - redo MAIN; - } - if (not $done and (m@SGI VISUAL WORKSTATION 320 AND 540@)) { - print OUTPUT <<'EOF'; -SENSORS DRIVERS -L: lm-sensors@lm-sensors.org -W: http://www.lm-sensors.org/ -S: Maintained - -EOF - $done = 1; - } - print OUTPUT; - } - close INPUT; - close OUTPUT; - die "Automatic patch generation for `MAINTAINERS' failed.\n". - "See our home page http://www.lm-sensors.org/ for assistance!" if $done == 0; - print_diff $package_root,$kernel_root,$kernel_file,$package_file; -} - -# Generate the diffs for dmi_scan.c and i386_ksyms.c -# $_[0]: i2c package root (like /tmp/i2c) -# $_[1]: Linux kernel tree (like /usr/src/linux) -sub gen_dmi_scan -{ - my ($package_root,$kernel_root) = @_; - my $kernel_file = "arch/i386/kernel/dmi_scan.c"; - my $package_file = $temp; - my $done = 0; - - open INPUT,"$kernel_root/$kernel_file" - or die "Can't open `$kernel_root/$kernel_file'"; - open OUTPUT,">$package_root/$package_file" - or die "Can't open $package_root/$package_file"; - MAIN: while() { - if ($done == 0 && m/^\s*int is_sony_vaio_laptop;\s*$/) { - print OUTPUT <<'EOF'; -int is_unsafe_smbus; -EOF - $done++; - } - if ($done == 1 && m/^\s*\* Check for a Sony Vaio system\s*$/) { - print OUTPUT <<'EOF'; - * Don't access SMBus on IBM systems which get corrupted eeproms - */ - -static __init int disable_smbus(struct dmi_blacklist *d) -{ - if (is_unsafe_smbus == 0) { - is_unsafe_smbus = 1; - printk(KERN_INFO "%s machine detected. Disabling SMBus accesses.\n", d->ident); - } - return 0; -} - -/* -EOF - $done++; - } - if ($done == 2 && m/^\s*\{ sony_vaio_laptop, "Sony Vaio", \{ \/\* This is a Sony Vaio laptop \*\/\s*$/) { - print OUTPUT <<'EOF'; - { disable_smbus, "IBM", { - MATCH(DMI_SYS_VENDOR, "IBM"), - NO_MATCH, NO_MATCH, NO_MATCH - } }, -EOF - $done++; - } - print OUTPUT; - } - close INPUT; - close OUTPUT; - die "Automatic patch generation for `$kernel_file' failed.\n". - "See our home page http://www.lm-sensors.org/ for assistance!" if $done != 3; - print_diff $package_root,$kernel_root,$kernel_file,$package_file; - - $kernel_file = "arch/i386/kernel/i386_ksyms.c"; - $done = 0; - - open INPUT,"$kernel_root/$kernel_file" - or die "Can't open `$kernel_root/$kernel_file'"; - open OUTPUT,">$package_root/$package_file" - or die "Can't open $package_root/$package_file"; - MAIN: while() { - if ($done == 0 && m/^\s*extern int is_sony_vaio_laptop;\s*$/) { - print OUTPUT <<'EOF'; -extern int is_unsafe_smbus; -EXPORT_SYMBOL(is_unsafe_smbus); - -EOF - $done++; - } - print OUTPUT; - } - close INPUT; - close OUTPUT; - die "Automatic patch generation for `$kernel_file' failed.\n". - "See our home page http://www.lm-sensors.org/ for assistance!" if $done != 1; - print_diff $package_root,$kernel_root,$kernel_file,$package_file; -} - - -sub usage -{ - print "Usage: $0 package_root kernel_root\n"; - exit 1; -} - -# Main function -sub main -{ - my ($package_root,$kernel_root,%files,%includes,$package_file,$kernel_file); - my ($diff_command,$dummy,$data0,$data1,$sedscript,$version_string); - - # --> Read the command-line - $package_root = $ARGV[0]; - usage() unless defined $package_root; - die "Package root `$package_root' is not found\n" - unless -d "$package_root/mkpatch"; - $kernel_root = $ARGV[1]; - usage() unless defined $kernel_root; - die "Kernel root `$kernel_root' is not found\n" - unless -f "$kernel_root/Rules.make"; - - # --> Read FILES - open INPUT, "$package_root/mkpatch/FILES" - or die "Can't open `$package_root/mkpatch/FILES'"; - while () { - ($data0,$data1) = /(\S+)\s+(\S+)/; - $files{$data0} = $data1; - } - close INPUT; - - # --> Read INCLUDES - open INPUT, "$package_root/mkpatch/INCLUDES" - or die "Can't open `$package_root/mkpatch/INCLUDES'"; - while () { - ($data0,$data1) = /(\S+)\s+(\S+)/; - $includes{$data0} = $data1; - $sedscript .= 's,(#\s*include\s*)'.$data0.'(\s*),$1'."$data1".'$2, ; '; - } - close INPUT; - - die "First apply the i2c patches to `$kernel_root'!" - if ! -d "$kernel_root/drivers/i2c"; - - # --> Read "version.h" - open INPUT, "$package_root/version.h" - or die "Can't open `$package_root/version.h'"; - $version_string .= $_ while ; - close INPUT; - - # --> Start generating - foreach $package_file (sort keys %files) { - open INPUT,"$package_root/$package_file" - or die "Can't open `$package_root/$package_file'"; - open OUTPUT,">$package_root/$temp" - or die "Can't open `$package_root/$temp'"; - while () { - eval $sedscript; - if (m@#\s*include\s*"version.h"@) { - print OUTPUT $version_string; - } else { - print OUTPUT; - } - } - close INPUT; - close OUTPUT; - - $kernel_file = $files{$package_file}; - print_diff $package_root,$kernel_root,$kernel_file,$temp; - } - - gen_Makefile $package_root, $kernel_root; - gen_drivers_Makefile $package_root, $kernel_root; - gen_drivers_sensors_Makefile $package_root, $kernel_root; - gen_drivers_char_Config_in $package_root, $kernel_root; - gen_drivers_i2c_Config_in $package_root, $kernel_root; - gen_drivers_i2c_Makefile $package_root, $kernel_root; - gen_Documentation_Configure_help $package_root, $kernel_root; - gen_MAINTAINERS $package_root, $kernel_root; - gen_dmi_scan $package_root, $kernel_root; - - # Clear temporary file - unlink("$package_root/$temp"); -} - -main; - diff --git a/prog/config/grab_busses.sh b/prog/config/grab_busses.sh deleted file mode 100755 index 3d2bc769..00000000 --- a/prog/config/grab_busses.sh +++ /dev/null @@ -1,29 +0,0 @@ -#!/bin/bash - -# This simple shell script grabs the contents of /proc/bus/i2c and outputs it -# in sensors.conf format through stdout. You can use it to generate those -# nasty 'bus' statements in config files. - -if [ $# = 0 ] ; then - file=/proc/bus/i2c -elif [ $# = 1 ] ; then - file="$1" -else - echo "Syntax: grab_busses [file]" >&2 - exit 1 -fi - -if [ ! -e "$file" ]; then - echo "Can't find file \`$file';"\ - "try \`modprobe i2c-proc' for /proc/bus/i2c" >&2 - exit 1 -fi - -cat -- "$file" | awk \ - ' BEGIN { FS = "\t" } - { sub(" *$","",$3) - sub(" *$","",$4) - printf "bus \"%s\" \"%s\" \"%s\"\n",$1,$3,$4 } - { nrlines++ } - END { printf "Total lines: %d\n",nrlines > "/dev/stderr" } - ' diff --git a/prog/detect/Module.mk b/prog/detect/Module.mk index c1f57ead..d2526d80 100644 --- a/prog/detect/Module.mk +++ b/prog/detect/Module.mk @@ -13,7 +13,8 @@ # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software -# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, +# MA 02110-1301 USA. # Note that MODULE_DIR (the directory in which this file resides) is a # 'simply expanded variable'. That means that its value is substituted @@ -22,28 +23,18 @@ MODULE_DIR := prog/detect PROGDETECTDIR := $(MODULE_DIR) PROGDETECTMAN8DIR := $(MANDIR)/man8 -PROGDETECTMAN8FILES := $(MODULE_DIR)/i2cdetect.8 $(MODULE_DIR)/sensors-detect.8 +PROGDETECTMAN8FILES := $(MODULE_DIR)/sensors-detect.8 # Regrettably, even 'simply expanded variables' will not put their currently # defined value verbatim into the command-list of rules... -PROGDETECTTARGETS := $(MODULE_DIR)/i2cdetect -PROGDETECTSOURCES := $(MODULE_DIR)/i2cdetect.c -PROGDETECTSBININSTALL := $(MODULE_DIR)/sensors-detect \ - $(MODULE_DIR)/i2cdetect - -# Include all dependency files. We use '.rd' to indicate this will create -# executables. -INCLUDEFILES += $(PROGDETECTSOURCES:.c=.rd) +PROGDETECTSBININSTALL := $(MODULE_DIR)/sensors-detect REMOVEDETECTBIN := $(patsubst $(MODULE_DIR)/%,$(DESTDIR)$(SBINDIR)/%,$(PROGDETECTSBININSTALL)) REMOVEDETECTMAN := $(patsubst $(MODULE_DIR)/%,$(DESTDIR)$(PROGDETECTMAN8DIR)/%,$(PROGDETECTMAN8FILES)) -all-prog-detect: $(PROGDETECTTARGETS) +all-prog-detect: user :: all-prog-detect -$(MODULE_DIR)/i2cdetect: $(MODULE_DIR)/i2cdetect.ro prog/dump/i2cbusses.ro - $(CC) $(EXLDFLAGS) -o $@ $^ - install-prog-detect: all-prog-detect $(MKDIR) $(DESTDIR)$(SBINDIR) $(DESTDIR)$(PROGDETECTMAN8DIR) $(INSTALL) -m 755 $(PROGDETECTSBININSTALL) $(DESTDIR)$(SBINDIR) @@ -55,5 +46,4 @@ user_uninstall:: $(RM) $(REMOVEDETECTMAN) clean-prog-detect: - $(RM) $(PROGDETECTDIR)/*.rd $(PROGDETECTDIR)/*.ro $(PROGDETECTTARGETS) clean :: clean-prog-detect diff --git a/prog/detect/i2cdetect.8 b/prog/detect/i2cdetect.8 deleted file mode 100644 index 09c85cb7..00000000 --- a/prog/detect/i2cdetect.8 +++ /dev/null @@ -1,88 +0,0 @@ -.TH I2CDETECT 8 "October 2006" -.SH NAME -i2cdetect \- detect I2C chips - -.SH SYNOPSIS -.B i2cdetect -.RI [ -y ] -.RI [ -a ] -.RI [ -q | -r ] -.I i2cbus -.RI [ "first last" ] -.br -.B i2cdetect -.I -F -.I i2cbus -.br -.B i2cdetect -.I -V -.br -.B i2cdetect -.I -l - -.SH DESCRIPTION -i2cdetect is a userspace program to scan an I2C bus for devices. It -outputs a table with the list of detected devices on the specified bus. -\fIi2cbus\fR indicates the number of the I2C bus to be scanned, and -should correspond to one of the busses listed by \fIi2cdetect -l\fR. -The optional parameters \fIfirst\fR and \fIlast\fR restrict the scanning -range (default: from 0x03 to 0x77). -.PP -i2cdetect can also be used to query the functionalities of an I2C bus -(see option \fB-F\fP.) - -.SH WARNING -This program can confuse your I2C bus, cause data loss and worse! - -.SH INTERPRETING THE OUTPUT -Each cell in the output table will contain one of the following symbols: -.IP \(bu "\w'\(bu'u+1n" -"--". The address was probed but no chip answered. -.IP \(bu -"UU". Probing was skipped, because this address is currently in use by -a driver. This strongly suggests that there is a chip at this address. -.IP \(bu -An address number in hexadecimal, e.g. "2d" or "4e". A chip -was found at this address. - -.SH OPTIONS -.TP -.B "\-y" -Disable interactive mode. By default, i2cdetect will wait for a confirmation -from the user before messing with the I2C bus. When this flag is used, it -will perform the operation directly. This is mainly meant to be used in -scripts. -.TP -.B "\-a" -Force scanning of non-regular addresses. Not recommended. -.TP -.B "\-q" -Use SMBus "quick write" commands for probing (by default, the command -used is the one believed to be the safest for each address). -Not recommended. This is known to corrupt the Atmel AT24RF08 EEPROM -found on many IBM Thinkpad laptops. -.TP -.B "\-r" -Use SMBus "read byte" commands for probing (by default, the command -used is the one believed to be the safest for each address). -Not recommended. This is known to lock SMBus on various write-only -chips (most notably clock chips at address 0x69). -.TP -.B "\-F" -Display the list of functionalities implemented by the adapter and exit. -.TP -.B "\-V" -Display the version and exit. -.TP -.B "\-l" -Output a list of installed busses. - -.SH SEE ALSO -i2cdump(8), sensors-detect(8) - -.SH AUTHOR -Frodo Looijaard, Mark D. Studebaker, and the lm_sensors group -http://www.lm-sensors.org/ -This manual page was written by Aurelien Jarno , for -the Debian GNU/Linux system. It was then reviewed by the lm_sensors team and -is now part of the lm_sensors source distribution. diff --git a/prog/detect/i2cdetect.c b/prog/detect/i2cdetect.c deleted file mode 100644 index 9c189f5e..00000000 --- a/prog/detect/i2cdetect.c +++ /dev/null @@ -1,347 +0,0 @@ -/* - i2cdetect.c - a user-space program to scan for I2C devices - Copyright (C) 1999-2004 Frodo Looijaard , - Mark D. Studebaker and - Jean Delvare - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#include -#include -#include -#include -#include -#include "../dump/i2cbusses.h" -#include "i2c-dev.h" -#include "version.h" - -#define MODE_AUTO 0 -#define MODE_QUICK 1 -#define MODE_READ 2 -#define MODE_FUNC 3 - -void help(void) -{ - fprintf(stderr, - "Syntax: i2cdetect [-y] [-a] [-q|-r] I2CBUS [FIRST LAST]\n" - " i2cdetect -F I2CBUS\n" - " i2cdetect -l\n" - " i2cdetect -V\n" - " I2CBUS is an integer\n" - " With -a, probe all addresses (NOT RECOMMENDED)\n" - " With -q, uses only quick write commands for probing (NOT " - "RECOMMENDED)\n" - " With -r, uses only read byte commands for probing (NOT " - "RECOMMENDED)\n" - " If provided, FIRST and LAST limit the probing range.\n" - " With -l, lists installed busses only\n"); - print_i2c_busses(0); -} - -int scan_i2c_bus(int file, const int mode, const int first, const int last) -{ - int i, j; - int res; - - printf(" 0 1 2 3 4 5 6 7 8 9 a b c d e f\n"); - - for (i = 0; i < 128; i += 16) { - printf("%02x: ", i); - for(j = 0; j < 16; j++) { - fflush(stdout); - - /* Skip unwanted addresses */ - if (i+j < first || i+j > last) { - printf(" "); - continue; - } - - /* Set slave address */ - if (ioctl(file, I2C_SLAVE, i+j) < 0) { - if (errno == EBUSY) { - printf("UU "); - continue; - } else { - fprintf(stderr, "Error: Could not set " - "address to 0x%02x: %s\n", i+j, - strerror(errno)); - return -1; - } - } - - /* Probe this address */ - switch (mode) { - case MODE_QUICK: - /* This is known to corrupt the Atmel AT24RF08 - EEPROM */ - res = i2c_smbus_write_quick(file, - I2C_SMBUS_WRITE); - break; - case MODE_READ: - /* This is known to lock SMBus on various - write-only chips (mainly clock chips) */ - res = i2c_smbus_read_byte(file); - break; - default: - if ((i+j >= 0x30 && i+j <= 0x37) - || (i+j >= 0x50 && i+j <= 0x5F)) - res = i2c_smbus_read_byte(file); - else - res = i2c_smbus_write_quick(file, - I2C_SMBUS_WRITE); - } - - if (res < 0) - printf("-- "); - else - printf("%02x ", i+j); - } - printf("\n"); - } - - return 0; -} - -struct func -{ - long value; - const char* name; -}; - -static const struct func all_func[] = { - { .value = I2C_FUNC_I2C, - .name = "I2C" }, - { .value = I2C_FUNC_SMBUS_QUICK, - .name = "SMBus Quick Command" }, - { .value = I2C_FUNC_SMBUS_WRITE_BYTE, - .name = "SMBus Send Byte" }, - { .value = I2C_FUNC_SMBUS_READ_BYTE, - .name = "SMBus Receive Byte" }, - { .value = I2C_FUNC_SMBUS_WRITE_BYTE_DATA, - .name = "SMBus Write Byte" }, - { .value = I2C_FUNC_SMBUS_READ_BYTE_DATA, - .name = "SMBus Read Byte" }, - { .value = I2C_FUNC_SMBUS_WRITE_WORD_DATA, - .name = "SMBus Write Word" }, - { .value = I2C_FUNC_SMBUS_READ_WORD_DATA, - .name = "SMBus Read Word" }, - { .value = I2C_FUNC_SMBUS_PROC_CALL, - .name = "SMBus Process Call" }, - { .value = I2C_FUNC_SMBUS_WRITE_BLOCK_DATA, - .name = "SMBus Block Write" }, - { .value = I2C_FUNC_SMBUS_READ_BLOCK_DATA, - .name = "SMBus Block Read" }, - { .value = I2C_FUNC_SMBUS_BLOCK_PROC_CALL, - .name = "SMBus Block Process Call" }, - { .value = I2C_FUNC_SMBUS_PEC, - .name = "SMBus PEC" }, - { .value = I2C_FUNC_SMBUS_WRITE_I2C_BLOCK, - .name = "I2C Block Write" }, - { .value = I2C_FUNC_SMBUS_READ_I2C_BLOCK, - .name = "I2C Block Read" }, - { } -}; - -void print_functionality(unsigned long funcs) -{ - int i; - - for (i = 0; all_func[i].value; i++) { - printf("%-32s %s\n", all_func[i].name, - (funcs & all_func[i].value) ? "yes" : "no"); - } -} - -int main(int argc, char *argv[]) -{ - char *end; - int i2cbus, file, res; - char filename[20]; - unsigned long funcs; - int mode = MODE_AUTO; - int first = 0x03, last = 0x77; - int flags = 0; - int yes = 0, version = 0, list = 0; - - /* handle (optional) flags first */ - while (1+flags < argc && argv[1+flags][0] == '-') { - switch (argv[1+flags][1]) { - case 'V': version = 1; break; - case 'y': yes = 1; break; - case 'l': list = 1; break; - case 'F': - if (mode != MODE_AUTO && mode != MODE_FUNC) { - fprintf(stderr, "Error: Different modes " - "specified!\n"); - exit(1); - } - mode = MODE_FUNC; - break; - case 'r': - if (mode == MODE_QUICK) { - fprintf(stderr, "Error: Different modes " - "specified!\n"); - exit(1); - } - mode = MODE_READ; - break; - case 'q': - if (mode == MODE_READ) { - fprintf(stderr, "Error: Different modes " - "specified!\n"); - exit(1); - } - mode = MODE_QUICK; - break; - case 'a': - first = 0x00; - last = 0x7F; - break; - default: - fprintf(stderr, "Warning: Unsupported flag " - "\"-%c\"!\n", argv[1+flags][1]); - help(); - exit(1); - } - flags++; - } - - if (version) { - fprintf(stderr, "i2cdetect version %s\n", LM_VERSION); - exit(0); - } - - if (list) { - print_i2c_busses(1); - exit(0); - } - - if (argc < flags + 2) { - fprintf(stderr, "Error: No i2c-bus specified!\n"); - help(); - exit(1); - } - i2cbus = strtol(argv[flags+1], &end, 0); - if (*end) { - fprintf(stderr, "Error: I2CBUS argument not a number!\n"); - help(); - exit(1); - } - if ((i2cbus < 0) || (i2cbus > 0xff)) { - fprintf(stderr, "Error: I2CBUS argument out of range " - "(0-255)!\n"); - help(); - exit(1); - } - - /* read address range if present */ - if (argc == flags + 4 && mode != MODE_FUNC) { - int tmp; - - tmp = strtol(argv[flags+2], &end, 0); - if (*end) { - fprintf(stderr, "Error: FIRST argment not a " - "number!\n"); - help(); - exit(1); - } - if (tmp < first || tmp > last) { - fprintf(stderr, "Error: FIRST argument out of range " - "(0x%02x-0x%02x)!\n", first, last); - help(); - exit(1); - } - first = tmp; - - tmp = strtol(argv[flags+3], &end, 0); - if (*end) { - fprintf(stderr, "Error: LAST argment not a " - "number!\n"); - help(); - exit(1); - } - if (tmp < first || tmp > last) { - fprintf(stderr, "Error: LAST argument out of range " - "(0x%02x-0x%02x)!\n", first, last); - help(); - exit(1); - } - last = tmp; - } else if (argc != flags + 2) { - help(); - exit(1); - } - - file = open_i2c_dev(i2cbus, filename, 0); - if (file < 0) { - exit(1); - } - - if (ioctl(file, I2C_FUNCS, &funcs) < 0) { - fprintf(stderr, "Error: Could not get the adapter " - "functionality matrix: %s\n", strerror(errno)); - close(file); - exit(1); - } - - /* Special case, we only list the implemented functionalities */ - if (mode == MODE_FUNC) { - close(file); - printf("Functionalities implemented by %s:\n", filename); - print_functionality(funcs); - exit(0); - } - - if (mode != MODE_READ && !(funcs & I2C_FUNC_SMBUS_QUICK)) { - fprintf(stderr, "Error: Can't use SMBus Quick Write command " - "on this bus (ISA bus?)\n"); - close(file); - exit(1); - } - if (mode != MODE_QUICK && !(funcs & I2C_FUNC_SMBUS_READ_BYTE)) { - fprintf(stderr, "Error: Can't use SMBus Read Byte command " - "on this bus (ISA bus?)\n"); - close(file); - exit(1); - } - - if (!yes) { - char s[2]; - - fprintf(stderr, "WARNING! This program can confuse your I2C " - "bus, cause data loss and worse!\n"); - - fprintf(stderr, "I will probe file %s%s.\n", filename, - mode==MODE_QUICK?" using quick write commands": - mode==MODE_READ?" using read byte commands":""); - fprintf(stderr, "I will probe address range 0x%02x-0x%02x.\n", - first, last); - - fprintf(stderr, "Continue? [Y/n] "); - fflush(stderr); - if (!fgets(s, 2, stdin) - || (s[0] != '\n' && s[0] != 'y' && s[0] != 'Y')) { - fprintf(stderr, "Aborting on user request.\n"); - exit(0); - } - } - - res = scan_i2c_bus(file, mode, first, last); - - close(file); - - exit(res?1:0); -} diff --git a/prog/detect/sensors-detect b/prog/detect/sensors-detect index 4e72abd2..2b31765f 100755 --- a/prog/detect/sensors-detect +++ b/prog/detect/sensors-detect @@ -1,7 +1,6 @@ #!/usr/bin/perl -w - # -# sensors-detect - Detect PCI bus and chips +# sensors-detect - Detect hardware monitoring chips # Copyright (C) 1998 - 2002 Frodo Looijaard # Copyright (C) 2004 - 2008 Jean Delvare # @@ -21,17 +20,10 @@ # MA 02110-1301 USA. # -# TODO: Better handling of chips with several addresses - -# A Perl wizard really ought to look upon this; the PCI and I2C stuff should -# each be put in a separate file, using modules and packages. That is beyond -# me. - require 5.004; use strict; use Fcntl; -use POSIX; use File::Basename; # We will call modprobe, which typically lives in either /sbin, @@ -45,8 +37,9 @@ foreach ('/usr/sbin', '/usr/local/sbin', '/sbin') { # CONSTANT DECLARATIONS # ######################### -use vars qw(@pci_adapters @chip_ids $i2c_addresses_to_scan @superio_ids - @cpu_ids $revision); +use constant NO_CACHE => 1; +use vars qw(@pci_adapters @chip_ids @ipmi_ifs @non_hwmon_chip_ids + $i2c_addresses_to_scan $revision @i2c_byte_cache); $revision = '$Revision$ ($Date$)'; $revision =~ s/\$\w+: (.*?) \$/$1/g; @@ -56,2168 +49,1847 @@ $revision =~ s/ \([^()]*\)//; # signature. This is an easy and fast way to determine which SMBus or I2C # adapters should be present. # Each entry must have a vendid (Vendor ID), devid (Device ID) and -# procid (string as appears in /proc/pci; see linux/driver/pci, -# either pci.c or oldproc.c). If no driver is written yet, set the -# driver (Driver Name) field to "to-be-written". -# The match (Match Description) field should contain a regular expression -# matching the adapter name as it would appear in /proc/bus/i2c or /sys. +# procid (Device name) and driver (Device driver). @pci_adapters = ( - { - vendid => 0x8086, - devid => 0x7113, - procid => "Intel 82371AB PIIX4 ACPI", - driver => "i2c-piix4", - match => qr/^SMBus PIIX4 adapter at /, - }, - { - vendid => 0x8086, - devid => 0x7603, - procid => "Intel 82372FB PIIX5 ACPI", - driver => "to-be-tested", - }, - { - vendid => 0x8086, - devid => 0x719b, - procid => "Intel 82443MX Mobile", - driver => "i2c-piix4", - match => qr/^SMBus PIIX4 adapter at /, - }, - { - vendid => 0x8086, - devid => 0x2413, - procid => "Intel 82801AA ICH", - driver => "i2c-i801", - match => qr/^SMBus I801 adapter at [0-9a-f]{4}/, - }, - { - vendid => 0x8086, - devid => 0x2423, - procid => "Intel 82801AB ICH0", - driver => "i2c-i801", - match => qr/^SMBus I801 adapter at [0-9a-f]{4}/, - }, - { - vendid => 0x8086, - devid => 0x2443, - procid => "Intel 82801BA ICH2", - driver => "i2c-i801", - match => qr/^SMBus I801 adapter at [0-9a-f]{4}/, - }, - { - vendid => 0x8086, - devid => 0x2483, - procid => "Intel 82801CA/CAM ICH3", - driver => "i2c-i801", - match => qr/^SMBus I801 adapter at [0-9a-f]{4}/, - }, - { - vendid => 0x8086, - devid => 0x24C3, - procid => "Intel 82801DB ICH4", - driver => "i2c-i801", - match => qr/^SMBus I801 adapter at [0-9a-f]{4}/, - }, - { - vendid => 0x8086, - devid => 0x24D3, - procid => "Intel 82801EB ICH5", - driver => "i2c-i801", - match => qr/^SMBus I801 adapter at [0-9a-f]{4}/, - }, - { - vendid => 0x8086, - devid => 0x25A4, - procid => "Intel 6300ESB", - driver => "i2c-i801", - match => qr/^SMBus I801 adapter at [0-9a-f]{4}/, - }, - { - vendid => 0x8086, - devid => 0x269B, - procid => "Intel Enterprise Southbridge - ESB2", - driver => "i2c-i801", - match => qr/^SMBus I801 adapter at [0-9a-f]{4}/, - }, - { - vendid => 0x8086, - devid => 0x266A, - procid => "Intel 82801FB ICH6", - driver => "i2c-i801", - match => qr/^SMBus I801 adapter at [0-9a-f]{4}/, - }, - { - vendid => 0x8086, - devid => 0x27DA, - procid => "Intel 82801G ICH7", - driver => "i2c-i801", - match => qr/^SMBus I801 adapter at [0-9a-f]{4}/, - }, - { - vendid => 0x8086, - devid => 0x283E, - procid => "Intel 82801H ICH8", - driver => "i2c-i801", - match => qr/^SMBus I801 adapter at [0-9a-f]{4}/, - }, - { - vendid => 0x8086, - devid => 0x2930, - procid => "Intel ICH9", - driver => "i2c-i801", - match => qr/^SMBus I801 adapter at [0-9a-f]{4}/, - }, - { - vendid => 0x8086, - devid => 0x5032, - procid => "Intel Tolapai", - driver => "i2c-i801", - match => qr/^SMBus I801 adapter at [0-9a-f]{4}/, - }, - { - vendid => 0x8086, - devid => 0x3A30, - procid => "Intel ICH10", - driver => "i2c-i801", - match => qr/^SMBus I801 adapter at [0-9a-f]{4}/, - }, - { - vendid => 0x8086, - devid => 0x3A60, - procid => "Intel ICH10", - driver => "i2c-i801", - match => qr/^SMBus I801 adapter at [0-9a-f]{4}/, - }, - { - vendid => 0x1106, - devid => 0x3040, - procid => "VIA Technologies VT82C586B Apollo ACPI", - driver => "i2c-via", - match => qr/^VIA i2c/, - }, - { - vendid => 0x1106, - devid => 0x3050, - procid => "VIA Technologies VT82C596 Apollo ACPI", - driver => "i2c-viapro", - match => qr/^SMBus V(IA|ia) Pro adapter at/, - }, - { - vendid => 0x1106, - devid => 0x3051, - procid => "VIA Technologies VT82C596B ACPI", - driver => "i2c-viapro", - match => qr/^SMBus V(IA|ia) Pro adapter at/, - }, - { - vendid => 0x1106, - devid => 0x3057, - procid => "VIA Technologies VT82C686 Apollo ACPI", - driver => "i2c-viapro", - match => qr/^SMBus V(IA|ia) Pro adapter at/, - }, - { - vendid => 0x1106, - devid => 0x3074, - procid => "VIA Technologies VT8233 VLink South Bridge", - driver => "i2c-viapro", - match => qr/^SMBus V(IA|ia) Pro adapter at/, - }, - { - vendid => 0x1106, - devid => 0x3147, - procid => "VIA Technologies VT8233A South Bridge", - driver => "i2c-viapro", - match => qr/^SMBus V(IA|ia) Pro adapter at/, - }, - { - vendid => 0x1106, - devid => 0x3177, - procid => "VIA Technologies VT8233A/8235 South Bridge", - driver => "i2c-viapro", - match => qr/^SMBus V(IA|ia) Pro adapter at/, - }, - { - vendid => 0x1106, - devid => 0x3227, - procid => "VIA Technologies VT8237 South Bridge", - driver => "i2c-viapro", - match => qr/^SMBus V(IA|ia) Pro adapter at/, - }, - { - vendid => 0x1106, - devid => 0x3337, - procid => "VIA Technologies VT8237A South Bridge", - driver => "i2c-viapro", - match => qr/^SMBus V(IA|ia) Pro adapter at/, - }, - { - vendid => 0x1106, - devid => 0x8235, - procid => "VIA Technologies VT8231 South Bridge", - driver => "i2c-viapro", - match => qr/^SMBus V(IA|ia) Pro adapter at/, - }, - { - vendid => 0x1106, - devid => 0x3287, - procid => "VIA Technologies VT8251 South Bridge", - driver => "i2c-viapro", - match => qr/^SMBus V(IA|ia) Pro adapter at/, - }, - { - vendid => 0x1106, - devid => 0x8324, - procid => "VIA Technologies CX700 South Bridge", - driver => "i2c-viapro", - match => qr/^SMBus V(IA|ia) Pro adapter at/, - }, - { - vendid => 0x1106, - devid => 0x8353, - procid => "VIA Technologies VX800/VX820 South Bridge", - driver => "i2c-viapro", - match => qr/^SMBus V(IA|ia) Pro adapter at/, - }, - { - vendid => 0x1039, - devid => 0x5597, - procid => "Silicon Integrated Systems SIS5581/5582/5597/5598 (To be written - Do not use 5595 drivers)", - driver => "to-be-written", - }, - { - vendid => 0x1039, - devid => 0x5598, - procid => "Silicon Integrated Systems SIS5598 (To be written - Do not use 5595 drivers)", - driver => "to-be-written", - }, - { - vendid => 0x1039, - devid => 0x0540, - procid => "Silicon Integrated Systems SIS540 (To be written - Do not use 5595 drivers)", - driver => "to-be-written", - }, - { - vendid => 0x1039, - devid => 0x0630, - procid => "Silicon Integrated Systems SIS630", - driver => "i2c-sis630", - match => qr/^SMBus SIS630 adapter at [0-9a-f]{4}/, - }, - { - vendid => 0x1039, - devid => 0x0730, - procid => "Silicon Integrated Systems SIS730", - driver => "i2c-sis630", - match => qr/^SMBus SIS630 adapter at [0-9a-f]{4}/, - }, -# -# Both Ali chips below have same PCI ID. Can't be helped. Only one should load. -# - { - vendid => 0x10b9, - devid => 0x7101, - procid => "Acer Labs 1533/1543", - driver => "i2c-ali15x3", - match => qr/^SMBus ALI15X3 adapter at/, - }, - { - vendid => 0x10b9, - devid => 0x7101, - procid => "Acer Labs 1535", - driver => "i2c-ali1535", - match => qr/^SMBus ALI1535 adapter at/, - }, - { - vendid => 0x10b9, - devid => 0x1563, - procid => "Acer Labs 1563", - driver => "i2c-ali1563", - match => qr/^SMBus ALi 1563 Adapter @/, - }, - { - vendid => 0x1022, - devid => 0x740b, - procid => "AMD-756 Athlon ACPI", - driver => "i2c-amd756", - match => qr/^SMBus AMD756 adapter at [0-9a-f]{4}/, - }, - { - vendid => 0x1022, - devid => 0x7413, - procid => "AMD-766 Athlon ACPI", - driver => "i2c-amd756", - match => qr/^SMBus AMD766 adapter at [0-9a-f]{4}/, - }, - { - vendid => 0x1022, - devid => 0x7443, - procid => "AMD-768 System Management", - driver => "i2c-amd756", - match => qr/^SMBus AMD768 adapter at [0-9a-f]{4}/, - }, - { - vendid => 0x1022, - devid => 0x746b, - procid => "AMD-8111 ACPI", - driver => "i2c-amd756", - match => qr/^SMBus AMD8111 adapter at [0-9a-f]{4}/, - }, - { - vendid => 0x1022, - devid => 0x746a, - procid => "AMD-8111 SMBus 2.0", - driver => "i2c-amd8111", - match => qr/^SMBus2 AMD8111 adapter at [0-9a-f]{4}/, - }, - { - vendid => 0x10de, - devid => 0x01b4, - procid => "nVidia nForce SMBus", - driver => "i2c-amd756", - match => qr/^SMBus nVidia nForce adapter at [0-9a-f]{4}/, - }, - { - vendid => 0x10de, - devid => 0x0064, - procid => "nVidia Corporation nForce2 SMBus (MCP)", - driver => "i2c-nforce2", - match => qr/^SMBus nForce2 adapter at /, - }, - { - vendid => 0x10de, - devid => 0x0084, - procid => "nVidia Corporation nForce2 Ultra 400 SMBus (MCP)", - driver => "i2c-nforce2", - match => qr/^SMBus nForce2 adapter at /, - }, - { - vendid => 0x10de, - devid => 0x00D4, - procid => "nVidia Corporation nForce3 Pro150 SMBus (MCP)", - driver => "i2c-nforce2", - match => qr/^SMBus nForce2 adapter at /, - }, - { - vendid => 0x10de, - devid => 0x00E4, - procid => "nVidia Corporation nForce3 250Gb SMBus (MCP)", - driver => "i2c-nforce2", - match => qr/^SMBus nForce2 adapter at /, - }, - { - vendid => 0x10de, - devid => 0x0052, - procid => "nVidia Corporation nForce4 SMBus (MCP)", - driver => "i2c-nforce2", - match => qr/^SMBus nForce2 adapter at /, - }, - { - vendid => 0x10de, - devid => 0x0034, - procid => "nVidia Corporation nForce4 SMBus (MCP-04)", - driver => "i2c-nforce2", - match => qr/^SMBus nForce2 adapter at /, - }, - { - vendid => 0x10de, - devid => 0x0264, - procid => "nVidia Corporation nForce4 SMBus (MCP51)", - driver => "i2c-nforce2", - match => qr/^SMBus nForce2 adapter at /, - }, - { - vendid => 0x10de, - devid => 0x0368, - procid => "nVidia Corporation nForce4 SMBus (MCP55)", - driver => "i2c-nforce2", - match => qr/^SMBus nForce2 adapter at /, - }, - { - vendid => 0x10de, - devid => 0x03eb, - procid => "nVidia Corporation nForce4 SMBus (MCP61)", - driver => "i2c-nforce2", - match => qr/^SMBus nForce2 adapter at /, - }, - { - vendid => 0x10de, - devid => 0x0446, - procid => "nVidia Corporation nForce4 SMBus (MCP65)", - driver => "i2c-nforce2", - match => qr/^SMBus nForce2 adapter at /, - }, - { - vendid => 0x1166, - devid => 0x0200, - procid => "ServerWorks OSB4 South Bridge", - driver => "i2c-piix4", - match => qr/^SMBus PIIX4 adapter at /, - }, - { - vendid => 0x1055, - devid => 0x9463, - procid => "SMSC Victory66 South Bridge", - driver => "i2c-piix4", - match => qr/^SMBus PIIX4 adapter at /, - }, - { - vendid => 0x1166, - devid => 0x0201, - procid => "ServerWorks CSB5 South Bridge", - driver => "i2c-piix4", - match => qr/^SMBus PIIX4 adapter at /, - }, - { - vendid => 0x1166, - devid => 0x0203, - procid => "ServerWorks CSB6 South Bridge", - driver => "i2c-piix4", - match => qr/^SMBus PIIX4 adapter at /, - }, - { - vendid => 0x1166, - devid => 0x0205, - procid => "ServerWorks HT-1000 South Bridge", - driver => "i2c-piix4", - match => qr/^SMBus PIIX4 adapter at /, - }, - { - vendid => 0x1002, - devid => 0x4353, - procid => "ATI Technologies Inc ATI SMBus", - driver => "i2c-piix4", - match => qr/^SMBus PIIX4 adapter at /, - }, - { - vendid => 0x1002, - devid => 0x4363, - procid => "ATI Technologies Inc ATI SMBus", - driver => "i2c-piix4", - match => qr/^SMBus PIIX4 adapter at /, - }, - { - vendid => 0x1002, - devid => 0x4372, - procid => "ATI Technologies Inc IXP SB400 SMBus Controller", - driver => "i2c-piix4", - match => qr/^SMBus PIIX4 adapter at /, - }, - { - vendid => 0x1002, - devid => 0x4385, - procid => "ATI Technologies Inc SB600 SMBus", - driver => "i2c-piix4", - match => qr/^SMBus PIIX4 adapter at /, - }, - { - vendid => 0x100B, - devid => 0x0500, - procid => "SCx200 Bridge", - driver => "scx200_acb", - match => qr/^(NatSemi SCx200 ACCESS\.bus|SCx200 ACB\d+) /, - }, - { - vendid => 0x100B, - devid => 0x0510, - procid => "SC1100 Bridge", - driver => "scx200_acb", - match => qr/^(NatSemi SCx200 ACCESS\.bus|SCx200 ACB\d+) /, - }, - { - vendid => 0x100B, - devid => 0x002B, - procid => "CS5535 ISA bridge", - driver => "scx200_acb", - match => qr/^CS5535 ACB\d+ /, - }, - { - vendid => 0x1022, - devid => 0x2090, - procid => "CS5536 [Geode companion] ISA", - driver => "scx200_acb", - match => qr/^CS553[56] ACB\d+ /, - }, + { + vendid => 0x8086, + devid => 0x7113, + procid => "Intel 82371AB PIIX4 ACPI", + driver => "i2c-piix4", + }, { + vendid => 0x8086, + devid => 0x7603, + procid => "Intel 82372FB PIIX5 ACPI", + driver => "to-be-tested", + }, { + vendid => 0x8086, + devid => 0x719b, + procid => "Intel 82443MX Mobile", + driver => "i2c-piix4", + }, { + vendid => 0x8086, + devid => 0x2413, + procid => "Intel 82801AA ICH", + driver => "i2c-i801", + }, { + vendid => 0x8086, + devid => 0x2423, + procid => "Intel 82801AB ICH0", + driver => "i2c-i801", + }, { + vendid => 0x8086, + devid => 0x2443, + procid => "Intel 82801BA ICH2", + driver => "i2c-i801", + }, { + vendid => 0x8086, + devid => 0x2483, + procid => "Intel 82801CA/CAM ICH3", + driver => "i2c-i801", + }, { + vendid => 0x8086, + devid => 0x24C3, + procid => "Intel 82801DB ICH4", + driver => "i2c-i801", + }, { + vendid => 0x8086, + devid => 0x24D3, + procid => "Intel 82801EB ICH5", + driver => "i2c-i801", + }, { + vendid => 0x8086, + devid => 0x25A4, + procid => "Intel 6300ESB", + driver => "i2c-i801", + }, { + vendid => 0x8086, + devid => 0x269B, + procid => "Intel Enterprise Southbridge - ESB2", + driver => "i2c-i801", + }, { + vendid => 0x8086, + devid => 0x266A, + procid => "Intel 82801FB ICH6", + driver => "i2c-i801", + }, { + vendid => 0x8086, + devid => 0x27DA, + procid => "Intel 82801G ICH7", + driver => "i2c-i801", + }, { + vendid => 0x8086, + devid => 0x283E, + procid => "Intel 82801H ICH8", + driver => "i2c-i801", + }, { + vendid => 0x8086, + devid => 0x2930, + procid => "Intel ICH9", + driver => "i2c-i801", + }, { + vendid => 0x8086, + devid => 0x5032, + procid => "Intel Tolapai", + driver => "i2c-i801", + }, { + vendid => 0x8086, + devid => 0x3A30, + procid => "Intel ICH10", + driver => "i2c-i801", + }, { + vendid => 0x8086, + devid => 0x3A60, + procid => "Intel ICH10", + driver => "i2c-i801", + }, { + vendid => 0x8086, + devid => 0x8119, + procid => "Intel SCH", + driver => "i2c-isch", + }, { + vendid => 0x1106, + devid => 0x3040, + procid => "VIA Technologies VT82C586B Apollo ACPI", + driver => "i2c-via", + }, { + vendid => 0x1106, + devid => 0x3050, + procid => "VIA Technologies VT82C596 Apollo ACPI", + driver => "i2c-viapro", + }, { + vendid => 0x1106, + devid => 0x3051, + procid => "VIA Technologies VT82C596B ACPI", + driver => "i2c-viapro", + }, { + vendid => 0x1106, + devid => 0x3057, + procid => "VIA Technologies VT82C686 Apollo ACPI", + driver => "i2c-viapro", + }, { + vendid => 0x1106, + devid => 0x3074, + procid => "VIA Technologies VT8233 VLink South Bridge", + driver => "i2c-viapro", + }, { + vendid => 0x1106, + devid => 0x3147, + procid => "VIA Technologies VT8233A South Bridge", + driver => "i2c-viapro", + }, { + vendid => 0x1106, + devid => 0x3177, + procid => "VIA Technologies VT8233A/8235 South Bridge", + driver => "i2c-viapro", + }, { + vendid => 0x1106, + devid => 0x3227, + procid => "VIA Technologies VT8237 South Bridge", + driver => "i2c-viapro", + }, { + vendid => 0x1106, + devid => 0x3337, + procid => "VIA Technologies VT8237A South Bridge", + driver => "i2c-viapro", + }, { + vendid => 0x1106, + devid => 0x8235, + procid => "VIA Technologies VT8231 South Bridge", + driver => "i2c-viapro", + }, { + vendid => 0x1106, + devid => 0x3287, + procid => "VIA Technologies VT8251 South Bridge", + driver => "i2c-viapro", + }, { + vendid => 0x1106, + devid => 0x8324, + procid => "VIA Technologies CX700 South Bridge", + driver => "i2c-viapro", + }, { + vendid => 0x1106, + devid => 0x8353, + procid => "VIA Technologies VX800/VX820 South Bridge", + driver => "i2c-viapro", + }, { + vendid => 0x1039, + devid => 0x0008, + procid => "Silicon Integrated Systems SIS5595", + driver => "i2c-sis5595", + }, { + vendid => 0x1039, + devid => 0x0630, + procid => "Silicon Integrated Systems SIS630", + driver => "i2c-sis630", + }, { + vendid => 0x1039, + devid => 0x0730, + procid => "Silicon Integrated Systems SIS730", + driver => "i2c-sis630", + }, { + vendid => 0x1039, + devid => 0x0016, + procid => "Silicon Integrated Systems SMBus Controller", + driver => "i2c-sis96x", + }, { + # Both Ali chips below have same PCI ID. Can't be helped. Only one should load. + vendid => 0x10b9, + devid => 0x7101, + procid => "Acer Labs 1533/1543", + driver => "i2c-ali15x3", + }, { + vendid => 0x10b9, + devid => 0x7101, + procid => "Acer Labs 1535", + driver => "i2c-ali1535", + }, { + vendid => 0x10b9, + devid => 0x1563, + procid => "Acer Labs 1563", + driver => "i2c-ali1563", + }, { + vendid => 0x1022, + devid => 0x740b, + procid => "AMD-756 Athlon ACPI", + driver => "i2c-amd756", + }, { + vendid => 0x1022, + devid => 0x7413, + procid => "AMD-766 Athlon ACPI", + driver => "i2c-amd756", + }, { + vendid => 0x1022, + devid => 0x7443, + procid => "AMD-768 System Management", + driver => "i2c-amd756", + }, { + vendid => 0x1022, + devid => 0x746b, + procid => "AMD-8111 ACPI", + driver => "i2c-amd756", + }, { + vendid => 0x1022, + devid => 0x746a, + procid => "AMD-8111 SMBus 2.0", + driver => "i2c-amd8111", + }, { + vendid => 0x10de, + devid => 0x01b4, + procid => "nVidia nForce SMBus", + driver => "i2c-amd756", + }, { + vendid => 0x10de, + devid => 0x0064, + procid => "nVidia Corporation nForce2 SMBus (MCP)", + driver => "i2c-nforce2", + }, { + vendid => 0x10de, + devid => 0x0084, + procid => "nVidia Corporation nForce2 Ultra 400 SMBus (MCP)", + driver => "i2c-nforce2", + }, { + vendid => 0x10de, + devid => 0x00D4, + procid => "nVidia Corporation nForce3 Pro150 SMBus (MCP)", + driver => "i2c-nforce2", + }, { + vendid => 0x10de, + devid => 0x00E4, + procid => "nVidia Corporation nForce3 250Gb SMBus (MCP)", + driver => "i2c-nforce2", + }, { + vendid => 0x10de, + devid => 0x0052, + procid => "nVidia Corporation nForce4 SMBus (MCP)", + driver => "i2c-nforce2", + }, { + vendid => 0x10de, + devid => 0x0034, + procid => "nVidia Corporation nForce4 SMBus (MCP-04)", + driver => "i2c-nforce2", + }, { + vendid => 0x10de, + devid => 0x0264, + procid => "nVidia Corporation nForce SMBus (MCP51)", + driver => "i2c-nforce2", + }, { + vendid => 0x10de, + devid => 0x0368, + procid => "nVidia Corporation nForce SMBus (MCP55)", + driver => "i2c-nforce2", + }, { + vendid => 0x10de, + devid => 0x03eb, + procid => "nVidia Corporation nForce SMBus (MCP61)", + driver => "i2c-nforce2", + }, { + vendid => 0x10de, + devid => 0x0446, + procid => "nVidia Corporation nForce SMBus (MCP65)", + driver => "i2c-nforce2", + }, { + vendid => 0x10de, + devid => 0x0542, + procid => "nVidia Corporation nForce SMBus (MCP67)", + driver => "i2c-nforce2", + }, { + vendid => 0x10de, + devid => 0x07d8, + procid => "nVidia Corporation nForce SMBus (MCP73)", + driver => "i2c-nforce2", + }, { + vendid => 0x10de, + devid => 0x0aa2, + procid => "nVidia Corporation nForce SMBus (MCP79)", + driver => "i2c-nforce2", + }, { + vendid => 0x1166, + devid => 0x0200, + procid => "ServerWorks OSB4 South Bridge", + driver => "i2c-piix4", + }, { + vendid => 0x1055, + devid => 0x9463, + procid => "SMSC Victory66 South Bridge", + driver => "i2c-piix4", + }, { + vendid => 0x1166, + devid => 0x0201, + procid => "ServerWorks CSB5 South Bridge", + driver => "i2c-piix4", + }, { + vendid => 0x1166, + devid => 0x0203, + procid => "ServerWorks CSB6 South Bridge", + driver => "i2c-piix4", + }, { + vendid => 0x1166, + devid => 0x0205, + procid => "ServerWorks HT-1000 South Bridge", + driver => "i2c-piix4", + }, { + vendid => 0x1002, + devid => 0x4353, + procid => "ATI Technologies Inc ATI SMBus", + driver => "i2c-piix4", + }, { + vendid => 0x1002, + devid => 0x4363, + procid => "ATI Technologies Inc ATI SMBus", + driver => "i2c-piix4", + }, { + vendid => 0x1002, + devid => 0x4372, + procid => "ATI Technologies Inc IXP SB400 SMBus Controller", + driver => "i2c-piix4", + }, { + vendid => 0x1002, + devid => 0x4385, + procid => "ATI Technologies Inc SB600 SMBus", + driver => "i2c-piix4", + }, { + vendid => 0x100B, + devid => 0x0500, + procid => "SCx200 Bridge", + driver => "scx200_acb", + }, { + vendid => 0x100B, + devid => 0x0510, + procid => "SC1100 Bridge", + driver => "scx200_acb", + }, { + vendid => 0x100B, + devid => 0x002B, + procid => "CS5535 ISA bridge", + driver => "scx200_acb", + }, { + vendid => 0x1022, + devid => 0x2090, + procid => "CS5536 [Geode companion] ISA", + driver => "scx200_acb", + } ); -# The following entries used to appear directly in @pci_adapters. -# Because of the tendency of SiS chipsets to have their real PCI -# IDs obscured, we have to qualify these with a custom detection -# routine before we add them to the @pci_adapters list. -# -use vars qw(@pci_adapters_sis5595 @pci_adapters_sis645 @pci_adapters_sis96x); -@pci_adapters_sis5595 = ( - { - vendid => 0x1039, - devid => 0x0008, - procid => "Silicon Integrated Systems SIS5595", - driver => "i2c-sis5595", - match => qr/^SMBus SIS5595 adapter at [0-9a-f]{4}/, - }, +# Look-up table to find out an I2C bus' driver based on the bus name. +# The match field should contain a regular expression matching the I2C +# bus name as it would appear in /sys/class/i2c-adapter. +# Note that new drivers probably don't need to be added to this table +# if they bind to their device, as we will be able to get the driver name +# from sysfs directly. +use vars qw(@i2c_adapter_names); +@i2c_adapter_names = ( + { driver => "i2c-piix4", match => qr/^SMBus PIIX4 adapter at / }, + { driver => "i2c-i801", match => qr/^SMBus I801 adapter at / }, + { driver => "i2c-via", match => qr/^VIA i2c/ }, + { driver => "i2c-viapro", match => qr/^SMBus V(IA|ia) Pro adapter at / }, + { driver => "i2c-sis5595", match => qr/^SMBus SIS5595 adapter at / }, + { driver => "i2c-sis630", match => qr/^SMBus SIS630 adapter at / }, + { driver => "i2c-sis96x", match => qr/^SiS96x SMBus adapter at / }, + { driver => "i2c-ali15x3", match => qr/^SMBus ALI15X3 adapter at / }, + { driver => "i2c-ali1535", match => qr/^SMBus ALI1535 adapter at/ }, + { driver => "i2c-ali1563", match => qr/^SMBus ALi 1563 Adapter @ / }, + { driver => "i2c-amd756", match => qr/^SMBus (AMD756|AMD766|AMD768|AMD8111|nVidia nForce) adapter at / }, + { driver => "i2c-amd8111", match => qr/^SMBus2 AMD8111 adapter at / }, + { driver => "i2c-nforce2", match => qr/^SMBus nForce2 adapter at / }, + { driver => "scx200_acb", match => qr/^(NatSemi SCx200 ACCESS\.bus|SCx200 ACB\d+|CS553[56] ACB\d+)/ }, ); -@pci_adapters_sis645 = ( - { - vendid => 0x1039, - devid => 0x0008, - procid => "Silicon Integrated Systems SIS5595", - driver => "i2c-sis645", - match => qr/^SiS645 SMBus adapter at [0-9a-f]{4}/, - }, - { - vendid => 0x1039, - devid => 0x0016, - procid => "Silicon Integrated Systems SMBus Controller", - driver => "i2c-sis645", - match => qr/^SiS645 SMBus adapter at 0x[0-9a-f]{4}/, - }, - { - vendid => 0x1039, - devid => 0x0018, - procid => "Silicon Integrated Systems 85C503/5513 (LPC Bridge)", - driver => "i2c-sis645", - match => qr/^SiS645 SMBus adapter at 0x[0-9a-f]{4}/, - }, -); - -@pci_adapters_sis96x = ( - { - vendid => 0x1039, - devid => 0x0016, - procid => "Silicon Integrated Systems SMBus Controller", - driver => "i2c-sis96x", - match => qr/^SiS96x SMBus adapter at 0x[0-9a-f]{4}/, - }, -); - -# This is a list of all recognized chips. +# This is a list of all recognized I2C and ISA chips. # Each entry must have the following fields: # name: The full chip name -# driver: The driver name (without .o extension). Put in exactly -# "to-be-written" if it is not yet available. Put in exactly -# "not-a-sensor" if it is not a hardware monitoring chip. -# Put in exactly "use-isa-instead" if no i2c driver will be written. -# i2c_addrs (optional): For I2C chips, the range of valid I2C addresses to -# probe. Recommend avoiding 0x69 because of clock chips. +# driver: The driver name. Put in exactly: +# * "to-be-written" if it is not yet available +# * "use-isa-instead" if no i2c driver will be written +# i2c_addrs (optional): For I2C chips, the list of I2C addresses to +# probe. # i2c_detect (optional): For I2C chips, the function to call to detect -# this chip. The function should take two parameters: an open file +# this chip. The function will be passed two parameters: an open file # descriptor to access the bus, and the I2C address to probe. -# isa_addrs (optional): For ISA chips, the range of valid port addresses to +# isa_addrs (optional): For ISA chips, the list of port addresses to # probe. # isa_detect (optional): For ISA chips, the function to call to detect -# this chip. The function should take one parameter: the ISA address +# this chip. The function will be passed one parameter: the ISA address # to probe. # alias_detect (optional): For chips which can be both on the ISA and the -# I2C bus, a function which detectes whether two entries are the same. -# The function should take three parameters: The ISA address, the -# I2C bus number, and the I2C address. +# I2C bus, a function which detects whether two entries are the same. +# The function will be passed three parameters: the ISA address, an +# open file descriptor to access the I2C bus, and the I2C address. @chip_ids = ( - { - name => "Myson MTP008", - driver => "mtp008", - i2c_addrs => [0x2c..0x2e], - i2c_detect => sub { mtp008_detect(@_); }, - }, - { - name => "National Semiconductor LM78", - driver => "lm78", - i2c_addrs => [0x28..0x2f], - i2c_detect => sub { lm78_detect(0, @_); }, - isa_addrs => [0x290], - isa_detect => sub { lm78_isa_detect(0, @_); }, - alias_detect => sub { lm78_alias_detect(0, @_); }, - }, - { - name => "National Semiconductor LM78-J", - driver => "lm78", - i2c_addrs => [0x28..0x2f], - i2c_detect => sub { lm78_detect(1, @_); }, - isa_addrs => [0x290], - isa_detect => sub { lm78_isa_detect(1, @_); }, - alias_detect => sub { lm78_alias_detect(1, @_); }, - }, - { - name => "National Semiconductor LM79", - driver => "lm78", - i2c_addrs => [0x28..0x2f], - i2c_detect => sub { lm78_detect(2, @_); }, - isa_addrs => [0x290], - isa_detect => sub { lm78_isa_detect(2, @_); }, - alias_detect => sub { lm78_alias_detect(2, @_); }, - }, - { - name => "National Semiconductor LM75", - driver => "lm75", - i2c_addrs => [0x48..0x4f], - i2c_detect => sub { lm75_detect(0, @_); }, - }, - { - name => "Dallas Semiconductor DS75", - driver => "lm75", - i2c_addrs => [0x48..0x4f], - i2c_detect => sub { lm75_detect(1, @_); }, - }, - { - name => "National Semiconductor LM77", - driver => "lm77", - i2c_addrs => [0x48..0x4b], - i2c_detect => sub { lm77_detect(@_); }, - }, - { - name => "National Semiconductor LM80", - driver => "lm80", - i2c_addrs => [0x28..0x2f], - i2c_detect => sub { lm80_detect(@_); }, - }, - { - name => "National Semiconductor LM85 or LM96000", - driver => "lm85", - i2c_addrs => [0x2c..0x2e], - i2c_detect => sub { lm85_detect(0x01, @_); }, - }, - { - name => "Analog Devices ADM1027, ADT7460 or ADT7463", - driver => "lm85", - i2c_addrs => [0x2c..0x2e], - i2c_detect => sub { lm85_detect(0x41, @_); }, - }, - { - name => "SMSC EMC6D100, EMC6D101 or EMC6D102", - driver => "lm85", - i2c_addrs => [0x2c..0x2e], - i2c_detect => sub { lm85_detect(0x5c, @_); }, - }, - { - name => "Analog Devices ADT7462", - driver => "adt7462", - i2c_addrs => [0x5c, 0x58], - i2c_detect => sub { adt7467_detect(2, @_); }, - }, - { - name => "Analog Devices ADT7466", - driver => "to-be-written", - i2c_addrs => [0x4c], - i2c_detect => sub { adt7467_detect(3, @_); }, - }, - { - name => "Analog Devices ADT7467 or ADT7468", - driver => "to-be-written", - i2c_addrs => [0x2e], - i2c_detect => sub { adt7467_detect(0, @_); }, - }, - { - name => "Analog Devices ADT7470", - driver => "adt7470", - i2c_addrs => [0x2c, 0x2e, 0x2f], - i2c_detect => sub { adt7467_detect(4, @_); }, - }, - { - name => "Analog Devices ADT7473", - driver => "adt7473", - i2c_addrs => [0x2e], - i2c_detect => sub { adt7473_detect(0, @_); }, - }, - { - name => "Analog Devices ADT7475", - driver => "adt7475", - i2c_addrs => [0x2e], - i2c_detect => sub { adt7473_detect(1, @_); }, - }, - { - name => "Analog Devices ADT7476", - driver => "to-be-written", - i2c_addrs => [0x2c..0x2e], - i2c_detect => sub { adt7467_detect(1, @_); }, - }, - { - name => "Andigilog aSC7511", - driver => "to-be-written", - i2c_addrs => [0x4c], - i2c_detect => sub { andigilog_aSC7511_detect(0, @_); }, - }, - { - name => "Andigilog aSC7512", - driver => "to-be-written", - i2c_addrs => [0x58], - i2c_detect => sub { andigilog_detect(0, @_); }, - }, - { - name => "Andigilog aSC7611", - driver => "to-be-written", - i2c_addrs => [0x2c, 0x2d, 0x2e], - i2c_detect => sub { andigilog_detect(1, @_); }, - }, - { - name => "Andigilog aSC7621", - driver => "to-be-written", - i2c_addrs => [0x2c, 0x2d, 0x2e], - i2c_detect => sub { andigilog_detect(2, @_); }, - }, - { - name => "National Semiconductor LM87", - driver => "lm87", - i2c_addrs => [0x2c..0x2e], - i2c_detect => sub { lm87_detect(@_); }, - }, - { - name => "National Semiconductor LM93", - driver => "lm93", - i2c_addrs => [0x2c..0x2e], - i2c_detect => sub { lm93_detect(@_); }, - }, - { - name => "Winbond W83781D", - driver => "w83781d", - i2c_detect => sub { w83781d_detect(0, @_); }, - i2c_addrs => [0x28..0x2f], - isa_addrs => [0x290], - isa_detect => sub { w83781d_isa_detect(0, @_); }, - alias_detect => sub { w83781d_alias_detect(0, @_); }, - }, - { - name => "Winbond W83782D", - driver => "w83781d", - i2c_addrs => [0x28..0x2f], - i2c_detect => sub { w83781d_detect(1, @_); }, - isa_addrs => [0x290], - isa_detect => sub { w83781d_isa_detect(1, @_); }, - alias_detect => sub { w83781d_alias_detect(1, @_); }, - }, - { - name => "Winbond W83783S", - driver => "w83781d", - i2c_addrs => [0x2d], - i2c_detect => sub { w83781d_detect(2, @_); }, - }, - { - name => "Winbond W83792D", - driver => "w83792d", - i2c_addrs => [0x2c..0x2f], - i2c_detect => sub { w83781d_detect(8, @_); }, - }, - { - name => "Winbond W83793R/G", - driver => "w83793", - i2c_addrs => [0x2c..0x2f], - i2c_detect => sub { w83793_detect(0, @_); }, - }, - { - name => "Winbond W83791SD", - driver => "not-a-sensor", - i2c_addrs => [0x2c..0x2f], - i2c_detect => sub { w83791sd_detect(@_); }, - }, - { - name => "Winbond W83627HF", - driver => "use-isa-instead", - i2c_addrs => [0x28..0x2f], - i2c_detect => sub { w83781d_detect(3, @_); }, - }, - { - name => "Winbond W83627EHF", - driver => "use-isa-instead", - i2c_addrs => [0x28..0x2f], - i2c_detect => sub { w83781d_detect(9, @_); }, - }, - { - name => "Winbond W83627DHG", - driver => "use-isa-instead", - i2c_addrs => [0x28..0x2f], - i2c_detect => sub { w83781d_detect(10, @_); }, - }, - { - name => "Asus AS99127F (rev.1)", - driver => "w83781d", - i2c_addrs => [0x28..0x2f], - i2c_detect => sub { w83781d_detect(4, @_); }, - }, - { - name => "Asus AS99127F (rev.2)", - driver => "w83781d", - i2c_addrs => [0x28..0x2f], - i2c_detect => sub { w83781d_detect(5, @_); }, - }, - { - name => "Asus ASB100 Bach", - driver => "asb100", - i2c_addrs => [0x28..0x2f], - i2c_detect => sub { w83781d_detect(6, @_); }, - }, - { - name => "Asus ASM58 Mozart-2", - driver => "to-be-written", - i2c_addrs => [0x77], - i2c_detect => sub { mozart_detect(0, @_); }, - }, - { - name => "Asus AS2K129R Mozart-2", - driver => "to-be-written", - i2c_addrs => [0x77], - i2c_detect => sub { mozart_detect(1, @_); }, - }, - { - name => "Asus Mozart-2", - driver => "to-be-written", - i2c_addrs => [0x77], - i2c_detect => sub { mozart_detect(2, @_); }, - }, - { - name => "Winbond W83L784R/AR/G", - driver => "to-be-written", - i2c_addrs => [0x2d], - i2c_detect => sub { w83l784r_detect(0, @_); }, - }, - { - name => "Winbond W83L785R/G", - driver => "to-be-written", - i2c_addrs => [0x2d], - i2c_detect => sub { w83l784r_detect(1, @_); }, - }, - { - name => "Winbond W83L786NR/NG/R/G", - driver => "w83l786ng", - i2c_addrs => [0x2e, 0x2f], - i2c_detect => sub { w83l784r_detect(2, @_); }, - }, - { - name => "Winbond W83L785TS-S", - driver => "w83l785ts", - i2c_addrs => [0x2e], - i2c_detect => sub { w83l785ts_detect(0, @_); }, - }, - { - name => "Genesys Logic GL518SM Revision 0x00", - driver => "gl518sm", - i2c_addrs => [0x2c, 0x2d], - i2c_detect => sub { gl518sm_detect(0, @_); }, - }, - { - name => "Genesys Logic GL518SM Revision 0x80", - driver => "gl518sm", - i2c_addrs => [0x2c, 0x2d], - i2c_detect => sub { gl518sm_detect(1, @_); }, - }, - { - name => "Genesys Logic GL520SM", - driver => "gl520sm", - i2c_addrs => [0x2c, 0x2d], - i2c_detect => sub { gl520sm_detect(@_); }, - }, - { - name => "Genesys Logic GL525SM", - driver => "Unwritten (GL525SM)", - i2c_addrs => [0x2d], - i2c_detect => sub { gl525sm_detect(@_); }, - }, - { - name => "Analog Devices ADM9240", - driver => "adm9240", - i2c_addrs => [0x2c..0x2f], - i2c_detect => sub { adm9240_detect(0, @_); }, - }, - { - name => "Dallas Semiconductor DS1621/DS1631", - driver => "ds1621", - i2c_addrs => [0x48..0x4f], - i2c_detect => sub { ds1621_detect(@_); }, - }, - { - name => "Dallas Semiconductor DS1780", - driver => "adm9240", - i2c_addrs => [0x2c..0x2f], - i2c_detect => sub { adm9240_detect(1, @_); }, - }, - { - name => "National Semiconductor LM81", - driver => "adm9240", - i2c_addrs => [0x2c..0x2f], - i2c_detect => sub { adm9240_detect(2, @_); }, - }, - { - name => "Analog Devices ADM1026", - driver => "adm1026", - i2c_addrs => [0x2c, 0x2d, 0x2e], - i2c_detect => sub { adm1026_detect(0, @_); }, - }, - { - name => "Analog Devices ADM1025", - driver => "adm1025", - i2c_addrs => [0x2c..0x2e], - i2c_detect => sub { adm1025_detect(0, @_); }, - }, - { - name => "Philips NE1619", - driver => "adm1025", - i2c_addrs => [0x2c..0x2d], - i2c_detect => sub { adm1025_detect(1, @_); }, - }, - { - name => "Analog Devices ADM1021", - driver => "adm1021", - i2c_addrs => [0x18..0x1a, 0x29..0x2b, 0x4c..0x4e], - i2c_detect => sub { adm1021_detect(0, @_); }, - }, - { - name => "Analog Devices ADM1021A/ADM1023", - driver => "adm1021", - i2c_addrs => [0x18..0x1a, 0x29..0x2b, 0x4c..0x4e], - i2c_detect => sub { adm1021_detect(1, @_); }, - }, - { - name => "Maxim MAX1617", - driver => "adm1021", - i2c_addrs => [0x18..0x1a, 0x29..0x2b, 0x4c..0x4e], - i2c_detect => sub { adm1021_detect(2, @_); }, - }, - { - name => "Maxim MAX1617A", - driver => "adm1021", - i2c_addrs => [0x18..0x1a, 0x29..0x2b, 0x4c..0x4e], - i2c_detect => sub { adm1021_detect(3, @_); }, - }, - { - name => "Maxim MAX1668", - driver => "max1668", - i2c_addrs => [0x18..0x1a, 0x29..0x2b, 0x4c..0x4e], - i2c_detect => sub { max1668_detect(0, @_); }, - }, - { - name => "Maxim MAX1805", - driver => "max1668", - i2c_addrs => [0x18..0x1a, 0x29..0x2b, 0x4c..0x4e], - i2c_detect => sub { max1668_detect(1, @_); }, - }, - { - name => "Maxim MAX1989", - driver => "max1668", - i2c_addrs => [0x18..0x1a, 0x29..0x2b, 0x4c..0x4e], - i2c_detect => sub { max1668_detect(2, @_); }, - }, - { - name => "Maxim MAX6650/MAX6651", - driver => "max6650", - i2c_addrs => [0x1b, 0x1f, 0x48, 0x4b], - i2c_detect => sub { max6650_detect(0, @_); }, - }, - { - name => "Maxim MAX6655/MAX6656", - driver => "max6655", - i2c_addrs => [0x18..0x1a, 0x29..0x2b, 0x4c..0x4e], - i2c_detect => sub { max6655_detect(0, @_); }, - }, - { - name => "TI THMC10", - driver => "adm1021", - i2c_addrs => [0x18..0x1a, 0x29..0x2b, 0x4c..0x4e], - i2c_detect => sub { adm1021_detect(4, @_); }, - }, - { - name => "National Semiconductor LM84", - driver => "adm1021", - i2c_addrs => [0x18..0x1a, 0x29..0x2b, 0x4c..0x4e], - i2c_detect => sub { adm1021_detect(5, @_); }, - }, - { - name => "Genesys Logic GL523SM", - driver => "adm1021", - i2c_addrs => [0x18..0x1a, 0x29..0x2b, 0x4c..0x4e], - i2c_detect => sub { adm1021_detect(6, @_); }, - }, - { - name => "Onsemi MC1066", - driver => "adm1021", - i2c_addrs => [0x18..0x1a, 0x29..0x2b, 0x4c..0x4e], - i2c_detect => sub { adm1021_detect(7, @_); }, - }, - { - name => "Maxim MAX1619", - driver => "max1619", - i2c_addrs => [0x18..0x1a, 0x29..0x2b, 0x4c..0x4e], - i2c_detect => sub { max1619_detect(0, @_); }, - }, - { - name => "National Semiconductor LM82/LM83", - driver => "lm83", - i2c_addrs => [0x18..0x1a, 0x29..0x2b, 0x4c..0x4e], - i2c_detect => sub { lm83_detect(0, @_); }, - }, - { - name => "National Semiconductor LM90", - driver => "lm90", - i2c_addrs => [0x4c], - i2c_detect => sub { lm90_detect(0, @_); }, - }, - { - name => "National Semiconductor LM89/LM99", - driver => "lm90", - i2c_addrs => [0x4c..0x4d], - i2c_detect => sub { lm90_detect(1, @_); }, - }, - { - name => "National Semiconductor LM86", - driver => "lm90", - i2c_addrs => [0x4c], - i2c_detect => sub { lm90_detect(2, @_); }, - }, - { - name => "Analog Devices ADM1032", - driver => "lm90", - i2c_addrs => [0x4c..0x4d], - i2c_detect => sub { lm90_detect(3, @_); }, - }, - { - name => "Maxim MAX6657/MAX6658/MAX6659", - driver => "lm90", - i2c_addrs => [0x4c], - i2c_detect => sub { lm90_detect(4, @_); }, - }, - { - name => "Maxim MAX6659", - driver => "lm90", - i2c_addrs => [0x4d..0x4e], # 0x4c is handled above - i2c_detect => sub { lm90_detect(4, @_); }, - }, - { - name => "Maxim MAX6648/MAX6692", - driver => "to-be-written", - i2c_addrs => [0x4c], - i2c_detect => sub { lm90_detect(6, @_); }, - }, - { - name => "Maxim MAX6680/MAX6681", - driver => "lm90", - i2c_addrs => [0x18..0x1a, 0x29..0x2b, 0x4c..0x4e], - i2c_detect => sub { lm90_detect(7, @_); }, - }, - { - name => "Winbond W83L771W/G", - driver => "lm90", - i2c_addrs => [0x4c], - i2c_detect => sub { lm90_detect(8, @_); }, - }, - { - name => "Texas Instruments TMP401", - driver => "tmp401", - i2c_addrs => [0x4c], - i2c_detect => sub { lm90_detect(9, @_); }, - }, - { - name => "Texas Instruments TMP411", - driver => "to-be-written", - i2c_addrs => [0x4c..0x4e], - i2c_detect => sub { lm90_detect(10, @_); }, - }, - { - name => "National Semiconductor LM63", - driver => "lm63", - i2c_addrs => [0x4c], - i2c_detect => sub { lm63_detect(1, @_); }, - }, - { - name => "National Semiconductor LM64", - driver => "to-be-written", # lm63 - i2c_addrs => [0x18, 0x4e], - i2c_detect => sub { lm63_detect(3, @_); }, - }, - { - name => "Fintek F75363SG", - driver => "lm63", # Not yet - i2c_addrs => [0x4c], - i2c_detect => sub { lm63_detect(2, @_); }, - }, - { - name => "National Semiconductor LM92", - driver => "lm92", - i2c_addrs => [0x48..0x4b], - i2c_detect => sub { lm92_detect(0, @_); }, - }, - { - name => "National Semiconductor LM76", - driver => "lm92", - i2c_addrs => [0x48..0x4b], - i2c_detect => sub { lm92_detect(1, @_); }, - }, - { - name => "Maxim MAX6633/MAX6634/MAX6635", - driver => "lm92", - i2c_addrs => [0x48..0x4f], # The MAX6633 can also use 0x40-0x47 but we - # don't want to probe these addresses, it's - # dangerous. - i2c_detect => sub { lm92_detect(2, @_); }, - }, - { - name => "Analog Devices ADT7461", - driver => "lm90", - i2c_addrs => [0x4c..0x4d], - i2c_detect => sub { lm90_detect(5, @_); }, - }, - { - name => "Analog Devices ADM1029", - driver => "adm1029", - i2c_addrs => [0x28..0x2f], - i2c_detect => sub { adm1029_detect(0, @_); }, - }, - { - name => "Analog Devices ADM1030", - driver => "adm1031", - i2c_addrs => [0x2c..0x2e], - i2c_detect => sub { adm1031_detect(0, @_); }, - }, - { - name => "Analog Devices ADM1031", - driver => "adm1031", - i2c_addrs => [0x2c..0x2e], - i2c_detect => sub { adm1031_detect(1, @_); }, - }, - { - name => "Analog Devices ADM1033", - driver => "to-be-written", - i2c_addrs => [0x50..0x53], - i2c_detect => sub { adm1034_detect(0, @_); }, - }, - { - name => "Analog Devices ADM1034", - driver => "to-be-written", - i2c_addrs => [0x50..0x53], - i2c_detect => sub { adm1034_detect(1, @_); }, - }, - { - name => "Analog Devices ADM1022", - driver => "thmc50", - i2c_addrs => [0x2c..0x2e], - i2c_detect => sub { adm1022_detect(0, @_); }, - }, - { - name => "Texas Instruments THMC50", - driver => "thmc50", - i2c_addrs => [0x2c..0x2e], - i2c_detect => sub { adm1022_detect(1, @_); }, - }, - { - name => "Analog Devices ADM1028", - driver => "thmc50", - i2c_addrs => [0x2e], - i2c_detect => sub { adm1022_detect(2, @_); }, - }, - { - name => "VIA VT1211 (I2C)", - driver => "use-isa-instead", - i2c_addrs => [0x2d], - i2c_detect => sub { vt1211_i2c_detect(0, @_); }, - }, - { - name => "ITE IT8712F", - driver => "it87", - i2c_addrs => [0x28..0x2f], - i2c_detect => sub { ite_detect(0, @_); }, - }, - { - name => "ITE IT8201R/IT8203R/IT8206R/IT8266R", - driver => "not-a-sensor", - i2c_addrs => [0x4e], - i2c_detect => sub { ite_overclock_detect(@_); }, - }, - { - name => "SPD EEPROM", - driver => "not-a-sensor", - # Can also live at 0x54-0x57, but we don't care: we only check - # for SPD and EDID EEPROMs because some hardware monitoring chips - # can live at 0x50-0x53. - i2c_addrs => [0x50..0x53], - i2c_detect => sub { eeprom_detect(@_); }, - }, - { - name => "EDID EEPROM", - driver => "not-a-sensor", - i2c_addrs => [0x50..0x53], - i2c_detect => sub { ddcmonitor_detect(@_); }, - }, - { - name => "FSC Poseidon II", - driver => "to-be-written", - i2c_addrs => [0x73], - i2c_detect => sub { fscpos_detect(@_); }, - }, - { - name => "FSC Heimdal", - driver => "fschmd", - i2c_addrs => [0x73], - i2c_detect => sub { fschmd_detect(@_); }, - }, - { - name => "FSC Heracles", - driver => "fschmd", - i2c_addrs => [0x73], - i2c_detect => sub { fschrc_detect(@_); }, - }, - { - name => "ALi M5879", - driver => "to-be-written", - i2c_addrs => [0x2c..0x2d], - i2c_detect => sub { m5879_detect(@_); }, - }, - { - name => "SMSC LPC47M15x/192/292/997", - driver => "smsc47m192", - i2c_addrs => [0x2c..0x2d], - i2c_detect => sub { smsc47m192_detect(@_); }, - }, - { - name => "SMSC DME1737", - driver => "dme1737", - i2c_addrs => [0x2c..0x2e], - i2c_detect => sub { dme1737_detect(1, @_); }, - }, - { - name => "SMSC SCH5027D-NW", - driver => "dme1737", - i2c_addrs => [0x2c..0x2e], - i2c_detect => sub { dme1737_detect(2, @_); }, - }, - { - name => "Fintek F75111R/RG/N (GPIO)", - driver => "not-a-sensor", - i2c_addrs => [0x4e], # 0x37 not probed - i2c_detect => sub { fintek_detect(1, @_); }, - }, - { - name => "Fintek F75121R/F75122R/RG (VID+GPIO)", - driver => "to-be-written", - i2c_addrs => [0x4e], # 0x37 not probed - i2c_detect => sub { fintek_detect(2, @_); }, - }, - { - name => "Fintek F75373S/SG", - driver => "f75375s", - i2c_addrs => [0x2d..0x2e], - i2c_detect => sub { fintek_detect(3, @_); }, - }, - { - name => "Fintek F75375S/SP", - driver => "f75375s", - i2c_addrs => [0x2d..0x2e], - i2c_detect => sub { fintek_detect(4, @_); }, - }, - { - name => "Fintek F75387SG/RG", - driver => "to-be-written", - i2c_addrs => [0x2d..0x2e], - i2c_detect => sub { fintek_detect(5, @_); }, - }, - { - name => "Fintek F75383S/M", - driver => "to-be-written", - i2c_addrs => [0x4c], - i2c_detect => sub { fintek_detect(6, @_); }, - }, - { - name => "Fintek F75384S/M", - driver => "to-be-written", - i2c_addrs => [0x4d], - i2c_detect => sub { fintek_detect(6, @_); }, - }, - { - name => "Fintek custom power control IC", - driver => "to-be-written", - i2c_addrs => [0x2f], - i2c_detect => sub { fintek_detect(7, @_); }, - }, - { - name => "Smart Battery", - driver => "smartbatt", - i2c_addrs => [0x0b], - i2c_detect => sub { smartbatt_detect(@_); }, - }, + { + name => "Myson MTP008", + driver => "mtp008", + i2c_addrs => [0x2c..0x2e], + i2c_detect => sub { mtp008_detect(@_); }, + }, { + name => "National Semiconductor LM78", + driver => "lm78", + i2c_addrs => [0x28..0x2f], + i2c_detect => sub { lm78_detect(@_, 0); }, + isa_addrs => [0x290], + isa_detect => sub { lm78_isa_detect(@_, 0); }, + alias_detect => sub { winbond_alias_detect(@_, 0x2b, 0x3d); }, + }, { + name => "National Semiconductor LM79", + driver => "lm78", + i2c_addrs => [0x28..0x2f], + i2c_detect => sub { lm78_detect(@_, 2); }, + isa_addrs => [0x290], + isa_detect => sub { lm78_isa_detect(@_, 2); }, + alias_detect => sub { winbond_alias_detect(@_, 0x2b, 0x3d); }, + }, { + name => "National Semiconductor LM75", + driver => "lm75", + i2c_addrs => [0x48..0x4f], + i2c_detect => sub { lm75_detect(@_, 0); }, + }, { + name => "Dallas Semiconductor DS75", + driver => "lm75", + i2c_addrs => [0x48..0x4f], + i2c_detect => sub { lm75_detect(@_, 1); }, + }, { + name => "National Semiconductor LM77", + driver => "lm77", + i2c_addrs => [0x48..0x4b], + i2c_detect => sub { lm77_detect(@_); }, + }, { + name => "National Semiconductor LM80", + driver => "lm80", + i2c_addrs => [0x28..0x2f], + i2c_detect => sub { lm80_detect(@_); }, + }, { + name => "National Semiconductor LM85", + driver => "lm85", + i2c_addrs => [0x2c..0x2e], + i2c_detect => sub { lm85_detect(@_, 0); }, + }, { + name => "National Semiconductor LM96000 or PC8374L", + driver => "lm85", + i2c_addrs => [0x2c..0x2e], + i2c_detect => sub { lm85_detect(@_, 1); }, + }, { + name => "Analog Devices ADM1027", + driver => "lm85", + i2c_addrs => [0x2c..0x2e], + i2c_detect => sub { lm85_detect(@_, 2); }, + }, { + name => "Analog Devices ADT7460 or ADT7463", + driver => "lm85", + i2c_addrs => [0x2c..0x2e], + i2c_detect => sub { lm85_detect(@_, 3); }, + }, { + name => "SMSC EMC6D100 or EMC6D101", + driver => "lm85", + i2c_addrs => [0x2c..0x2e], + i2c_detect => sub { lm85_detect(@_, 4); }, + }, { + name => "SMSC EMC6D102", + driver => "lm85", + i2c_addrs => [0x2c..0x2e], + i2c_detect => sub { lm85_detect(@_, 5); }, + }, { + name => "SMSC EMC6D103", + driver => "lm85", + i2c_addrs => [0x2c..0x2e], + i2c_detect => sub { lm85_detect(@_, 6); }, + }, { + name => "Analog Devices ADT7462", + driver => "adt7462", + i2c_addrs => [0x5c, 0x58], + i2c_detect => sub { adt7467_detect(@_, 2); }, + }, { + name => "Analog Devices ADT7466", + driver => "to-be-written", + i2c_addrs => [0x4c], + i2c_detect => sub { adt7467_detect(@_, 3); }, + }, { + name => "Analog Devices ADT7467 or ADT7468", + driver => "to-be-written", + i2c_addrs => [0x2e], + i2c_detect => sub { adt7467_detect(@_, 0); }, + }, { + name => "Analog Devices ADT7470", + driver => "adt7470", + i2c_addrs => [0x2c, 0x2e, 0x2f], + i2c_detect => sub { adt7467_detect(@_, 4); }, + }, { + name => "Analog Devices ADT7473", + driver => "adt7473", + i2c_addrs => [0x2e], + i2c_detect => sub { adt7473_detect(@_, 0); }, + }, { + name => "Analog Devices ADT7475", + driver => "adt7475", + i2c_addrs => [0x2e], + i2c_detect => sub { adt7473_detect(@_, 1); }, + }, { + name => "Analog Devices ADT7476", + driver => "to-be-written", + i2c_addrs => [0x2c..0x2e], + i2c_detect => sub { adt7467_detect(@_, 1); }, + }, { + name => "Andigilog aSC7511", + driver => "to-be-written", + i2c_addrs => [0x4c], + i2c_detect => sub { andigilog_aSC7511_detect(@_); }, + }, { + name => "Andigilog aSC7512", + driver => "to-be-written", + i2c_addrs => [0x58], + i2c_detect => sub { andigilog_detect(@_, 0); }, + }, { + name => "Andigilog aSC7611", + driver => "to-be-written", + i2c_addrs => [0x2c..0x2e], + i2c_detect => sub { andigilog_detect(@_, 1); }, + }, { + name => "Andigilog aSC7621", + driver => "to-be-written", + i2c_addrs => [0x2c..0x2e], + i2c_detect => sub { andigilog_detect(@_, 2); }, + }, { + name => "National Semiconductor LM87", + driver => "lm87", + i2c_addrs => [0x2c..0x2e], + i2c_detect => sub { lm87_detect(@_, 0); }, + }, { + name => "Analog Devices ADM1024", + driver => "lm87", + i2c_addrs => [0x2c..0x2e], + i2c_detect => sub { lm87_detect(@_, 1); }, + }, { + name => "National Semiconductor LM93", + driver => "lm93", + i2c_addrs => [0x2c..0x2e], + i2c_detect => sub { lm93_detect(@_); }, + }, { + name => "Winbond W83781D", + driver => "w83781d", + i2c_addrs => [0x28..0x2f], + i2c_detect => sub { w83781d_detect(@_, 0); }, + isa_addrs => [0x290], + isa_detect => sub { w83781d_isa_detect(@_, 0); }, + alias_detect => sub { winbond_alias_detect(@_, 0x2b, 0x3d); }, + }, { + name => "Winbond W83782D", + driver => "w83781d", + i2c_addrs => [0x28..0x2f], + i2c_detect => sub { w83781d_detect(@_, 1); }, + isa_addrs => [0x290], + isa_detect => sub { w83781d_isa_detect(@_, 1); }, + alias_detect => sub { winbond_alias_detect(@_, 0x2b, 0x3d); }, + }, { + name => "Winbond W83783S", + driver => "w83781d", + i2c_addrs => [0x2d], + i2c_detect => sub { w83781d_detect(@_, 2); }, + }, { + name => "Winbond W83791D", + driver => "w83791d", + i2c_addrs => [0x2c..0x2f], + i2c_detect => sub { w83781d_detect(@_, 7); }, + }, { + name => "Winbond W83792D", + driver => "w83792d", + i2c_addrs => [0x2c..0x2f], + i2c_detect => sub { w83781d_detect(@_, 8); }, + }, { + name => "Winbond W83793R/G", + driver => "w83793", + i2c_addrs => [0x2c..0x2f], + i2c_detect => sub { w83793_detect(@_); }, + }, { + name => "Winbond W83627HF", + driver => "use-isa-instead", + i2c_addrs => [0x28..0x2f], + i2c_detect => sub { w83781d_detect(@_, 3); }, + }, { + name => "Winbond W83627EHF", + driver => "use-isa-instead", + i2c_addrs => [0x28..0x2f], + i2c_detect => sub { w83781d_detect(@_, 9); }, + }, { + name => "Winbond W83627DHG", + driver => "use-isa-instead", + i2c_addrs => [0x28..0x2f], + i2c_detect => sub { w83781d_detect(@_, 10); }, + }, { + name => "Asus AS99127F (rev.1)", + driver => "w83781d", + i2c_addrs => [0x28..0x2f], + i2c_detect => sub { w83781d_detect(@_, 4); }, + }, { + name => "Asus AS99127F (rev.2)", + driver => "w83781d", + i2c_addrs => [0x28..0x2f], + i2c_detect => sub { w83781d_detect(@_, 5); }, + }, { + name => "Asus ASB100 Bach", + driver => "asb100", + i2c_addrs => [0x28..0x2f], + i2c_detect => sub { w83781d_detect(@_, 6); }, + }, { + name => "Asus Mozart-2", + driver => "to-be-written", + i2c_addrs => [0x77], + i2c_detect => sub { mozart_detect(@_); }, + }, { + name => "Winbond W83L784R/AR/G", + driver => "to-be-written", + i2c_addrs => [0x2d], + i2c_detect => sub { w83l784r_detect(@_, 0); }, + }, { + name => "Winbond W83L785R/G", + driver => "to-be-written", + i2c_addrs => [0x2d], + i2c_detect => sub { w83l784r_detect(@_, 1); }, + }, { + name => "Winbond W83L786NR/NG/R/G", + driver => "w83l786ng", + i2c_addrs => [0x2e, 0x2f], + i2c_detect => sub { w83l784r_detect(@_, 2); }, + }, { + name => "Winbond W83L785TS-S", + driver => "w83l785ts", + i2c_addrs => [0x2e], + i2c_detect => sub { w83l784r_detect(@_, 3); }, + }, { + name => "Genesys Logic GL518SM", + driver => "gl518sm", + i2c_addrs => [0x2c, 0x2d], + i2c_detect => sub { gl518sm_detect(@_, 0); }, + }, { + name => "Genesys Logic GL520SM", + driver => "gl520sm", + i2c_addrs => [0x2c, 0x2d], + i2c_detect => sub { gl518sm_detect(@_, 1); }, + }, { + name => "Genesys Logic GL525SM", + driver => "to-be-written", + i2c_addrs => [0x2d], + i2c_detect => sub { gl525sm_detect(@_); }, + }, { + name => "Analog Devices ADM9240", + driver => "adm9240", + i2c_addrs => [0x2c..0x2f], + i2c_detect => sub { adm9240_detect(@_, 0); }, + }, { + name => "Dallas Semiconductor DS1621/DS1631", + driver => "ds1621", + i2c_addrs => [0x48..0x4f], + i2c_detect => sub { ds1621_detect(@_); }, + }, { + name => "Dallas Semiconductor DS1780", + driver => "adm9240", + i2c_addrs => [0x2c..0x2f], + i2c_detect => sub { adm9240_detect(@_, 1); }, + }, { + name => "National Semiconductor LM81", + driver => "adm9240", + i2c_addrs => [0x2c..0x2f], + i2c_detect => sub { adm9240_detect(@_, 2); }, + }, { + name => "Analog Devices ADM1026", + driver => "adm1026", + i2c_addrs => [0x2c..0x2e], + i2c_detect => sub { adm1026_detect(@_); }, + }, { + name => "Analog Devices ADM1025", + driver => "adm1025", + i2c_addrs => [0x2c..0x2e], + i2c_detect => sub { adm1025_detect(@_, 0); }, + }, { + name => "Philips NE1619", + driver => "adm1025", + i2c_addrs => [0x2c..0x2d], + i2c_detect => sub { adm1025_detect(@_, 1); }, + }, { + name => "Analog Devices ADM1021", + driver => "adm1021", + i2c_addrs => [0x18..0x1a, 0x29..0x2b, 0x4c..0x4e], + i2c_detect => sub { adm1021_detect(@_, 0); }, + }, { + name => "Analog Devices ADM1021A/ADM1023", + driver => "adm1021", + i2c_addrs => [0x18..0x1a, 0x29..0x2b, 0x4c..0x4e], + i2c_detect => sub { adm1021_detect(@_, 1); }, + }, { + name => "Maxim MAX1617", + driver => "adm1021", + i2c_addrs => [0x18..0x1a, 0x29..0x2b, 0x4c..0x4e], + i2c_detect => sub { adm1021_detect(@_, 2); }, + }, { + name => "Maxim MAX1617A", + driver => "adm1021", + i2c_addrs => [0x18..0x1a, 0x29..0x2b, 0x4c..0x4e], + i2c_detect => sub { adm1021_detect(@_, 3); }, + }, { + name => "Maxim MAX1668", + driver => "max1668", + i2c_addrs => [0x18..0x1a, 0x29..0x2b, 0x4c..0x4e], + i2c_detect => sub { max1668_detect(@_, 0); }, + }, { + name => "Maxim MAX1805", + driver => "max1668", + i2c_addrs => [0x18..0x1a, 0x29..0x2b, 0x4c..0x4e], + i2c_detect => sub { max1668_detect(@_, 1); }, + }, { + name => "Maxim MAX1989", + driver => "max1668", + i2c_addrs => [0x18..0x1a, 0x29..0x2b, 0x4c..0x4e], + i2c_detect => sub { max1668_detect(@_, 2); }, + }, { + name => "Maxim MAX6650/MAX6651", + driver => "max6650", + i2c_addrs => [0x1b, 0x1f, 0x48, 0x4b], + i2c_detect => sub { max6650_detect(@_); }, + }, { + name => "Maxim MAX6655/MAX6656", + driver => "max6655", + i2c_addrs => [0x18..0x1a, 0x29..0x2b, 0x4c..0x4e], + i2c_detect => sub { max6655_detect(@_); }, + }, { + name => "TI THMC10", + driver => "adm1021", + i2c_addrs => [0x18..0x1a, 0x29..0x2b, 0x4c..0x4e], + i2c_detect => sub { adm1021_detect(@_, 4); }, + }, { + name => "National Semiconductor LM84", + driver => "adm1021", + i2c_addrs => [0x18..0x1a, 0x29..0x2b, 0x4c..0x4e], + i2c_detect => sub { adm1021_detect(@_, 5); }, + }, { + name => "Genesys Logic GL523SM", + driver => "adm1021", + i2c_addrs => [0x18..0x1a, 0x29..0x2b, 0x4c..0x4e], + i2c_detect => sub { adm1021_detect(@_, 6); }, + }, { + name => "Onsemi MC1066", + driver => "adm1021", + i2c_addrs => [0x18..0x1a, 0x29..0x2b, 0x4c..0x4e], + i2c_detect => sub { adm1021_detect(@_, 7); }, + }, { + name => "Maxim MAX1618", + driver => "max1619", + i2c_addrs => [0x18..0x1a, 0x29..0x2b, 0x4c..0x4e], + i2c_detect => sub { max1619_detect(@_, 1); }, + }, { + name => "Maxim MAX1619", + driver => "max1619", + i2c_addrs => [0x18..0x1a, 0x29..0x2b, 0x4c..0x4e], + i2c_detect => sub { max1619_detect(@_, 0); }, + }, { + name => "National Semiconductor LM82/LM83", + driver => "lm83", + i2c_addrs => [0x18..0x1a, 0x29..0x2b, 0x4c..0x4e], + i2c_detect => sub { lm83_detect(@_); }, + }, { + name => "National Semiconductor LM90", + driver => "lm90", + i2c_addrs => [0x4c], + i2c_detect => sub { lm90_detect(@_, 0); }, + }, { + name => "National Semiconductor LM89/LM99", + driver => "lm90", + i2c_addrs => [0x4c..0x4d], + i2c_detect => sub { lm90_detect(@_, 1); }, + }, { + name => "National Semiconductor LM86", + driver => "lm90", + i2c_addrs => [0x4c], + i2c_detect => sub { lm90_detect(@_, 2); }, + }, { + name => "Analog Devices ADM1032", + driver => "lm90", + i2c_addrs => [0x4c..0x4d], + i2c_detect => sub { lm90_detect(@_, 3); }, + }, { + name => "Maxim MAX6654/MAX6690", + driver => "to-be-written", # probably lm90 + i2c_addrs => [0x18..0x1a, 0x29..0x2b, 0x4c..0x4e], + i2c_detect => sub { lm90_detect(@_, 4); }, + }, { + name => "Maxim MAX6657/MAX6658/MAX6659", + driver => "lm90", + i2c_addrs => [0x4c], + i2c_detect => sub { max6657_detect(@_); }, + }, { + name => "Maxim MAX6659", + driver => "lm90", + i2c_addrs => [0x4d..0x4e], # 0x4c is handled above + i2c_detect => sub { max6657_detect(@_); }, + }, { + name => "Maxim MAX6646", + driver => "lm90", + i2c_addrs => [0x4d], + i2c_detect => sub { lm90_detect(@_, 6); }, + }, { + name => "Maxim MAX6647", + driver => "lm90", + i2c_addrs => [0x4e], + i2c_detect => sub { lm90_detect(@_, 6); }, + }, { + name => "Maxim MAX6648/MAX6649/MAX6692", + driver => "lm90", + i2c_addrs => [0x4c], + i2c_detect => sub { lm90_detect(@_, 6); }, + }, { + name => "Maxim MAX6680/MAX6681", + driver => "lm90", + i2c_addrs => [0x18..0x1a, 0x29..0x2b, 0x4c..0x4e], + i2c_detect => sub { lm90_detect(@_, 7); }, + }, { + name => "Winbond W83L771W/G", + driver => "lm90", + i2c_addrs => [0x4c], + i2c_detect => sub { lm90_detect(@_, 8); }, + }, { + name => "Texas Instruments TMP401", + driver => "tmp401", + i2c_addrs => [0x4c], + i2c_detect => sub { lm90_detect(@_, 9); }, + }, { + name => "Texas Instruments TMP411", + driver => "to-be-written", + i2c_addrs => [0x4c..0x4e], + i2c_detect => sub { lm90_detect(@_, 10); }, + }, { + name => "National Semiconductor LM95231", + driver => "to-be-written", + i2c_addrs => [0x2b, 0x19, 0x2a], + i2c_detect => sub { lm95231_detect(@_); }, + }, { + name => "National Semiconductor LM63", + driver => "lm63", + i2c_addrs => [0x4c], + i2c_detect => sub { lm63_detect(@_, 1); }, + }, { + name => "National Semiconductor LM64", + driver => "to-be-written", # lm63 + i2c_addrs => [0x18, 0x4e], + i2c_detect => sub { lm63_detect(@_, 3); }, + }, { + name => "Fintek F75363SG", + driver => "lm63", # Not yet + i2c_addrs => [0x4c], + i2c_detect => sub { lm63_detect(@_, 2); }, + }, { + name => "National Semiconductor LM92", + driver => "lm92", + i2c_addrs => [0x48..0x4b], + i2c_detect => sub { lm92_detect(@_, 0); }, + }, { + name => "National Semiconductor LM76", + driver => "lm92", + i2c_addrs => [0x48..0x4b], + i2c_detect => sub { lm92_detect(@_, 1); }, + }, { + name => "Maxim MAX6633/MAX6634/MAX6635", + driver => "lm92", + i2c_addrs => [0x48..0x4f], # The MAX6633 can also use 0x40-0x47 but we + # don't want to probe these addresses, it's + # dangerous. + i2c_detect => sub { lm92_detect(@_, 2); }, + }, { + name => "Analog Devices ADT7461", + driver => "lm90", + i2c_addrs => [0x4c..0x4d], + i2c_detect => sub { lm90_detect(@_, 5); }, + }, { + name => "Analog Devices ADT7481", + driver => "to-be-written", + i2c_addrs => [0x4c, 0x4b], + i2c_detect => sub { adt7481_detect(@_); }, + }, { + name => "Analog Devices ADM1029", + driver => "adm1029", + i2c_addrs => [0x28..0x2f], + i2c_detect => sub { adm1029_detect(@_); }, + }, { + name => "Analog Devices ADM1030", + driver => "adm1031", + i2c_addrs => [0x2c..0x2e], + i2c_detect => sub { adm1031_detect(@_, 0); }, + }, { + name => "Analog Devices ADM1031", + driver => "adm1031", + i2c_addrs => [0x2c..0x2e], + i2c_detect => sub { adm1031_detect(@_, 1); }, + }, { + name => "Analog Devices ADM1033", + driver => "to-be-written", + i2c_addrs => [0x50..0x53], + i2c_detect => sub { adm1034_detect(@_, 0); }, + }, { + name => "Analog Devices ADM1034", + driver => "to-be-written", + i2c_addrs => [0x50..0x53], + i2c_detect => sub { adm1034_detect(@_, 1); }, + }, { + name => "Analog Devices ADM1022", + driver => "thmc50", + i2c_addrs => [0x2c..0x2e], + i2c_detect => sub { adm1022_detect(@_, 0); }, + }, { + name => "Texas Instruments THMC50", + driver => "thmc50", + i2c_addrs => [0x2c..0x2e], + i2c_detect => sub { adm1022_detect(@_, 1); }, + }, { + name => "Analog Devices ADM1028", + driver => "thmc50", + i2c_addrs => [0x2e], + i2c_detect => sub { adm1022_detect(@_, 2); }, + }, { + name => "Texas Instruments THMC51", + driver => "to-be-written", # thmc50 + i2c_addrs => [0x2e], # At least (no datasheet) + i2c_detect => sub { adm1022_detect(@_, 3); }, + }, { + name => "VIA VT1211 (I2C)", + driver => "use-isa-instead", + i2c_addrs => [0x2d], + i2c_detect => sub { vt1211_i2c_detect(@_); }, + }, { + name => "ITE IT8712F", + driver => "it87", + i2c_addrs => [0x28..0x2f], + i2c_detect => sub { it8712_i2c_detect(@_); }, + }, { + name => "FSC Poseidon I", + driver => sub { kernel_version_at_least(2, 6, 24) ? "fschmd" : "fscpos" }, + i2c_addrs => [0x73], + i2c_detect => sub { fsc_detect(@_, 0); }, + }, { + name => "FSC Poseidon II", + driver => "to-be-written", + i2c_addrs => [0x73], + i2c_detect => sub { fsc_detect(@_, 1); }, + }, { + name => "FSC Scylla", + driver => "fschmd", + i2c_addrs => [0x73], + i2c_detect => sub { fsc_detect(@_, 2); }, + }, { + name => "FSC Hermes", + driver => sub { kernel_version_at_least(2, 6, 24) ? "fschmd" : "fscher" }, + i2c_addrs => [0x73], + i2c_detect => sub { fsc_detect(@_, 3); }, + }, { + name => "FSC Heimdal", + driver => "fschmd", + i2c_addrs => [0x73], + i2c_detect => sub { fsc_detect(@_, 4); }, + }, { + name => "FSC Heracles", + driver => "fschmd", + i2c_addrs => [0x73], + i2c_detect => sub { fsc_detect(@_, 5); }, + }, { + name => "ALi M5879", + driver => "to-be-written", + i2c_addrs => [0x2c..0x2d], + i2c_detect => sub { m5879_detect(@_); }, + }, { + name => "SMSC LPC47M15x/192/292/997", + driver => "smsc47m192", + i2c_addrs => [0x2c..0x2d], + i2c_detect => sub { smsc47m192_detect(@_); }, + }, { + name => "SMSC DME1737", + driver => "dme1737", + i2c_addrs => [0x2c..0x2e], + i2c_detect => sub { dme1737_detect(@_, 1); }, + }, { + name => "SMSC SCH5027D-NW", + driver => "dme1737", + i2c_addrs => [0x2c..0x2e], + i2c_detect => sub { dme1737_detect(@_, 2); }, + }, { + name => "Fintek F75121R/F75122R/RG (VID+GPIO)", + driver => "to-be-written", + i2c_addrs => [0x4e], # 0x37 not probed + i2c_detect => sub { fintek_detect(@_, 2); }, + }, { + name => "Fintek F75373S/SG", + driver => "f75375s", + i2c_addrs => [0x2d..0x2e], + i2c_detect => sub { fintek_detect(@_, 3); }, + }, { + name => "Fintek F75375S/SP", + driver => "f75375s", + i2c_addrs => [0x2d..0x2e], + i2c_detect => sub { fintek_detect(@_, 4); }, + }, { + name => "Fintek F75387SG/RG", + driver => "to-be-written", + i2c_addrs => [0x2d..0x2e], + i2c_detect => sub { fintek_detect(@_, 5); }, + }, { + name => "Fintek F75383S/M", + driver => "to-be-written", + i2c_addrs => [0x4c], + i2c_detect => sub { fintek_detect(@_, 6); }, + }, { + name => "Fintek F75384S/M", + driver => "to-be-written", + i2c_addrs => [0x4d], + i2c_detect => sub { fintek_detect(@_, 6); }, + }, { + name => "Fintek custom power control IC", + driver => "to-be-written", + i2c_addrs => [0x2f], + i2c_detect => sub { fintek_detect(@_, 7); }, + }, { + name => "Smart Battery", + driver => "sbs", # ACPI driver, not sure if it always works + i2c_addrs => [0x0b], + i2c_detect => sub { smartbatt_detect(@_); }, + } ); -# Special case chip information goes here and would be included in -# the chip_special_cases routine below -use vars qw(@chip_kern24_ids @chip_kern26_ids - @chip_oldfsc_ids @chip_fschmd_ids); -@chip_kern24_ids = ( - { - name => "Analog Devices ADM1024", - driver => "adm1024", - i2c_addrs => [0x2c..0x2e], - i2c_detect => sub { adm1024_detect(0, @_); }, - }, - { - name => "Winbond W83791D", - driver => "w83781d", - i2c_addrs => [0x2c..0x2f], - i2c_detect => sub { w83781d_detect(7, @_); }, - }, - { - name => "FSC Scylla", - driver => "fscscy", - i2c_addrs => [0x73], - i2c_detect => sub { fscscy_detect(@_); }, - }, - { - name => "IPMI BMC KCS", - driver => "bmcsensors", - isa_addrs => [0x0ca0], - isa_detect => sub { ipmi_kcs_detect(@_); }, - }, - { - name => "IPMI BMC SMIC", - driver => "bmcsensors", - isa_addrs => [0x0ca8], - isa_detect => sub { ipmi_smic_detect(@_); }, - }, +# IPMI interfaces have their own array now +@ipmi_ifs = ( + { + name => "IPMI BMC KCS", + driver => "ipmisensors", + isa_addrs => [0x0ca0], + isa_detect => sub { ipmi_detect(@_); }, + }, { + name => "IPMI BMC SMIC", + driver => "ipmisensors", + isa_addrs => [0x0ca8], + isa_detect => sub { ipmi_detect(@_); }, + } ); -@chip_kern26_ids = ( - { - name => "Analog Devices ADM1024", - driver => "lm87", - i2c_addrs => [0x2c..0x2e], - i2c_detect => sub { adm1024_detect(0, @_); }, - }, - { - name => "Winbond W83791D", - driver => "w83791d", - i2c_addrs => [0x2c..0x2f], - i2c_detect => sub { w83781d_detect(7, @_); }, - }, - { - name => "FSC Scylla", - driver => "fschmd", - i2c_addrs => [0x73], - i2c_detect => sub { fscscy_detect(@_); }, - }, - { - name => "IPMI BMC KCS", - driver => "ipmisensors", - isa_addrs => [0x0ca0], - isa_detect => sub { ipmi_kcs_detect(@_); }, - }, - { - name => "IPMI BMC SMIC", - driver => "ipmisensors", - isa_addrs => [0x0ca8], - isa_detect => sub { ipmi_smic_detect(@_); }, - }, +# Here is a similar list, but for devices which are not hardware monitoring +# chips. We only list popular devices which happen to live at the same I2C +# address as recognized hardware monitoring chips. The idea is to make it +# clear that the chip in question is of no interest for lm-sensors. +@non_hwmon_chip_ids = ( + { + name => "Winbond W83791SD", + i2c_addrs => [0x2c..0x2f], + i2c_detect => sub { w83791sd_detect(@_); }, + }, { + name => "Fintek F75111R/RG/N (GPIO)", + i2c_addrs => [0x37, 0x4e], + i2c_detect => sub { fintek_detect(@_, 1); }, + }, { + name => "ITE IT8201R/IT8203R/IT8206R/IT8266R", + i2c_addrs => [0x4e], + i2c_detect => sub { ite_overclock_detect(@_); }, + }, { + name => "SPD EEPROM", + i2c_addrs => [0x50..0x57], + i2c_detect => sub { eeprom_detect(@_); }, + }, { + name => "EDID EEPROM", + i2c_addrs => [0x50], + i2c_detect => sub { ddcmonitor_detect(@_); }, + } ); -# sigh special case for old separate FSC drivers to new merged one mapping -@chip_oldfsc_ids = ( - { - name => "FSC Poseidon I", - driver => "fscpos", - i2c_addrs => [0x73], - i2c_detect => sub { fscpeg_detect(@_); }, - }, - { - name => "FSC Hermes", - driver => "fscher", - i2c_addrs => [0x73], - i2c_detect => sub { fscher_detect(@_); }, - }, -); - -@chip_fschmd_ids = ( - { - name => "FSC Poseidon I", - driver => "fschmd", - i2c_addrs => [0x73], - i2c_detect => sub { fscpeg_detect(@_); }, - }, - { - name => "FSC Hermes", - driver => "fschmd", - i2c_addrs => [0x73], - i2c_detect => sub { fscher_detect(@_); }, - }, -); - - # This is a list of all recognized superio chips. # Each entry must have the following fields: # name: The full chip name -# driver: The driver name (without .o extension). Put in -# "to-be-written" if it is not yet available. -# Put in "not-a-sensor" if the chip doesn't have hardware monitoring -# capabilities (listing such chips here removes the need of manual -# lookup when people report them). -# Put in exactly "via-smbus-only" if this is a Super-I/O chip whose -# hardware monitoring registers can only be accessed via the SMBus. -# devid: The device ID(s) we have to match (base device) +# driver: The driver name. Put in exactly: +# * "to-be-written" if it is not yet available +# * "not-a-sensor" if the chip doesn't have hardware monitoring +# capabilities (listing such chips here removes the need of manual +# lookup when people report them) +# * "via-smbus-only" if this is a Super-I/O chip whose hardware +# monitoring registers can only be accessed via the SMBus +# devid: The device ID we have to match (base device) # devid_mask (optional): Bitmask to apply before checking the device ID # logdev: The logical device containing the sensors -# alias_detect (optional): For chips which can be both on the ISA and the -# I2C bus, a function which detectes whether two entries are the same. -# The function should take three parameters: The ISA address, the -# I2C bus number, and the I2C address. +# features (optional): Features supported by this device, amongst: +# * FEAT_IN +# * FEAT_FAN +# * FEAT_TEMP +use vars qw(@superio_ids_natsemi @superio_ids_smsc @superio_ids_smsc_ns + @superio_ids_winbond @superio_ids_ite @superio_ids); + +use constant FEAT_IN => (1 << 0); +use constant FEAT_FAN => (1 << 1); +use constant FEAT_TEMP => (1 << 2); +use constant FEAT_SMBUS => (1 << 7); + +@superio_ids_natsemi = ( + { + name => "Nat. Semi. PC8374L Super IO Sensors", + driver => "to-be-written", + devid => 0xf1, + logdev => 0x08, + features => FEAT_IN | FEAT_FAN | FEAT_TEMP, + }, { + name => "Nat. Semi. PC87351 Super IO Fan Sensors", + driver => "to-be-written", + devid => 0xe2, + logdev => 0x08, + }, { + name => "Nat. Semi. PC87360 Super IO Fan Sensors", + driver => "pc87360", + devid => 0xe1, + logdev => 0x09, + features => FEAT_FAN, + }, { + name => "Nat. Semi. PC87363 Super IO Fan Sensors", + driver => "pc87360", + devid => 0xe8, + logdev => 0x09, + features => FEAT_FAN, + }, { + name => "Nat. Semi. PC87364 Super IO Fan Sensors", + driver => "pc87360", + devid => 0xe4, + logdev => 0x09, + features => FEAT_FAN, + }, { + name => "Nat. Semi. PC87365 Super IO Fan Sensors", + driver => "pc87360", + devid => 0xe5, + logdev => 0x09, + features => FEAT_FAN, + }, { + name => "Nat. Semi. PC87365 Super IO Voltage Sensors", + driver => "pc87360", + devid => 0xe5, + logdev => 0x0d, + features => FEAT_IN, + }, { + name => "Nat. Semi. PC87365 Super IO Thermal Sensors", + driver => "pc87360", + devid => 0xe5, + logdev => 0x0e, + features => FEAT_TEMP, + }, { + name => "Nat. Semi. PC87366 Super IO Fan Sensors", + driver => "pc87360", + devid => 0xe9, + logdev => 0x09, + features => FEAT_FAN, + }, { + name => "Nat. Semi. PC87366 Super IO Voltage Sensors", + driver => "pc87360", + devid => 0xe9, + logdev => 0x0d, + features => FEAT_IN, + }, { + name => "Nat. Semi. PC87366 Super IO Thermal Sensors", + driver => "pc87360", + devid => 0xe9, + logdev => 0x0e, + features => FEAT_TEMP, + }, { + name => "Nat. Semi. PC87372 Super IO Fan Sensors", + driver => "to-be-written", + devid => 0xf0, + logdev => 0x09, + features => FEAT_FAN, + }, { + name => "Nat. Semi. PC87373 Super IO Fan Sensors", + driver => "to-be-written", + devid => 0xf3, + logdev => 0x09, + features => FEAT_FAN, + }, { + name => "Nat. Semi. PC87591 Super IO", + driver => "to-be-written", + devid => 0xec, + logdev => 0x0f, + }, { + name => "Nat. Semi. PC87317 Super IO", + driver => "not-a-sensor", + devid => 0xd0, + }, { + name => "Nat. Semi. PC97317 Super IO", + driver => "not-a-sensor", + devid => 0xdf, + }, { + name => "Nat. Semi. PC8739x Super IO", + driver => "not-a-sensor", + devid => 0xea, + }, { + name => "Nat. Semi. PC8741x Super IO", + driver => "not-a-sensor", + devid => 0xee, + }, { + name => "Nat. Semi. PC87427 Super IO Fan Sensors", + driver => "pc87427", + devid => 0xf2, + logdev => 0x09, + features => FEAT_FAN, + }, { + name => "Nat. Semi. PC87427 Super IO Health Sensors", + driver => "to-be-written", + devid => 0xf2, + logdev => 0x14, + features => FEAT_IN | FEAT_TEMP, + } +); + +@superio_ids_smsc = ( + { + name => "SMSC DME1737 Super IO", + # Hardware monitoring features are accessed on the SMBus + driver => "via-smbus-only", + devid => 0x78, + }, { + name => "SMSC DME1737 Super IO", + # The DME1737 shows up twice in this list because it can return either + # 0x78 or 0x77 as its device ID. + # Hardware monitoring features are accessed on the SMBus + driver => "via-smbus-only", + devid => 0x77, + }, { + name => "SMSC EMC2700LPC Super IO", + # no datasheet + devid => 0x67, + }, { + name => "SMSC FDC37B72x Super IO", + driver => "not-a-sensor", + devid => 0x4c, + }, { + name => "SMSC FDC37B78x Super IO", + driver => "not-a-sensor", + devid => 0x44, + }, { + name => "SMSC FDC37C672 Super IO", + driver => "not-a-sensor", + devid => 0x40, + }, { + name => "SMSC FDC37M707 Super IO", + driver => "not-a-sensor", + devid => 0x42, + }, { + name => "SMSC FDC37M81x Super IO", + driver => "not-a-sensor", + devid => 0x4d, + }, { + name => "SMSC LPC47B27x Super IO Fan Sensors", + driver => "smsc47m1", + devid => 0x51, + logdev => 0x0a, + features => FEAT_FAN, + }, { + name => "SMSC LPC47B34x Super IO", + driver => "not-a-sensor", + devid => 0x56, + }, { + name => "SMSC LPC47B357/M967 Super IO", + driver => "not-a-sensor", + devid => 0x5d, + }, { + name => "SMSC LPC47B367-NC Super IO", + driver => "not-a-sensor", + devid => 0x6d, + }, { + name => "SMSC LPC47B37x Super IO Fan Sensors", + driver => "to-be-written", + devid => 0x52, + logdev => 0x0a, + features => FEAT_FAN, + }, { + name => "SMSC LPC47B397-NC Super IO", + driver => "smsc47b397", + devid => 0x6f, + logdev => 0x08, + features => FEAT_FAN | FEAT_TEMP, + }, { + name => "SMSC LPC47M10x/112/13x Super IO Fan Sensors", + driver => "smsc47m1", + devid => 0x59, + logdev => 0x0a, + features => FEAT_FAN, + }, { + name => "SMSC LPC47M14x Super IO Fan Sensors", + driver => "smsc47m1", + devid => 0x5f, + logdev => 0x0a, + features => FEAT_FAN, + }, { + name => "SMSC LPC47M15x/192/997 Super IO Fan Sensors", + driver => "smsc47m1", + devid => 0x60, + logdev => 0x0a, + features => FEAT_FAN, + }, { + name => "SMSC LPC47M172 Super IO Fan Sensors", + driver => "to-be-written", + devid => 0x14, + logdev => 0x0a, + features => FEAT_FAN, + }, { + name => "SMSC LPC47M182 Super IO Fan Sensors", + driver => "to-be-written", + devid => 0x74, + logdev => 0x0a, + features => FEAT_FAN, + }, { + name => "SMSC LPC47M233 Super IO Sensors", + driver => "smsc47m1", + devid => 0x6b80, + devid_mask => 0xff80, + logdev => 0x0a, + features => FEAT_IN | FEAT_FAN | FEAT_TEMP, + }, { + name => "SMSC LPC47M292 Super IO Fan Sensors", + driver => "smsc47m1", + devid => 0x6b00, + devid_mask => 0xff80, + logdev => 0x0a, + features => FEAT_FAN, + }, { + name => "SMSC LPC47M584-NC Super IO", + # No datasheet + devid => 0x76, + }, { + name => "SMSC LPC47N252 Super IO Fan Sensors", + driver => "to-be-written", + devid => 0x0e, + logdev => 0x09, + features => FEAT_FAN, + }, { + name => "SMSC LPC47S42x Super IO Fan Sensors", + driver => "to-be-written", + devid => 0x57, + logdev => 0x0a, + features => FEAT_FAN, + }, { + name => "SMSC LPC47S45x Super IO Fan Sensors", + driver => "to-be-written", + devid => 0x62, + logdev => 0x0a, + features => FEAT_FAN, + }, { + name => "SMSC LPC47U33x Super IO Fan Sensors", + driver => "to-be-written", + devid => 0x54, + logdev => 0x0a, + features => FEAT_FAN, + }, { + name => "SMSC SCH3112 Super IO", + driver => "dme1737", + devid => 0x7c, + logdev => 0x0a, + features => FEAT_IN | FEAT_FAN | FEAT_TEMP, + }, { + name => "SMSC SCH3114 Super IO", + driver => "dme1737", + devid => 0x7d, + logdev => 0x0a, + features => FEAT_IN | FEAT_FAN | FEAT_TEMP, + }, { + name => "SMSC SCH3116 Super IO", + driver => "dme1737", + devid => 0x7f, + logdev => 0x0a, + features => FEAT_IN | FEAT_FAN | FEAT_TEMP, + }, { + name => "SMSC SCH4307 Super IO Fan Sensors", + driver => "to-be-written", + devid => 0x90, + logdev => 0x08, + features => FEAT_FAN, + }, { + name => "SMSC SCH5027D-NW Super IO", + # Hardware monitoring features are accessed on the SMBus + driver => "via-smbus-only", + devid => 0x89, + }, { + name => "SMSC SCH5127 Super IO", + driver => "dme1737", + devid => 0x86, + logdev => 0x0a, + features => FEAT_IN | FEAT_FAN | FEAT_TEMP, + }, { + name => "SMSC SCH5307-NS Super IO", + driver => "smsc47b397", + devid => 0x81, + logdev => 0x08, + features => FEAT_FAN | FEAT_TEMP, + }, { + name => "SMSC SCH5317 Super IO", + driver => "smsc47b397", + devid => 0x85, + logdev => 0x08, + features => FEAT_FAN | FEAT_TEMP, + }, { + name => "SMSC SCH5317 Super IO", + # The SCH5317 shows up twice in this list because it can return either + # 0x85 or 0x8c as its device ID. + driver => "smsc47b397", + devid => 0x8c, + logdev => 0x08, + features => FEAT_FAN | FEAT_TEMP, + }, { + name => "SMSC SCH5504-NS Super IO", + # No datasheet + driver => "not-a-sensor", + devid => 0x79, + }, { + name => "SMSC SCH5514D-NS Super IO", + # No datasheet + driver => "not-a-sensor", + devid => 0x83, + } +); + +# Non-standard SMSC chip list. These chips differ from the standard ones +# listed above in that the device ID register address is 0x0d instead of +# 0x20 (as specified by the ISA PNP spec). +@superio_ids_smsc_ns = ( + { + name => "SMSC FDC37C665 Super IO", + driver => "not-a-sensor", + devid => 0x65, + }, { + name => "SMSC FDC37C666 Super IO", + driver => "not-a-sensor", + devid => 0x66, + }, { + name => "SMSC FDC37C669 Super IO", + driver => "not-a-sensor", + devid => 0x03, + }, { + name => "SMSC FDC37N769 Super IO", + driver => "not-a-sensor", + devid => 0x28, + }, { + name => "SMSC LPC47N227 Super IO", + driver => "not-a-sensor", + devid => 0x5a, + } +); + +@superio_ids_winbond = ( + { + name => "VIA VT1211 Super IO Sensors", + driver => "vt1211", + devid => 0x3c, + logdev => 0x0b, + features => FEAT_IN | FEAT_FAN | FEAT_TEMP, + }, { + name => "VIA VT1212 Super IO Lite", # in 100 pin TQFP package + driver => "not-a-sensor", + devid => 0x3e, + }, { + name => "VIA VT1212 Super IO Lite", # in 48 pin LQFP package + driver => "not-a-sensor", + devid => 0x3f, + }, { + name => "Winbond W83627HF/F/HG/G Super IO Sensors", + driver => "w83627hf", + devid => 0x52, + logdev => 0x0b, + features => FEAT_IN | FEAT_FAN | FEAT_TEMP, + }, { + name => "Winbond W83627THF/THG Super IO Sensors", + driver => "w83627hf", + devid => 0x82, + logdev => 0x0b, + features => FEAT_IN | FEAT_FAN | FEAT_TEMP, + }, { + name => "Winbond W83637HF/HG Super IO Sensors", + driver => "w83627hf", + devid => 0x70, + logdev => 0x0b, + features => FEAT_IN | FEAT_FAN | FEAT_TEMP, + }, { + name => "Winbond W83687THF Super IO Sensors", + driver => "w83627hf", + devid => 0x85, + logdev => 0x0b, + features => FEAT_IN | FEAT_FAN | FEAT_TEMP, + }, { + name => "Winbond W83697HF/F/HG Super IO Sensors", + driver => "w83627hf", + devid => 0x60, + logdev => 0x0b, + features => FEAT_IN | FEAT_FAN | FEAT_TEMP, + }, { + name => "Winbond W83697SF/UF/UG Super IO PWM", + driver => "to-be-written", + devid => 0x68, + logdev => 0x0b, + features => FEAT_IN | FEAT_FAN | FEAT_TEMP, + }, { + name => "Winbond W83627EHF/EF/EHG/EG Super IO Sensors", + driver => "w83627ehf", + # W83627EHF datasheet says 0x886x but 0x8853 was seen, thus the + # broader mask. W83627EHG was seen with ID 0x8863. + devid => 0x8840, + devid_mask => 0xFFC0, + logdev => 0x0b, + features => FEAT_IN | FEAT_FAN | FEAT_TEMP, + }, { + name => "Winbond W83627DHG Super IO Sensors", + driver => "w83627ehf", + devid => 0xA020, + devid_mask => 0xFFF0, + logdev => 0x0b, + features => FEAT_IN | FEAT_FAN | FEAT_TEMP, + }, { + name => "Winbond W83667HG Super IO Sensors", + driver => "to-be-written", + devid => 0xA510, + devid_mask => 0xFFF0, + logdev => 0x0b, + features => FEAT_IN | FEAT_FAN | FEAT_TEMP, + }, { + name => "Winbond W83L517D Super IO", + driver => "not-a-sensor", + devid => 0x61, + }, { + name => "Fintek F71805F/FG Super IO Sensors", + driver => "f71805f", + devid => 0x0406, + logdev => 0x04, + features => FEAT_IN | FEAT_FAN | FEAT_TEMP, + }, { + name => "Fintek F71862FG Super IO Sensors", + driver => "to-be-written", + devid => 0x0601, + logdev => 0x04, + features => FEAT_IN | FEAT_FAN | FEAT_TEMP, + }, { + name => "Fintek F71806FG/F71872FG Super IO Sensors", + driver => "f71805f", + devid => 0x0341, + logdev => 0x04, + features => FEAT_IN | FEAT_FAN | FEAT_TEMP, + }, { + name => "Fintek F71858DG Super IO Sensors", + driver => "to-be-written", + devid => 0x0507, + logdev => 0x02, + features => FEAT_IN | FEAT_FAN | FEAT_TEMP, + }, { + name => "Fintek F71882FG/F71883FG Super IO Sensors", + driver => "f71882fg", + devid => 0x0541, + logdev => 0x04, + features => FEAT_IN | FEAT_FAN | FEAT_TEMP, + }, { + name => "Fintek F81216D Super IO", + driver => "not-a-sensor", + devid => 0x0208, + }, { + name => "Fintek F81218D Super IO", + driver => "not-a-sensor", + devid => 0x0206, + }, { + name => "Asus F8000 Super IO", + driver => "f71882fg", + devid => 0x0581, + logdev => 0x04, + features => FEAT_IN | FEAT_FAN | FEAT_TEMP, + }, { + # Shouldn't be in this family, but seems to be still. + name => "ITE IT8708F Super IO", + driver => "not-a-sensor", + devid => 0x8708, + }, { + # Shouldn't be in this family, but seems to be still. + name => "ITE IT8710F Super IO", + driver => "not-a-sensor", + devid => 0x8710, + } +); + +@superio_ids_ite = ( + { + name => "ITE IT8702F Super IO Fan Sensors", + driver => "to-be-written", + devid => 0x8702, + logdev => 0x04, + features => FEAT_FAN, + }, { + name => "ITE IT8705F Super IO Sensors", + driver => "it87", + devid => 0x8705, + logdev => 0x04, + features => FEAT_IN | FEAT_FAN | FEAT_TEMP, + }, { + name => "ITE IT8712F Super IO Sensors", + driver => "it87", + devid => 0x8712, + logdev => 0x04, + features => FEAT_IN | FEAT_FAN | FEAT_TEMP, + }, { + name => "ITE IT8716F Super IO Sensors", + driver => "it87", + devid => 0x8716, + logdev => 0x04, + features => FEAT_IN | FEAT_FAN | FEAT_TEMP, + }, { + name => "ITE IT8718F Super IO Sensors", + driver => "it87", + devid => 0x8718, + logdev => 0x04, + features => FEAT_IN | FEAT_FAN | FEAT_TEMP, + }, { + name => "ITE IT8720F Super IO Sensors", + driver => "it87", + devid => 0x8720, + logdev => 0x04, + features => FEAT_IN | FEAT_FAN | FEAT_TEMP, + }, { + name => "ITE IT8726F Super IO Sensors", + driver => "it87", + devid => 0x8726, + logdev => 0x04, + features => FEAT_IN | FEAT_FAN | FEAT_TEMP, + } +); + # Entries are grouped by family. Each family entry has the following fields: # family: The family name # guess (optional): Typical logical device address. This lets us do -# generic probing if we fail to recognize the chip. +# generic probing if we fail to recognize the chip. # enter: The password sequence to write to the address register # chips: Array of chips # The order of families matters, because we stop as soon as one family # succeeds. So we have to list families with shorter password sequences # first. @superio_ids = ( - { - family => "National Semiconductor", - enter => - { - 0x2e => [], - 0x4e => [], - }, - chips => - [ - { - name => "Nat. Semi. PC8374L Super IO Sensors", - driver => "to-be-written", - devid => 0xf1, - logdev => 0x08, - }, - { - name => "Nat. Semi. PC87351 Super IO Fan Sensors", - driver => "to-be-written", - devid => 0xe2, - logdev => 0x08, - }, - { - name => "Nat. Semi. PC87360 Super IO Fan Sensors", - driver => "pc87360", - devid => 0xe1, - logdev => 0x09, - }, - { - name => "Nat. Semi. PC87363 Super IO Fan Sensors", - driver => "pc87360", - devid => 0xe8, - logdev => 0x09, - }, - { - name => "Nat. Semi. PC87364 Super IO Fan Sensors", - driver => "pc87360", - devid => 0xe4, - logdev => 0x09, - }, - { - name => "Nat. Semi. PC87365 Super IO Fan Sensors", - driver => "pc87360", - devid => 0xe5, - logdev => 0x09, - }, - { - name => "Nat. Semi. PC87365 Super IO Voltage Sensors", - driver => "pc87360", - devid => 0xe5, - logdev => 0x0d, - }, - { - name => "Nat. Semi. PC87365 Super IO Thermal Sensors", - driver => "pc87360", - devid => 0xe5, - logdev => 0x0e, - }, - { - name => "Nat. Semi. PC87366 Super IO Fan Sensors", - driver => "pc87360", - devid => 0xe9, - logdev => 0x09, - }, - { - name => "Nat. Semi. PC87366 Super IO Voltage Sensors", - driver => "pc87360", - devid => 0xe9, - logdev => 0x0d, - }, - { - name => "Nat. Semi. PC87366 Super IO Thermal Sensors", - driver => "pc87360", - devid => 0xe9, - logdev => 0x0e, - }, - { - name => "Nat. Semi. PC87372 Super IO Fan Sensors", - driver => "to-be-written", - devid => 0xf0, - logdev => 0x09, - }, - { - name => "Nat. Semi. PC87373 Super IO Fan Sensors", - driver => "to-be-written", - devid => 0xf3, - logdev => 0x09, - }, - { - name => "Nat. Semi. PC87591 Super IO", - driver => "to-be-written", - devid => 0xec, - logdev => 0x0f, - }, - { - name => "Nat. Semi. PC87317 Super IO", - driver => "not-a-sensor", - devid => 0xd0, - }, - { - name => "Nat. Semi. PC97317 Super IO", - driver => "not-a-sensor", - devid => 0xdf, - }, - { - name => "Nat. Semi. PC8739x Super IO", - driver => "not-a-sensor", - devid => 0xea, - }, - { - name => "Nat. Semi. PC8741x Super IO", - driver => "not-a-sensor", - devid => 0xee, - }, - { - name => "Nat. Semi. PC87427 Super IO Fan Sensors", - driver => "pc87427", - devid => 0xf2, - logdev => 0x09, - }, - { - name => "Nat. Semi. PC87427 Super IO Health Sensors", - driver => "to-be-written", - devid => 0xf2, - logdev => 0x14, - }, - ], - }, - { - family => "SMSC", - enter => - { - 0x2e => [0x55], - 0x4e => [0x55], - }, - chips => - [ - { - name => "SMSC DME1737 Super IO", - # Hardware monitoring features are accessed on the SMBus - driver => "via-smbus-only", - devid => 0x78, - }, - { - name => "SMSC DME1737 Super IO", - # The DME1737 shows up twice in this list because it can return either - # 0x78 or 0x77 as its device ID. - # Hardware monitoring features are accessed on the SMBus - driver => "via-smbus-only", - devid => 0x77, - }, - { - name => "SMSC EMC2700LPC Super IO", - # no datasheet - devid => 0x67, - }, - { - name => "SMSC FDC37B72x Super IO", - driver => "not-a-sensor", - devid => 0x4c, - }, - { - name => "SMSC FDC37B78x Super IO", - driver => "not-a-sensor", - devid => 0x44, - }, - { - name => "SMSC FDC37C672 Super IO", - driver => "not-a-sensor", - devid => 0x40, - }, - { - name => "SMSC FDC37M707 Super IO", - driver => "not-a-sensor", - devid => 0x42, - }, - { - name => "SMSC FDC37M81x Super IO", - driver => "not-a-sensor", - devid => 0x4d, - }, - { - name => "SMSC LPC47B27x Super IO Fan Sensors", - driver => "smsc47m1", - devid => 0x51, - logdev => 0x0a, - }, - { - name => "SMSC LPC47B34x Super IO", - driver => "not-a-sensor", - devid => 0x56, - }, - { - name => "SMSC LPC47B357/M967 Super IO", - driver => "not-a-sensor", - devid => 0x5d, - }, - { - name => "SMSC LPC47B367-NC Super IO", - driver => "not-a-sensor", - devid => 0x6d, - }, - { - name => "SMSC LPC47B37x Super IO Fan Sensors", - driver => "to-be-written", - devid => 0x52, - logdev => 0x0a, - }, - { - name => "SMSC LPC47B397-NC Super IO", - driver => "smsc47b397", - devid => 0x6f, - logdev => 0x08, - }, - { - name => "SMSC LPC47M10x/112/13x Super IO Fan Sensors", - driver => "smsc47m1", - devid => 0x59, - logdev => 0x0a, - }, - { - name => "SMSC LPC47M14x Super IO Fan Sensors", - driver => "smsc47m1", - devid => 0x5f, - logdev => 0x0a, - }, - { - name => "SMSC LPC47M15x/192/997 Super IO Fan Sensors", - driver => "smsc47m1", - devid => 0x60, - logdev => 0x0a, - }, - { - name => "SMSC LPC47M172 Super IO Fan Sensors", - driver => "to-be-written", - devid => 0x14, - logdev => 0x0a, - }, - { - name => "SMSC LPC47M182 Super IO Fan Sensors", - driver => "to-be-written", - devid => 0x74, - logdev => 0x0a, - }, - { - name => "SMSC LPC47M233 Super IO Sensors", - driver => "to-be-written", - devid => 0x6b80, - devid_mask => 0xff80, - logdev => 0x0a, - }, - { - name => "SMSC LPC47M292 Super IO Fan Sensors", - driver => "smsc47m1", - devid => 0x6b00, - devid_mask => 0xff80, - logdev => 0x0a, - }, - { - name => "SMSC LPC47M584-NC Super IO", - # No datasheet - devid => 0x76, - }, - { - name => "SMSC LPC47N252 Super IO Fan Sensors", - driver => "to-be-written", - devid => 0x0e, - logdev => 0x09, - }, - { - name => "SMSC LPC47S42x Super IO Fan Sensors", - driver => "to-be-written", - devid => 0x57, - logdev => 0x0a, - }, - { - name => "SMSC LPC47S45x Super IO Fan Sensors", - driver => "to-be-written", - devid => 0x62, - logdev => 0x0a, - }, - { - name => "SMSC LPC47U33x Super IO Fan Sensors", - driver => "to-be-written", - devid => 0x54, - logdev => 0x0a, - }, - { - name => "SMSC SCH3112 Super IO", - driver => "dme1737", - devid => 0x7c, - logdev => 0x0a, - }, - { - name => "SMSC SCH3114 Super IO", - driver => "dme1737", - devid => 0x7d, - logdev => 0x0a, - }, - { - name => "SMSC SCH3116 Super IO", - driver => "dme1737", - devid => 0x7f, - logdev => 0x0a, - }, - { - name => "SMSC SCH4307 Super IO Fan Sensors", - driver => "to-be-written", - devid => 0x90, - logdev => 0x08, - }, - { - name => "SMSC SCH5027D-NW Super IO", - # Hardware monitoring features are accessed on the SMBus - driver => "via-smbus-only", - devid => 0x89, - }, - { - name => "SMSC SCH5127 Super IO", - driver => "dme1737", - devid => 0x86, - logdev => 0x0a, - }, - { - name => "SMSC SCH5307-NS Super IO", - driver => "smsc47b397", - devid => 0x81, - logdev => 0x08, - }, - { - name => "SMSC SCH5317 Super IO", - driver => "smsc47b397", - devid => 0x85, - logdev => 0x08, - }, - { - name => "SMSC SCH5317 Super IO", - # The SCH5317 shows up twice in this list because it can return either - # 0x85 or 0x8c as its device ID. - driver => "smsc47b397", - devid => 0x8c, - logdev => 0x08, - }, - { - name => "SMSC SCH5504-NS Super IO", - # No datasheet - driver => "not-a-sensor", - devid => 0x79, - }, - { - name => "SMSC SCH5514D-NS Super IO", - # No datasheet - driver => "not-a-sensor", - devid => 0x83, - }, - ], - # Non-standard SMSC detection callback and chip list. These chips differ - # from the standard ones listed above in that the device ID register - # address is 0x0d instead of 0x20 (as specified by the ISA PNP spec). - ns_detect => \&smsc_ns_detect_superio, - ns_chips => - [ - { - name => "SMSC FDC37C665 Super IO", - driver => "not-a-sensor", - devid => 0x65, - }, - { - name => "SMSC FDC37C666 Super IO", - driver => "not-a-sensor", - devid => 0x66, - }, - { - name => "SMSC FDC37C669 Super IO", - driver => "not-a-sensor", - devid => 0x03, - }, - { - name => "SMSC FDC37N769 Super IO", - driver => "not-a-sensor", - devid => 0x28, - }, - { - name => "SMSC LPC47N227 Super IO", - driver => "not-a-sensor", - devid => 0x5a, - }, - ], - }, - { - family => "VIA/Winbond/Fintek", - guess => 0x290, - enter => - { - 0x2e => [0x87, 0x87], - 0x4e => [0x87, 0x87], - }, - chips => - [ - { - name => "VIA VT1211 Super IO Sensors", - driver => "vt1211", - devid => 0x3c, - logdev => 0x0b, - alias_detect => sub { vt1211_alias_detect(0, @_); }, - }, - { - name => "VIA VT1212 Super IO Lite", # in 100 pin TQFP package - driver => "not-a-sensor", - devid => 0x3e, - }, - { - name => "VIA VT1212 Super IO Lite", # in 48 pin LQFP package - driver => "not-a-sensor", - devid => 0x3f, - }, - { - name => "Winbond W83627HF/F/HG/G Super IO Sensors", - driver => "w83627hf", - devid => 0x52, - logdev => 0x0b, - alias_detect => sub { w83781d_alias_detect(3, @_); }, - }, - { - name => "Winbond W83627THF/THG Super IO Sensors", - driver => "w83627hf", - devid => 0x82, - logdev => 0x0b, - }, - { - name => "Winbond W83637HF/HG Super IO Sensors", - driver => "w83627hf", - devid => 0x70, - logdev => 0x0b, - }, - { - name => "Winbond W83687THF Super IO Sensors", - driver => "w83627hf", - devid => 0x85, - logdev => 0x0b, - }, - { - name => "Winbond W83697HF/F/HG Super IO Sensors", - driver => "w83627hf", - devid => 0x60, - logdev => 0x0b, - }, - { - name => "Winbond W83697SF/UF/UG Super IO PWM", - driver => "to-be-written", - devid => 0x68, - logdev => 0x0b, - }, - { - name => "Winbond W83627EHF/EF/EHG/EG Super IO Sensors", - driver => "w83627ehf", - # W83627EHF datasheet says 0x886x but 0x8853 was seen, thus the - # broader mask. W83627EHG was seen with ID 0x8863. - devid => 0x8840, - devid_mask => 0xFFC0, - logdev => 0x0b, - alias_detect => sub { w83781d_alias_detect(9, @_); }, - }, - { - name => "Winbond W83627DHG Super IO Sensors", - driver => "w83627ehf", - devid => 0xA020, - devid_mask => 0xFFF0, - logdev => 0x0b, - alias_detect => sub { w83781d_alias_detect(10, @_); }, - }, - { - name => "Winbond W83L517D Super IO", - driver => "not-a-sensor", - devid => 0x61, - }, - { - name => "Fintek F71805F/FG Super IO Sensors", - driver => "f71805f", - devid => 0x0406, - logdev => 0x04, - }, - { - name => "Fintek F71862FG Super IO Sensors", - driver => "to-be-written", - devid => 0x0601, - logdev => 0x04, - }, - { - name => "Fintek F71806FG/F71872FG Super IO Sensors", - driver => "f71805f", - devid => 0x0341, - logdev => 0x04, - }, - { - name => "Fintek F71858DG Super IO Sensors", - driver => "to-be-written", - devid => 0x0507, - logdev => 0x02, - }, - { - name => "Fintek F71882FG/F71883FG Super IO Sensors", - driver => "f71882fg", - devid => 0x0541, - logdev => 0x04, - }, - { - name => "Fintek F81216D Super IO", - driver => "not-a-sensor", - devid => 0x0208, - }, - { - name => "Fintek F81218D Super IO", - driver => "not-a-sensor", - devid => 0x0206, - }, - { - name => "Asus F8000 Super IO", - driver => "f71882fg", - devid => 0x0581, - logdev => 0x04, - }, - { - # Shouldn't be in this family, but seems to be still. - name => "ITE IT8708F Super IO", - driver => "not-a-sensor", - devid => 0x8708, - }, - { - # Shouldn't be in this family, but seems to be still. - name => "ITE IT8710F Super IO", - driver => "not-a-sensor", - devid => 0x8710, - }, - ], - }, - { - family => "ITE", - guess => 0x290, - enter => - { - 0x2e => [0x87, 0x01, 0x55, 0x55], - 0x4e => [0x87, 0x01, 0x55, 0xaa], - }, - chips => - [ - { - name => "ITE IT8702F Super IO Sensors", - driver => "to-be-written", - devid => 0x8702, - logdev => 0x04, - }, - { - name => "ITE IT8705F Super IO Sensors", - driver => "it87", - devid => 0x8705, - logdev => 0x04, - }, - { - name => "ITE IT8712F Super IO Sensors", - driver => "it87", - devid => 0x8712, - logdev => 0x04, - alias_detect => sub { ite_alias_detect(0, @_); }, - }, - { - name => "ITE IT8716F Super IO Sensors", - driver => "it87", - devid => 0x8716, - logdev => 0x04, - }, - { - name => "ITE IT8718F Super IO Sensors", - driver => "it87", - devid => 0x8718, - logdev => 0x04, - }, - { - name => "ITE IT8720F Super IO Sensors", - driver => "it87", - devid => 0x8720, - logdev => 0x04, - }, - { - name => "ITE IT8726F Super IO Sensors", - driver => "it87", - devid => 0x8726, - logdev => 0x04, - }, - ], - }, + { + family => "National Semiconductor", + enter => + { + 0x2e => [], + 0x4e => [], + }, + chips => \@superio_ids_natsemi, + }, { + family => "SMSC", + enter => + { + 0x2e => [0x55], + 0x4e => [0x55], + }, + chips => \@superio_ids_smsc, + ns_detect => \&smsc_ns_detect_superio, + ns_chips => \@superio_ids_smsc_ns, + }, { + family => "VIA/Winbond/Fintek", + guess => 0x290, + enter => + { + 0x2e => [0x87, 0x87], + 0x4e => [0x87, 0x87], + }, + chips => \@superio_ids_winbond, + }, { + family => "ITE", + guess => 0x290, + enter => + { + 0x2e => [0x87, 0x01, 0x55, 0x55], + 0x4e => [0x87, 0x01, 0x55, 0xaa], + }, + chips => \@superio_ids_ite, + } ); -# Drivers for CPU embedded sensors +# Drivers for bridge, CPU and memory embedded sensors # Each entry must have the following fields: -# name: The CPU family name +# name: The device name # driver: The driver name. Put "to-be-written" if no driver is available. # detect: Detection callback function. No parameter will be passed to -# this function, it must use global lists of PCI devices, CPU, -# etc. It must return a confidence value, undef if no supported -# CPU is found. +# this function, it must use global lists of PCI devices, CPU, +# etc. It must return a confidence value, undef if no supported +# CPU is found. +use vars qw(@cpu_ids); + @cpu_ids = ( - { - name => "Silicon Integrated Systems SIS5595", - driver => "sis5595", - detect => sub { sis5595_pci_detect(); }, - }, - { - name => "VIA VT82C686 Integrated Sensors", - driver => "via686a", - detect => sub { via686a_pci_detect(); }, - }, - { - name => "VIA VT8231 Integrated Sensors", - driver => "vt8231", - detect => sub { via8231_pci_detect(); }, - }, - { - name => "AMD K8 thermal sensors", - driver => "k8temp", - detect => sub { k8temp_pci_detect(); }, - }, - { - name => "AMD K10 thermal sensors", - driver => "to-be-written", - detect => sub { k10temp_pci_detect(); }, - }, - { - name => "Intel Core family thermal sensor", - driver => "coretemp", - detect => sub { coretemp_detect(); }, - }, - { - name => "Intel AMB FB-DIMM thermal sensor", - driver => "i5k_amb", - detect => sub { intel_amb_detect(); }, - }, - { - name => "VIA C7 thermal and voltage sensors", - driver => "c7temp", - detect => sub { c7temp_detect(); }, - }, + { + name => "Silicon Integrated Systems SIS5595", + driver => "sis5595", + detect => \&sis5595_pci_detect, + }, { + name => "VIA VT82C686 Integrated Sensors", + driver => "via686a", + detect => \&via686a_pci_detect, + }, { + name => "VIA VT8231 Integrated Sensors", + driver => "vt8231", + detect => \&via8231_pci_detect, + }, { + name => "AMD K8 thermal sensors", + driver => "k8temp", + detect => \&k8temp_pci_detect, + }, { + name => "AMD K10 thermal sensors", + driver => "to-be-written", + detect => \&k10temp_pci_detect, + }, { + name => "Intel Core family thermal sensor", + driver => "coretemp", + detect => \&coretemp_detect, + }, { + name => "Intel AMB FB-DIMM thermal sensor", + driver => "i5k_amb", + detect => \&intel_amb_detect, + }, { + name => "VIA C7 thermal and voltage sensors", + driver => "c7temp", + detect => \&c7temp_detect, + } ); ####################### # AUXILIARY FUNCTIONS # ####################### -sub swap_bytes -{ - return (($_[0] & 0xff00) >> 8) + (($_[0] & 0x00ff) << 8) -} - # $_[0] is the sought value -# @_[1..] is the list to seek in -# Returns: 0 on failure, 1 if found. -# Note: Every use of this sub probably indicates the use of the wrong -# datastructure +# $_[1..] is the list to seek in +# Returns: 1 if found, 0 if not. sub contains { - my $sought = shift; - foreach (@_) { - return 1 if $sought eq $_; - } - return 0; + my $sought = shift; + local $_; + + foreach (@_) { + return 1 if $sought eq $_; + } + return 0; } # Address can be decimal or hexadecimal sub valid_address { - my $value = shift; + my $value = shift; - if ($value !~ m/^(0x[0-9a-f]+|[0-9]+)$/i) { - print "$value is not a valid address, sorry.\n"; - exit -1; - } - $value = oct($value) if $value =~ /^0x/i; + if ($value !~ m/^(0x[0-9a-f]+|[0-9]+)$/i) { + print "$value is not a valid address, sorry.\n"; + exit -1; + } + $value = oct($value) if $value =~ m/^0x/i; - return $value; + return $value; } sub parse_not_to_scan { - my ($min, $max, $to_parse) = @_; - my @ranges = split /\s*, \s*/, $to_parse; - my @res; - my $range; - foreach $range (@ranges) { - my ($start, $end) = split /\s*-\s*/, $range; - $start = valid_address($start); - if (defined $end) { - $end = valid_address($end); - if ($end <= $start) { - print "$start-$end is not a valid range, sorry.\n"; - exit -1; - } - $start = $min if $start < $min; - $end = $max if $end > $max; - push @res, ($start..$end); - } else { - push @res, $start if $start >= $min and $start <= $max; - } - } - return sort { $a <=> $b } @res; + my ($min, $max, $to_parse) = @_; + my @ranges = split /\s*, \s*/, $to_parse; + my @res; + my $range; + + foreach $range (@ranges) { + my ($start, $end) = split /\s*-\s*/, $range; + $start = valid_address($start); + if (defined $end) { + $end = valid_address($end); + if ($end <= $start) { + print "$start-$end is not a valid range, sorry.\n"; + exit -1; + } + $start = $min if $start < $min; + $end = $max if $end > $max; + push @res, ($start..$end); + } else { + push @res, $start if $start >= $min and $start <= $max; + } + } + + return sort { $a <=> $b } @res; } -# @_[0]: Reference to list 1 -# @_[1]: Reference to list 2 +# $_[0]: Reference to list 1 +# $_[1]: Reference to list 2 # Result: 0 if they have no elements in common, 1 if they have # Elements must be numeric. sub any_list_match { - my ($list1, $list2) = @_; - my ($el1, $el2); - foreach $el1 (@$list1) { - foreach $el2 (@$list2) { - return 1 if $el1 == $el2; - } - } - return 0; + my ($list1, $list2) = @_; + my ($el1, $el2); + + foreach $el1 (@$list1) { + foreach $el2 (@$list2) { + return 1 if $el1 == $el2; + } + } + return 0; } ################### -# I/O port access # +# I/O PORT ACCESS # ################### sub initialize_ioports { - sysopen (IOPORTS, "/dev/port", O_RDWR) - or die "/dev/port: $!\n"; - binmode IOPORTS; + sysopen(IOPORTS, "/dev/port", O_RDWR) + or die "/dev/port: $!\n"; + binmode(IOPORTS); } sub close_ioports { - close (IOPORTS) - or print "Warning: $!\n"; + close(IOPORTS); } # $_[0]: port to read # Returns: -1 on failure, read value on success. sub inb { - my ($res, $nrchars); - sysseek IOPORTS, $_[0], 0 or return -1; - $nrchars = sysread IOPORTS, $res, 1; - return -1 if not defined $nrchars or $nrchars != 1; - $res = unpack "C", $res; - return $res; + my ($res, $nrchars); + sysseek(IOPORTS, $_[0], 0) or return -1; + $nrchars = sysread(IOPORTS, $res, 1); + return -1 if not defined $nrchars or $nrchars != 1; + $res = unpack("C", $res); + return $res; } # $_[0]: port to write # $_[1]: value to write -# Returns: -1 on failure, 0 on success. +# We assume this can't fail. sub outb { - my $towrite = pack "C", $_[1]; - sysseek IOPORTS, $_[0], 0 or return -1; - my $nrchars = syswrite IOPORTS, $towrite, 1; - return -1 if not defined $nrchars or $nrchars != 1; - return 0; + sysseek(IOPORTS, $_[0], 0); + syswrite(IOPORTS, pack("C", $_[1]), 1); } # $_[0]: Address register @@ -2226,86 +1898,86 @@ sub outb # Returns: read value sub isa_read_byte { - outb $_[0], $_[2]; - return inb $_[1]; + outb($_[0], $_[2]); + return inb($_[1]); } -# $_[0]: Address register -# $_[1]: Data register -# $_[2]: Register to write -# $_[3}: Value to write -# Returns: nothing -sub isa_write_byte +# $_[0]: Base address +# $_[1]: Register to read +# Returns: read value +# This one can be used for any ISA chip with index register at +# offset 5 and data register at offset 6. +sub isa_read_i5d6 { - outb $_[0], $_[2]; - outb $_[1], $_[3]; + my ($addr, $reg) = @_; + return isa_read_byte($addr + 5, $addr + 6, $reg); } ################# # AUTODETECTION # ################# -use vars qw($modules_conf $dev_i2c $sysfs_root); +use vars qw($dev_i2c $sysfs_root); sub initialize_conf { - my $use_devfs = 0; - open(local *INPUTFILE, "/proc/mounts") or die "Can't access /proc/mounts!"; - local $_; - while () { - if (m@^\w+ /dev devfs @) { - $use_devfs = 1; - $dev_i2c = '/dev/i2c/'; - } - if (m@^\S+ (/\w+) sysfs @) { - $sysfs_root = $1; - } - } - close INPUTFILE; + my $use_devfs = 0; + open(local *INPUTFILE, "/proc/mounts") or die "Can't access /proc/mounts!"; + local $_; + while () { + if (m@^\w+ /dev devfs @) { + $use_devfs = 1; + $dev_i2c = '/dev/i2c/'; + } + if (m@^\S+ (/\w+) sysfs @) { + $sysfs_root = $1; + } + } + close(INPUTFILE); - my $use_udev = 0; - if (open(*INPUTFILE, '/etc/udev/udev.conf')) { - while () { - if (m/^\s*udev_db\s*=\s*\"([^"]*)\"/ || m/^\s*udev_db\s*=\s*(\S+)/) { - if (-e $1) { - $use_udev = 1; - $dev_i2c = '/dev/i2c-'; - } - last; - } - } - close INPUTFILE; - } + # We need sysfs for many things + if (!defined $sysfs_root) { + print "Sysfs not mounted?\n"; + exit -1; + } - if (!$use_udev) { - # Try some known default udev db locations, just in case - if (-e '/dev/.udev.tdb' || -e '/dev/.udev' - || -e '/dev/.udevdb') { - $use_udev = 1; - $dev_i2c = '/dev/i2c-'; - } - } + my $use_udev = 0; + if (open(*INPUTFILE, '/etc/udev/udev.conf')) { + while () { + next unless m/^\s*udev_db\s*=\s*\"([^"]*)\"/ + || m/^\s*udev_db\s*=\s*(\S+)/; + if (-e $1) { + $use_udev = 1; + $dev_i2c = '/dev/i2c-'; + } + last; + } + close(INPUTFILE); + } - if (kernel_version_at_least(2, 6, 0)) { - $modules_conf = '/etc/modprobe.conf'; - } else { - $modules_conf = '/etc/modules.conf'; - } + if (!$use_udev) { + # Try some known default udev db locations, just in case + if (-e '/dev/.udev.tdb' || -e '/dev/.udev' + || -e '/dev/.udevdb') { + $use_udev = 1; + $dev_i2c = '/dev/i2c-'; + } + } - if (!($use_devfs || $use_udev)) { - if (! -c '/dev/i2c-0' && -x '/sbin/MAKEDEV') { - system("/sbin/MAKEDEV i2c"); - } - if (! -c '/dev/i2c-0' && -x '/dev/MAKEDEV') { - system("/dev/MAKEDEV i2c"); - } - if (-c '/dev/i2c-0') { - $dev_i2c = '/dev/i2c-'; - } else { # default - print "No i2c device files found. Use prog/mkdev/mkdev.sh to create them.\n"; - exit -1; - } - } + if (!($use_devfs || $use_udev)) { + if (! -c '/dev/i2c-0' && -x '/sbin/MAKEDEV') { + system("/sbin/MAKEDEV i2c"); + } + if (! -c '/dev/i2c-0' && -x '/dev/MAKEDEV') { + system("/dev/MAKEDEV i2c"); + } + if (-c '/dev/i2c-0') { + $dev_i2c = '/dev/i2c-'; + } else { # default + print "No i2c device files found.\n"; + exit -1; + } + } } # [0] -> VERSION @@ -2317,20 +1989,26 @@ use vars qw(@kernel_version $kernel_arch); sub initialize_kernel_version { - `uname -r` =~ /(\d+)\.(\d+)\.(\d+)(.*)/; - @kernel_version = ($1, $2, $3, $4); - chomp($kernel_arch = `uname -m`); + `uname -r` =~ /(\d+)\.(\d+)\.(\d+)(.*)/; + @kernel_version = ($1, $2, $3, $4); + chomp($kernel_arch = `uname -m`); + + # We only support kernels >= 2.6.5 + if (!kernel_version_at_least(2, 6, 5)) { + print "Kernel version is unsupported (too old, >= 2.6.5 needed)\n"; + exit -1; + } } sub kernel_version_at_least { - my ($vers, $plvl, $slvl) = @_; - return 1 if ($kernel_version[0] > $vers || - ($kernel_version[0] == $vers && - ($kernel_version[1] > $plvl || - ($kernel_version[1] == $plvl && - ($kernel_version[2] >= $slvl))))); - return 0; + my ($vers, $plvl, $slvl) = @_; + return 1 if ($kernel_version[0] > $vers || + ($kernel_version[0] == $vers && + ($kernel_version[1] > $plvl || + ($kernel_version[1] == $plvl && + ($kernel_version[2] >= $slvl))))); + return 0; } # @cpu is a list of reference to hashes, one hash per CPU. @@ -2340,119 +2018,294 @@ use vars qw(@cpu); sub initialize_cpu_list { - open(local *INPUTFILE, "/proc/cpuinfo") or die "Can't access /proc/cpuinfo!"; - local $_; - my $entry; + local $_; + my $entry; - while () { - if (m/^processor\s*:\s*(\d+)/) { - push @cpu, $entry if scalar keys(%{$entry}); # Previous entry - $entry = {}; # New entry - next; - } - if (m/^(vendor_id|cpu family|model|model name|stepping)\s*:\s*(.+)$/) { - my $k = $1; - my $v = $2; - $v =~ s/\s+/ /g; # Merge multiple spaces - $v =~ s/ $//; # Trim trailing space - $entry->{$k} = $v; - next; - } - } - push @cpu, $entry if scalar keys(%{$entry}); # Last entry - close INPUTFILE; + open(local *INPUTFILE, "/proc/cpuinfo") or die "Can't access /proc/cpuinfo!"; + while () { + if (m/^processor\s*:\s*(\d+)/) { + push @cpu, $entry if scalar keys(%{$entry}); # Previous entry + $entry = {}; # New entry + next; + } + if (m/^(vendor_id|cpu family|model|model name|stepping)\s*:\s*(.+)$/) { + my $k = $1; + my $v = $2; + $v =~ s/\s+/ /g; # Merge multiple spaces + $v =~ s/ $//; # Trim trailing space + $entry->{$k} = $v; + next; + } + } + close(INPUTFILE); + push @cpu, $entry if scalar keys(%{$entry}); # Last entry } # @i2c_adapters is a list of references to hashes, one hash per I2C/SMBus # adapter present on the system. Each entry has the following keys: name -# (directly taken from either /proc/bus/i2c or /sys/class/i2c-adapter) and -# driver. +# (directly taken from /sys/class/i2c-adapter) and driver. use vars qw(@i2c_adapters); sub initialize_i2c_adapters_list { - my $entry; - local $_; + my $entry; + local $_; - if (defined $sysfs_root) { - my $class_dir = "${sysfs_root}/class/i2c-adapter"; - opendir(local *ADAPTERS, $class_dir) or return; + my $class_dir = "${sysfs_root}/class/i2c-adapter"; + opendir(local *ADAPTERS, $class_dir) or return; - while (defined($_ = readdir(ADAPTERS))) { - next unless m/^i2c-(\d+)$/; - $entry = {}; # New entry - $entry->{'name'} = sysfs_device_attribute("${class_dir}/i2c-$1", "name") - || sysfs_device_attribute("${class_dir}/i2c-$1/device", "name"); - next if $entry->{'name'} eq "ISA main adapter"; - $entry->{'driver'} = find_adapter_driver($entry->{'name'}); - $i2c_adapters[$1] = $entry; - } - closedir(ADAPTERS); - } else { - open(local *INPUTFILE, "/proc/bus/i2c") or return; + while (defined($_ = readdir(ADAPTERS))) { + next unless m/^i2c-(\d+)$/; + $entry = {}; # New entry + $entry->{name} = sysfs_device_attribute("${class_dir}/i2c-$1", + "name") + || sysfs_device_attribute("${class_dir}/i2c-$1/device", + "name"); + next if $entry->{name} eq "ISA main adapter"; - while () { - my ($nr, $type, $name) = /^i2c-(\d+)\s+(\S+)\s+(.*?) *(\t|$)/; - next if ($type eq "dummy" || $type eq "isa"); - $entry = {}; # New entry - $entry->{'name'} = $name; - $entry->{'driver'} = find_adapter_driver($name); - $i2c_adapters[$nr] = $entry; - } - close(INPUTFILE); - } + # First try to get the I2C adapter driver name from sysfs, + # and if it fails, fall back to searching our list of known + # I2C adapters. + $entry->{driver} = sysfs_device_driver("${class_dir}/i2c-$1/device") + || find_i2c_adapter_driver($entry->{name}) + || 'UNKNOWN'; + $i2c_adapters[$1] = $entry; + } + closedir(ADAPTERS); } ########### # MODULES # ########### -use vars qw(%modules_list %modules_supported); +use vars qw(%modules_list %modules_supported @modules_we_loaded); sub initialize_modules_list { - open(local *INPUTFILE, "/proc/modules") or return; - local $_; - while () { - tr/_/-/; - $modules_list{$1} = 1 if m/^(\S*)/; - } + local $_; + + open(local *INPUTFILE, "/proc/modules") or return; + while () { + tr/-/_/; # Probably not needed + $modules_list{$1} = 1 if m/^(\S*)/; + } +} + +sub is_module_loaded +{ + my $module = shift; + $module =~ tr/-/_/; + return exists $modules_list{$module} +} + +sub load_module +{ + my $module = shift; + + return if is_module_loaded($module); + + system("modprobe", $module); + if (($? >> 8) != 0) { + print "Failed to load module $module.\n"; + return -1; + } + + print "Module $module loaded successfully.\n"; + push @modules_we_loaded, $module; + + # Update the list of loaded modules + my $normalized = $module; + $normalized =~ tr/-/_/; + $modules_list{$normalized} = 1; +} + +sub loaded_by_us +{ + my $sought = shift; + local $_; + + $sought =~ tr/-/_/; + foreach (@modules_we_loaded) { + my $module = $_; + $module =~ tr/-/_/; + return 1 if $module eq $sought; + } + return 0; } sub initialize_modules_supported { - foreach my $chip (@chip_ids) { - $modules_supported{$chip->{driver}}++; - } + foreach my $chip (@chip_ids) { + next if $chip->{driver} eq "to-be-written"; + next if $chip->{driver} eq "use-isa-instead"; + + my $normalized = $chip->{driver}; + $normalized =~ tr/-/_/; + $modules_supported{$normalized}++; + } +} + +sub unload_modules +{ + return unless @modules_we_loaded; + + # Attempt to unload all kernel drivers we loaded ourselves + while (my $module = pop @modules_we_loaded) { + print "Unloading $module... "; + system("modprobe -r $module 2> /dev/null"); + if (($? >> 8) == 0) { + print "OK\n"; + } else { + print "failed\n"; + } + } + print "\n"; +} + +############ +# DMI DATA # +############ + +use vars qw(%dmi); + +sub initialize_dmi_data +{ + my %items = ( + # sysfs file name => dmidecode string name + sys_vendor => 'system-manufacturer', + product_name => 'system-product-name', + product_version => 'system-version', + board_vendor => 'baseboard-manufacturer', + board_name => 'baseboard-product-name', + board_version => 'baseboard-product-name', + chassis_type => 'chassis-type', + ); + # Many BIOS have broken DMI data, filter it out + my %fake = ( + 'System Manufacturer' => 1, + 'System Name' => 1, + ); + my $dmi_id_dir; + + # First try reading the strings from sysfs if available + if (-d ($dmi_id_dir = "$sysfs_root/devices/virtual/dmi/id") # kernel >= 2.6.28 + || -d ($dmi_id_dir = "$sysfs_root/class/dmi/id")) { + foreach my $k (keys %items) { + $dmi{$k} = sysfs_device_attribute($dmi_id_dir, $k); + } + } else { + # Else fallback on calling dmidecode + my $version; + if (open(local *DMIDECODE, "dmidecode --version 2>/dev/null |")) { + $version = ; + close(DMIDECODE); + chomp $version if defined $version; + } + + if (!defined $version + || !($version =~ m/^(\d+).(\d+)$/) + || !(($1 == 2 && $2 >= 7) || $1 > 2)) { + print "# DMI data unavailable, please consider installing dmidecode 2.7\n". + "# or later for better results.\n"; + return; + } + + foreach my $k (keys %items) { + next unless open(local *DMIDECODE, + "dmidecode -s $items{$k} 2>/dev/null |"); + $dmi{$k} = ; + close(DMIDECODE); + } + } + + # Strip trailing white-space, discard empty field + foreach my $k (keys %dmi) { + if (!defined $dmi{$k}) { + delete $dmi{$k}; + next; + } + $dmi{$k} =~ s/\s*$//; + delete $dmi{$k} if $dmi{$k} eq '' || exists $fake{$dmi{$k}}; + } +} + +sub print_dmi_summary +{ + my ($system, $board); + if (defined $dmi{sys_vendor} && defined $dmi{product_name}) { + $system = "$dmi{sys_vendor} $dmi{product_name}"; + } + if (defined $dmi{board_vendor} && defined $dmi{board_name}) { + $board = "$dmi{board_vendor} $dmi{board_name}"; + } + + if (defined $system) { + print "# System: $system"; + print " (laptop)" if (is_laptop()); + print "\n"; + } + print "# Board: $board\n" if defined $board + && (!defined $system || $system ne $board); +} + +sub dmi_match +{ + my $key = shift; + my $value; + + return unless defined $dmi{$key}; + while (defined ($value = shift)) { + return 1 if $dmi{$key} =~ m/\b$value\b/i; + } + return 0; +} + +sub is_laptop +{ + return 0 unless $dmi{chassis_type}; + return 1 if $dmi{chassis_type} =~ m/(Laptop|Notebook|Hand Held)/i; + return 1 if $dmi{chassis_type} =~ m/^(9|10|11|14)$/; + return 0; } ################# # SYSFS HELPERS # ################# -# From a sysfs device path, return the driver name, or undef -sub sysfs_device_driver($) +# From a sysfs device path, return the driver (module) name, or undef +sub sysfs_device_driver { - my $device = shift; + my $device = shift; - my $link = readlink("$device/driver"); - return unless defined $link; - return basename($link); + my $link = readlink("$device/driver/module"); + return unless defined $link; + return basename($link); +} + +# From a sysfs device path, return the subsystem name, or undef +sub sysfs_device_subsystem +{ + my $device = shift; + + my $link = readlink("$device/subsystem"); + return unless defined $link; + return basename($link); } # From a sysfs device path and an attribute name, return the attribute # value, or undef -sub sysfs_device_attribute($$) +sub sysfs_device_attribute { - my ($device, $attr) = @_; - my $value; + my ($device, $attr) = @_; + my $value; - open(local *FILE, "$device/$attr") or return; - return unless defined($value = ); - close(FILE); + open(local *FILE, "$device/$attr") or return; + $value = ; + close(FILE); + return unless defined $value; - chomp($value); - return $value; + chomp($value); + return $value; } ############## @@ -2465,204 +2318,133 @@ use vars qw(%pci_list); # 'domain', 'bus', 'slot' and 'func' uniquely identify a PCI device in a # computer; 'vendid' and 'devid' uniquely identify a type of device. # 'class' lets us spot unknown SMBus adapters. -# This function is used when sysfs is available (Linux 2.6). -sub read_sys_dev_pci($) +sub read_sys_dev_pci { - my $devices = shift; - my ($dev, @pci_list); + my $devices = shift; + my ($dev, @pci_list); - opendir(local *DEVICES, "$devices") - or die "$devices: $!"; + opendir(local *DEVICES, "$devices") + or die "$devices: $!"; - while (defined($dev = readdir(DEVICES))) { - my %record; - next unless $dev =~ - m/^(?:([\da-f]+):)?([\da-f]+):([\da-f]+)\.([\da-f]+)$/; + while (defined($dev = readdir(DEVICES))) { + my %record; + next unless $dev =~ + m/^(?:([\da-f]+):)?([\da-f]+):([\da-f]+)\.([\da-f]+)$/; - $record{domain} = hex $1; - $record{bus} = hex $2; - $record{slot} = hex $3; - $record{func} = hex $4; + $record{domain} = hex $1; + $record{bus} = hex $2; + $record{slot} = hex $3; + $record{func} = hex $4; - $record{vendid} = oct sysfs_device_attribute("$devices/$dev", "vendor"); - $record{devid} = oct sysfs_device_attribute("$devices/$dev", "device"); - $record{class} = (oct sysfs_device_attribute("$devices/$dev", "class")) - >> 8; + $record{vendid} = oct sysfs_device_attribute("$devices/$dev", + "vendor"); + $record{devid} = oct sysfs_device_attribute("$devices/$dev", + "device"); + $record{class} = (oct sysfs_device_attribute("$devices/$dev", + "class")) >> 8; - push @pci_list, \%record; - } + push @pci_list, \%record; + } - return \@pci_list; + return \@pci_list; } -# This function returns a list of hashes. Each hash has some PCI information: -# 'bus', 'slot' and 'func' uniquely identify a PCI device in a computer; -# 'vendid' and 'devid' uniquely identify a type of device. -# This function is used when sysfs is not available (Linux 2.4). -sub read_proc_dev_pci +sub initialize_pci { - my ($dfn, $vend, @pci_list); - open(local *INPUTFILE, "/proc/bus/pci/devices") - or die "/proc/bus/pci/devices: $!"; - local $_; - while () { - my %record; - ($dfn, $vend) = map { hex } (split) [0..1]; - $record{bus} = $dfn >> 8; - $record{slot} = ($dfn & 0xf8) >> 3; - $record{func} = $dfn & 0x07; - $record{vendid} = $vend >> 16; - $record{devid} = $vend & 0xffff; + my $pci_list; + local $_; - push @pci_list, \%record; - } - return \@pci_list; -} + $pci_list = read_sys_dev_pci("$sysfs_root/bus/pci/devices"); -sub initialize_proc_pci -{ - my $pci_list; - - if (defined $sysfs_root) { - $pci_list = read_sys_dev_pci("$sysfs_root/bus/pci/devices"); - } else { - $pci_list = read_proc_dev_pci(); - } - - # Note that we lose duplicate devices at this point, but we don't - # really care. What matters to us is which unique devices are present, - # not how many of each. - %pci_list = map { - sprintf("%04x:%04x", $_->{vendid}, $_->{devid}) => $_ - } @{$pci_list}; + # Note that we lose duplicate devices at this point, but we don't + # really care. What matters to us is which unique devices are present, + # not how many of each. + %pci_list = map { + sprintf("%04x:%04x", $_->{vendid}, $_->{devid}) => $_ + } @{$pci_list}; } ##################### # ADAPTER DETECTION # ##################### -sub adapter_pci_detection_sis_96x -{ - my $driver=""; - - # first, determine which driver if any... - if (kernel_version_at_least(2, 6, 0)) { - if (exists $pci_list{"1039:0016"}) { - $driver = "i2c-sis96x"; - } elsif (exists $pci_list{"1039:0008"}) { - $driver = "i2c-sis5595"; - } - } elsif (kernel_version_at_least(2, 4, 0)) { - if (exists $pci_list{"1039:0008"}) { - if ((exists $pci_list{"1039:0645"}) || - (exists $pci_list{"1039:0646"}) || - (exists $pci_list{"1039:0648"}) || - (exists $pci_list{"1039:0650"}) || - (exists $pci_list{"1039:0651"}) || - (exists $pci_list{"1039:0655"}) || - (exists $pci_list{"1039:0661"}) || - (exists $pci_list{"1039:0735"}) || - (exists $pci_list{"1039:0745"}) || - (exists $pci_list{"1039:0746"})) { - $driver = "i2c-sis645"; - } else { - $driver = "i2c-sis5595"; - } - } elsif ((exists $pci_list{"1039:0016"}) || - (exists $pci_list{"1039:0018"})) { - $driver = "i2c-sis645"; - } - } - - # then, add the appropriate entries to @pci_adapters - if ($driver eq "i2c-sis5595") { - push @pci_adapters, @pci_adapters_sis5595; - } elsif ($driver eq "i2c-sis645") { - push @pci_adapters, @pci_adapters_sis645; - } elsif ($driver eq "i2c-sis96x") { - push @pci_adapters, @pci_adapters_sis96x; - } -} - # Build and return a PCI device's bus ID -sub pci_busid($) +sub pci_busid { - my $device = shift; - my $busid; + my $device = shift; + my $busid; - $busid = sprintf("\%02x:\%02x.\%x", - $device->{bus}, $device->{slot}, $device->{func}); - $busid = sprintf("\%04x:", $device->{domain}) . $busid - if defined $device->{domain}; + $busid = sprintf("\%02x:\%02x.\%x", + $device->{bus}, $device->{slot}, $device->{func}); + $busid = sprintf("\%04x:", $device->{domain}) . $busid + if defined $device->{domain}; - return $busid; + return $busid; } sub adapter_pci_detection { - my ($key, $device, $try, @res, %smbus); - print "Probing for PCI bus adapters...\n"; + my ($key, $device, $try, %smbus, $count); - # Custom detection routine for some SiS chipsets - adapter_pci_detection_sis_96x(); + # Build a list of detected SMBus devices + foreach $key (keys %pci_list) { + $device = $pci_list{$key}; + $smbus{$key}++ + if exists $device->{class} && + $device->{class} == 0x0c05; # SMBus + } - # Build a list of detected SMBus devices - foreach $key (keys %pci_list) { - $device = $pci_list{$key}; - $smbus{$key}++ - if exists $device->{class} && $device->{class} == 0x0c05; # SMBus - } + # Loop over the known I2C/SMBus adapters + foreach $try (@pci_adapters) { + $key = sprintf("%04x:%04x", $try->{vendid}, $try->{devid}); + next unless exists $pci_list{$key}; - # Loop over the known I2C/SMBus adapters - foreach $try (@pci_adapters) { - $key = sprintf("%04x:%04x", $try->{vendid}, $try->{devid}); - if (exists $pci_list{$key}) { - $device = $pci_list{$key}; - if ($try->{driver} =~ m/^to-be-/) { - printf "No known driver for device \%s: \%s\n", - pci_busid($device), $try->{procid}; + $device = $pci_list{$key}; + if ($try->{driver} eq "to-be-tested") { + print "\nWe are currently looking for testers for this adapter!\n". + "Please check http://www.lm-sensors.org/wiki/Devices\n". + "and/or contact us if you want to help.\n\n". + "Continue... "; + ; + print "\n"; + } - if ($try->{driver} eq "to-be-tested") { - print "\nWe are currently looking for testers for this adapter!\n". - "Please check http://www.lm-sensors.org/wiki/Devices\n". - "and/or contact us if you want to help.\n\n"; - print "Continue... "; - ; - print "\n"; - } - } else { - printf "Use driver `\%s' for device \%s: \%s\n", - $try->{driver}, pci_busid($device), $try->{procid}; - push @res, $try->{driver}; - } + if ($try->{driver} =~ m/^to-be-/) { + printf "No known driver for device \%s: \%s\n", + pci_busid($device), $try->{procid}; + } else { + printf "Using driver `\%s' for device \%s: \%s\n", + $try->{driver}, pci_busid($device), + $try->{procid}; + $count++; + load_module($try->{driver}); + } - # Delete from detected SMBus device list - delete $smbus{$key}; - } - } + # Delete from detected SMBus device list + delete $smbus{$key}; + } - # Now see if there are unknown SMBus devices left - foreach $key (keys %smbus) { - $device = $pci_list{$key}; - printf "Found unknown SMBus adapter \%04x:\%04x at \%s.\n", - $device->{vendid}, $device->{devid}, pci_busid($device); - } + # Now see if there are unknown SMBus devices left + foreach $key (keys %smbus) { + $device = $pci_list{$key}; + printf "Found unknown SMBus adapter \%04x:\%04x at \%s.\n", + $device->{vendid}, $device->{devid}, pci_busid($device); + } - if (! @res) { - print "Sorry, no supported PCI bus adapters found.\n"; - } - return @res; + print "Sorry, no supported PCI bus adapters found.\n" + unless $count; } -# $_[0]: Adapter description as found in /proc/bus/i2c or sysfs -sub find_adapter_driver +# $_[0]: Adapter description as found in /sys/class/i2c-adapter +sub find_i2c_adapter_driver { - my $adapter; - for $adapter (@pci_adapters) { - return $adapter->{driver} - if (exists $adapter->{match} && $_[0] =~ $adapter->{match}); - } - return "UNKNOWN"; + my $name = shift; + my $entry; + + foreach $entry (@i2c_adapter_names) { + return $entry->{driver} + if $name =~ $entry->{match}; + } } ############################# @@ -2673,17 +2455,17 @@ sub find_adapter_driver # These are copied from -use constant IOCTL_I2C_SLAVE => 0x0703; -use constant IOCTL_I2C_FUNCS => 0x0705; -use constant IOCTL_I2C_SMBUS => 0x0720; +use constant IOCTL_I2C_SLAVE => 0x0703; +use constant IOCTL_I2C_FUNCS => 0x0705; +use constant IOCTL_I2C_SMBUS => 0x0720; -use constant SMBUS_READ => 1; -use constant SMBUS_WRITE => 0; +use constant SMBUS_READ => 1; +use constant SMBUS_WRITE => 0; -use constant SMBUS_QUICK => 0; -use constant SMBUS_BYTE => 1; -use constant SMBUS_BYTE_DATA => 2; -use constant SMBUS_WORD_DATA => 3; +use constant SMBUS_QUICK => 0; +use constant SMBUS_BYTE => 1; +use constant SMBUS_BYTE_DATA => 2; +use constant SMBUS_WORD_DATA => 3; use constant I2C_FUNC_SMBUS_QUICK => 0x00010000; use constant I2C_FUNC_SMBUS_READ_BYTE => 0x00020000; @@ -2691,15 +2473,15 @@ use constant I2C_FUNC_SMBUS_READ_BYTE => 0x00020000; # Get the i2c adapter's functionalities # $_[0]: Reference to an opened filehandle # Returns: -1 on failure, functionality bitfield on success. -sub i2c_get_funcs($) +sub i2c_get_funcs { - my $file = shift; - my $funcs = pack "L", 0; # Allocate space + my $file = shift; + my $funcs = pack("L", 0); # Allocate space - ioctl $file, IOCTL_I2C_FUNCS, $funcs or return -1; - $funcs = unpack "L", $funcs; + ioctl($file, IOCTL_I2C_FUNCS, $funcs) or return -1; + $funcs = unpack("L", $funcs); - return $funcs; + return $funcs; } # Select the device to communicate with through its address. @@ -2708,16 +2490,18 @@ sub i2c_get_funcs($) # Returns: 0 on failure, 1 on success. sub i2c_set_slave_addr { - my ($file, $addr) = @_; - $addr += 0; # Make sure it's a number not a string - ioctl $file, IOCTL_I2C_SLAVE, $addr or return 0; - return 1; + my ($file, $addr) = @_; + + # Reset register data cache + @i2c_byte_cache = (); + + $addr += 0; # Make sure it's a number not a string + ioctl($file, IOCTL_I2C_SLAVE, $addr) or return 0; + return 1; } # i2c_smbus_access is based upon the corresponding C function (see # ). You should not need to call this directly. -# Exact calling conventions are intricate; read i2c-dev.c if you really need -# to know. # $_[0]: Reference to an opened filehandle # $_[1]: SMBUS_READ for reading, SMBUS_WRITE for writing # $_[2]: Command (usually register number) @@ -2729,47 +2513,45 @@ sub i2c_set_slave_addr # way to do this. sub i2c_smbus_access { - my ($file, $read_write, $command, $size, $data) = @_; - my $data_array = pack "C32", @$data; - my $ioctl_data = pack "C2x2Ip", ($read_write, $command, $size, $data_array); - ioctl $file, IOCTL_I2C_SMBUS, $ioctl_data or return 0; - @{$_[4]} = unpack "C32", $data_array; - return 1; -} + my ($file, $read_write, $command, $size, $data) = @_; + my $data_array = pack("C32", @$data); + my $ioctl_data = pack("C2x2Ip", $read_write, $command, $size, + $data_array); -# $_[0]: Reference to an opened filehandle -# $_[1]: Either 0 or 1 -# Returns: -1 on failure, the 0 on success. -sub i2c_smbus_write_quick -{ - my ($file, $value) = @_; - my @data; - i2c_smbus_access $file, $value, 0, SMBUS_QUICK, \@data - or return -1; - return 0; + ioctl($file, IOCTL_I2C_SMBUS, $ioctl_data) or return 0; + @{$_[4]} = unpack("C32", $data_array); + return 1; } # $_[0]: Reference to an opened filehandle # Returns: -1 on failure, the read byte on success. sub i2c_smbus_read_byte { - my ($file) = @_; - my @data; - i2c_smbus_access $file, SMBUS_READ, 0, SMBUS_BYTE, \@data - or return -1; - return $data[0]; + my ($file) = @_; + my @data; + + i2c_smbus_access($file, SMBUS_READ, 0, SMBUS_BYTE, \@data) + or return -1; + return $data[0]; } # $_[0]: Reference to an opened filehandle # $_[1]: Command byte (usually register number) # Returns: -1 on failure, the read byte on success. +# Read byte data values are cached by default. As we keep reading the +# same registers over and over again in the detection functions, and +# SMBus can be slow, caching results in a big performance boost. sub i2c_smbus_read_byte_data { - my ($file, $command) = @_; - my @data; - i2c_smbus_access $file, SMBUS_READ, $command, SMBUS_BYTE_DATA, \@data - or return -1; - return $data[0]; + my ($file, $command, $nocache) = @_; + my @data; + + return $i2c_byte_cache[$command] + if !$nocache && exists $i2c_byte_cache[$command]; + + i2c_smbus_access($file, SMBUS_READ, $command, SMBUS_BYTE_DATA, \@data) + or return -1; + return ($i2c_byte_cache[$command] = $data[0]); } # $_[0]: Reference to an opened filehandle @@ -2779,15 +2561,14 @@ sub i2c_smbus_read_byte_data # so you should do as much of the detection as possible using byte reads, # and only start using word reads when there is a good chance that # the detection will succeed. -# Note: some devices use the wrong endiannes; use swap_bytes to correct for -# this. +# Note: some devices use the wrong endianness. sub i2c_smbus_read_word_data { - my ($file, $command) = @_; - my @data; - i2c_smbus_access $file, SMBUS_READ, $command, SMBUS_WORD_DATA, \@data - or return -1; - return $data[0] + 256 * $data[1]; + my ($file, $command) = @_; + my @data; + i2c_smbus_access($file, SMBUS_READ, $command, SMBUS_WORD_DATA, \@data) + or return -1; + return $data[0] + 256 * $data[1]; } # $_[0]: Reference to an opened filehandle @@ -2797,23 +2578,24 @@ sub i2c_smbus_read_word_data # This function is meant to prevent AT24RF08 corruption and write-only # chips locks. This is done by choosing the best probing method depending # on the address range. -sub i2c_probe($$$) +sub i2c_probe { - my ($file, $addr, $funcs) = @_; - my $data = []; - if (($addr >= 0x50 && $addr <= 0x5F) - || ($addr >= 0x30 && $addr <= 0x37)) { - # This covers all EEPROMs we know of, including page protection addresses. - # Note that some page protection addresses will not reveal themselves with - # this, because they ack on write only, but this is probably better since - # some EEPROMs write-protect themselves permanently on almost any write to - # their page protection address. - return 0 unless ($funcs & I2C_FUNC_SMBUS_READ_BYTE); - return i2c_smbus_access($file, SMBUS_READ, 0, SMBUS_BYTE, $data); - } else { - return 0 unless ($funcs & I2C_FUNC_SMBUS_QUICK); - return i2c_smbus_access($file, SMBUS_WRITE, 0, SMBUS_QUICK, $data); - } + my ($file, $addr, $funcs) = @_; + + if (($addr >= 0x50 && $addr <= 0x5F) + || ($addr >= 0x30 && $addr <= 0x37)) { + # This covers all EEPROMs we know of, including page protection + # addresses. Note that some page protection addresses will not + # reveal themselves with this, because they ack on write only, + # but this is probably better since some EEPROMs write-protect + # themselves permanently on almost any write to their page + # protection address. + return 0 unless ($funcs & I2C_FUNC_SMBUS_READ_BYTE); + return i2c_smbus_access($file, SMBUS_READ, 0, SMBUS_BYTE, []); + } else { + return 0 unless ($funcs & I2C_FUNC_SMBUS_QUICK); + return i2c_smbus_access($file, SMBUS_WRITE, 0, SMBUS_QUICK, []); + } } # $_[0]: Reference to an opened file handle @@ -2828,56 +2610,45 @@ sub i2c_probe($$$) # but that's the best we can do. sub i2c_safety_check { - my ($file) = @_; - my $data; + my ($file) = @_; + my $data; - # First we receive a byte from the chip, and remember it. - $data = i2c_smbus_read_byte($file); - return 1 if ($data < 0); + # First we receive a byte from the chip, and remember it. + $data = i2c_smbus_read_byte($file); + return 1 if ($data < 0); - # We receive a byte again; very likely to be the same for - # 1-register-only devices. - return 1 if (i2c_smbus_read_byte($file) != $data); + # We receive a byte again; very likely to be the same for + # 1-register-only devices. + return 1 if (i2c_smbus_read_byte($file) != $data); - # Then we try a standard byte read, with a register offset equal to - # the byte we received; we should receive the same byte value in return. - return 1 if (i2c_smbus_read_byte_data($file, $data) != $data); + # Then we try a standard byte read, with a register offset equal to + # the byte we received; we should receive the same byte value in return. + return 1 if (i2c_smbus_read_byte_data($file, $data) != $data); - # Then we try a standard byte read, with a slightly different register - # offset; we should again receive the same byte value in return. - return 1 if (i2c_smbus_read_byte_data($file, $data ^ 1) != ($data ^ 1)); + # Then we try a standard byte read, with a slightly different register + # offset; we should again receive the same byte value in return. + return 1 if (i2c_smbus_read_byte_data($file, $data ^ 1) != ($data ^ 1)); - # Apprently this is a 1-register-only device, restore the original register - # value and leave it alone. - i2c_smbus_read_byte_data($file, $data); - return 0; + # Apprently this is a 1-register-only device, restore the original + # register value and leave it alone. + i2c_smbus_read_byte_data($file, $data); + return 0; } #################### # ADAPTER SCANNING # #################### -use vars qw(@chips_detected); +use vars qw(%chips_detected); -# We will build a complicated structure @chips_detected here, being: -# A list of -# references to hashes -# with field 'driver', being a string with the driver name for this chip; -# with field 'detected' -# being a reference to a list of -# references to hashes of type 'detect_data'; -# with field 'misdetected' -# being a reference to a list of -# references to hashes of type 'detect_data' +# We will build a complicated structure %chips_detected here, being a hash +# where keys are driver names and values are detected chip information in +# the form of a list of hashes of type 'detect_data'. # Type detect_data: # A hash -# with field 'i2c_adap' containing an adapter string as appearing -# in /proc/bus/i2c (if this is an I2C detection) # with field 'i2c_devnr', contianing the /dev/i2c-* number of this # adapter (if this is an I2C detection) -# with field 'i2c_driver', containing the driver name for this adapter -# (if this is an I2C detection) # with field 'i2c_addr', containing the I2C address of the detection; # (if this is an I2C detection) # with field 'i2c_sub_addrs', containing a reference to a list of @@ -2886,9 +2657,10 @@ use vars qw(@chips_detected); # (if this is an ISA detection) # with field 'conf', containing the confidence level of this detection # with field 'chipname', containing the chip name +# with optional field 'alias_detect', containing a reference to an alias +# detection function for this chip -# This adds a detection to the above structure. We do no alias detection -# here; so you should do ISA detections *after* all I2C detections. +# This adds a detection to the above structure. # Not all possibilities of i2c_addr and i2c_sub_addrs are exhausted. # In all normal cases, it should be all right. # $_[0]: chip driver @@ -2896,385 +2668,399 @@ use vars qw(@chips_detected); # Returns: Nothing sub add_i2c_to_chips_detected { - my ($chipdriver, $datahash) = @_; - my ($i, $new_detected_ref, $new_misdetected_ref, $detected_ref, $misdetected_ref, - $main_entry, $detected_entry, $put_in_detected, @hash_addrs, @entry_addrs, - $do_not_add); + my ($chipdriver, $datahash) = @_; + my ($i, $new_detected_ref, $detected_ref, $detected_entry, + $put_in_detected, @hash_addrs, @entry_addrs); - # First determine where the hash has to be added. - for ($i = 0; $i < @chips_detected; $i++) { - last if ($chips_detected[$i]->{driver} eq $chipdriver); - } - if ($i == @chips_detected) { - push @chips_detected, { driver => $chipdriver, - detected => [], - misdetected => [] }; - } - $new_detected_ref = $chips_detected[$i]->{detected}; - $new_misdetected_ref = $chips_detected[$i]->{misdetected}; + # First determine where the hash has to be added. + $chips_detected{$chipdriver} = [] + unless exists $chips_detected{$chipdriver}; + $new_detected_ref = $chips_detected{$chipdriver}; - # Find out whether our new entry should go into the detected or the - # misdetected list. We compare all i2c addresses; if at least one matches, - # but our conf value is lower, we assume this is a misdetect. - @hash_addrs = ($datahash->{i2c_addr}); - push @hash_addrs, @{$datahash->{i2c_sub_addrs}} - if exists $datahash->{i2c_sub_addrs}; - $put_in_detected = 1; - $do_not_add = 0; - FIND_LOOP: - foreach $main_entry (@chips_detected) { - foreach $detected_entry (@{$main_entry->{detected}}) { - @entry_addrs = ($detected_entry->{i2c_addr}); - push @entry_addrs, @{$detected_entry->{i2c_sub_addrs}} - if exists $detected_entry->{i2c_sub_addrs}; - if ($detected_entry->{i2c_devnr} == $datahash->{i2c_devnr} and - any_list_match \@entry_addrs, \@hash_addrs) { - if ($detected_entry->{conf} >= $datahash->{conf}) { - $put_in_detected = 0; - } - if ($chipdriver eq $main_entry->{driver}) { - $do_not_add = 1; - } - last FIND_LOOP; - } - } - } + # Find out whether our new entry should go into the detected list + # or not. We compare all i2c addresses; if at least one matches, + # but our confidence value is lower, we assume this is a misdetection, + # in which case we simply discard our new entry. + @hash_addrs = ($datahash->{i2c_addr}); + push @hash_addrs, @{$datahash->{i2c_sub_addrs}} + if exists $datahash->{i2c_sub_addrs}; + $put_in_detected = 1; + FIND_LOOP: + foreach $detected_ref (values %chips_detected) { + foreach $detected_entry (@{$detected_ref}) { + next unless defined $detected_entry->{i2c_addr}; + @entry_addrs = ($detected_entry->{i2c_addr}); + push @entry_addrs, @{$detected_entry->{i2c_sub_addrs}} + if exists $detected_entry->{i2c_sub_addrs}; + if ($detected_entry->{i2c_devnr} == $datahash->{i2c_devnr} && + any_list_match(\@entry_addrs, \@hash_addrs)) { + if ($detected_entry->{conf} >= $datahash->{conf}) { + $put_in_detected = 0; + } + last FIND_LOOP; + } + } + } - if ($put_in_detected) { - # Here, we move all entries from detected to misdetected which - # match at least in one main or sub address. This may not be the - # best idea to do, as it may remove detections without replacing - # them with second-best ones. Too bad. - # (Khali 2003-09-13) If the driver is the same, the "misdetected" - # entry is simply deleted; failing to do so cause the configuration - # lines generated later to look very confusing (the driver will - # be told to ignore valid addresses). - @hash_addrs = ($datahash->{i2c_addr}); - push @hash_addrs, @{$datahash->{i2c_sub_addrs}} - if exists $datahash->{i2c_sub_addrs}; - foreach $main_entry (@chips_detected) { - $detected_ref = $main_entry->{detected}; - $misdetected_ref = $main_entry->{misdetected}; - for ($i = @$detected_ref-1; $i >=0; $i--) { - @entry_addrs = ($detected_ref->[$i]->{i2c_addr}); - push @entry_addrs, @{$detected_ref->[$i]->{i2c_sub_addrs}} - if exists $detected_ref->[$i]->{i2c_sub_addrs}; - if ($detected_ref->[$i]->{i2c_devnr} == $datahash->{i2c_devnr} and - any_list_match \@entry_addrs, \@hash_addrs) { - push @$misdetected_ref, $detected_ref->[$i] - unless $chipdriver eq $main_entry->{driver}; - splice @$detected_ref, $i, 1; - } - } - } + return unless $put_in_detected; - # Now add the new entry to detected - push @$new_detected_ref, $datahash; - } else { - # No hard work here - push @$new_misdetected_ref, $datahash - unless $do_not_add; - } + # Here, we discard all entries which match at least in one main or + # sub address. This may not be the best idea to do, as it may remove + # detections without replacing them with second-best ones. Too bad. + foreach $detected_ref (values %chips_detected) { + for ($i = @$detected_ref-1; $i >=0; $i--) { + next unless defined $detected_ref->[$i]->{i2c_addr}; + @entry_addrs = ($detected_ref->[$i]->{i2c_addr}); + push @entry_addrs, @{$detected_ref->[$i]->{i2c_sub_addrs}} + if exists $detected_ref->[$i]->{i2c_sub_addrs}; + if ($detected_ref->[$i]->{i2c_devnr} == $datahash->{i2c_devnr} && + any_list_match(\@entry_addrs, \@hash_addrs)) { + splice @$detected_ref, $i, 1; + } + } + } + + # Now add the new entry to detected + push @$new_detected_ref, $datahash; } -# This adds a detection to the above structure. We also do alias detection -# here; so you should do ISA detections *after* all I2C detections. -# $_[0]: alias detection function -# $_[1]: chip driver -# $_[2]: reference to data hash -# Returns: 0 if it is not an alias, datahash reference if it is. +# This adds a detection to the above structure. +# $_[0]: chip driver +# $_[1]: reference to data hash sub add_isa_to_chips_detected { - my ($alias_detect, $chipdriver, $datahash) = @_; - my ($i, $new_detected_ref, $new_misdetected_ref, $detected_ref, $misdetected_ref, - $main_entry, $isalias); + my ($chipdriver, $datahash) = @_; + my ($i, $new_detected_ref, $detected_ref); - # First determine where the hash has to be added. - $isalias=0; - for ($i = 0; $i < @chips_detected; $i++) { - last if ($chips_detected[$i]->{driver} eq $chipdriver); - } - if ($i == @chips_detected) { - push @chips_detected, { driver => $chipdriver, - detected => [], - misdetected => [] }; - } - $new_detected_ref = $chips_detected[$i]->{detected}; - $new_misdetected_ref = $chips_detected[$i]->{misdetected}; + # First determine where the hash has to be added. + $chips_detected{$chipdriver} = [] + unless exists $chips_detected{$chipdriver}; + $new_detected_ref = $chips_detected{$chipdriver}; - # Now, we are looking for aliases. An alias can only be the same chiptype. - # If an alias is found in the misdetected list, we add the new information - # and terminate this function. If it is found in the detected list, we - # still have to check whether another chip has claimed this ISA address. - # So we remove the old entry from the detected list and put it in datahash. + # Find out whether our new entry should go into the detected list + # or not. We only compare main isa_addr here, of course. + foreach $detected_ref (values %chips_detected) { + for ($i = 0; $i < @{$detected_ref}; $i++) { + if (exists $detected_ref->[$i]->{isa_addr} and + exists $datahash->{isa_addr} and + $detected_ref->[$i]->{isa_addr} == $datahash->{isa_addr}) { + if ($detected_ref->[$i]->{conf} < $datahash->{conf}) { + splice @$detected_ref, $i, 1; + push @$new_detected_ref, $datahash; + } + return; + } + } + } - # Misdetected alias detection: - for ($i = 0; $i < @$new_misdetected_ref; $i++) { - if (exists $new_misdetected_ref->[$i]->{i2c_addr} and - not exists $new_misdetected_ref->[$i]->{isa_addr} and - defined $alias_detect and - $new_misdetected_ref->[$i]->{chipname} eq $datahash->{chipname}) { - open(local *FILE, "$dev_i2c$new_misdetected_ref->[$i]->{i2c_devnr}") or - print("Can't open $dev_i2c$new_misdetected_ref->[$i]->{i2c_devnr}?!?\n"), - next; - binmode FILE; - i2c_set_slave_addr \*FILE, $new_misdetected_ref->[$i]->{i2c_addr} or - print("Can't set I2C address for ", - "$dev_i2c$new_misdetected_ref->[$i]->{i2c_devnr}?!?\n"), - next; - if (&$alias_detect ($datahash->{isa_addr}, \*FILE, - $new_misdetected_ref->[$i]->{i2c_addr})) { - $new_misdetected_ref->[$i]->{isa_addr} = $datahash->{isa_addr}; - return $new_misdetected_ref->[$i]; - } - } - } + # Not found? OK, put it in the detected list + push @$new_detected_ref, $datahash; +} - # Detected alias detection: - for ($i = 0; $i < @$new_detected_ref; $i++) { - if (exists $new_detected_ref->[$i]->{i2c_addr} and - not exists $new_detected_ref->[$i]->{isa_addr} and - defined $alias_detect and - $new_detected_ref->[$i]->{chipname} eq $datahash->{chipname}) { - open(local *FILE, "$dev_i2c$new_detected_ref->[$i]->{i2c_devnr}") or - print("Can't open $dev_i2c$new_detected_ref->[$i]->{i2c_devnr}?!?\n"), - next; - binmode FILE; - i2c_set_slave_addr \*FILE, $new_detected_ref->[$i]->{i2c_addr} or - print("Can't set I2C address for ", - "$dev_i2c$new_detected_ref->[$i]->{i2c_devnr}?!?\n"), - next; - if (&$alias_detect ($datahash->{isa_addr}, \*FILE, - $new_detected_ref->[$i]->{i2c_addr})) { - $new_detected_ref->[$i]->{isa_addr} = $datahash->{isa_addr}; - ($datahash) = splice (@$new_detected_ref, $i, 1); - $isalias=1; - last; - } - } - } +# $_[0]: reference to an array of chips which may be aliases of each other +sub find_aliases +{ + my $detected = shift; + my ($isa, $i2c, $dev, $alias_detect, $is_alias); + for ($isa = 0; $isa < @{$detected}; $isa++) { + # Look for chips with an ISA address but no I2C address + next unless defined $detected->[$isa]; + next unless $detected->[$isa]->{isa_addr}; + next if defined $detected->[$isa]->{i2c_addr}; + # Additionally, the chip must possibly have I2C aliases + next unless defined $detected->[$isa]->{alias_detect}; - # Find out whether our new entry should go into the detected or the - # misdetected list. We only compare main isa_addr here, of course. - # (Khali 2004-05-12) If the driver is the same, the "misdetected" - # entry is simply deleted; same we do for I2C chips. - foreach $main_entry (@chips_detected) { - $detected_ref = $main_entry->{detected}; - $misdetected_ref = $main_entry->{misdetected}; - for ($i = 0; $i < @{$main_entry->{detected}}; $i++) { - if (exists $detected_ref->[$i]->{isa_addr} and - exists $datahash->{isa_addr} and - $detected_ref->[$i]->{isa_addr} == $datahash->{isa_addr}) { - if ($detected_ref->[$i]->{conf} >= $datahash->{conf}) { - push @$new_misdetected_ref, $datahash - unless $main_entry->{driver} eq $chipdriver; - } else { - push @$misdetected_ref, $detected_ref->[$i] - unless $main_entry->{driver} eq $chipdriver; - splice @$detected_ref, $i, 1; - push @$new_detected_ref, $datahash; - } - if ($isalias) { - return $datahash; - } else { - return 0; - } - } - } - } + for ($i2c = 0; $i2c < @{$detected}; $i2c++) { + # Look for chips with an I2C address but no ISA address + next unless defined $detected->[$i2c]; + next unless defined $detected->[$i2c]->{i2c_addr}; + next if $detected->[$i2c]->{isa_addr}; + # Additionally, it must have the same chip name + next unless $detected->[$i2c]->{chipname} eq + $detected->[$isa]->{chipname}; - # Not found? OK, put it in the detected list - push @$new_detected_ref, $datahash; - if ($isalias) { - return $datahash; - } else { - return 0; - } + # We have potential aliases, check if they actually are + $dev = $dev_i2c.$detected->[$i2c]->{i2c_devnr}; + open(local *FILE, $dev) or + print("Can't open $dev\n"), + next; + binmode(FILE); + i2c_set_slave_addr(\*FILE, $detected->[$i2c]->{i2c_addr}) or + print("Can't set I2C address for $dev\n"), + next; + + initialize_ioports(); + $alias_detect = $detected->[$isa]->{alias_detect}; + $is_alias = &$alias_detect($detected->[$isa]->{isa_addr}, + \*FILE, + $detected->[$i2c]->{i2c_addr}); + close(FILE); + close_ioports(); + + next unless $is_alias; + # This is an alias: copy the I2C data into the ISA + # entry, then discard the I2C entry + $detected->[$isa]->{i2c_devnr} = $detected->[$i2c]->{i2c_devnr}; + $detected->[$isa]->{i2c_addr} = $detected->[$i2c]->{i2c_addr}; + $detected->[$isa]->{i2c_sub_addr} = $detected->[$i2c]->{i2c_sub_addr}; + undef $detected->[$i2c]; + last; + } + } + + # The loops above may have made the chip list sparse, make it + # compact again + for ($isa = 0; $isa < @{$detected}; ) { + if (defined($detected->[$isa])) { + $isa++; + } else { + splice @{$detected}, $isa, 1; + } + } } # From the list of known I2C/SMBus devices, build a list of I2C addresses # which are worth probing. There's no point in probing an address for which # we don't know a single device, and probing some addresses has caused # random trouble in the past. -sub i2c_addresses_to_scan() +sub i2c_addresses_to_scan { - my @used; - my @addresses; - my $addr; + my @used; + my @addresses; + my $addr; - foreach my $chip (@chip_ids) { - next unless defined $chip->{'i2c_addrs'}; - next if $chip->{'driver'} eq 'not-a-sensor'; - foreach $addr (@{$chip->{'i2c_addrs'}}) { - $used[$addr]++; - } - } + foreach my $chip (@chip_ids) { + next unless defined $chip->{i2c_addrs}; + foreach $addr (@{$chip->{i2c_addrs}}) { + $used[$addr]++; + } + } - for ($addr = 0x03; $addr <= 0x77; $addr++) { - push @addresses, $addr if $used[$addr]; - } - return \@addresses; + for ($addr = 0x03; $addr <= 0x77; $addr++) { + push @addresses, $addr if $used[$addr]; + } + return \@addresses; } # $_[0]: The number of the adapter to scan -# $_[1]: The name of the adapter, as appearing in /proc/bus/i2c -# $_[2]: The driver of the adapter -# @_[3]: Addresses not to scan (array reference) -sub scan_adapter +# $_[1]: Address +sub add_busy_i2c_address { - my ($adapter_nr, $adapter_name, $adapter_driver, $not_to_scan) = @_; - my ($funcs, $chip, $addr, $conf, @chips, $new_hash, $other_addr); + my ($adapter_nr, $addr) = @_; + # If the address is busy, we can normally find out which driver + # requested it (if the kernel is recent enough, at least 2.6.16 and + # later are known to work), and we assume it is the right one. + my ($device, $driver, $new_hash); - # As we modify it, we need a copy - my @not_to_scan = @$not_to_scan; + $device = sprintf("$sysfs_root/bus/i2c/devices/\%d-\%04x", + $adapter_nr, $addr); + $driver = sysfs_device_driver($device); - open(local *FILE, "$dev_i2c$adapter_nr") or - (print "Can't open $dev_i2c$adapter_nr\n"), return; - binmode FILE; + if (!defined($driver)) { + printf("Client at address 0x%02x can not be probed - ". + "unload all client drivers first!\n", $addr); + return; + } - # Can we probe this adapter? - $funcs = i2c_get_funcs(\*FILE); - if ($funcs < 0) { - print "Adapter failed to provide its functionalities, skipping.\n"; - return; - } - if (!($funcs & (I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_READ_BYTE))) { - print "Adapter cannot be probed, skipping.\n"; - return; - } - if (~$funcs & (I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_READ_BYTE)) { - print "Adapter doesn't support all probing functions.\n", - "Some addresses won't be probed.\n"; - } + $new_hash = { + conf => 6, # Arbitrary confidence + i2c_addr => $addr, + chipname => sysfs_device_attribute($device, "name") + || "unknown", + i2c_devnr => $adapter_nr, + }; - # Now scan each address in turn - foreach $addr (@{$i2c_addresses_to_scan}) { - # As the not_to_scan list is sorted, we can check it fast - shift @not_to_scan # User skipped an address which we didn't intend to probe anyway - while (@not_to_scan and $not_to_scan[0] < $addr); - if (@not_to_scan and $not_to_scan[0] == $addr) { - shift @not_to_scan; - next; - } + printf "Client found at address 0x\%02x\n", $addr; + printf "Handled by driver `\%s' (already loaded), chip type `\%s'\n", + $driver, $new_hash->{chipname}; - if (!i2c_set_slave_addr(\*FILE, $addr)) { - # If the address is busy, in Linux 2.6 we can find out which driver - # is using it, and we assume it is the right one. In Linux 2.4 we - # just give up and warn the user. - my ($device, $driver); - if (defined($sysfs_root)) { - $device = sprintf("$sysfs_root/bus/i2c/devices/\%d-\%04x", - $adapter_nr, $addr); - $driver = sysfs_device_driver($device); - } - if (defined($driver)) { - $new_hash = { - conf => 6, # Arbitrary confidence - i2c_addr => $addr, - chipname => sysfs_device_attribute($device, "name") || "unknown", - i2c_adap => $adapter_name, - i2c_driver => $adapter_driver, - i2c_devnr => $adapter_nr, - }; + # Only add it to the list if this is something we would have detected, + # else we end up with random i2c chip drivers listed (for example + # media/video drivers.) + if (exists $modules_supported{$driver}) { + add_i2c_to_chips_detected($driver, $new_hash); + } else { + print " (note: this is probably NOT a sensor chip!)\n"; + } +} - printf "Client found at address 0x\%02x\n", $addr; - printf "Handled by driver `\%s' (already loaded), chip type `\%s'\n", - $driver, $new_hash->{chipname}; +# $_[0]: The number of the adapter to scan +# $_[1]: Address +# $_[2]: Chip being probed +sub probe_free_i2c_address +{ + my ($adapter_nr, $addr, $chip) = @_; + my ($conf, @other_addr, $new_hash); - # Only add it to the list if this is something we would have - # detected, else we end up with random i2c chip drivers listed - # (for example media/video drivers.) - if (exists $modules_supported{$driver}) { - add_i2c_to_chips_detected($driver, $new_hash); - } else { - print " (note: this is probably NOT a sensor chip!)\n"; - } - } else { - printf("Client at address 0x%02x can not be probed - ". - "unload all client drivers first!\n", $addr); - } - next; - } + printf("\%-60s", sprintf("Probing for `\%s'... ", $chip->{name})); + if (($conf, @other_addr) = &{$chip->{i2c_detect}} (\*FILE, $addr)) { + if ($chip->{driver} eq "not-a-sensor") { + print "Yes\n", + " (confidence $conf, not a hardware monitoring chip"; + } else { + print "Success!\n", + " (confidence $conf, driver `$chip->{driver}'"; + } + if (@other_addr) { + print ", other addresses:"; + @other_addr = sort @other_addr; + foreach my $other_addr (@other_addr) { + printf(" 0x%02x", $other_addr); + } + } + print ")\n"; - next unless i2c_probe(\*FILE, $addr, $funcs); - printf "Client found at address 0x%02x\n", $addr; - if (!i2c_safety_check(\*FILE)) { - print "Seems to be a 1-register-only device, skipping.\n"; - next; - } + return if ($chip->{driver} eq "not-a-sensor" + || $chip->{driver} eq "use-isa-instead"); - $| = 1; - foreach $chip (@chip_ids) { - if (exists $chip->{i2c_addrs} and contains $addr, @{$chip->{i2c_addrs}}) { - printf("\%-60s", sprintf("Probing for `\%s'... ", $chip->{name})); - if (($conf, @chips) = &{$chip->{i2c_detect}} (\*FILE, $addr)) { - if ($chip->{driver} eq "not-a-sensor") { - print "Yes\n", - " (confidence $conf, not a hardware monitoring chip"; - } else { - print "Success!\n", - " (confidence $conf, driver `$chip->{driver}'"; - } - if (@chips) { - print ", other addresses:"; - @chips = sort @chips; - foreach $other_addr (@chips) { - printf(" 0x%02x", $other_addr); - } - } - printf ")\n"; + $new_hash = { + conf => $conf, + i2c_addr => $addr, + chipname => $chip->{name}, + i2c_devnr => $adapter_nr, + }; + if (@other_addr) { + my @other_addr_copy = @other_addr; + $new_hash->{i2c_sub_addrs} = \@other_addr_copy; + } + add_i2c_to_chips_detected($chip->{driver}, $new_hash); + } else { + print "No\n"; + } +} - next if ($chip->{driver} eq "not-a-sensor" - || $chip->{driver} eq "use-isa-instead"); +# $_[0]: The number of the adapter to check +# Returns: PCI class of the adapter if available, 0 if not +sub get_i2c_adapter_class +{ + my ($adapter_nr) = @_; + my ($adapter, $subsystem, $class); - $new_hash = { conf => $conf, - i2c_addr => $addr, - chipname => $chip->{name}, - i2c_adap => $adapter_name, - i2c_driver => $adapter_driver, - i2c_devnr => $adapter_nr, - }; - if (@chips) { - my @chips_copy = @chips; - $new_hash->{i2c_sub_addrs} = \@chips_copy; - } - add_i2c_to_chips_detected $chip->{driver}, $new_hash; - } else { - print "No\n"; - } - } - } - $| = 0; - } + $adapter = "$sysfs_root/class/i2c-adapter/i2c-$adapter_nr"; + $subsystem = sysfs_device_subsystem("$adapter/device"); + return 0 unless defined $subsystem && $subsystem eq "pci"; + + $class = sysfs_device_attribute("$adapter/device", "class"); + return 0 unless defined $class; + $class = oct($class) if $class =~ /^0/; + return $class >> 8; +} + +# $_[0]: The number of the adapter to scan +sub scan_i2c_adapter +{ + my ($adapter_nr, $smbus_default) = @_; + my ($funcs, $chip, $addr, $class, $default, $input, @not_to_scan); + + $class = get_i2c_adapter_class($adapter_nr); + if (($class & 0xff00) == 0x0400) { + # Do not probe adapters on PCI multimedia cards by default + $default = 0; + } elsif ($class == 0x0c01 || $class == 0x0c05 + || find_i2c_adapter_driver($i2c_adapters[$adapter_nr]->{name})) { + $default = $smbus_default; + } else { + $default = 1; + } + + printf "Next adapter: $i2c_adapters[$adapter_nr]->{name} (i2c-$adapter_nr)\n". + "Do you want to scan it? (\%s/selectively): ", + $default ? "YES/no" : "yes/NO"; + + $input = ; + if ($input =~ /^\s*n/i + || (!$default && $input !~ /^\s*[ys]/i)) { + print "\n"; + return; + } + + if ($input =~ /^\s*s/i) { + print "Please enter one or more addresses not to scan. Separate them with commas.\n", + "You can specify a range by using dashes. Example: 0x58-0x5f,0x69.\n", + "Addresses: "; + $input = ; + chomp($input); + @not_to_scan = parse_not_to_scan(0x03, 0x77, $input); + } + + open(local *FILE, "$dev_i2c$adapter_nr") or + (print "Can't open $dev_i2c$adapter_nr\n"), return; + binmode(FILE); + + # Can we probe this adapter? + $funcs = i2c_get_funcs(\*FILE); + if ($funcs < 0) { + print "Adapter failed to provide its functionalities, skipping.\n"; + return; + } + if (!($funcs & (I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_READ_BYTE))) { + print "Adapter cannot be probed, skipping.\n"; + return; + } + if (~$funcs & (I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_READ_BYTE)) { + print "Adapter doesn't support all probing functions.\n", + "Some addresses won't be probed.\n"; + } + + # Now scan each address in turn + foreach $addr (@{$i2c_addresses_to_scan}) { + # As the not_to_scan list is sorted, we can check it fast + shift @not_to_scan # User skipped an address which we didn't intend to probe anyway + while (@not_to_scan and $not_to_scan[0] < $addr); + if (@not_to_scan and $not_to_scan[0] == $addr) { + shift @not_to_scan; + next; + } + + if (!i2c_set_slave_addr(\*FILE, $addr)) { + add_busy_i2c_address($adapter_nr, $addr); + next; + } + + next unless i2c_probe(\*FILE, $addr, $funcs); + printf "Client found at address 0x%02x\n", $addr; + if (!i2c_safety_check(\*FILE)) { + print "Seems to be a 1-register-only device, skipping.\n"; + next; + } + + $| = 1; + foreach $chip (@chip_ids, @non_hwmon_chip_ids) { + next unless exists $chip->{i2c_addrs} + && contains($addr, @{$chip->{i2c_addrs}}); + probe_free_i2c_address($adapter_nr, $addr, $chip); + } + $| = 0; + } + print "\n"; } sub scan_isa_bus { - my ($chip, $addr, $conf); - $| = 1; - foreach $chip (@chip_ids) { - next if not exists $chip->{isa_addrs} or not exists $chip->{isa_detect}; - foreach $addr (@{$chip->{isa_addrs}}) { - printf("\%-60s", sprintf("Probing for `\%s'\ at 0x\%x... ", $chip->{name}, - $addr)); - $conf = &{$chip->{isa_detect}} ($addr); - print("No\n"), next if not defined $conf; - print "Success!\n"; - printf " (confidence %d, driver `%s')\n", $conf, $chip->{driver}; - my $new_hash = { conf => $conf, - isa_addr => $addr, - chipname => $chip->{name} - }; - $new_hash = add_isa_to_chips_detected $chip->{alias_detect}, $chip->{driver}, - $new_hash; - if ($new_hash) { - printf " Alias of the chip on I2C bus `%s', address 0x%04x\n", - $new_hash->{i2c_adap}, $new_hash->{i2c_addr}; - } - } - } - $| = 0; + my $chip_list_ref = shift; + my ($chip, $addr, $conf); + + $| = 1; + foreach $chip (@{$chip_list_ref}) { + next if not exists $chip->{isa_addrs} or not exists $chip->{isa_detect}; + foreach $addr (@{$chip->{isa_addrs}}) { + printf("\%-60s", sprintf("Probing for `\%s'\ at 0x\%x... ", + $chip->{name}, $addr)); + $conf = &{$chip->{isa_detect}} ($addr); + print("No\n"), next if not defined $conf; + print "Success!\n"; + printf " (confidence %d, driver `%s')\n", $conf, $chip->{driver}; + my $new_hash = { + conf => $conf, + isa_addr => $addr, + chipname => $chip->{name}, + alias_detect => $chip->{alias_detect}, + }; + add_isa_to_chips_detected($chip->{driver}, $new_hash); + } + } + $| = 0; } use vars qw(%superio); @@ -3287,107 +3073,109 @@ use vars qw(%superio); # actmask: The activation bit in the activation register # basereg: The I/O base register within the logical device %superio = ( - devidreg => 0x20, - logdevreg => 0x07, - actreg => 0x30, - actmask => 0x01, - basereg => 0x60, + devidreg => 0x20, + logdevreg => 0x07, + actreg => 0x30, + actmask => 0x01, + basereg => 0x60, ); sub exit_superio { - my ($addrreg, $datareg) = @_; + my ($addrreg, $datareg) = @_; - # Some chips (SMSC, Winbond) want this - outb($addrreg, 0xaa); + # Some chips (SMSC, Winbond) want this + outb($addrreg, 0xaa); - # Return to "Wait For Key" state (PNP-ISA spec) - outb($addrreg, 0x02); - outb($datareg, 0x02); + # Return to "Wait For Key" state (PNP-ISA spec) + outb($addrreg, 0x02); + outb($datareg, 0x02); } # Guess if an unknown Super-I/O chip has sensors -sub guess_superio_ld($$$) +sub guess_superio_ld { - my ($addrreg, $datareg, $typical_addr) = @_; - my ($oldldn, $ldn, $addr); + my ($addrreg, $datareg, $typical_addr) = @_; + my ($oldldn, $ldn, $addr); - # Save logical device number - outb($addrreg, $superio{logdevreg}); - $oldldn = inb($datareg); + # Save logical device number + outb($addrreg, $superio{logdevreg}); + $oldldn = inb($datareg); - for ($ldn = 0; $ldn < 16; $ldn++) { - # Select logical device - outb($addrreg, $superio{logdevreg}); - outb($datareg, $ldn); + for ($ldn = 0; $ldn < 16; $ldn++) { + # Select logical device + outb($addrreg, $superio{logdevreg}); + outb($datareg, $ldn); - # Read base I/O address - outb($addrreg, $superio{basereg}); - $addr = inb($datareg) << 8; - outb($addrreg, $superio{basereg} + 1); - $addr |= inb($datareg); - next unless ($addr & 0xfff8) == $typical_addr; + # Read base I/O address + outb($addrreg, $superio{basereg}); + $addr = inb($datareg) << 8; + outb($addrreg, $superio{basereg} + 1); + $addr |= inb($datareg); + next unless ($addr & 0xfff8) == $typical_addr; - printf " (logical device \%X has address 0x\%x, could be sensors)\n", - $ldn, $addr; - last; - } + printf " (logical device \%X has address 0x\%x, could be sensors)\n", + $ldn, $addr; + last; + } - # Be nice, restore original logical device - outb($addrreg, $superio{logdevreg}); - outb($datareg, $oldldn); + # Be nice, restore original logical device + outb($addrreg, $superio{logdevreg}); + outb($datareg, $oldldn); } -sub probe_superio($$$) +# Returns: features bitmask if device added to chips_detected, 0 if not +sub probe_superio { - my ($addrreg, $datareg, $chip) = @_; - my ($val, $addr); + my ($addrreg, $datareg, $chip) = @_; + my ($val, $addr); - printf "\%-60s", "Found `$chip->{name}'"; + printf "\%-60s", "Found `$chip->{name}'"; - # Does it have hardware monitoring capabilities? - if (!exists $chip->{driver}) { - print "\n (no information available)\n"; - return; - } - if ($chip->{driver} eq "not-a-sensor") { - print "\n (no hardware monitoring capabilities)\n"; - return; - } - if ($chip->{driver} eq "via-smbus-only") { - print "\n (hardware monitoring capabilities accessible via SMBus only)\n"; - return; - } + # Does it have hardware monitoring capabilities? + if (!exists $chip->{driver}) { + print "\n (no information available)\n"; + return 0; + } + if ($chip->{driver} eq "not-a-sensor") { + print "\n (no hardware monitoring capabilities)\n"; + return 0; + } + if ($chip->{driver} eq "via-smbus-only") { + print "\n (hardware monitoring capabilities accessible via SMBus only)\n"; + return FEAT_SMBUS; + } - # Switch to the sensor logical device - outb($addrreg, $superio{logdevreg}); - outb($datareg, $chip->{logdev}); + # Switch to the sensor logical device + outb($addrreg, $superio{logdevreg}); + outb($datareg, $chip->{logdev}); - # Check the activation register - outb($addrreg, $superio{actreg}); - $val = inb($datareg); - if (!($val & $superio{actmask})) { - print "\n (but not activated)\n"; - return; - } + # Check the activation register + outb($addrreg, $superio{actreg}); + $val = inb($datareg); + if (!($val & $superio{actmask})) { + print "\n (but not activated)\n"; + return 0; + } - # Get the IO base register - outb($addrreg, $superio{basereg}); - $addr = inb($datareg); - outb($addrreg, $superio{basereg} + 1); - $addr = ($addr << 8) | inb($datareg); - if ($addr == 0) { - print "\n (but no address specified)\n"; - return; - } - print "Success!\n"; - printf " (address 0x\%x, driver `%s')\n", $addr, $chip->{driver}; - my $new_hash = { conf => 9, - isa_addr => $addr, - chipname => $chip->{name} - }; - add_isa_to_chips_detected $chip->{alias_detect}, $chip->{driver}, - $new_hash; + # Get the IO base register + outb($addrreg, $superio{basereg}); + $addr = inb($datareg); + outb($addrreg, $superio{basereg} + 1); + $addr = ($addr << 8) | inb($datareg); + if ($addr == 0) { + print "\n (but no address specified)\n"; + return 0; + } + print "Success!\n"; + printf " (address 0x\%x, driver `%s')\n", $addr, $chip->{driver}; + my $new_hash = { + conf => 9, + isa_addr => $addr, + chipname => $chip->{name} + }; + add_isa_to_chips_detected($chip->{driver}, $new_hash); + return $chip->{features}; } # Detection routine for non-standard SMSC Super I/O chips @@ -3397,241 +3185,176 @@ sub probe_superio($$$) # Return values: 1 if non-standard chip found, 0 otherwise sub smsc_ns_detect_superio { - my ($addrreg, $datareg, $ns_chips) = @_; - my ($val, $chip); + my ($addrreg, $datareg, $ns_chips) = @_; + my ($val, $chip); - # read alternate device ID register - outb($addrreg, 0x0d); - $val = inb($datareg); - if ($val == 0x00 || $val == 0xff) { - return 0; - } + # read alternate device ID register + outb($addrreg, 0x0d); + $val = inb($datareg); + return 0 if $val == 0x00 || $val == 0xff; - print "Yes\n"; + print "Yes\n"; - foreach $chip (@{$ns_chips}) { - if ($chip->{devid} == $val) { - probe_superio($addrreg, $datareg, $chip); - return 1; + foreach $chip (@{$ns_chips}) { + if ($chip->{devid} == $val) { + probe_superio($addrreg, $datareg, $chip); + return 1; + } } - } - printf("Found unknown non-standard chip with ID 0x%02x\n", $val); - return 1; + printf("Found unknown non-standard chip with ID 0x%02x\n", $val); + return 1; } +# Returns: features supported by the device added, if any sub scan_superio { - my ($addrreg, $datareg) = @_; - my ($val, $found); + my ($addrreg, $datareg) = @_; + my ($val, $found); + my $features = 0; - printf("Probing for Super-I/O at 0x\%x/0x\%x\n", $addrreg, $datareg); + printf("Probing for Super-I/O at 0x\%x/0x\%x\n", $addrreg, $datareg); - $| = 1; -# reset state to avoid false positives - exit_superio($addrreg, $datareg); - FAMILY: - foreach my $family (@superio_ids) { - printf("\%-60s", "Trying family `$family->{family}'... "); -# write the password - foreach $val (@{$family->{enter}->{$addrreg}}) { - outb($addrreg, $val); - } -# call the non-standard detection routine first if it exists - if (defined($family->{ns_detect}) && - &{$family->{ns_detect}}($addrreg, $datareg, $family->{ns_chips})) { - exit_superio($addrreg, $datareg); - last FAMILY; - } -# did it work? - outb($addrreg, $superio{devidreg}); - $val = inb($datareg); - outb($addrreg, $superio{devidreg} + 1); - $val = ($val << 8) | inb($datareg); - if ($val == 0x0000 || $val == 0xffff) { - print "No\n"; - next FAMILY; - } - print "Yes\n"; + $| = 1; + # reset state to avoid false positives + exit_superio($addrreg, $datareg); + foreach my $family (@superio_ids) { + printf("\%-60s", "Trying family `$family->{family}'... "); + # write the password + foreach $val (@{$family->{enter}->{$addrreg}}) { + outb($addrreg, $val); + } + # call the non-standard detection routine first if it exists + if (defined($family->{ns_detect}) && + &{$family->{ns_detect}}($addrreg, $datareg, $family->{ns_chips})) { + last; + } - $found = 0; - foreach my $chip (@{$family->{chips}}) { - if (($chip->{devid} > 0xff && ($val & ($chip->{devid_mask} || 0xffff)) == $chip->{devid}) - || ($chip->{devid} <= 0xff && ($val >> 8) == $chip->{devid})) { - probe_superio($addrreg, $datareg, $chip); - $found++; - } - } + # did it work? + outb($addrreg, $superio{devidreg}); + $val = inb($datareg); + outb($addrreg, $superio{devidreg} + 1); + $val = ($val << 8) | inb($datareg); + if ($val == 0x0000 || $val == 0xffff) { + print "No\n"; + next; + } + print "Yes\n"; - if (!$found) { - printf("Found unknown chip with ID 0x%04x\n", $val); - # Guess if a logical device could correspond to sensors - guess_superio_ld($addrreg, $datareg, $family->{guess}) - if defined $family->{guess}; - } + $found = 0; + foreach my $chip (@{$family->{chips}}) { + if (($chip->{devid} > 0xff && + ($val & ($chip->{devid_mask} || 0xffff)) == $chip->{devid}) + || ($chip->{devid} <= 0xff && + ($val >> 8) == $chip->{devid})) { + $features |= probe_superio($addrreg, $datareg, $chip); + $found++; + } + } - exit_superio($addrreg, $datareg); - last FAMILY; - } - $| = 0; + if (!$found) { + printf("Found unknown chip with ID 0x%04x\n", $val); + # Guess if a logical device could correspond to sensors + guess_superio_ld($addrreg, $datareg, $family->{guess}) + if defined $family->{guess}; + } + last; + } + exit_superio($addrreg, $datareg); + $| = 0; + return $features; } - -sub scan_cpu($) +sub scan_cpu { - my $entry = shift; - my $confidence; + my $entry = shift; + my $confidence; - printf("\%-60s", "$entry->{name}... "); - if (defined ($confidence = $entry->{detect}())) { - print "Success!\n"; - printf " (driver `%s')\n", $entry->{driver}; - my $new_hash = { - conf => $confidence, - chipname => $entry->{name}, - }; - add_isa_to_chips_detected(undef, $entry->{driver}, $new_hash); - } else { - print "No\n"; - } + printf("\%-60s", "$entry->{name}... "); + if (defined ($confidence = $entry->{detect}())) { + print "Success!\n"; + printf " (driver `%s')\n", $entry->{driver}; + my $new_hash = { + conf => $confidence, + chipname => $entry->{name}, + }; + add_isa_to_chips_detected($entry->{driver}, $new_hash); + } else { + print "No\n"; + } } - ################## # CHIP DETECTION # ################## -# This routine allows you to select which chips are optionally added to the -# chip detection list. The most common use is to allow for different chip -# detection/drivers based on different linux kernels -# This routine follows the pattern of the SiS adapter special cases +# This routine allows you to dynamically update the chip detection list. +# The most common use is to allow for different chip to driver mappings +# based on different linux kernels sub chip_special_cases { - # Based on the kernel, add the appropriate chip structures to the - # chip_ids detection list - if (kernel_version_at_least(2, 6, 24)) { - push @chip_ids, @chip_fschmd_ids; - } else { - push @chip_ids, @chip_oldfsc_ids; + # Some chip to driver mappings depend on the environment + foreach my $chip (@chip_ids) { + if (ref($chip->{driver}) eq 'CODE') { + $chip->{driver} = $chip->{driver}->(); + } } - if (kernel_version_at_least(2, 6, 0)) { - push @chip_ids, @chip_kern26_ids; - } else { - push @chip_ids, @chip_kern24_ids; + # Also fill the fake driver name of non-hwmon chips + foreach my $chip (@non_hwmon_chip_ids) { + $chip->{driver} = "not-a-sensor"; } } # Each function returns a confidence value. The higher this value, the more -# sure we are about this chip. A Winbond W83781D, for example, will be -# detected as a LM78 too; but as the Winbond detection has a higher confidence -# factor, you should identify it as a Winbond. +# sure we are about this chip. This may help overrule false positives, +# although we also attempt to prevent false positives in the first place. # Each function returns a list. The first element is the confidence value; # Each element after it is an SMBus address. In this way, we can detect # chips with several SMBus addresses. The SMBus address for which the # function was called is never returned. -# If there are devices which get confused if they are only read from, then -# this program will surely confuse them. But we guarantee never to write to -# any of these devices. - - -# $_[0]: A reference to the file descriptor to access this chip. +# All I2C detection functions below take at least 2 parameters: +# $_[0]: Reference to the file descriptor to access the chip # $_[1]: Address -# Returns: undef if not detected, (7) if detected. +# Some of these functions which can detect more than one type of device, +# take a third parameter: +# $_[2]: Chip to detect + # Registers used: 0x58 sub mtp008_detect { - my ($file, $addr) = @_; - return if (i2c_smbus_read_byte_data($file, 0x58)) != 0xac; - return (8); + my ($file, $addr) = @_; + return if i2c_smbus_read_byte_data($file, 0x58) != 0xac; + return 3; } -# $_[0]: Chip to detect (0 = LM78, 1 = LM78-J, 2 = LM79) -# $_[1]: A reference to the file descriptor to access this chip. -# $_[2]: Address -# Returns: undef if not detected, (6) if detected. +# Chip to detect: 0 = LM78, 2 = LM79 # Registers used: # 0x40: Configuration # 0x48: Full I2C Address # 0x49: Device ID sub lm78_detect { - my $reg; - my ($chip, $file, $addr) = @_; - return unless i2c_smbus_read_byte_data($file, 0x48) == $addr; - return unless (i2c_smbus_read_byte_data($file, 0x40) & 0x80) == 0x00; - $reg = i2c_smbus_read_byte_data($file, 0x49); - return unless ($chip == 0 and ($reg == 0x00 or $reg == 0x20)) or - ($chip == 1 and $reg == 0x40) or - ($chip == 2 and ($reg & 0xfe) == 0xc0); + my ($file, $addr, $chip) = @_; + my $reg; - # Explicitly prevent misdetection of Winbond chips - $reg = i2c_smbus_read_byte_data($file, 0x4f); - return if $reg == 0xa3 || $reg == 0x5c; + return unless i2c_smbus_read_byte_data($file, 0x48) == $addr; + return unless (i2c_smbus_read_byte_data($file, 0x40) & 0x80) == 0x00; - return (6); + $reg = i2c_smbus_read_byte_data($file, 0x49); + return if $chip == 0 && ($reg != 0x00 && $reg != 0x20 && $reg != 0x40); + return if $chip == 2 && ($reg & 0xfe) != 0xc0; + + # Explicitly prevent misdetection of Winbond chips + $reg = i2c_smbus_read_byte_data($file, 0x4f); + return if $reg == 0xa3 || $reg == 0x5c; + + return 6; } -# $_[0]: Chip to detect (0 = LM78, 1 = LM78-J, 2 = LM79) -# $_[1]: Address -# Returns: undef if not detected, 6 if detected. -# Note: Only address 0x290 is scanned at this moment. -sub lm78_isa_detect -{ - my ($chip, $addr) = @_; - my $val = inb ($addr + 1); - return if inb ($addr + 2) != $val or inb ($addr + 3) != $val or - inb ($addr + 7) != $val; - - $val = inb($addr + 5); - outb($addr + 5, ~$val & 0x7f); - if ((inb ($addr+5) & 0x7f) != (~ $val & 0x7f)) { - outb($addr+5, $val); - return; - } - my $readproc = sub { isa_read_byte $addr + 5, $addr + 6, @_ }; - return unless (&$readproc(0x40) & 0x80) == 0x00; - my $reg = &$readproc(0x49); - return unless ($chip == 0 and ($reg == 0x00 or $reg == 0x20)) or - ($chip == 1 and $reg == 0x40) or - ($chip == 2 and ($reg & 0xfe) == 0xc0); - - # Explicitly prevent misdetection of Winbond chips - $reg = &$readproc(0x4f); - return if $reg == 0xa3 || $reg == 0x5c; - - # Explicitly prevent misdetection of ITE chips - $reg = &$readproc(0x58); - return if $reg == 0x90; - - return 6; -} - - -# $_[0]: Chip to detect (0 = LM78, 1 = LM78-J, 2 = LM79) -# $_[1]: ISA address -# $_[2]: I2C file handle -# $_[3]: I2C address -sub lm78_alias_detect -{ - my ($chip, $isa_addr, $file, $i2c_addr) = @_; - my $i; - my $readproc = sub { isa_read_byte $isa_addr + 5, $isa_addr + 6, @_ }; - return 0 unless &$readproc(0x48) == $i2c_addr; - for ($i = 0x2b; $i <= 0x3d; $i ++) { - return 0 unless &$readproc($i) == i2c_smbus_read_byte_data($file, $i); - } - return 1; -} - -# $_[0]: Chip to detect (0 = LM75, 1 = DS75) -# $_[1]: A reference to the file descriptor to access this chip. -# $_[2]: Address (unused) -# Returns: undef if not detected, 3 or 6 if detected; -# 6 means that the temperatures make sense; -# 3 means that the temperatures look strange; +# Chip to detect: 0 = LM75, 1 = DS75 # Registers used: # 0x00: Temperature # 0x01: Configuration @@ -3652,48 +3375,43 @@ sub lm78_alias_detect # useful for detection anyway. sub lm75_detect { - my $i; - my ($chip, $file, $addr) = @_; - my $cur = i2c_smbus_read_byte_data($file, 0x00); - my $conf = i2c_smbus_read_byte_data($file, 0x01); + my ($file, $addr, $chip) = @_; + my $i; + my $cur = i2c_smbus_read_byte_data($file, 0x00); + my $conf = i2c_smbus_read_byte_data($file, 0x01); - my $hyst = i2c_smbus_read_byte_data($file, 0x02); - my $maxreg = $chip == 1 ? 0x0f : 0x07; - for $i (0x04 .. $maxreg) { - return if i2c_smbus_read_byte_data($file, $i) != $hyst; - } + my $hyst = i2c_smbus_read_byte_data($file, 0x02, NO_CACHE); + my $maxreg = $chip == 1 ? 0x0f : 0x07; + for $i (0x04 .. $maxreg) { + return if i2c_smbus_read_byte_data($file, $i, NO_CACHE) != $hyst; + } - my $os = i2c_smbus_read_byte_data($file, 0x03); - for $i (0x04 .. $maxreg) { - return if i2c_smbus_read_byte_data($file, $i) != $os; - } + my $os = i2c_smbus_read_byte_data($file, 0x03, NO_CACHE); + for $i (0x04 .. $maxreg) { + return if i2c_smbus_read_byte_data($file, $i, NO_CACHE) != $os; + } - if ($chip == 0) { - for ($i = 8; $i <= 248; $i += 40) { - return if i2c_smbus_read_byte_data($file, $i + 0x01) != $conf - or i2c_smbus_read_byte_data($file, $i + 0x02) != $hyst - or i2c_smbus_read_byte_data($file, $i + 0x03) != $os; - } - } + if ($chip == 0) { + for ($i = 8; $i <= 248; $i += 40) { + return if i2c_smbus_read_byte_data($file, $i + 0x01) != $conf + or i2c_smbus_read_byte_data($file, $i + 0x02) != $hyst + or i2c_smbus_read_byte_data($file, $i + 0x03) != $os; + } + } - # All registers hold the same value, obviously a misdetection - return if $conf == $cur and $cur == $hyst and $cur == $os; + # All registers hold the same value, obviously a misdetection + return if $conf == $cur and $cur == $hyst and $cur == $os; - # Unused bits - return if $chip == 0 and ($conf & 0xe0); - return if $chip == 1 and ($conf & 0x80); + # Unused bits + return if $chip == 0 and ($conf & 0xe0); + return if $chip == 1 and ($conf & 0x80); - # Most probable value ranges - return 6 if $cur <= 100 and ($hyst >= 10 && $hyst <= 125) - and ($os >= 20 && $os <= 127) and $hyst < $os; - return 3; + # Most probable value ranges + return 6 if $cur <= 100 and ($hyst >= 10 && $hyst <= 125) + and ($os >= 20 && $os <= 127) and $hyst < $os; + return 3; } -# $_[0]: A reference to the file descriptor to access this chip. -# $_[1]: Address -# Returns: undef if not detected, 3 or 6 if detected; -# 6 means that the temperatures make sense; -# 3 means that the temperatures look strange; # Registers used: # 0x00: Temperature # 0x01: Configuration @@ -3714,69 +3432,50 @@ sub lm75_detect # LM77 chip. sub lm77_detect { - my $i; - my ($file, $addr) = @_; - my $cur = i2c_smbus_read_byte_data($file, 0x00); - my $conf = i2c_smbus_read_byte_data($file, 0x01); - my $hyst = i2c_smbus_read_byte_data($file, 0x02); - my $os = i2c_smbus_read_byte_data($file, 0x03); + my ($file, $addr) = @_; + my $i; + my $cur = i2c_smbus_read_byte_data($file, 0x00); + my $conf = i2c_smbus_read_byte_data($file, 0x01); + my $hyst = i2c_smbus_read_byte_data($file, 0x02); + my $os = i2c_smbus_read_byte_data($file, 0x03); - my $low = i2c_smbus_read_byte_data($file, 0x04); - return if i2c_smbus_read_byte_data($file, 0x06) != $low; - return if i2c_smbus_read_byte_data($file, 0x07) != $low; + my $low = i2c_smbus_read_byte_data($file, 0x04, NO_CACHE); + return if i2c_smbus_read_byte_data($file, 0x06, NO_CACHE) != $low; + return if i2c_smbus_read_byte_data($file, 0x07, NO_CACHE) != $low; - my $high = i2c_smbus_read_byte_data($file, 0x05); - return if i2c_smbus_read_byte_data($file, 0x06) != $high; - return if i2c_smbus_read_byte_data($file, 0x07) != $high; + my $high = i2c_smbus_read_byte_data($file, 0x05, NO_CACHE); + return if i2c_smbus_read_byte_data($file, 0x06, NO_CACHE) != $high; + return if i2c_smbus_read_byte_data($file, 0x07, NO_CACHE) != $high; - for ($i = 8; $i <= 248; $i += 40) { - return if i2c_smbus_read_byte_data($file, $i + 0x01) != $conf; - return if i2c_smbus_read_byte_data($file, $i + 0x02) != $hyst; - return if i2c_smbus_read_byte_data($file, $i + 0x03) != $os; - return if i2c_smbus_read_byte_data($file, $i + 0x04) != $low; - return if i2c_smbus_read_byte_data($file, $i + 0x05) != $high; - } + for ($i = 8; $i <= 248; $i += 40) { + return if i2c_smbus_read_byte_data($file, $i + 0x01) != $conf; + return if i2c_smbus_read_byte_data($file, $i + 0x02) != $hyst; + return if i2c_smbus_read_byte_data($file, $i + 0x03) != $os; + return if i2c_smbus_read_byte_data($file, $i + 0x04) != $low; + return if i2c_smbus_read_byte_data($file, $i + 0x05) != $high; + } - # All registers hold the same value, obviously a misdetection - return if $conf == $cur and $cur == $hyst - and $cur == $os and $cur == $low and $cur == $high; + # All registers hold the same value, obviously a misdetection + return if $conf == $cur and $cur == $hyst + and $cur == $os and $cur == $low and $cur == $high; - # Unused bits - return if ($conf & 0xe0) - or (($cur >> 4) != 0 && ($cur >> 4) != 0xf) - or (($hyst >> 4) != 0 && ($hyst >> 4) != 0xf) - or (($os >> 4) != 0 && ($os >> 4) != 0xf) - or (($low >> 4) != 0 && ($low >> 4) != 0xf) - or (($high >> 4) != 0 && ($high >> 4) != 0xf); + # Unused bits + return if ($conf & 0xe0) + or (($cur >> 4) != 0 && ($cur >> 4) != 0xf) + or (($hyst >> 4) != 0 && ($hyst >> 4) != 0xf) + or (($os >> 4) != 0 && ($os >> 4) != 0xf) + or (($low >> 4) != 0 && ($low >> 4) != 0xf) + or (($high >> 4) != 0 && ($high >> 4) != 0xf); - # Make sure the chip supports SMBus read word transactions - $cur = i2c_smbus_read_word_data($file, 0x00); - return if $cur < 0; - $hyst = i2c_smbus_read_word_data($file, 0x02); - return if $hyst < 0; - $os = i2c_smbus_read_word_data($file, 0x03); - return if $os < 0; - $low = i2c_smbus_read_word_data($file, 0x04); - return if $low < 0; - $high = i2c_smbus_read_word_data($file, 0x05); - return if $high < 0; + # Make sure the chip supports SMBus read word transactions + foreach $i (0x00, 0x02, 0x03, 0x04, 0x05) { + return if i2c_smbus_read_word_data($file, $i) < 0; + } - $cur /= 16; - $hyst /= 16; - $os /= 16; - $high /= 16; - $low /= 16; - - # Most probable value ranges - return 6 if $cur <= 100 and $hyst <= 40 - and ($os >= 20 && $os <= 127) and ($high >= 20 && $high <= 127); - return 3; + return 3; } -# $_[0]: Chip to detect (0 = LM92, 1 = LM76, 2 = MAX6633/MAX6634/MAX6635) -# $_[1]: A reference to the file descriptor to access this chip. -# $_[2]: Address -# Returns: undef if not detected, 2 or 4 if detected; +# Chip to detect: 0 = LM92, 1 = LM76, 2 = MAX6633/MAX6634/MAX6635 # Registers used: # 0x01: Configuration (National Semiconductor only) # 0x02: Hysteresis @@ -3793,54 +3492,50 @@ sub lm77_detect # have an LM92 chip or compatible. sub lm92_detect { - my ($chip, $file, $addr) = @_; + my ($file, $addr, $chip) = @_; - my $conf = i2c_smbus_read_byte_data($file, 0x01); - my $hyst = i2c_smbus_read_byte_data($file, 0x02); - my $crit = i2c_smbus_read_byte_data($file, 0x03); - my $low = i2c_smbus_read_byte_data($file, 0x04); - my $high = i2c_smbus_read_byte_data($file, 0x05); + my $conf = i2c_smbus_read_byte_data($file, 0x01); + my $hyst = i2c_smbus_read_byte_data($file, 0x02); + my $crit = i2c_smbus_read_byte_data($file, 0x03); + my $low = i2c_smbus_read_byte_data($file, 0x04); + my $high = i2c_smbus_read_byte_data($file, 0x05); - return if $conf == 0 and $hyst == 0 and $crit == 0 - and $low == 0 and $high == 0; + return if $conf == 0 and $hyst == 0 and $crit == 0 + and $low == 0 and $high == 0; - # Unused bits - return if ($chip == 0 || $chip == 1) - and ($conf & 0xE0); + # Unused bits + return if ($chip == 0 || $chip == 1) + and ($conf & 0xE0); - for (my $i = 0; $i <= 240; $i += 16) { - return if i2c_smbus_read_byte_data($file, $i + 0x01) != $conf; - return if i2c_smbus_read_byte_data($file, $i + 0x02) != $hyst; - return if i2c_smbus_read_byte_data($file, $i + 0x03) != $crit; - return if i2c_smbus_read_byte_data($file, $i + 0x04) != $low; - return if i2c_smbus_read_byte_data($file, $i + 0x05) != $high; - } + for (my $i = 0; $i <= 240; $i += 16) { + return if i2c_smbus_read_byte_data($file, $i + 0x01) != $conf; + return if i2c_smbus_read_byte_data($file, $i + 0x02) != $hyst; + return if i2c_smbus_read_byte_data($file, $i + 0x03) != $crit; + return if i2c_smbus_read_byte_data($file, $i + 0x04) != $low; + return if i2c_smbus_read_byte_data($file, $i + 0x05) != $high; + } - return if $chip == 0 - and i2c_smbus_read_word_data($file, 0x07) != 0x0180; + return if $chip == 0 + and i2c_smbus_read_word_data($file, 0x07) != 0x0180; - # Make sure the chip supports SMBus read word transactions - $hyst = i2c_smbus_read_word_data($file, 0x02); - return if $hyst < 0; - $crit = i2c_smbus_read_word_data($file, 0x03); - return if $crit < 0; - $low = i2c_smbus_read_word_data($file, 0x04); - return if $low < 0; - $high = i2c_smbus_read_word_data($file, 0x05); - return if $high < 0; + # Make sure the chip supports SMBus read word transactions + $hyst = i2c_smbus_read_word_data($file, 0x02); + return if $hyst < 0; + $crit = i2c_smbus_read_word_data($file, 0x03); + return if $crit < 0; + $low = i2c_smbus_read_word_data($file, 0x04); + return if $low < 0; + $high = i2c_smbus_read_word_data($file, 0x05); + return if $high < 0; - foreach my $temp ($hyst, $crit, $low, $high) { - return if $chip == 2 and ($temp & 0x7F00); - return if $chip != 2 and ($temp & 0x0700); - } + foreach my $temp ($hyst, $crit, $low, $high) { + return if $chip == 2 and ($temp & 0x7F00); + return if $chip != 2 and ($temp & 0x0700); + } - return 4 if $chip == 0; - return 2; + return ($chip == 0) ? 4 : 2; } -# $_[0]: A reference to the file descriptor to access this chip. -# $_[1]: Address -# Returns: undef if not detected, 3 if detected # Registers used: # 0xAA: Temperature # 0xA1: High limit @@ -3858,33 +3553,30 @@ sub lm92_detect # transactions second. sub ds1621_detect { - my ($file, $addr) = @_; + my ($file, $addr) = @_; - my $conf = i2c_smbus_read_byte_data($file, 0xAC); - return if ($conf & 0x10); + my $conf = i2c_smbus_read_byte_data($file, 0xAC); + return if ($conf & 0x10); - my $temp = i2c_smbus_read_word_data($file, 0xAA); - return if $temp < 0 || ($temp & 0x0f00); - # On the DS1631, the following two checks are too strict in theory, - # but in practice I very much doubt that anyone will set temperature - # limits not a multiple of 0.5 degrees C. - my $high = i2c_smbus_read_word_data($file, 0xA1); - return if $high < 0 || ($high & 0x7f00); - my $low = i2c_smbus_read_word_data($file, 0xA2); - return if $low < 0 || ($low & 0x7f00); + my $temp = i2c_smbus_read_word_data($file, 0xAA); + return if $temp < 0 || ($temp & 0x0f00); + # On the DS1631, the following two checks are too strict in theory, + # but in practice I very much doubt that anyone will set temperature + # limits not a multiple of 0.5 degrees C. + my $high = i2c_smbus_read_word_data($file, 0xA1); + return if $high < 0 || ($high & 0x7f00); + my $low = i2c_smbus_read_word_data($file, 0xA2); + return if $low < 0 || ($low & 0x7f00); - return if ($temp == 0 && $high == 0 && $low == 0 && $conf == 0); + return if ($temp == 0 && $high == 0 && $low == 0 && $conf == 0); - # Old versions of the DS1621 apparently don't have the counter and - # slope registers (or they return crap) - my $counter = i2c_smbus_read_byte_data($file, 0xA8); - my $slope = i2c_smbus_read_byte_data($file, 0xA9); - return ($slope == 0x10 && $counter <= $slope) ? 3 : 2; + # Old versions of the DS1621 apparently don't have the counter and + # slope registers (or they return crap) + my $counter = i2c_smbus_read_byte_data($file, 0xA8); + my $slope = i2c_smbus_read_byte_data($file, 0xA9); + return ($slope == 0x10 && $counter <= $slope) ? 3 : 2; } -# $_[0]: A reference to the file descriptor to access this chip. -# $_[1]: Address -# Returns: undef if not detected, 1 to 3 if detected. # Registers used: # 0x00: Configuration register # 0x02: Interrupt state register @@ -3902,51 +3594,46 @@ sub ds1621_detect # to loose comparisons did not change the score. sub lm80_detect { - my ($i, $reg); - my ($file, $addr) = @_; + my ($file, $addr) = @_; + my ($i, $reg); - return if (i2c_smbus_read_byte_data($file, 0x00) & 0x80) != 0; - return if (i2c_smbus_read_byte_data($file, 0x02) & 0xc0) != 0; + return if (i2c_smbus_read_byte_data($file, 0x00) & 0x80) != 0; + return if (i2c_smbus_read_byte_data($file, 0x02) & 0xc0) != 0; - for ($i = 0x2a; $i <= 0x3d; $i++) { - $reg = i2c_smbus_read_byte_data($file, $i); - return if i2c_smbus_read_byte_data($file, $i+0x40) != $reg; - return if i2c_smbus_read_byte_data($file, $i+0x80) != $reg; - return if i2c_smbus_read_byte_data($file, $i+0xc0) != $reg; - } + for ($i = 0x2a; $i <= 0x3d; $i++) { + $reg = i2c_smbus_read_byte_data($file, $i); + return if i2c_smbus_read_byte_data($file, $i+0x40) != $reg; + return if i2c_smbus_read_byte_data($file, $i+0x80) != $reg; + return if i2c_smbus_read_byte_data($file, $i+0xc0) != $reg; + } - # Refine a bit by checking wether limits are in the correct order - # (min> 1) - 4; - # $confidence is now between -4 and 3 + # $confidence is between 0 and 14 + $confidence = ($confidence >> 1) - 4; + # $confidence is now between -4 and 3 - return unless $confidence > 0; + return unless $confidence > 0; - return $confidence; + return $confidence; } -# $_[0]: Chip to detect -# (0 = LM82/LM83) -# $_[1]: A reference to the file descriptor to access this chip. -# $_[2]: Address -# Returns: undef if not detected, 4 to 8 if detected. # Registers used: # 0x02: Status 1 # 0x03: Configuration @@ -3964,33 +3651,28 @@ sub lm80_detect # Thanks to Ben Gardner for reporting. sub lm83_detect { - my ($chip, $file) = @_; - return if i2c_smbus_read_byte_data($file, 0xfe) != 0x01; - my $chipid = i2c_smbus_read_byte_data($file, 0xff); - return if $chipid != 0x01 && $chipid != 0x03; + my ($file, $addr) = @_; + return if i2c_smbus_read_byte_data($file, 0xfe) != 0x01; + my $chipid = i2c_smbus_read_byte_data($file, 0xff); + return if $chipid != 0x01 && $chipid != 0x03; - my $confidence = 4; - $confidence++ - if (i2c_smbus_read_byte_data($file, 0x02) & 0xa8) == 0x00; - $confidence++ - if (i2c_smbus_read_byte_data($file, 0x03) & 0x41) == 0x00; - $confidence++ - if i2c_smbus_read_byte_data($file, 0x04) == 0x00; - $confidence++ - if (i2c_smbus_read_byte_data($file, 0x35) & 0x48) == 0x00; + my $confidence = 4; + $confidence++ + if (i2c_smbus_read_byte_data($file, 0x02) & 0xa8) == 0x00; + $confidence++ + if (i2c_smbus_read_byte_data($file, 0x03) & 0x41) == 0x00; + $confidence++ + if i2c_smbus_read_byte_data($file, 0x04) == 0x00; + $confidence++ + if (i2c_smbus_read_byte_data($file, 0x35) & 0x48) == 0x00; - return $confidence; + return $confidence; } -# $_[0]: Chip to detect -# (0 = LM90, 1=LM89/LM99, 2=LM86, 3=ADM1032, 4=MAX6657/MAX6658/MAX6659, -# 5 = ADT7461, 6 = MAX6648/MAX6692, 7 = MAX6680/MAX6681, -# 8 = W83L771W/G), 9 = TMP401, 10 = TMP411 -# $_[1]: A reference to the file descriptor to access this chip. -# $_[2]: Address -# Returns: undef if not detected, 4, 6 or 8 if detected. -# The Maxim chips MAX6657, MAX6658 and MAX6659 have a low confidence -# value (4) because they don't have a die revision register. +# Chip to detect: 0 = LM90, 1 = LM89/LM99, 2 = LM86, 3 = ADM1032, +# 4 = MAX6654/MAX6690, 5 = ADT7461, +# 6 = MAX6646/MAX6647/MAX6648/MAX6649/MAX6692, +# 7 = MAX6680/MAX6681, 8 = W83L771W/G, 9 = TMP401, 10 = TMP411 # Registers used: # 0x03: Configuration # 0x04: Conversion rate @@ -3998,99 +3680,154 @@ sub lm83_detect # 0xff: Chip ID / die revision sub lm90_detect { - my ($chip, $file, $addr) = @_; - my $mid = i2c_smbus_read_byte_data($file, 0xfe); - my $cid = i2c_smbus_read_byte_data($file, 0xff); - my $conf = i2c_smbus_read_byte_data($file, 0x03); - my $rate = i2c_smbus_read_byte_data($file, 0x04); + my ($file, $addr, $chip) = @_; + my $mid = i2c_smbus_read_byte_data($file, 0xfe); + my $cid = i2c_smbus_read_byte_data($file, 0xff); + my $conf = i2c_smbus_read_byte_data($file, 0x03); + my $rate = i2c_smbus_read_byte_data($file, 0x04); - if ($chip == 0) { - return if ($conf & 0x2a) != 0; - return if $rate > 0x09; - return if $mid != 0x01; # National Semiconductor - return 8 if $cid == 0x21; # LM90 - return 6 if ($cid & 0x0f) == 0x20; - } - if ($chip == 1) { - return if ($conf & 0x2a) != 0; - return if $rate > 0x09; - return if $mid != 0x01; # National Semiconductor - return 8 if $addr == 0x4c and $cid == 0x31; # LM89/LM99 - return 8 if $addr == 0x4d and $cid == 0x34; # LM89-1/LM99-1 - return 6 if ($cid & 0x0f) == 0x30; - } - if ($chip == 2) { - return if ($conf & 0x2a) != 0; - return if $rate > 0x09; - return if $mid != 0x01; # National Semiconductor - return 8 if $cid == 0x11; # LM86 - return 6 if ($cid & 0xf0) == 0x10; - } - if ($chip == 3) { - return if ($conf & 0x3f) != 0; - return if $rate > 0x0a; - return if $mid != 0x41; # Analog Devices - return 8 if ($cid & 0xf0) == 0x40; # ADM1032 - } - if ($chip == 4) { - return if ($conf & 0x1f) != ($mid & 0x0f); # No low nibble, - # returns previous low nibble - return if $rate > 0x09; - return if $mid != 0x4d; # Maxim - return if $cid != 0x4d; # No register, returns previous value - return 4; - } - if ($chip == 5) { - return if ($conf & 0x1b) != 0; - return if $rate > 0x0a; - return if $mid != 0x41; # Analog Devices - return 8 if $cid == 0x51; # ADT7461 - } - if ($chip == 6) { - return if ($conf & 0x3f) != 0; - return if $rate > 0x07; - return if $mid != 0x4d; # Maxim - return if $cid != 0x59; # MAX6648/MAX6692 - return 8; - } - if ($chip == 7) { - return if ($conf & 0x03) != 0; - return if $rate > 0x07; - return if $mid != 0x4d; # Maxim - return if $cid != 0x01; # MAX6680/MAX6681 - return 6; - } - if ($chip == 8) { - return if ($conf & 0x2a) != 0; - return if $rate > 0x09; - return if $mid != 0x5c; # Winbond - return if $cid != 0x00; # W83L771W/G - return 6; - } - if ($chip == 9) { - return if ($conf & 0x1B) != 0; - return if $rate > 0x0F; - return if $mid != 0x55; # Texas Instruments - return if $cid != 0x11; # TMP401 - return 6; - } - if ($chip == 10) { - return if ($conf & 0x1B) != 0; - return if $rate > 0x0F; - return if $mid != 0x55; # Texas Instruments - return 6 if ($addr == 0x4c && $cid == 0x12); # TMP411A - return 6 if ($addr == 0x4d && $cid == 0x13); # TMP411B - return 6 if ($addr == 0x4e && $cid == 0x10); # TMP411C - return; - } - return; + if ($chip == 0) { + return if ($conf & 0x2a) != 0; + return if $rate > 0x09; + return if $mid != 0x01; # National Semiconductor + return 8 if $cid == 0x21; # LM90 + return 6 if ($cid & 0x0f) == 0x20; + } + if ($chip == 1) { + return if ($conf & 0x2a) != 0; + return if $rate > 0x09; + return if $mid != 0x01; # National Semiconductor + return 8 if $addr == 0x4c and $cid == 0x31; # LM89/LM99 + return 8 if $addr == 0x4d and $cid == 0x34; # LM89-1/LM99-1 + return 6 if ($cid & 0x0f) == 0x30; + } + if ($chip == 2) { + return if ($conf & 0x2a) != 0; + return if $rate > 0x09; + return if $mid != 0x01; # National Semiconductor + return 8 if $cid == 0x11; # LM86 + return 6 if ($cid & 0xf0) == 0x10; + } + if ($chip == 3) { + return if ($conf & 0x3f) != 0; + return if $rate > 0x0a; + return if $mid != 0x41; # Analog Devices + return 6 if ($cid & 0xf0) == 0x40; # ADM1032 + } + if ($chip == 4) { + return if ($conf & 0x07) != 0; + return if $rate > 0x07; + return if $mid != 0x4d; # Maxim + return 8 if $cid == 0x08; # MAX6654/MAX6690 + } + if ($chip == 5) { + return if ($conf & 0x1b) != 0; + return if $rate > 0x0a; + return if $mid != 0x41; # Analog Devices + return 8 if $cid == 0x51; # ADT7461 + } + if ($chip == 6) { + return if ($conf & 0x3f) != 0; + return if $rate > 0x07; + return if $mid != 0x4d; # Maxim + return 8 if $cid == 0x59; # MAX6648/MAX6692 + } + if ($chip == 7) { + return if ($conf & 0x03) != 0; + return if $rate > 0x07; + return if $mid != 0x4d; # Maxim + return 8 if $cid == 0x01; # MAX6680/MAX6681 + } + if ($chip == 8) { + return if ($conf & 0x2a) != 0; + return if $rate > 0x09; + return if $mid != 0x5c; # Winbond + return 6 if $cid == 0x00; # W83L771W/G + } + if ($chip == 9) { + return if ($conf & 0x1B) != 0; + return if $rate > 0x0F; + return if $mid != 0x55; # Texas Instruments + return 8 if $cid == 0x11; # TMP401 + } + if ($chip == 10) { + return if ($conf & 0x1B) != 0; + return if $rate > 0x0F; + return if $mid != 0x55; # Texas Instruments + return 6 if ($addr == 0x4c && $cid == 0x12); # TMP411A + return 6 if ($addr == 0x4d && $cid == 0x13); # TMP411B + return 6 if ($addr == 0x4e && $cid == 0x10); # TMP411C + } + return; } -# $_[0]: Chip to detect -# (1 = LM63, 2 = F75363SG, 3 = LM64) -# $_[1]: A reference to the file descriptor to access this chip. -# $_[2]: Address (unused) -# Returns: undef if not detected, 6 if detected. +# Registers used: +# 0x03: Configuration (no low nibble, returns the previous low nibble) +# 0x04: Conversion rate +# 0xfe: Manufacturer ID +# 0xff: no register +sub max6657_detect +{ + my ($file, $addr) = @_; + my $mid = i2c_smbus_read_byte_data($file, 0xfe, NO_CACHE); + my $cid = i2c_smbus_read_byte_data($file, 0xff, NO_CACHE); + my $conf = i2c_smbus_read_byte_data($file, 0x03, NO_CACHE); + + return if $mid != 0x4d; # Maxim + return if ($conf & 0x1f) != 0x0d; + return if $cid != 0x4d; # No register, returns previous value + + my $rate = i2c_smbus_read_byte_data($file, 0x04, NO_CACHE); + return if $rate > 0x09; + + $cid = i2c_smbus_read_byte_data($file, 0xff, NO_CACHE); + $conf = i2c_smbus_read_byte_data($file, 0x03, NO_CACHE); + return if ($conf & 0x0f) != $rate; + return if $cid != $rate; # No register, returns previous value + + return 5; +} + +# Registers used: +# 0x03: Configuration +# 0xfe: Manufacturer ID +# 0xff: Revision ID +sub lm95231_detect +{ + my ($file, $addr) = @_; + my $mid = i2c_smbus_read_byte_data($file, 0xfe); + my $cid = i2c_smbus_read_byte_data($file, 0xff); + my $conf = i2c_smbus_read_byte_data($file, 0x03); + + return if ($conf & 0x89) != 0; + return if $mid != 0x01; # National Semiconductor + return if $cid != 0xa1; # LM95231 + + return 6; +} + +# Registers used: +# 0x03: Configuration 1 +# 0x24: Configuration 2 +# 0x3d: Manufacturer ID +# 0x3e: Device ID +sub adt7481_detect +{ + my ($file, $addr) = @_; + my $mid = i2c_smbus_read_byte_data($file, 0x3d); + my $cid = i2c_smbus_read_byte_data($file, 0x3e); + my $conf1 = i2c_smbus_read_byte_data($file, 0x03); + my $conf2 = i2c_smbus_read_byte_data($file, 0x24); + + return if ($conf1 & 0x10) != 0; + return if ($conf2 & 0x7f) != 0; + return if $mid != 0x41; # Analog Devices + return if $cid != 0x81; # ADT7481 + + return 6; +} + +# Chip to detect: 1 = LM63, 2 = F75363SG, 3 = LM64 # Registers used: # 0xfe: Manufacturer ID # 0xff: Chip ID / die revision @@ -4098,38 +3835,33 @@ sub lm90_detect # 0x16: Alert mask (two or three unused bits) sub lm63_detect { - my ($chip, $file, $addr) = @_; + my ($file, $addr, $chip) = @_; - my $mid = i2c_smbus_read_byte_data($file, 0xfe); - my $cid = i2c_smbus_read_byte_data($file, 0xff); - my $conf = i2c_smbus_read_byte_data($file, 0x03); - my $mask = i2c_smbus_read_byte_data($file, 0x16); + my $mid = i2c_smbus_read_byte_data($file, 0xfe); + my $cid = i2c_smbus_read_byte_data($file, 0xff); + my $conf = i2c_smbus_read_byte_data($file, 0x03); + my $mask = i2c_smbus_read_byte_data($file, 0x16); - if ($chip == 1) { - return if $mid != 0x01 # National Semiconductor - || $cid != 0x41; # LM63 - return if ($conf & 0x18) != 0x00 - || ($mask & 0xa4) != 0xa4; - } elsif ($chip == 2) { - return if $mid != 0x23 # Fintek - || $cid != 0x20; # F75363SG - return if ($conf & 0x1a) != 0x00 - || ($mask & 0x84) != 0x00; - } elsif ($chip == 3) { - return if $mid != 0x01 # National Semiconductor - || $cid != 0x51; # LM64 - return if ($conf & 0x18) != 0x00 - || ($mask & 0xa4) != 0xa4; - } + if ($chip == 1) { + return if $mid != 0x01 # National Semiconductor + || $cid != 0x41; # LM63 + return if ($conf & 0x18) != 0x00 + || ($mask & 0xa4) != 0xa4; + } elsif ($chip == 2) { + return if $mid != 0x23 # Fintek + || $cid != 0x20; # F75363SG + return if ($conf & 0x1a) != 0x00 + || ($mask & 0x84) != 0x00; + } elsif ($chip == 3) { + return if $mid != 0x01 # National Semiconductor + || $cid != 0x51; # LM64 + return if ($conf & 0x18) != 0x00 + || ($mask & 0xa4) != 0xa4; + } - return 6; + return 6; } -# $_[0]: Chip to detect -# (0 = ADM1029) -# $_[1]: A reference to the file descriptor to access this chip. -# $_[2]: Address (unused) -# Returns: undef if not detected, 6 if detected. # Registers used: # 0x02, 0x03: Fan support # 0x06: Temperature support @@ -4138,36 +3870,28 @@ sub lm63_detect # 0x0e: Chip ID / die revision sub adm1029_detect { - my ($chip, $file, $addr) = @_; - my $mid = i2c_smbus_read_byte_data($file, 0x0d); - my $cid = i2c_smbus_read_byte_data($file, 0x0e); - my $cfg; + my ($file, $addr) = @_; + my $mid = i2c_smbus_read_byte_data($file, 0x0d); + my $cid = i2c_smbus_read_byte_data($file, 0x0e); + my $cfg; - if ($chip == 0) { - return unless $mid == 0x41; # Analog Devices - return unless ($cid & 0xF0) == 0x00; # ADM1029 + return unless $mid == 0x41; # Analog Devices + return unless ($cid & 0xF0) == 0x00; # ADM1029 - # Extra check on unused bits - $cfg = i2c_smbus_read_byte_data($file, 0x02); - return unless $cfg == 0x03; - $cfg = i2c_smbus_read_byte_data($file, 0x06); - return unless ($cfg & 0xF9) == 0x01; - foreach my $reg (0x03, 0x07, 0x08, 0x09) { - $cfg = i2c_smbus_read_byte_data($file, $reg); - return unless ($cfg & 0xFC) == 0x00; - } + # Extra check on unused bits + $cfg = i2c_smbus_read_byte_data($file, 0x02); + return unless $cfg == 0x03; + $cfg = i2c_smbus_read_byte_data($file, 0x06); + return unless ($cfg & 0xF9) == 0x01; + foreach my $reg (0x03, 0x07, 0x08, 0x09) { + $cfg = i2c_smbus_read_byte_data($file, $reg); + return unless ($cfg & 0xFC) == 0x00; + } - return 7; - } - return; + return 7; } -# $_[0]: Chip to detect -# (0 = ADM1030, 1=ADM1031) -# $_[1]: A reference to the file descriptor to access this chip. -# $_[2]: Address -# Returns: undef if not detected, 3 to 7 (ADM1031) or 9 (ADM1030) -# if detected. +# Chip to detect: 0 = ADM1030, 1 = ADM1031 # Registers used: # 0x01: Config 2 # 0x03: Status 2 @@ -4178,272 +3902,239 @@ sub adm1029_detect # 0x3f: Die revision sub adm1031_detect { - my ($chip, $file, $addr) = @_; - my $mid = i2c_smbus_read_byte_data($file, 0x3e); - my $cid = i2c_smbus_read_byte_data($file, 0x3d); - my $drev = i2c_smbus_read_byte_data($file, 0x3f); - my $conf2 = i2c_smbus_read_byte_data($file, 0x01); - my $stat2 = i2c_smbus_read_byte_data($file, 0x03); - my $fsc = i2c_smbus_read_byte_data($file, 0x22); - my $lto = i2c_smbus_read_byte_data($file, 0x0d); - my $r1to = i2c_smbus_read_byte_data($file, 0x0e); - my $r2to = i2c_smbus_read_byte_data($file, 0x0f); - my $confidence = 3; + my ($file, $addr, $chip) = @_; + my $mid = i2c_smbus_read_byte_data($file, 0x3e); + my $cid = i2c_smbus_read_byte_data($file, 0x3d); + my $drev = i2c_smbus_read_byte_data($file, 0x3f); + my $conf2 = i2c_smbus_read_byte_data($file, 0x01); + my $stat2 = i2c_smbus_read_byte_data($file, 0x03); + my $fsc = i2c_smbus_read_byte_data($file, 0x22); + my $lto = i2c_smbus_read_byte_data($file, 0x0d); + my $r1to = i2c_smbus_read_byte_data($file, 0x0e); + my $r2to = i2c_smbus_read_byte_data($file, 0x0f); + my $confidence = 3; - if ($chip == 0) { - return if $mid != 0x41; # Analog Devices - return if $cid != 0x30; # ADM1030 - $confidence++ if ($drev & 0x70) == 0x00; - $confidence++ if ($conf2 & 0x4A) == 0x00; - $confidence++ if ($stat2 & 0x3F) == 0x00; - $confidence++ if ($fsc & 0xF0) == 0x00; - $confidence++ if ($lto & 0x70) == 0x00; - $confidence++ if ($r1to & 0x70) == 0x00; - return $confidence; - } - if ($chip == 1) { - return if $mid != 0x41; # Analog Devices - return if $cid != 0x31; # ADM1031 - $confidence++ if ($drev & 0x70) == 0x00; - $confidence++ if ($lto & 0x70) == 0x00; - $confidence++ if ($r1to & 0x70) == 0x00; - $confidence++ if ($r2to & 0x70) == 0x00; - return $confidence; - } - return; + if ($chip == 0) { + return if $mid != 0x41; # Analog Devices + return if $cid != 0x30; # ADM1030 + $confidence++ if ($drev & 0x70) == 0x00; + $confidence++ if ($conf2 & 0x4A) == 0x00; + $confidence++ if ($stat2 & 0x3F) == 0x00; + $confidence++ if ($fsc & 0xF0) == 0x00; + $confidence++ if ($lto & 0x70) == 0x00; + $confidence++ if ($r1to & 0x70) == 0x00; + return $confidence; + } + if ($chip == 1) { + return if $mid != 0x41; # Analog Devices + return if $cid != 0x31; # ADM1031 + $confidence++ if ($drev & 0x70) == 0x00; + $confidence++ if ($lto & 0x70) == 0x00; + $confidence++ if ($r1to & 0x70) == 0x00; + $confidence++ if ($r2to & 0x70) == 0x00; + return $confidence; + } } -# $_[0]: Chip to detect -# (0 = ADM1033, 1 = ADM1034) -# $_[1]: A reference to the file descriptor to access this chip. -# $_[2]: Address (unused) -# Returns: undef if not detected, 4 or 6 if detected. +# Chip to detect: 0 = ADM1033, 1 = ADM1034 # Registers used: # 0x3d: Chip ID # 0x3e: Manufacturer ID # 0x3f: Die revision sub adm1034_detect { - my ($chip, $file, $addr) = @_; - my $mid = i2c_smbus_read_byte_data($file, 0x3e); - my $cid = i2c_smbus_read_byte_data($file, 0x3d); - my $drev = i2c_smbus_read_byte_data($file, 0x3f); + my ($file, $addr, $chip) = @_; + my $mid = i2c_smbus_read_byte_data($file, 0x3e); + my $cid = i2c_smbus_read_byte_data($file, 0x3d); + my $drev = i2c_smbus_read_byte_data($file, 0x3f); - if ($chip == 0) { - return if $mid != 0x41; # Analog Devices - return if $cid != 0x33; # ADM1033 - return if ($drev & 0xf8) != 0x00; - return 6 if $drev == 0x02; - return 4; - } - if ($chip == 1) { - return if $mid != 0x41; # Analog Devices - return if $cid != 0x34; # ADM1034 - return if ($drev & 0xf8) != 0x00; - return 6 if $drev == 0x02; - return 4; - } - return + if ($chip == 0) { + return if $mid != 0x41; # Analog Devices + return if $cid != 0x33; # ADM1033 + return if ($drev & 0xf8) != 0x00; + return 6 if $drev == 0x02; + return 4; + } + if ($chip == 1) { + return if $mid != 0x41; # Analog Devices + return if $cid != 0x34; # ADM1034 + return if ($drev & 0xf8) != 0x00; + return 6 if $drev == 0x02; + return 4; + } } -# $_[0]: Chip to detect -# (0 = ADT7467/ADT7468, 1 = ADT7476, 2 = ADT7462, 3 = ADT7466, -# 4 = ADT7470) -# $_[1]: A reference to the file descriptor to access this chip. -# $_[2]: Address -# Returns: undef if not detected, 5 or 7 if detected. +# Chip to detect: 0 = ADT7467/ADT7468, 1 = ADT7476, 2 = ADT7462, 3 = ADT7466, +# 4 = ADT7470 # Registers used: # 0x3d: Chip ID # 0x3e: Manufacturer ID # 0x3f: Die revision sub adt7467_detect { - my ($chip, $file, $addr) = @_; - my $mid = i2c_smbus_read_byte_data($file, 0x3e); - my $cid = i2c_smbus_read_byte_data($file, 0x3d); - my $drev = i2c_smbus_read_byte_data($file, 0x3f); + my ($file, $addr, $chip) = @_; + my $mid = i2c_smbus_read_byte_data($file, 0x3e); + my $cid = i2c_smbus_read_byte_data($file, 0x3d); + my $drev = i2c_smbus_read_byte_data($file, 0x3f); - if ($chip == 0) { - return if $mid != 0x41; # Analog Devices - return if $cid != 0x68; # ADT7467 - return if ($drev & 0xf0) != 0x70; - return 7 if ($drev == 0x71 || $drev == 0x72); - return 5; - } - if ($chip == 1) { - return if $mid != 0x41; # Analog Devices - return if $cid != 0x76; # ADT7476 - return if ($drev & 0xf0) != 0x60; - return 7 if ($drev == 0x69); - return 5; - } - if ($chip == 2) { - return if $mid != 0x41; # Analog Devices - return if $cid != 0x62; # ADT7462 - return if ($drev & 0xf0) != 0x00; - return 7 if ($drev == 0x04); - return 5; - } - if ($chip == 3) { - return if $mid != 0x41; # Analog Devices - return if $cid != 0x66; # ADT7466 - return if ($drev & 0xf0) != 0x00; - return 7 if ($drev == 0x02); - return 5; - } - if ($chip == 4) { - return if $mid != 0x41; # Analog Devices - return if $cid != 0x70; # ADT7470 - return if ($drev & 0xf0) != 0x00; - return 7 if ($drev == 0x00); - return 5; - } - return + return if $mid != 0x41; # Analog Devices + + if ($chip == 0) { + return if $cid != 0x68; # ADT7467 + return if ($drev & 0xf0) != 0x70; + return 7 if $drev == 0x71 || $drev == 0x72; + return 5; + } + if ($chip == 1) { + return if $cid != 0x76; # ADT7476 + return if ($drev & 0xf0) != 0x60; + return 7 if $drev == 0x69; + return 5; + } + if ($chip == 2) { + return if $cid != 0x62; # ADT7462 + return if ($drev & 0xf0) != 0x00; + return 7 if $drev == 0x04; + return 5; + } + if ($chip == 3) { + return if $cid != 0x66; # ADT7466 + return if ($drev & 0xf0) != 0x00; + return 7 if $drev == 0x02; + return 5; + } + if ($chip == 4) { + return if $cid != 0x70; # ADT7470 + return if ($drev & 0xf0) != 0x00; + return 7 if $drev == 0x00; + return 5; + } } -# $_[0]: Chip to detect -# (0 = ADT7473, 1 = ADT7475) -# $_[1]: A reference to the file descriptor to access this chip. -# $_[2]: Address (unused) -# Returns: undef if not detected, 5 if detected. +# Chip to detect: 0 = ADT7473, 1 = ADT7475 # Registers used: # 0x3d: Chip ID # 0x3e: Manufacturer ID sub adt7473_detect { - my ($chip, $file, $addr) = @_; - my $mid = i2c_smbus_read_byte_data($file, 0x3e); - my $cid = i2c_smbus_read_byte_data($file, 0x3d); + my ($file, $addr, $chip) = @_; + my $mid = i2c_smbus_read_byte_data($file, 0x3e); + my $cid = i2c_smbus_read_byte_data($file, 0x3d); - if ($chip == 0) { - return if $mid != 0x41; # Analog Devices - return if $cid != 0x73; # ADT7473 - return 5; - } - if ($chip == 1) { - return if $mid != 0x41; # Analog Devices - return if $cid != 0x75; # ADT7475 - return 5; - } - return + return if $mid != 0x41; # Analog Devices + + return if $chip == 0 && $cid != 0x73; # ADT7473 + return if $chip == 1 && $cid != 0x75; # ADT7475 + return 5; } -# $_[0]: Chip to detect -# (0 = aSC7512, 1 = aSC7611, 2 = aSC7621) -# $_[1]: A reference to the file descriptor to access this chip. -# $_[2]: Address (unused) -# Returns: undef if not detected, 1 if detected. +# Chip to detect: 0 = aSC7512, 1 = aSC7611, 2 = aSC7621 # Registers used: -# 0x3e: Manufacturer ID (0x61) +# 0x3e: Manufacturer ID # 0x3f: Version - sub andigilog_detect { - my ($chip, $file, $addr) = @_; - my $mid = i2c_smbus_read_byte_data($file, 0x3e); - my $cid = i2c_smbus_read_byte_data($file, 0x3f); + my ($file, $addr, $chip) = @_; + my $mid = i2c_smbus_read_byte_data($file, 0x3e); + my $cid = i2c_smbus_read_byte_data($file, 0x3f); - return if ($mid != 0x61); + return if $mid != 0x61; # Andigilog - if ($chip == 0) { - return if $cid != 0x62; - return 5; - } - - if ($chip == 1) { - return if $cid != 0x69; - return 5; - } - - if ($chip == 2) { - return if ($cid != 0x6C && $cid != 0x6D); - return 5; - } - - return; + return if $chip == 0 && $cid != 0x62; + return if $chip == 1 && $cid != 0x69; + return if $chip == 2 && ($cid != 0x6C && $cid != 0x6D); + return 5; } -# $_[0]: Chip to detect -# (0 = aSC7511) -# $_[1]: A reference to the file descriptor to access this chip. -# $_[2]: Address (unused) -# Returns: undef if not detected, 1 if detected. # Registers used: # 0xfe: Manufacturer ID # 0xff: Die Code sub andigilog_aSC7511_detect { - my ($chip, $file, $addr) = @_; - my $mid = i2c_smbus_read_byte_data($file, 0xfe); - my $die = i2c_smbus_read_byte_data($file, 0xff); + my ($file, $addr) = @_; + my $mid = i2c_smbus_read_byte_data($file, 0xfe); + my $die = i2c_smbus_read_byte_data($file, 0xff); - if ($chip == 0) { - return if $mid != 0x61; # Andigilog - if ($die == 0x0) { - return 3; - } else { - return 1; - } - } - return; + return if $mid != 0x61; # Andigilog + return if $die != 0x00; + return 3; } -# $_[0]: Vendor to check for -# (0x01 = National Semi, 0x41 = Analog Dev, 0x5c = SMSC) -# $_[1]: A reference to the file descriptor to access this chip. -# #_[2]: Base address. -# Returns: undef if not detected, (7) or (8) if detected. -# Registers used: 0x3e == Vendor register. -# 0x3d == Device ID register (Analog Devices only). -# 0x3f == Version/Stepping register. -# Constants used: 0x01 == National Semiconductor Vendor Id. -# 0x41 == Analog Devices Vendor Id. -# 0x5c == SMSC Vendor Id. -# 0x60 == Version number. The lower 4 stepping -# bits are masked and ignored. +# Chip to detect: 0 = LM85, 1 = LM96000, 2 = ADM1027, 3 = ADT7463, +# 4 = EMC6D100/101, 5 = EMC6D102, 6 = EMC6D103 +# Registers used: +# 0x3e: Vendor register +# 0x3d: Device ID register (Analog Devices only) +# 0x3f: Version/Stepping register sub lm85_detect { - my ($vendor, $file, $addr) = @_; - return if (i2c_smbus_read_byte_data($file, 0x3e)) != $vendor; + my ($file, $addr, $chip) = @_; + my $vendor = i2c_smbus_read_byte_data($file, 0x3e); + my $verstep = i2c_smbus_read_byte_data($file, 0x3f); - my $verstep = i2c_smbus_read_byte_data($file, 0x3f); - return if ($verstep & 0xf0) != 0x60; + if ($chip == 0) { + return if $vendor != 0x01; # National Semiconductor + return if $verstep != 0x60 # LM85 C + && $verstep != 0x62; # LM85 B + } elsif ($chip == 1) { + return if $vendor != 0x01; # National Semiconductor + return if $verstep != 0x68 # LM96000 + && $verstep != 0x69; # LM96000 + } elsif ($chip == 2) { + return if $vendor != 0x41; # Analog Devices + return if $verstep != 0x60; # ADM1027 + } elsif ($chip == 3) { + return if $vendor != 0x41; # Analog Devices + return if $verstep != 0x62 # ADT7463 + && $verstep != 0x6a; # ADT7463 C + } elsif ($chip == 4) { + return if $vendor != 0x5c; # SMSC + return if $verstep != 0x60 # EMC6D100/101 A0 + && $verstep != 0x61; # EMC6D100/101 A1 + } elsif ($chip == 5) { + return if $vendor != 0x5c; # SMSC + return if $verstep != 0x65; # EMC6D102 + } elsif ($chip == 6) { + return if $vendor != 0x5c; # SMSC + return if $verstep != 0x68; # EMC6D103 + } - if ($vendor == 0x41) { # Analog Devices - return if i2c_smbus_read_byte_data($file, 0x3d) != 0x27; - return (8); - } - - if ($vendor == 0x5c) { # SMSC - # Return undef if this is a SCH5027 - return if $verstep >= 0x69 and - i2c_smbus_read_byte_data($file, 0xba) == 0x0f; - } - - return (7); + if ($vendor == 0x41) { # Analog Devices + return if i2c_smbus_read_byte_data($file, 0x3d) != 0x27; + return 8; + } + return 7; } -# $_[0]: A reference to the file descriptor to access this chip. -# $_[1]: Address -# Returns: undef if not detected, (7) if detected. -# Registers used: 0x3E, 0x3F -# Assume lower 2 bits of reg 0x3F are for revisions. +# Chip to detect: 0 = LM87, 1 = ADM1024 +# Registers used: +# 0x3e: Company ID +# 0x3f: Revision +# 0x40: Configuration sub lm87_detect { - my ($file, $addr) = @_; - return if (i2c_smbus_read_byte_data($file, 0x3e)) != 0x02; - return if (i2c_smbus_read_byte_data($file, 0x3f) & 0xfc) != 0x04; - return (7); + my ($file, $addr, $chip) = @_; + my $cid = i2c_smbus_read_byte_data($file, 0x3e); + my $rev = i2c_smbus_read_byte_data($file, 0x3f); + + if ($chip == 0) { + return if $cid != 0x02; # National Semiconductor + return if ($rev & 0xfc) != 0x04; # LM87 + } + if ($chip == 1) { + return if $cid != 0x41; # Analog Devices + return if ($rev & 0xf0) != 0x10; # ADM1024 + } + + my $cfg = i2c_smbus_read_byte_data($file, 0x40); + return if ($cfg & 0x80) != 0x00; + + return 7; } -# $_[0]: Chip to detect (0 = W83781D, 1 = W83782D, 2 = W83783S, -# 3 = W83627HF, 4 = AS99127F (rev.1), -# 5 = AS99127F (rev.2), 6 = ASB100, 7 = W83791D, -# 8 = W83792D, 9 = W83627EHF, 10 = W83627DHG) -# $_[1]: A reference to the file descriptor to access this chip. -# $_[2]: Address -# Returns: undef if not detected, (8, addr1, addr2) if detected, but only -# if the LM75 chip emulation is enabled. +# Chip to detect: 0 = W83781D, 1 = W83782D, 2 = W83783S, 3 = W83627HF, +# 4 = AS99127F (rev.1), 5 = AS99127F (rev.2), 6 = ASB100, +# 7 = W83791D, 8 = W83792D, 9 = W83627EHF, 10 = W83627DHG # Registers used: # 0x48: Full I2C Address # 0x4a: I2C addresses of emulated LM75 chips @@ -4451,62 +4142,55 @@ sub lm87_detect # 0x4f: Vendor ID # 0x58: Device ID (only when in bank 0) # Note: Fails if the W8378xD is not in bank 0! -# Note: Detection overrules a previous LM78 detection # Note: Asus chips do not have their I2C address at register 0x48? # AS99127F rev.1 and ASB100 have 0x00, confirmation wanted for # AS99127F rev.2. sub w83781d_detect { - my ($reg1, $reg2, @res); - my ($chip, $file, $addr) = @_; + my ($file, $addr, $chip) = @_; + my ($reg1, $reg2, @res); - return unless (i2c_smbus_read_byte_data($file, 0x48) == $addr) - or ($chip >= 4 && $chip <= 6); + return unless (i2c_smbus_read_byte_data($file, 0x48) == $addr) + or ($chip >= 4 && $chip <= 6); - $reg1 = i2c_smbus_read_byte_data($file, 0x4e); - $reg2 = i2c_smbus_read_byte_data($file, 0x4f); - if ($chip == 4) { # Asus AS99127F (rev.1) - return unless (($reg1 & 0x80) == 0x00 and $reg2 == 0xc3) or - (($reg1 & 0x80) == 0x80 and $reg2 == 0x12); - } elsif ($chip == 6) { # Asus ASB100 - return unless (($reg1 & 0x80) == 0x00 and $reg2 == 0x94) or - (($reg1 & 0x80) == 0x80 and $reg2 == 0x06); - } else { # Winbond and Asus AS99127F (rev.2) - return unless (($reg1 & 0x80) == 0x00 and $reg2 == 0xa3) or - (($reg1 & 0x80) == 0x80 and $reg2 == 0x5c); - } + $reg1 = i2c_smbus_read_byte_data($file, 0x4e); + $reg2 = i2c_smbus_read_byte_data($file, 0x4f); + if ($chip == 4) { # Asus AS99127F (rev.1) + return unless (($reg1 & 0x80) == 0x00 and $reg2 == 0xc3) or + (($reg1 & 0x80) == 0x80 and $reg2 == 0x12); + } elsif ($chip == 6) { # Asus ASB100 + return unless (($reg1 & 0x80) == 0x00 and $reg2 == 0x94) or + (($reg1 & 0x80) == 0x80 and $reg2 == 0x06); + } else { # Winbond and Asus AS99127F (rev.2) + return unless (($reg1 & 0x80) == 0x00 and $reg2 == 0xa3) or + (($reg1 & 0x80) == 0x80 and $reg2 == 0x5c); + } - return unless ($reg1 & 0x07) == 0x00; + return unless ($reg1 & 0x07) == 0x00; - $reg1 = i2c_smbus_read_byte_data($file, 0x58); - return if $chip == 0 and ($reg1 != 0x10 && $reg1 != 0x11); - return if $chip == 1 and $reg1 != 0x30; - return if $chip == 2 and $reg1 != 0x40; - return if $chip == 3 and $reg1 != 0x21; - return if $chip == 4 and $reg1 != 0x31; - return if $chip == 5 and $reg1 != 0x31; - return if $chip == 6 and $reg1 != 0x31; - return if $chip == 7 and $reg1 != 0x71; - return if $chip == 8 and $reg1 != 0x7a; - return if $chip == 9 and ($reg1 != 0x88 && $reg1 != 0xa1); - return if $chip == 10 and $reg1 != 0xc1; - # Default address is 0x2d - @res = ($addr != 0x2d) ? (7) : (8); - return @res if $chip >= 9; # No subclients + $reg1 = i2c_smbus_read_byte_data($file, 0x58); + return if $chip == 0 and ($reg1 != 0x10 && $reg1 != 0x11); + return if $chip == 1 and $reg1 != 0x30; + return if $chip == 2 and $reg1 != 0x40; + return if $chip == 3 and $reg1 != 0x21; + return if $chip == 4 and $reg1 != 0x31; + return if $chip == 5 and $reg1 != 0x31; + return if $chip == 6 and $reg1 != 0x31; + return if $chip == 7 and $reg1 != 0x71; + return if $chip == 8 and $reg1 != 0x7a; + return if $chip == 9 and ($reg1 != 0x88 && $reg1 != 0xa1); + return if $chip == 10 and $reg1 != 0xc1; + # Default address is 0x2d + @res = ($addr != 0x2d) ? (7) : (8); + return @res if $chip >= 9; # No subclients - $reg1 = i2c_smbus_read_byte_data($file, 0x4a); - push @res, ($reg1 & 0x07) + 0x48 unless $reg1 & 0x08; - push @res, (($reg1 & 0x70) >> 4) + 0x48 unless ($reg1 & 0x80 or $chip == 2); - return @res; + $reg1 = i2c_smbus_read_byte_data($file, 0x4a); + push @res, ($reg1 & 0x07) + 0x48 unless $reg1 & 0x08; + push @res, (($reg1 & 0x70) >> 4) + 0x48 + unless ($reg1 & 0x80 or $chip == 2); + return @res; } -# $_[0]: Chip to detect (0 = W83793) -# $_[1]: A reference to the file descriptor to access this chip. -# $_[2]: Address -# Returns: undef if not detected -# 6 if detected and bank different from 0 -# (8, addr1, addr2) if detected, bank is 0 and LM75 chip emulation -# is enabled # Registers used: # 0x0b: Full I2C Address # 0x0c: I2C addresses of emulated LM75 chips @@ -4515,33 +4199,30 @@ sub w83781d_detect # 0x0e: Device ID(Bank 0, 1, 2) sub w83793_detect { - my ($bank, $reg, @res); - my ($chip, $file, $addr) = @_; + my ($file, $addr) = @_; + my ($bank, $reg, @res); - $bank = i2c_smbus_read_byte_data($file, 0x00); - $reg = i2c_smbus_read_byte_data($file, 0x0d); + $bank = i2c_smbus_read_byte_data($file, 0x00); + $reg = i2c_smbus_read_byte_data($file, 0x0d); - return unless (($bank & 0x80) == 0x00 and $reg == 0xa3) or - (($bank & 0x80) == 0x80 and $reg == 0x5c); + return unless (($bank & 0x80) == 0x00 and $reg == 0xa3) or + (($bank & 0x80) == 0x80 and $reg == 0x5c); - $reg = i2c_smbus_read_byte_data($file, 0x0e); - return if $chip == 0 and $reg != 0x7b; + $reg = i2c_smbus_read_byte_data($file, 0x0e); + return if $reg != 0x7b; -# If bank 0 is selected, we can do more checks - return 6 unless ($bank & 0x07) == 0; - $reg = i2c_smbus_read_byte_data($file, 0x0b); - return unless ($reg == ($addr << 1)); + # If bank 0 is selected, we can do more checks + return 6 unless ($bank & 0x07) == 0; + $reg = i2c_smbus_read_byte_data($file, 0x0b); + return unless ($reg == ($addr << 1)); - $reg = i2c_smbus_read_byte_data($file, 0x0c); - @res = (8); - push @res, ($reg & 0x07) + 0x48 unless $reg & 0x08; - push @res, (($reg & 0x70) >> 4) + 0x48 unless $reg & 0x80; - return @res; + $reg = i2c_smbus_read_byte_data($file, 0x0c); + @res = (8); + push @res, ($reg & 0x07) + 0x48 unless $reg & 0x08; + push @res, (($reg & 0x70) >> 4) + 0x48 unless $reg & 0x80; + return @res; } -# $_[0]: A reference to the file descriptor to access this chip. -# $_[1]: Address -# Returns: undef if not detected, 3 if detected # Registers used: # 0x48: Full I2C Address # 0x4e: Vendor ID byte selection @@ -4554,26 +4235,22 @@ sub w83793_detect # we should investigate about. sub w83791sd_detect { - my ($file, $addr) = @_; - my ($reg1, $reg2); + my ($file, $addr) = @_; + my ($reg1, $reg2); - return unless (i2c_smbus_read_byte_data($file, 0x48) == $addr); + return unless (i2c_smbus_read_byte_data($file, 0x48) == $addr); - $reg1 = i2c_smbus_read_byte_data($file, 0x4e); - $reg2 = i2c_smbus_read_byte_data($file, 0x4f); - return unless (!($reg1 & 0x80) && $reg2 == 0xa3) - || (($reg1 & 0x80) && $reg2 == 0x5c); + $reg1 = i2c_smbus_read_byte_data($file, 0x4e); + $reg2 = i2c_smbus_read_byte_data($file, 0x4f); + return unless (!($reg1 & 0x80) && $reg2 == 0xa3) + || (($reg1 & 0x80) && $reg2 == 0x5c); - $reg1 = i2c_smbus_read_byte_data($file, 0x58); - return unless $reg1 == 0x72; + $reg1 = i2c_smbus_read_byte_data($file, 0x58); + return unless $reg1 == 0x72; - return 3; + return 3; } -# $_[0]: Chip to detect (0 = ASM58, 1 = AS2K129R, 2 = ???) -# $_[1]: A reference to the file descriptor to access this chip -# $_[2]: Address (unused) -# Returns: undef if not detected, 5 if detected # Registers used: # 0x4e: Vendor ID high byte # 0x4f: Vendor ID low byte @@ -4582,242 +4259,135 @@ sub w83791sd_detect # to confirm. sub mozart_detect { - my ($vid, $dev); - my ($chip, $file, $addr) = @_; + my ($file, $addr) = @_; + my ($vid, $dev); - $vid = (i2c_smbus_read_byte_data($file, 0x4e) << 8) - + i2c_smbus_read_byte_data($file, 0x4f); - $dev = i2c_smbus_read_byte_data($file, 0x58); + $vid = (i2c_smbus_read_byte_data($file, 0x4e) << 8) + + i2c_smbus_read_byte_data($file, 0x4f); + $dev = i2c_smbus_read_byte_data($file, 0x58); - return if ($chip == 0) and ($dev != 0x56 || $vid != 0x9436); - return if ($chip == 1) and ($dev != 0x56 || $vid != 0x9406); - return if ($chip == 2) and ($dev != 0x10 || $vid != 0x5ca3); + return unless ($dev == 0x56 && $vid == 0x9436) # ASM58 + || ($dev == 0x56 && $vid == 0x9406) # AS2K129R + || ($dev == 0x10 && $vid == 0x5ca3); - return 5; + return 5; } -# $_[0]: Chip to detect (0 = W83781D, 1 = W83782D, 3 = W83627HF, -# 9 = W83627EHF, 10 = W83627DHG) -# $_[1]: ISA address -# $_[2]: I2C file handle -# $_[3]: I2C address -sub w83781d_alias_detect -{ - my ($chip, $isa_addr, $file, $i2c_addr) = @_; - my $i; - my $readproc = sub { isa_read_byte $isa_addr + 5, $isa_addr + 6, @_ }; - return 0 unless &$readproc(0x48) == $i2c_addr; - for ($i = 0x2b; $i <= 0x3d; $i ++) { - return 0 unless &$readproc($i) == i2c_smbus_read_byte_data($file, $i); - } - return 1; -} - -# $_[0]: Chip to detect (0 = W83781D, 1 = W83782D) -# $_[1]: Address -# Returns: undef if not detected, (8) if detected. -sub w83781d_isa_detect -{ - my ($chip, $addr) = @_; - my ($reg1, $reg2); - my $val = inb ($addr + 1); - return if inb ($addr + 2) != $val or inb ($addr + 3) != $val or - inb ($addr + 7) != $val; - - $val = inb($addr + 5); - outb($addr+5, ~$val & 0x7f); - if ((inb ($addr+5) & 0x7f) != (~ $val & 0x7f)) { - outb($addr+5, $val); - return; - } - - my $read_proc = sub { isa_read_byte $addr + 5, $addr + 6, @_ }; - $reg1 = &$read_proc(0x4e); - $reg2 = &$read_proc(0x4f); - return unless (($reg1 & 0x80) == 0x00 and $reg2 == 0xa3) or - (($reg1 & 0x80) == 0x80 and $reg2 == 0x5c); - return unless ($reg1 & 0x07) == 0x00; - $reg1 = &$read_proc(0x58); - return if $chip == 0 and ($reg1 & 0xfe) != 0x10; - return if $chip == 1 and ($reg1 & 0xfe) != 0x30; - - return 8; -} - -# $_[0]: Chip to detect (0 = Revision 0x00, 1 = Revision 0x80) -# $_[1]: A reference to the file descriptor to access this chip. -# $_[2]: Address -# Returns: undef if not detected, (6) if detected. +# Chip to detect: 0 = GL518SM, 1 = GL520SM # Registers used: # 0x00: Device ID # 0x01: Revision ID # 0x03: Configuration -# Mediocre detection sub gl518sm_detect { - my $reg; - my ($chip, $file, $addr) = @_; - return unless i2c_smbus_read_byte_data($file, 0x00) == 0x80; - return unless (i2c_smbus_read_byte_data($file, 0x03) & 0x80) == 0x00; - $reg = i2c_smbus_read_byte_data($file, 0x01); - return unless ($chip == 0 and $reg == 0x00) or - ($chip == 1 and $reg == 0x80); - return (6); + my ($file, $addr, $chip) = @_; + my $reg; + + $reg = i2c_smbus_read_byte_data($file, 0x00); + return if $chip == 0 && $reg != 0x80; + return if $chip == 1 && $reg != 0x20; + + return unless (i2c_smbus_read_byte_data($file, 0x03) & 0x80) == 0x00; + $reg = i2c_smbus_read_byte_data($file, 0x01); + return unless $reg == 0x00 or $reg == 0x80; + return 6; } -# $_[0]: A reference to the file descriptor to access this chip. -# $_[1]: Address -# Returns: undef if not detected, (5) if detected. # Registers used: # 0x00: Device ID -# 0x01: Revision ID # 0x03: Configuration # Mediocre detection -sub gl520sm_detect -{ - my ($file, $addr) = @_; - return unless i2c_smbus_read_byte_data($file, 0x00) == 0x20; - return unless (i2c_smbus_read_byte_data($file, 0x03) & 0x80) == 0x00; - # The line below must be better checked before I dare to use it. - # return unless i2c_smbus_read_byte_data($file, 0x01) == 0x00; - return (5); -} - -# $_[0]: A reference to the file descriptor to access this chip. -# $_[1]: Address -# Returns: undef if not detected, (5) if detected. -# Registers used: -# 0x00: Device ID -# Mediocre detection sub gl525sm_detect { - my ($file, $addr) = @_; - return unless i2c_smbus_read_byte_data($file, 0x00) == 0x25; - return (5); + my ($file, $addr) = @_; + return unless i2c_smbus_read_byte_data($file, 0x00) == 0x25; + return unless (i2c_smbus_read_byte_data($file, 0x03) & 0x80) == 0x00; + return 5; } -# $_[0]: Chip to detect (0 = ADM9240, 1 = DS1780, 2 = LM81) -# $_[1]: A reference to the file descriptor to access this chip. -# $_[2]: Address -# Returns: undef if not detected, (7) if detected. +# Chip to detect: 0 = ADM9240, 1 = DS1780, 2 = LM81 # Registers used: # 0x3e: Company ID # 0x40: Configuration # 0x48: Full I2C Address -# Note: Detection overrules a previous LM78 detection sub adm9240_detect { - my $reg; - my ($chip, $file, $addr) = @_; - $reg = i2c_smbus_read_byte_data($file, 0x3e); - return unless ($chip == 0 and $reg == 0x23) or - ($chip == 1 and $reg == 0xda) or - ($chip == 2 and $reg == 0x01); - return unless (i2c_smbus_read_byte_data($file, 0x40) & 0x80) == 0x00; - return unless i2c_smbus_read_byte_data($file, 0x48) == $addr; + my ($file, $addr, $chip) = @_; + my $reg; + $reg = i2c_smbus_read_byte_data($file, 0x3e); + return unless ($chip == 0 and $reg == 0x23) or + ($chip == 1 and $reg == 0xda) or + ($chip == 2 and $reg == 0x01); + return unless (i2c_smbus_read_byte_data($file, 0x40) & 0x80) == 0x00; + return unless i2c_smbus_read_byte_data($file, 0x48) == $addr; - return (7); + return 7; } -# $_[0]: Chip to detect (0 = ADM1022, 1 = THMC50, 2 = ADM1028) -# $_[1]: A reference to the file descriptor to access this chip. -# $_[2]: Address -# Returns: undef if not detected, (8) if detected. +# Chip to detect: 0 = ADM1022, 1 = THMC50, 2 = ADM1028, 3 = THMC51 # Registers used: # 0x3e: Company ID # 0x3f: Revision # 0x40: Configuration -# Note: Detection overrules a previous LM78 or ADM9240 detection sub adm1022_detect { - my $reg; - my ($chip, $file, $addr) = @_; - $reg = i2c_smbus_read_byte_data($file, 0x3e); - return unless ($chip == 0 and $reg == 0x41) or - ($chip == 1 and $reg == 0x49) or - ($chip == 2 and $reg == 0x41); - $reg = i2c_smbus_read_byte_data($file, 0x40); - return if ($reg & 0x10); # Soft Reset always reads 0 - return if ($chip != 0 and ($reg & 0x80)); # Reserved on THMC50 and ADM1028 - $reg = i2c_smbus_read_byte_data($file, 0x3f) & 0xf0; - return unless ($chip == 0 and $reg == 0xc0) or - ($chip == 1 and $reg == 0xc0) or - ($chip == 2 and $reg == 0xd0); - return (8); + my ($file, $addr, $chip) = @_; + my $reg; + $reg = i2c_smbus_read_byte_data($file, 0x3e); + return unless ($chip == 0 and $reg == 0x41) or + ($chip == 1 and $reg == 0x49) or + ($chip == 2 and $reg == 0x41) or + ($chip == 3 and $reg == 0x49); + $reg = i2c_smbus_read_byte_data($file, 0x40); + return if ($reg & 0x10); # Soft Reset always reads 0 + return if ($chip != 0 and ($reg & 0x80)); # Reserved on THMC50 and ADM1028 + $reg = i2c_smbus_read_byte_data($file, 0x3f) & 0xf0; + return unless ($chip == 0 and $reg == 0xc0) or + ($chip == 1 and $reg == 0xc0) or + ($chip == 2 and $reg == 0xd0) or + ($chip == 3 and $reg == 0xd0); + return 8; } -# $_[0]: Chip to detect (0 = ADM1025, 1 = NE1619) -# $_[1]: A reference to the file descriptor to access this chip. -# $_[2]: Address -# Returns: undef if not detected, (8) if detected. +# Chip to detect: 0 = ADM1025, 1 = NE1619 # Registers used: # 0x3e: Company ID # 0x3f: Revision # 0x40: Configuration # 0x41: Status 1 # 0x42: Status 2 -# Note: Detection overrules a previous LM78 or ADM9240 detection sub adm1025_detect { - my $reg; - my ($chip, $file, $addr) = @_; + my ($file, $addr, $chip) = @_; + my $reg; - $reg = i2c_smbus_read_byte_data($file, 0x3e); - return if ($chip == 0) and ($reg != 0x41); - return if ($chip == 1) and ($reg != 0xA1); + $reg = i2c_smbus_read_byte_data($file, 0x3e); + return if ($chip == 0) and ($reg != 0x41); + return if ($chip == 1) and ($reg != 0xA1); - return unless (i2c_smbus_read_byte_data($file, 0x40) & 0x80) == 0x00; - return unless (i2c_smbus_read_byte_data($file, 0x41) & 0xC0) == 0x00; - return unless (i2c_smbus_read_byte_data($file, 0x42) & 0xBC) == 0x00; - return unless (i2c_smbus_read_byte_data($file, 0x3f) & 0xf0) == 0x20; + return unless (i2c_smbus_read_byte_data($file, 0x40) & 0x80) == 0x00; + return unless (i2c_smbus_read_byte_data($file, 0x41) & 0xC0) == 0x00; + return unless (i2c_smbus_read_byte_data($file, 0x42) & 0xBC) == 0x00; + return unless (i2c_smbus_read_byte_data($file, 0x3f) & 0xf0) == 0x20; - return (8); + return 8; } -# $_[0]: Chip to detect (0 = ADM1026) -# $_[1]: A reference to the file descriptor to access this chip. -# $_[2]: Address -# Returns: undef if not detected, (8) if detected. # Registers used: # 0x16: Company ID # 0x17: Revision sub adm1026_detect { - my $reg; - my ($chip, $file, $addr) = @_; - $reg = i2c_smbus_read_byte_data($file, 0x16); - return unless ($reg == 0x41); - return unless (i2c_smbus_read_byte_data($file, 0x17) & 0xf0) == 0x40; - return (8); + my ($file, $addr) = @_; + my $reg; + $reg = i2c_smbus_read_byte_data($file, 0x16); + return unless ($reg == 0x41); + return unless (i2c_smbus_read_byte_data($file, 0x17) & 0xf0) == 0x40; + return 8; } -# $_[0]: Chip to detect (0 = ADM1024) -# $_[1]: A reference to the file descriptor to access this chip. -# $_[2]: Address -# Returns: undef if not detected, (8) if detected. -# Registers used: -# 0x3e: Company ID -# 0x3f: Revision -# 0x40: Configuration -sub adm1024_detect -{ - my $reg; - my ($chip, $file, $addr) = @_; - $reg = i2c_smbus_read_byte_data($file, 0x3e); - return unless ($reg == 0x41); - return unless (i2c_smbus_read_byte_data($file, 0x40) & 0x80) == 0x00; - return unless (i2c_smbus_read_byte_data($file, 0x3f) & 0xf0) == 0x10; - return (8); -} - -# $_[0]: Chip to detect -# (0 = ADM1021, 1 = ADM1021A/ADM1023, 2 = MAX1617, 3 = MAX1617A, 4 = THMC10, -# 5 = LM84, 6 = GL523, 7 = MC1066) -# $_[1]: A reference to the file descriptor to access this chip. -# $_[2]: Address -# Returns: undef if not detected, 3 if simply detected, 5 if detected and -# manufacturer ID matches, 7 if detected and manufacturer ID and -# revision match +# Chip to detect: 0 = ADM1021, 1 = ADM1021A/ADM1023, 2 = MAX1617, 3 = MAX1617A, +# 4 = THMC10, 5 = LM84, 6 = GL523, 7 = MC1066 # Registers used: # 0x04: Company ID (LM84 only) # 0xfe: Company ID (all but LM84 and MAX1617) @@ -4830,96 +4400,83 @@ sub adm1024_detect # confidence value. sub adm1021_detect { - my ($chip, $file, $addr) = @_; - my $man_id = i2c_smbus_read_byte_data($file, 0xfe); - my $rev = i2c_smbus_read_byte_data($file, 0xff); - my $conf = i2c_smbus_read_byte_data($file, 0x03); - my $status = i2c_smbus_read_byte_data($file, 0x02); - my $convrate = i2c_smbus_read_byte_data($file, 0x04); + my ($file, $addr, $chip) = @_; + my $man_id = i2c_smbus_read_byte_data($file, 0xfe); + my $rev = i2c_smbus_read_byte_data($file, 0xff); + my $conf = i2c_smbus_read_byte_data($file, 0x03); + my $status = i2c_smbus_read_byte_data($file, 0x02); + my $convrate = i2c_smbus_read_byte_data($file, 0x04); - # Check manufacturer IDs and product revisions when available - return if $chip == 0 and $man_id != 0x41 || - ($rev & 0xf0) != 0x00; - return if $chip == 1 and $man_id != 0x41 || - ($rev & 0xf0) != 0x30; - return if $chip == 3 and $man_id != 0x4d || - $rev != 0x01; - return if $chip == 4 and $man_id != 0x49; - return if $chip == 5 and $convrate != 0x00; - return if $chip == 6 and $man_id != 0x23; - return if $chip == 7 and $man_id != 0x54; + # Check manufacturer IDs and product revisions when available + return if $chip == 0 and $man_id != 0x41 || ($rev & 0xf0) != 0x00; + return if $chip == 1 and $man_id != 0x41 || ($rev & 0xf0) != 0x30; + return if $chip == 3 and $man_id != 0x4d || $rev != 0x01; + return if $chip == 4 and $man_id != 0x49; + return if $chip == 5 and $convrate != 0x00; + return if $chip == 6 and $man_id != 0x23; + return if $chip == 7 and $man_id != 0x54; - # Check unused bits - if ($chip == 5) { # LM84 - return if ($status & 0xab) != 0; - return if ($conf & 0x7f) != 0; - } else { - return if ($status & 0x03) != 0; - return if ($conf & 0x3f) != 0; - return if ($convrate & 0xf8) != 0; - } + # Check unused bits + if ($chip == 5) { # LM84 + return if ($status & 0xab) != 0; + return if ($conf & 0x7f) != 0; + } else { + return if ($status & 0x03) != 0; + return if ($conf & 0x3f) != 0; + return if ($convrate & 0xf8) != 0; + } - # Extra checks for MAX1617 and LM84, since those are often misdetected - # We verify several assertions (6 for the MAX1617, 4 for the LM84) and - # discard the chip if any fail. Note that these checks are not done - # by the adm1021 driver. - if ($chip == 2 || $chip == 5) { - my $lte = i2c_smbus_read_byte_data($file, 0x00); - my $rte = i2c_smbus_read_byte_data($file, 0x01); - my $lhi = i2c_smbus_read_byte_data($file, 0x05); - my $rhi = i2c_smbus_read_byte_data($file, 0x07); - my $llo = i2c_smbus_read_byte_data($file, 0x06); - my $rlo = i2c_smbus_read_byte_data($file, 0x08); + # Extra checks for MAX1617 and LM84, since those are often misdetected. + # We verify several assertions (6 for the MAX1617, 4 for the LM84) and + # discard the chip if any fail. Note that these checks are not done + # by the adm1021 driver. + if ($chip == 2 || $chip == 5) { + my $lte = i2c_smbus_read_byte_data($file, 0x00); + my $rte = i2c_smbus_read_byte_data($file, 0x01); + my $lhi = i2c_smbus_read_byte_data($file, 0x05); + my $rhi = i2c_smbus_read_byte_data($file, 0x07); + my $llo = i2c_smbus_read_byte_data($file, 0x06); + my $rlo = i2c_smbus_read_byte_data($file, 0x08); - # If all registers hold the same value, it has to be a misdetection - return if $lte == $rte and $lte == $lhi and $lte == $rhi - and $lte == $llo and $lte == $rlo; + # If all registers hold the same value, it has to be a misdetection + return if $lte == $rte and $lte == $lhi and $lte == $rhi + and $lte == $llo and $lte == $rlo; - # Negative temperatures - return if ($lte & 0x80) or ($rte & 0x80); - # Negative high limits - return if ($lhi & 0x80) or ($rhi & 0x80); - # Low limits over high limits - if ($chip != 5) { # LM84 doesn't have low limits - $llo-=256 if ($llo & 0x80); - $rlo-=256 if ($rlo & 0x80); - return if ($llo > $lhi) or ($rlo > $rhi); - } - } + # Negative temperatures + return if ($lte & 0x80) or ($rte & 0x80); + # Negative high limits + return if ($lhi & 0x80) or ($rhi & 0x80); + # Low limits over high limits + if ($chip == 2) { + $llo -= 256 if ($llo & 0x80); + $rlo -= 256 if ($rlo & 0x80); + return if ($llo > $lhi) or ($rlo > $rhi); + } + return 3; + } - return 3 if ($chip == 2) or ($chip == 5); - return 7 if $chip <= 3; - return 5; + return ($chip <= 3) ? 7 : 5; } -# $_[0]: Chip to detect -# (0 = MAX1668, 1 = MAX1805, 2 = MAX1989) -# $_[1]: A reference to the file descriptor to access this chip. -# We may assume an i2c_set_slave_addr was already done. -# $_[2]: Address -# Returns: undef if not detected, 7 if detected +# Chip to detect: 0 = MAX1668, 1 = MAX1805, 2 = MAX1989 # Registers used: # 0xfe: Company ID # 0xff: Device ID sub max1668_detect { - my ($chip, $file, $addr) = @_; - my $man_id = i2c_smbus_read_byte_data($file, 0xfe); - my $dev_id = i2c_smbus_read_byte_data($file, 0xff); + my ($file, $addr, $chip) = @_; + my $man_id = i2c_smbus_read_byte_data($file, 0xfe); + my $dev_id = i2c_smbus_read_byte_data($file, 0xff); - return if $man_id != 0x4d; - return if $chip == 0 and $dev_id != 0x03; - return if $chip == 1 and $dev_id != 0x05; - return if $chip == 2 and $dev_id != 0x0b; + return if $man_id != 0x4d; + return if $chip == 0 and $dev_id != 0x03; + return if $chip == 1 and $dev_id != 0x05; + return if $chip == 2 and $dev_id != 0x0b; - return 7; + return 7; } -# $_[0]: Chip to detect -# (0 = MAX1619) -# $_[1]: A reference to the file descriptor to access this chip. -# $_[2]: Address -# Returns: undef if not detected, 7 if detected +# Chip to detect: 0 = MAX1619, 1 = MAX1618 # Registers used: # 0xfe: Company ID # 0xff: Device ID @@ -4928,266 +4485,130 @@ sub max1668_detect # 0x04: Conversion rate sub max1619_detect { - my ($chip, $file, $addr) = @_; - my $man_id = i2c_smbus_read_byte_data($file, 0xfe); - my $dev_id = i2c_smbus_read_byte_data($file, 0xff); - my $conf = i2c_smbus_read_byte_data($file, 0x03); - my $status = i2c_smbus_read_byte_data($file, 0x02); - my $convrate = i2c_smbus_read_byte_data($file, 0x04); + my ($file, $addr, $chip) = @_; + my $man_id = i2c_smbus_read_byte_data($file, 0xfe); + my $dev_id = i2c_smbus_read_byte_data($file, 0xff); + my $conf = i2c_smbus_read_byte_data($file, 0x03); + my $status = i2c_smbus_read_byte_data($file, 0x02); + my $convrate = i2c_smbus_read_byte_data($file, 0x04); - return if $man_id != 0x4D - or $dev_id != 0x04 - or ($conf & 0x03) - or ($status & 0x61) - or $convrate >= 8; + return if $man_id != 0x4D; # Maxim - return 7; + if ($chip == 0) { # MAX1619 + return if $dev_id != 0x04 + or ($conf & 0x03) + or ($status & 0x61) + or $convrate >= 8; + } + if ($chip == 1) { # MAX1618 + return if $dev_id != 0x02 + or ($conf & 0x07) + or ($status & 0x63); + } + + return 7; } -# $_[0]: A reference to the file descriptor to access this chip. -# $_[1]: Address (unused) -# Returns: undef if not detected, 6 if detected. # Registers used: # 0x28: User ID # 0x29: User ID2 -# 0x2A: Version ID - sub ite_overclock_detect { - my ($file, $addr) = @_; + my ($file, $addr) = @_; - my $uid1 = i2c_smbus_read_byte_data($file, 0x28); - my $uid2 = i2c_smbus_read_byte_data($file, 0x29); - return if $uid1 != 0x83 - || $uid2 != 0x12; + my $uid1 = i2c_smbus_read_byte_data($file, 0x28); + my $uid2 = i2c_smbus_read_byte_data($file, 0x29); + return if $uid1 != 0x83 || $uid2 != 0x12; - return 6; + return 6; } -# $_[0]: Chip to detect (0 = IT8712F) -# $_[1]: A reference to the file descriptor to access this chip. -# $_[2]: Address -# Returns: undef if not detected, 7 or 8 if detected (tops LM78). # Registers used: # 0x00: Configuration # 0x48: Full I2C Address # 0x58: Mfr ID -# 0x5b: Device ID (not on IT8705) -sub ite_detect +# 0x5b: Device ID +sub it8712_i2c_detect { - my $reg; - my ($chip, $file, $addr) = @_; - return unless i2c_smbus_read_byte_data($file, 0x48) == $addr; - return unless (i2c_smbus_read_byte_data($file, 0x00) & 0x90) == 0x10; - return unless i2c_smbus_read_byte_data($file, 0x58) == 0x90; - return if $chip == 0 and i2c_smbus_read_byte_data($file, 0x5b) != 0x12; - return (7 + ($addr == 0x2d)); + my ($file, $addr) = @_; + my $reg; + return unless i2c_smbus_read_byte_data($file, 0x48) == $addr; + return unless (i2c_smbus_read_byte_data($file, 0x00) & 0x90) == 0x10; + return unless i2c_smbus_read_byte_data($file, 0x58) == 0x90; + return if i2c_smbus_read_byte_data($file, 0x5b) != 0x12; + return 7 + ($addr == 0x2d); } - -# $_[0]: Chip to detect (0 = IT8712F) -# $_[1]: ISA address -# $_[2]: I2C file handle -# $_[3]: I2C address -sub ite_alias_detect -{ - my ($chip, $isa_addr, $file, $i2c_addr) = @_; - my $i; - my $readproc = sub { isa_read_byte $isa_addr + 5, $isa_addr + 6, @_ }; - return 0 unless &$readproc(0x48) == $i2c_addr; - for ($i = 0x30; $i <= 0x45; $i++) { - return 0 unless &$readproc($i) == i2c_smbus_read_byte_data($file, $i); - } - return 1; -} - -# $_[0]: A reference to the file descriptor to access this chip -# $_[1]: Address -# Returns: 8 for a memory eeprom # Registers used: # 0-63: SPD Data and Checksum sub eeprom_detect { - my ($file, $addr) = @_; - my $checksum = 0; + my ($file, $addr) = @_; + my $checksum = 0; - # Check the checksum for validity (works for most DIMMs and RIMMs) - for (my $i = 0; $i <= 62; $i++) { - $checksum += i2c_smbus_read_byte_data($file, $i); - } - $checksum &= 255; + # Check the checksum for validity (works for most DIMMs and RIMMs) + for (my $i = 0; $i <= 62; $i++) { + $checksum += i2c_smbus_read_byte_data($file, $i); + } + $checksum &= 255; - return 8 - if $checksum == i2c_smbus_read_byte_data($file, 63); - - return; + return 8 if $checksum == i2c_smbus_read_byte_data($file, 63); + return; } -# $_[0]: A reference to the file descriptor to access this chip. -# $_[1]: Address -# Returns: undef if not detected, 8 if detected. # Registers used: # 0x00..0x07: DDC signature sub ddcmonitor_detect { - my ($file, $addr) = @_; + my ($file, $addr) = @_; - return unless - i2c_smbus_read_byte_data($file, 0x00) == 0x00 and - i2c_smbus_read_byte_data($file, 0x01) == 0xFF and - i2c_smbus_read_byte_data($file, 0x02) == 0xFF and - i2c_smbus_read_byte_data($file, 0x03) == 0xFF and - i2c_smbus_read_byte_data($file, 0x04) == 0xFF and - i2c_smbus_read_byte_data($file, 0x05) == 0xFF and - i2c_smbus_read_byte_data($file, 0x06) == 0xFF and - i2c_smbus_read_byte_data($file, 0x07) == 0x00; + return unless + i2c_smbus_read_byte_data($file, 0x00) == 0x00 and + i2c_smbus_read_byte_data($file, 0x01) == 0xFF and + i2c_smbus_read_byte_data($file, 0x02) == 0xFF and + i2c_smbus_read_byte_data($file, 0x03) == 0xFF and + i2c_smbus_read_byte_data($file, 0x04) == 0xFF and + i2c_smbus_read_byte_data($file, 0x05) == 0xFF and + i2c_smbus_read_byte_data($file, 0x06) == 0xFF and + i2c_smbus_read_byte_data($file, 0x07) == 0x00; - return 8; + return 8; } -# $_[0]: A reference to the file descriptor to access this chip. -# $_[1]: Address -# Returns: undef if not detected, (8) if detected. +# Chip to detect: 0 = Poseidon I, 1 = Poseidon II, 2 = Scylla, +# 3 = Hermes, 4 = Heimdal, 5 = Heracles # Registers used: -# 0x00-0x02: Identification ('P', 'E', 'G' -> Pegasus ? :-) aka Poseidon I -sub fscpeg_detect +# 0x00-0x02: Identification (3 capital ASCII letters) +sub fsc_detect { - my ($file, $addr) = @_; - # check the first 3 registers - if (i2c_smbus_read_byte_data($file, 0x00) != 0x50) { - return; - } - if (i2c_smbus_read_byte_data($file, 0x01) != 0x45) { - return; - } - if (i2c_smbus_read_byte_data($file, 0x02) != 0x47) { - return; - } - return (8); + my ($file, $addr, $chip) = @_; + my $id; + + $id = chr(i2c_smbus_read_byte_data($file, 0x00)) + . chr(i2c_smbus_read_byte_data($file, 0x01)) + . chr(i2c_smbus_read_byte_data($file, 0x02)); + + return if $chip == 0 and $id ne 'PEG'; # Pegasus? aka Poseidon I + return if $chip == 1 and $id ne 'POS'; # Poseidon II + return if $chip == 2 and $id ne 'SCY'; # Scylla + return if $chip == 3 and $id ne 'HER'; # Hermes + return if $chip == 4 and $id ne 'HMD'; # Heimdal + return if $chip == 5 and $id ne 'HRC'; # Heracles + + return 8; } -# $_[0]: A reference to the file descriptor to access this chip. -# $_[1]: Address -# Returns: undef if not detected, (8) if detected. -# Registers used: -# 0x00-0x02: Identification 'P', 'O', 'S' -> Poseideon II -sub fscpos_detect -{ - my ($file, $addr) = @_; - # check the first 3 registers - if (i2c_smbus_read_byte_data($file, 0x00) != 0x50) { - return; - } - if (i2c_smbus_read_byte_data($file, 0x01) != 0x4F) { - return; - } - if (i2c_smbus_read_byte_data($file, 0x02) != 0x53) { - return; - } - return (8); -} - -# $_[0]: A reference to the file descriptor to access this chip. -# $_[1]: Address -# Returns: undef if not detected, (8) if detected. -# Registers used: -# 0x00-0x02: Identification ('S', 'C', 'Y') -sub fscscy_detect -{ - my ($file, $addr) = @_; - # check the first 3 registers - if (i2c_smbus_read_byte_data($file, 0x00) != 0x53) { - return; - } - if (i2c_smbus_read_byte_data($file, 0x01) != 0x43) { - return; - } - if (i2c_smbus_read_byte_data($file, 0x02) != 0x59) { - return; - } - return (8); -} - -# $_[0]: A reference to the file descriptor to access this chip. -# $_[1]: Address -# Returns: undef if not detected, (8) if detected. -# Registers used: -# 0x00-0x02: Identification ('H', 'E', 'R') -sub fscher_detect -{ - my ($file, $addr) = @_; - # check the first 3 registers - if (i2c_smbus_read_byte_data($file, 0x00) != 0x48) { - return; - } - if (i2c_smbus_read_byte_data($file, 0x01) != 0x45) { - return; - } - if (i2c_smbus_read_byte_data($file, 0x02) != 0x52) { - return; - } - return (8); -} - -# $_[0]: A reference to the file descriptor to access this chip. -# $_[1]: Address -# Returns: undef if not detected, (8) if detected. -# Registers used: -# 0x00-0x02: Identification ('H', 'M', 'D') -sub fschmd_detect -{ - my ($file, $addr) = @_; - # check the first 3 registers - if (i2c_smbus_read_byte_data($file, 0x00) != 0x48) { - return; - } - if (i2c_smbus_read_byte_data($file, 0x01) != 0x4D) { - return; - } - if (i2c_smbus_read_byte_data($file, 0x02) != 0x44) { - return; - } - return (8); -} - -# $_[0]: A reference to the file descriptor to access this chip. -# $_[1]: Address -# Returns: undef if not detected, (8) if detected. -# Registers used: -# 0x00-0x02: Identification ('H', 'R', 'C') -sub fschrc_detect -{ - my ($file, $addr) = @_; - # check the first 3 registers - if (i2c_smbus_read_byte_data($file, 0x00) != 0x48) { - return; - } - if (i2c_smbus_read_byte_data($file, 0x01) != 0x52) { - return; - } - if (i2c_smbus_read_byte_data($file, 0x02) != 0x43) { - return; - } - return (8); -} - -# $_[0]: A reference to the file descriptor to access this chip. -# $_[1]: Address (unused) -# Returns: undef if not detected, 5 if detected. # Registers used: # 0x3E: Manufacturer ID # 0x3F: Version/Stepping sub lm93_detect { - my $file = shift; - return unless i2c_smbus_read_byte_data($file, 0x3E) == 0x01 - and i2c_smbus_read_byte_data($file, 0x3F) == 0x73; - return 5; + my ($file, $addr) = @_; + return unless i2c_smbus_read_byte_data($file, 0x3E) == 0x01 + and i2c_smbus_read_byte_data($file, 0x3F) == 0x73; + return 5; } -# $_[0]: A reference to the file descriptor to access this chip. -# $_[1]: Address -# Returns: undef if not detected, (7) if detected. # Registers used: # 0x3F: Revision ID # 0x48: Address @@ -5196,27 +4617,20 @@ sub lm93_detect # "VID4/Device ID" so it is doubtful bits 7-1 are really unused. sub m5879_detect { - my ($file, $addr) = @_; + my ($file, $addr) = @_; - return - unless i2c_smbus_read_byte_data($file, 0x3F) == 0x01; + return unless i2c_smbus_read_byte_data($file, 0x3F) == 0x01; + return unless i2c_smbus_read_byte_data($file, 0x48) == $addr; - return - unless i2c_smbus_read_byte_data($file, 0x48) == $addr; + return unless (i2c_smbus_read_byte_data($file, 0x4A) & 0x06) == 0 + and (i2c_smbus_read_byte_data($file, 0x4B) & 0xFC) == 0 + and (i2c_smbus_read_byte_data($file, 0x4F) & 0xFC) == 0 + and (i2c_smbus_read_byte_data($file, 0x57) & 0xFE) == 0 + and (i2c_smbus_read_byte_data($file, 0x58) & 0xEF) == 0; - return - unless (i2c_smbus_read_byte_data($file, 0x4A) & 0x06) == 0 - and (i2c_smbus_read_byte_data($file, 0x4B) & 0xFC) == 0 - and (i2c_smbus_read_byte_data($file, 0x4F) & 0xFC) == 0 - and (i2c_smbus_read_byte_data($file, 0x57) & 0xFE) == 0 - and (i2c_smbus_read_byte_data($file, 0x58) & 0xEF) == 0; - - return (7); + return 7; } -# $_[0]: A reference to the file descriptor to access this chip. -# $_[1]: Address -# Returns: undef if not detected, 5 or 6 if detected. # Registers used: # 0x3E: Manufacturer ID # 0x3F: Version/Stepping @@ -5224,19 +4638,15 @@ sub m5879_detect # 0x49: VID4 (7 reserved bits) sub smsc47m192_detect { - my ($file, $addr) = @_; - return unless i2c_smbus_read_byte_data($file, 0x3E) == 0x55 - and (i2c_smbus_read_byte_data($file, 0x3F) & 0xF0) == 0x20 - and (i2c_smbus_read_byte_data($file, 0x47) & 0x70) == 0x00 - and (i2c_smbus_read_byte_data($file, 0x49) & 0xFE) == 0x80; - return ($addr == 0x2d ? 6 : 5); + my ($file, $addr) = @_; + return unless i2c_smbus_read_byte_data($file, 0x3E) == 0x55 + and (i2c_smbus_read_byte_data($file, 0x3F) & 0xF0) == 0x20 + and (i2c_smbus_read_byte_data($file, 0x47) & 0x70) == 0x00 + and (i2c_smbus_read_byte_data($file, 0x49) & 0xFE) == 0x80; + return ($addr == 0x2d ? 6 : 5); } -# $_[0]: Chip to detect -# (1 = DME1737, 2 = SCH5027) -# $_[1]: A reference to the file descriptor to access this chip. -# $_[2]: Address -# Returns: undef if not detected, 5 or 6 if detected. +# Chip to detect: 1 = DME1737, 2 = SCH5027 # Registers used: # 0x3E: Manufacturer ID # 0x3F: Version/Stepping @@ -5245,107 +4655,76 @@ sub smsc47m192_detect # 0xBA: Read-only test register (8 test bits) sub dme1737_detect { - my ($chip, $file, $addr) = @_; - my $vendor = i2c_smbus_read_byte_data($file, 0x3E); - my $verstep = i2c_smbus_read_byte_data($file, 0x3F); + my ($file, $addr, $chip) = @_; + my $vendor = i2c_smbus_read_byte_data($file, 0x3E); + my $verstep = i2c_smbus_read_byte_data($file, 0x3F); - return unless $vendor == 0x5C; # SMSC + return unless $vendor == 0x5C; # SMSC - if ($chip == 1) { # DME1737 - return unless ($verstep & 0xF8) == 0x88 and - (i2c_smbus_read_byte_data($file, 0x73) & 0x0F) == 0x09 and - (i2c_smbus_read_byte_data($file, 0x8A) & 0x7F) == 0x4D; - } elsif ($chip == 2) { # SCH5027 - return unless $verstep >= 0x69 and $verstep <= 0x6F and - i2c_smbus_read_byte_data($file, 0xBA) == 0x0F; - } + if ($chip == 1) { # DME1737 + return unless ($verstep & 0xF8) == 0x88 and + (i2c_smbus_read_byte_data($file, 0x73) & 0x0F) == 0x09 and + (i2c_smbus_read_byte_data($file, 0x8A) & 0x7F) == 0x4D; + } elsif ($chip == 2) { # SCH5027 + return unless $verstep >= 0x69 and $verstep <= 0x6F and + i2c_smbus_read_byte_data($file, 0xBA) == 0x0F; + } - return ($addr == 0x2e ? 6 : 5); + return ($addr == 0x2e ? 6 : 5); } -# $_[0]: Chip to detect -# (1 = F75111R/RG/N, 2 = F75121R/F75122R/RG, 3 = F75373S/SG, -# 4 = F75375S/SP, 5 = F75387SG/RG, 6 = F75383M/S/F75384M/S, -# 7 = custom power control IC) -# $_[1]: A reference to the file descriptor to access this chip. -# $_[2]: Address (unused) -# Returns: undef if not detected, 7 if detected. +# Chip to detect: 1 = F75111R/RG/N, 2 = F75121R/F75122R/RG, 3 = F75373S/SG, +# 4 = F75375S/SP, 5 = F75387SG/RG, 6 = F75383M/S/F75384M/S, +# 7 = custom power control IC # Registers used: # 0x5A-0x5B: Chip ID # 0x5D-0x5E: Vendor ID sub fintek_detect { - my ($chip, $file, $addr) = @_; - my $chipid = (i2c_smbus_read_byte_data($file, 0x5A) << 8) - | i2c_smbus_read_byte_data($file, 0x5B); - my $vendid = (i2c_smbus_read_byte_data($file, 0x5D) << 8) - | i2c_smbus_read_byte_data($file, 0x5E); + my ($file, $addr, $chip) = @_; + my $chipid = (i2c_smbus_read_byte_data($file, 0x5A) << 8) + | i2c_smbus_read_byte_data($file, 0x5B); + my $vendid = (i2c_smbus_read_byte_data($file, 0x5D) << 8) + | i2c_smbus_read_byte_data($file, 0x5E); - return unless $vendid == 0x1934; # Fintek ID + return unless $vendid == 0x1934; # Fintek ID - if ($chip == 1) { # F75111R/RG/N - return unless $chipid == 0x0300; - } elsif ($chip == 2) { # F75121R/F75122R/RG - return unless $chipid == 0x0301; - } elsif ($chip == 3) { # F75373S/SG - return unless $chipid == 0x0204; - } elsif ($chip == 4) { # F75375S/SP - return unless $chipid == 0x0306; - } elsif ($chip == 5) { # F75387SG/RG - return unless $chipid == 0x0410; - } elsif ($chip == 6) { # F75383M/S/F75384M/S - # The datasheet has 0x0303, but Fintek say 0x0413 is also possible - return unless $chipid == 0x0303 || $chipid == 0x0413; - } elsif ($chip == 7) { # custom power control IC - return unless $chipid == 0x0302; - } + if ($chip == 1) { # F75111R/RG/N + return unless $chipid == 0x0300; + } elsif ($chip == 2) { # F75121R/F75122R/RG + return unless $chipid == 0x0301; + } elsif ($chip == 3) { # F75373S/SG + return unless $chipid == 0x0204; + } elsif ($chip == 4) { # F75375S/SP + return unless $chipid == 0x0306; + } elsif ($chip == 5) { # F75387SG/RG + return unless $chipid == 0x0410; + } elsif ($chip == 6) { # F75383M/S/F75384M/S + # The datasheet has 0x0303, but Fintek say 0x0413 is also + # possible + return unless $chipid == 0x0303 || $chipid == 0x0413; + } elsif ($chip == 7) { # custom power control IC + return unless $chipid == 0x0302; + } - return 7; + return 7; } # This checks for non-FFFF values for temperature, voltage, and current. # The address (0x0b) is specified by the SMBus standard so it's likely # that this really is a smart battery. -# $_[0]: A reference to the file descriptor to access this chip. -# $_[1]: Address -# Returns: 5 sub smartbatt_detect { - my ($file, $addr) = @_; - # check some registers - if (i2c_smbus_read_word_data($file, 0x08) == 0xffff) { - return; - } - if (i2c_smbus_read_word_data($file, 0x09) == 0xffff) { - return; - } - if (i2c_smbus_read_word_data($file, 0x0a) == 0xffff) { - return; - } - return (5); + my ($file, $addr) = @_; + + return if i2c_smbus_read_word_data($file, 0x08) == 0xffff + || i2c_smbus_read_word_data($file, 0x09) == 0xffff + || i2c_smbus_read_word_data($file, 0x0a) == 0xffff; + return 5; } -# Returns: 4 -# These are simple detectors that only look for a register at the -# standard location. No writes are performed. -# For KCS, use the STATUS register. For SMIC, use the FLAGS register. -sub ipmi_kcs_detect -{ - return if inb (0x0ca3) == 0xff; - return (4); -} - -sub ipmi_smic_detect -{ - return if inb (0x0cab) == 0xff; - return (4); -} - -# $_[0]: Chip to detect (0 = W83L784R/AR/G, 1 = W83L785R/G, -# 2 = W83L786NR/NG/R/G) -# $_[1]: A reference to the file descriptor to access this chip. -# $_[2]: Address -# Returns: undef if not detected, 6 or 8 if detected +# Chip to detect: 0 = W83L784R/AR/G, 1 = W83L785R/G, 2 = W83L786NR/NG/R/G, +# 3 = W83L785TS-S # Registers used: # 0x40: Configuration # 0x4a: Full I2C Address (W83L784R only) @@ -5355,50 +4734,30 @@ sub ipmi_smic_detect # 0x4e: Chip ID sub w83l784r_detect { - my ($reg, @res); - my ($chip, $file, $addr) = @_; + my ($file, $addr, $chip) = @_; + my ($reg, @res); - return unless (i2c_smbus_read_byte_data($file, 0x40) & 0x80) == 0x00; - return if $chip == 0 - and i2c_smbus_read_byte_data($file, 0x4a) != $addr; - return unless i2c_smbus_read_byte_data($file, 0x4c) == 0xa3; - return unless i2c_smbus_read_byte_data($file, 0x4d) == 0x5c; + return unless (i2c_smbus_read_byte_data($file, 0x40) & 0x80) == 0x00; + return if $chip == 0 + and i2c_smbus_read_byte_data($file, 0x4a) != $addr; + return unless i2c_smbus_read_byte_data($file, 0x4c) == 0xa3; + return unless i2c_smbus_read_byte_data($file, 0x4d) == 0x5c; - $reg = i2c_smbus_read_byte_data($file, 0x4e); - return if $chip == 0 and $reg != 0x50; - return if $chip == 1 and $reg != 0x60; - return if $chip == 2 and $reg != 0x80; + $reg = i2c_smbus_read_byte_data($file, 0x4e); + return if $chip == 0 and $reg != 0x50; + return if $chip == 1 and $reg != 0x60; + return if $chip == 2 and $reg != 0x80; + return if $chip == 3 and $reg != 0x70; - return 6 if $chip != 0; # No subclients + return 8 if $chip != 0; # No subclients - @res = (8); - $reg = i2c_smbus_read_byte_data($file, 0x4b); - push @res, ($reg & 0x07) + 0x48 unless $reg & 0x08; - push @res, (($reg & 0x70) >> 4) + 0x48 unless $reg & 0x80; - return @res; + @res = (8); + $reg = i2c_smbus_read_byte_data($file, 0x4b); + push @res, ($reg & 0x07) + 0x48 unless $reg & 0x08; + push @res, (($reg & 0x70) >> 4) + 0x48 unless $reg & 0x80; + return @res; } -# $_[0]: Chip to detect (0 = W83L785TS-S) -# $_[1]: A reference to the file descriptor to access this chip. -# $_[2]: Address -# Returns: undef if not detected, 8 if detected -# Registers used: -# 0x4C-4E: Mfr and Chip ID -sub w83l785ts_detect -{ - my ($chip, $file, $addr) = @_; - return unless i2c_smbus_read_byte_data($file, 0x4c) == 0xa3; - return unless i2c_smbus_read_byte_data($file, 0x4d) == 0x5c; - return unless i2c_smbus_read_byte_data($file, 0x4e) == 0x70; - return (8); -} - -# $_[0]: Chip to detect. Always zero for now, but available for future use -# if somebody finds a way to distinguish MAX6650 and MAX6651. -# $_[1]: A reference to the file descriptor to access this chip. -# $_[2]: Address -# Returns: undef if not detected, 3 if detected. -# # The max6650 has no device ID register. However, a few registers have # spare bits, which are documented as being always zero on read. We read # all of these registers check the spare bits. Any non-zero means this @@ -5414,104 +4773,171 @@ sub w83l785ts_detect # the configuration register. sub max6650_detect { - my ($chip, $file) = @_; + my ($file, $addr) = @_; - my $conf = i2c_smbus_read_byte_data($file, 0x02); + my $conf = i2c_smbus_read_byte_data($file, 0x02); - return if i2c_smbus_read_byte_data($file, 0x16) & 0xFC; - return if i2c_smbus_read_byte_data($file, 0x0A) & 0xE0; - return if i2c_smbus_read_byte_data($file, 0x08) & 0xE0; - return if i2c_smbus_read_byte_data($file, 0x14) & 0xE0; - return if ($conf & 0xC0) or ($conf & 0x07) > 4; + return if i2c_smbus_read_byte_data($file, 0x16) & 0xFC; + return if i2c_smbus_read_byte_data($file, 0x0A) & 0xE0; + return if i2c_smbus_read_byte_data($file, 0x08) & 0xE0; + return if i2c_smbus_read_byte_data($file, 0x14) & 0xE0; + return if ($conf & 0xC0) or ($conf & 0x07) > 4; - return 3; + return 3; } -# $_[0]: Chip to detect. Always zero. -# $_[1]: A reference to the file descriptor to access this chip. -# $_[2]: Address. -# -# Returns: undef if not detected, 6 if detected. sub max6655_detect { - my ($chip, $file, $addr) = @_; + my ($file, $addr) = @_; - # checking RDID (Device ID) - return unless i2c_smbus_read_byte_data($file, 0xfe) == 0x0a; - # checking RDRV (Manufacturer ID) - return unless i2c_smbus_read_byte_data($file, 0xff) == 0x4d; - # checking unused bits (conversion rate, extended temperature) - return unless i2c_smbus_read_byte_data($file, 0x04) & 0xf8; - return unless i2c_smbus_read_byte_data($file, 0x10) & 0x1f; - return unless i2c_smbus_read_byte_data($file, 0x11) & 0x1f; - return unless i2c_smbus_read_byte_data($file, 0x12) & 0x1f; + # checking RDID (Device ID) + return unless i2c_smbus_read_byte_data($file, 0xfe) == 0x0a; + # checking RDRV (Manufacturer ID) + return unless i2c_smbus_read_byte_data($file, 0xff) == 0x4d; + # checking unused bits (conversion rate, extended temperature) + return unless i2c_smbus_read_byte_data($file, 0x04) & 0xf8; + return unless i2c_smbus_read_byte_data($file, 0x10) & 0x1f; + return unless i2c_smbus_read_byte_data($file, 0x11) & 0x1f; + return unless i2c_smbus_read_byte_data($file, 0x12) & 0x1f; - return 6; + return 6; } -# $_[0]: Chip to detect (0 = VT1211) -# $_[1]: A reference to the file descriptor to access this chip. -# $_[2]: Address -# # This isn't very good detection. # Verify the i2c address, and the stepping ID (which is 0xb0 on # my chip but could be different for others... -# sub vt1211_i2c_detect { - my ($chip, $file, $addr) = @_; - return unless (i2c_smbus_read_byte_data($file, 0x48) & 0x7f) == $addr; - return unless i2c_smbus_read_byte_data($file, 0x3f) == 0xb0; - return 2; + my ($file, $addr) = @_; + return unless (i2c_smbus_read_byte_data($file, 0x48) & 0x7f) == $addr; + return unless i2c_smbus_read_byte_data($file, 0x3f) == 0xb0; + return 2; } -# $_[0]: Chip to detect (0 = VT1211) -# $_[1]: ISA address -# $_[2]: I2C file handle -# $_[3]: I2C address -sub vt1211_alias_detect +# All ISA detection functions below take at least 1 parameter: +# $_[0]: Address +# Some of these functions which can detect more than one type of device, +# take a second parameter: +# $_[1]: Chip to detect + +# Chip to detect: 0 = LM78, 2 = LM79 +sub lm78_isa_detect { - my ($chip, $isa_addr, $file, $i2c_addr) = @_; - my $i; - return 0 unless (inb($isa_addr + 0x48) & 0x7f) == $i2c_addr; - return 0 unless (i2c_smbus_read_byte_data($file, 0x48) & 0x7f) == $i2c_addr; - for ($i = 0x2b; $i <= 0x3d; $i ++) { - return 0 unless inb($isa_addr + $i) == i2c_smbus_read_byte_data($file, $i); - } - return 1; + my ($addr, $chip) = @_; + my $val = inb($addr + 1); + return if inb($addr + 2) != $val or inb($addr + 3) != $val or + inb($addr + 7) != $val; + + $val = inb($addr + 5); + outb($addr + 5, ~$val & 0x7f); + if ((inb($addr+5) & 0x7f) != (~ $val & 0x7f)) { + outb($addr+5, $val); + return; + } + + return unless (isa_read_i5d6($addr, 0x40) & 0x80) == 0x00; + my $reg = isa_read_i5d6($addr, 0x49); + return if $chip == 0 && ($reg != 0x00 && $reg != 0x20 && $reg != 0x40); + return if $chip == 2 && ($reg & 0xfe) != 0xc0; + + # Explicitly prevent misdetection of Winbond chips + $reg = isa_read_i5d6($addr, 0x4f); + return if $reg == 0xa3 || $reg == 0x5c; + + # Explicitly prevent misdetection of ITE chips + $reg = isa_read_i5d6($addr, 0x58); + return if $reg == 0x90; + + return 6; } +# Chip to detect: 0 = W83781D, 1 = W83782D +sub w83781d_isa_detect +{ + my ($addr, $chip) = @_; + my ($reg1, $reg2); + my $val = inb($addr + 1); + return if inb($addr + 2) != $val or inb($addr + 3) != $val or + inb($addr + 7) != $val; -###################### -# PCI CHIP DETECTION # -###################### + $val = inb($addr + 5); + outb($addr+5, ~$val & 0x7f); + if ((inb($addr+5) & 0x7f) != (~ $val & 0x7f)) { + outb($addr+5, $val); + return; + } + + $reg1 = isa_read_i5d6($addr, 0x4e); + $reg2 = isa_read_i5d6($addr, 0x4f); + return unless (($reg1 & 0x80) == 0x00 and $reg2 == 0xa3) or + (($reg1 & 0x80) == 0x80 and $reg2 == 0x5c); + return unless ($reg1 & 0x07) == 0x00; + $reg1 = isa_read_i5d6($addr, 0x58); + return if $chip == 0 && ($reg1 & 0xfe) != 0x10; + return if $chip == 1 && ($reg1 & 0xfe) != 0x30; + + return 8; +} + +# We simply look for a register at standard locations. +# For KCS, use the STATUS register. For SMIC, use the FLAGS register. +# Incidentally they live at the same offset. +sub ipmi_detect +{ + my ($addr) = @_; + return if inb($addr + 3) == 0xff; + return 4; +} + +################### +# ALIAS DETECTION # +################### + +# These functions take at least 3 parameters: +# $_[0]: ISA/LPC address +# $_[1]: I2C file handle +# $_[2]: I2C address +# Some of these functions may take extra parameters. +# They return 1 if both devices are the same, 0 if not. + +# Extra parameters: +# $_[3]: First limit register to compare +# $_[4]: Last limit register to compare +sub winbond_alias_detect +{ + my ($isa_addr, $file, $i2c_addr, $first, $last) = @_; + my $i; + + return 0 unless isa_read_i5d6($isa_addr, 0x48) == $i2c_addr; + for ($i = $first; $i <= $last; $i++) { + return 0 unless isa_read_i5d6($isa_addr, $i) == + i2c_smbus_read_byte_data($file, $i); + } + return 1; +} + +############################ +# PCI CHIP / CPU DETECTION # +############################ -# Returns: undef if not detected, (7) or (9) if detected. -# The address is encoded in PCI space. We could decode it and print it. -# For Linux 2.4 we should probably check for invalid matches (SiS645). sub sis5595_pci_detect { return unless exists $pci_list{'1039:0008'}; - return (kernel_version_at_least(2, 6, 0) ? 9 : 7); + return 9; } -# Returns: undef if not detected, (9) if detected. -# The address is encoded in PCI space. We could decode it and print it. sub via686a_pci_detect { return unless exists $pci_list{'1106:3057'}; return 9; } -# Returns: undef if not detected, (9) if detected. -# The address is encoded in PCI space. We could decode it and print it. sub via8231_pci_detect { return unless exists $pci_list{'1106:8235'}; return 9; } -# Returns: undef if not detected, (9) if detected. sub k8temp_pci_detect { return unless exists $pci_list{'1022:1103'}; @@ -5524,7 +4950,6 @@ sub k10temp_pci_detect return 9; } -# Returns: undef if not detected, (9) if detected. sub intel_amb_detect { if ((exists $pci_list{'8086:25f0'}) || # Intel 5000 @@ -5534,39 +4959,70 @@ sub intel_amb_detect return; } -# Returns: undef if not detected, (9) if detected. sub coretemp_detect { my $probecpu; foreach $probecpu (@cpu) { - if ($probecpu->{'vendor_id'} eq 'GenuineIntel' && + if ($probecpu->{vendor_id} eq 'GenuineIntel' && $probecpu->{'cpu family'} == 6 && - ($probecpu->{'model'} == 14 || - $probecpu->{'model'} == 15 || - $probecpu->{'model'} == 0x16 || - $probecpu->{'model'} == 0x17 || - $probecpu->{'model'} == 0x1a)) { + ($probecpu->{model} == 14 || + $probecpu->{model} == 15 || + $probecpu->{model} == 0x16 || + $probecpu->{model} == 0x17 || + $probecpu->{model} == 0x1a)) { return 9; } } return; } -# Returns: undef if not detected, (9) if detected. sub c7temp_detect { my $probecpu; foreach $probecpu (@cpu) { - if ($probecpu->{'vendor_id'} eq 'CentaurHauls' && + if ($probecpu->{vendor_id} eq 'CentaurHauls' && $probecpu->{'cpu family'} == 6 && - ($probecpu->{'model'} == 0xa || - $probecpu->{'model'} == 0xd)) { + ($probecpu->{model} == 0xa || + $probecpu->{model} == 0xd)) { return 9; } } return; } +################# +# SPECIAL MODES # +################# + +sub show_i2c_stats +{ + my ($chip, $addr, %histo, $chips); + + # Gather the data + foreach $chip (@chip_ids) { + next unless defined $chip->{i2c_addrs}; + $chips++; + foreach my $addr (@{$chip->{i2c_addrs}}) { + $histo{$addr}++; + } + } + + # Display the data + printf "\%d I2C chips known, \%d I2C addresses probed\n\n", + $chips, scalar keys %histo; + print " 0 1 2 3 4 5 6 7 8 9 a b c d e f\n". + "00: "; + for (my $addr = 0x03; $addr <= 0x77; $addr++) { + printf("\n\%02x:", $addr) if ($addr % 16) == 0; + if (defined $histo{$addr}) { + printf ' %02d', $histo{$addr}; + } else { + print ' --'; + } + } + print "\n"; +} + ################ # MAIN PROGRAM # ################ @@ -5574,488 +5030,407 @@ sub c7temp_detect # $_[0]: reference to a list of chip hashes sub print_chips_report { - my ($listref) = @_; - my $data; + my ($listref) = @_; + my $data; - foreach $data (@$listref) { - my $is_i2c = exists $data->{i2c_addr}; - my $is_isa = exists $data->{isa_addr}; - print " * "; - if ($is_i2c) { - printf "Bus `%s'\n", $data->{i2c_adap}; - printf " Busdriver `%s', I2C address 0x%02x", - $data->{i2c_driver}, $data->{i2c_addr}; - if (exists $data->{i2c_sub_addrs}) { - print " (and"; - my $sub_addr; - foreach $sub_addr (@{$data->{i2c_sub_addrs}}) { - printf " 0x%02x", $sub_addr; - } - print ")" - } - print "\n "; - } - if ($is_isa) { - print "ISA bus"; - if ($data->{isa_addr}) { - printf ", address 0x%x", $data->{isa_addr}; - } - print " (Busdriver `i2c-isa')" - unless kernel_version_at_least(2, 6, 18); - print "\n "; - } - printf "Chip `%s' (confidence: %d)\n", - $data->{chipname}, $data->{conf}; - } + foreach $data (@$listref) { + my $is_i2c = exists $data->{i2c_addr}; + my $is_isa = exists $data->{isa_addr}; + print " * "; + if ($is_i2c) { + printf "Bus `%s'\n", $i2c_adapters[$data->{i2c_devnr}]->{name}; + printf " Busdriver `%s', I2C address 0x%02x", + $i2c_adapters[$data->{i2c_devnr}]->{driver}, $data->{i2c_addr}; + if (exists $data->{i2c_sub_addrs}) { + print " (and"; + my $sub_addr; + foreach $sub_addr (@{$data->{i2c_sub_addrs}}) { + printf " 0x%02x", $sub_addr; + } + print ")" + } + print "\n "; + } + if ($is_isa) { + print "ISA bus"; + if ($data->{isa_addr}) { + printf ", address 0x%x", $data->{isa_addr}; + } + print " (Busdriver `i2c-isa')" + unless kernel_version_at_least(2, 6, 18); + print "\n "; + } + printf "Chip `%s' (confidence: %d)\n", + $data->{chipname}, $data->{conf}; + } } -# We build here an array adapters, indexed on the number the adapter has -# at this moment (we assume only loaded adapters are interesting at all; -# everything that got scanned also got loaded). Each entry is a reference -# to a hash containing: -# driver: Name of the adapter driver -# nr_now: Number of the bus now -# nr_later: Number of the bus when the modprobes are done (not included if the -# driver should not be loaded) -# A second array, called sub generate_modprobes { - my ($chip, $detection, $nr, $i, @optionlist, @probelist, $driver, $isa, $adap); - my $ipmi = 0; - my $modprobes = ""; - my $configfile; + my ($driver, $detection, $adap); + my ($configfile, %bus_modules, %hwmon_modules); - # Collect all adapters used - $nr = 0; - $isa = 0; - foreach $chip (@chips_detected) { - foreach $detection (@{$chip->{detected}}) { - # If there is more than one bus detected by a driver, they are - # still all added. So we number them in the correct order - if (exists $detection->{i2c_driver} and - not exists $i2c_adapters[$detection->{i2c_devnr}]->{nr_later} and - not exists $detection->{isa_addr}) { # Always use ISA access if possible - foreach $adap (@i2c_adapters) { - next unless exists $adap->{driver}; - $adap->{nr_later} = $nr++ if $adap->{driver} eq $detection->{i2c_driver}; - } - } - if (exists $detection->{isa_addr}) { - $isa=1; - } - if ($chip->{driver} eq "bmcsensors" || - $chip->{driver} eq "ipmisensors") { - $ipmi = 1; - } - } - } + foreach $driver (keys %chips_detected) { + foreach $detection (@{$chips_detected{$driver}}) { + # Tag adapters which host hardware monitoring chips we want to access + if (exists $detection->{i2c_devnr} + && !exists $detection->{isa_addr}) { + $i2c_adapters[$detection->{i2c_devnr}]->{used}++; + } - $modprobes .= "# I2C adapter drivers\n" if $nr; - for ($i = 0; $i < $nr; $i++) { - foreach $adap (@i2c_adapters) { - next unless exists $adap->{nr_later} and $adap->{nr_later} == $i; - if ($adap->{driver} eq "UNKNOWN") { - $modprobes .= "# modprobe unknown adapter ".$adap->{name}."\n"; - } else { - $modprobes .= "modprobe $adap->{driver}\n" - unless $modprobes =~ /modprobe $adap->{driver}\n/; - } - last; - } - } - # i2c-isa is loaded automatically (as a dependency) since 2.6.14, - # and will soon be gone. - $modprobes .= "modprobe i2c-isa\n" if ($isa && !kernel_version_at_least(2, 6, 18)); - if ($ipmi) { - $modprobes .= "# You must also install and load the IPMI modules\n"; - if (kernel_version_at_least(2, 6, 0)) { - $modprobes .= "modprobe ipmi-si\n"; - } else { - $modprobes .= "modprobe i2c-ipmi\n"; - } - } + # i2c-isa is loaded automatically (as a dependency) + # since 2.6.14, and will soon be gone. + if (exists $detection->{isa_addr} + && !kernel_version_at_least(2, 6, 18)) { + $bus_modules{"i2c-isa"}++ + } + } + if ($driver eq "ipmisensors") { + $bus_modules{"ipmi-si"}++; + } + } - # Now determine the chip probe lines - $modprobes .= "# Chip drivers\n"; - foreach $chip (@chips_detected) { - next if not @{$chip->{detected}}; - if ($chip->{driver} eq "to-be-written") { - $modprobes .= "# no driver for $chip->{detected}[0]{chipname} yet\n"; - } else { - # need the * for 2.4 kernels, won't necessarily be an exact match - open(local *INPUTFILE, "modprobe -l $chip->{driver}\\* 2>/dev/null |"); - local $_; - my $modulefound = 0; - while () { - if (m@/@) { - $modulefound = 1; - last; - } - } - close INPUTFILE; - #check return value from modprobe in case modprobe -l isn't supported - if ((($? >> 8) == 0) && ! $modulefound) { - $modprobes .= "# Warning: the required module $chip->{driver} is not currently installed\n". - "# on your system. For status of 2.6 kernel ports check\n". - "# http://www.lm-sensors.org/wiki/Devices. If driver is built\n". - "# into the kernel, or unavailable, comment out the following line.\n"; - } - $modprobes .= "modprobe $chip->{driver}\n"; - } + # Handle aliases + # As of kernel 2.6.28, alias detection is handled by kernel drivers + # directly, so module options are no longer needed. + unless (kernel_version_at_least(2, 6, 28)) { + foreach $driver (keys %chips_detected) { + my @optionlist = (); + foreach $detection (@{$chips_detected{$driver}}) { + next unless exists $detection->{i2c_addr} + && exists $detection->{isa_addr} + && $i2c_adapters[$detection->{i2c_devnr}]->{used}; - # Handle misdetects - foreach $detection (@{$chip->{misdetected}}) { - push @optionlist, $i2c_adapters[$detection->{i2c_devnr}]->{nr_later}, - $detection->{i2c_addr} - if exists $detection->{i2c_addr} and - exists $i2c_adapters[$detection->{i2c_devnr}]->{nr_later}; - push @optionlist, -1, $detection->{isa_addr} - if exists $detection->{isa_addr}; - } + push @optionlist, sprintf("%d,0x%02x", + $detection->{i2c_devnr}, + $detection->{i2c_addr}); + } - # Handle aliases - foreach $detection (@{$chip->{detected}}) { - if (exists $detection->{i2c_driver} and - exists $detection->{isa_addr} and - exists $i2c_adapters[$detection->{i2c_devnr}]->{nr_later}) { - push @optionlist, $i2c_adapters[$detection->{i2c_devnr}]->{nr_later}, - $detection->{i2c_addr}; - } - } + next if not @optionlist; + $configfile = "# hwmon module options\n" + unless defined $configfile; + $configfile .= "options $driver ignore=". + (join ",", @optionlist)."\n"; + } + } - next if not (@probelist or @optionlist); - $configfile = "# hwmon module options\n" unless defined $configfile; - $configfile .= "options $chip->{driver}"; - $configfile .= sprintf " ignore=%d,0x%02x", shift @optionlist, - shift @optionlist - if @optionlist; - $configfile .= sprintf ",%d,0x%02x", shift @optionlist, shift @optionlist - while @optionlist; - $configfile .= sprintf " probe=%d,0x%02x", shift @probelist, - shift @probelist - if @probelist; - $configfile .= sprintf ",%d,0x%02x", shift @probelist, shift @probelist - while @probelist; - $configfile .= "\n"; - } + # If we added any module option to handle aliases, we need to load all + # the adapter drivers so that the numbers will be the same. If not, then + # we only load the adapter drivers which are useful. + foreach $adap (@i2c_adapters) { + next unless loaded_by_us($adap->{driver}); + next if not defined $configfile and not $adap->{used}; + $bus_modules{$adap->{driver}}++; + } - return ($modprobes, $configfile); + # Now determine the chip probe lines + foreach $driver (keys %chips_detected) { + next if not @{$chips_detected{$driver}}; + if ($driver eq "to-be-written") { + print "Note: there is no driver for ${$chips_detected{$driver}}[0]{chipname} yet.\n". + "Check http://www.lm-sensors.org/wiki/Devices for updates.\n\n"; + } else { + open(local *INPUTFILE, "modprobe -l $driver 2>/dev/null |"); + local $_; + my $modulefound = 0; + while () { + if (m@/@) { + $modulefound = 1; + last; + } + } + close(INPUTFILE); + # Check return value from modprobe in case modprobe -l + # isn't supported + if ((($? >> 8) == 0) && ! $modulefound) { + print "Warning: the required module $driver is not currently installed\n". + "on your system. If it is built into the kernel then it's OK.\n". + "Otherwise, check http://www.lm-sensors.org/wiki/Devices for\n". + "driver availability.\n\n"; + } else { + $hwmon_modules{$driver}++; + } + } + } + + my @bus_modules = sort keys %bus_modules; + my @hwmon_modules = sort keys %hwmon_modules; + return ($configfile, \@bus_modules, \@hwmon_modules); +} + +sub write_config +{ + my ($configfile, $bus_modules, $hwmon_modules) = @_; + + if (defined $configfile) { + my $have_modprobe_d = -d '/etc/modprobe.d'; + printf "Do you want to \%s /etc/modprobe.d/lm_sensors? (\%s): ", + (-e '/etc/modprobe.d/lm_sensors' ? 'overwrite' : 'generate'), + ($have_modprobe_d ? 'YES/no' : 'yes/NO'); + $_ = ; + if (($have_modprobe_d and not m/^\s*n/i) or m/^\s*y/i) { + unless ($have_modprobe_d) { + mkdir('/etc/modprobe.d', 0777) + or die "Sorry, can't create /etc/modprobe.d ($!)"; + } + open(local *MODPROBE_D, ">/etc/modprobe.d/lm_sensors") + or die "Sorry, can't create /etc/modprobe.d/lm_sensors ($!)"; + print MODPROBE_D "# Generated by sensors-detect on " . scalar localtime() . "\n"; + print MODPROBE_D $configfile; + close(MODPROBE_D); + } else { + print "To make the sensors modules behave correctly, add these lines to\n". + "/etc/modprobe.conf:\n\n"; + print "#----cut here----\n". + $configfile. + "#----cut here----\n\n"; + } + } + + my $have_sysconfig = -d '/etc/sysconfig'; + printf "Do you want to \%s /etc/sysconfig/lm_sensors? (\%s): ", + (-e '/etc/sysconfig/lm_sensors' ? 'overwrite' : 'generate'), + ($have_sysconfig ? 'YES/no' : 'yes/NO'); + $_ = ; + if (($have_sysconfig and not m/^\s*n/i) or m/^\s*y/i) { + unless ($have_sysconfig) { + mkdir('/etc/sysconfig', 0777) + or die "Sorry, can't create /etc/sysconfig ($!)"; + } + open(local *SYSCONFIG, ">/etc/sysconfig/lm_sensors") + or die "Sorry, can't create /etc/sysconfig/lm_sensors ($!)"; + print SYSCONFIG "# Generated by sensors-detect on " . scalar localtime() . "\n"; + print SYSCONFIG <<'EOT'; +# This file is sourced by /etc/init.d/lm_sensors and defines the modules to +# be loaded/unloaded. +# +# The format of this file is a shell script that simply defines variables: +# HWMON_MODULES for hardware monitoring driver modules, and optionally +# BUS_MODULES for any required bus driver module (for example for I2C or SPI). + +EOT + print SYSCONFIG "BUS_MODULES=\"", join(" ", @{$bus_modules}), "\"\n" + if @{$bus_modules}; + print SYSCONFIG "HWMON_MODULES=\"", join(" ", @{$hwmon_modules}), "\"\n"; + + print SYSCONFIG <<'EOT'; + +# For compatibility reasons, modules are also listed individually as variables +# MODULE_0, MODULE_1, MODULE_2, etc. +# You should use BUS_MODULES and HWMON_MODULES instead if possible. + +EOT + my $i = 0; + foreach (@{$bus_modules}, @{$hwmon_modules}) { + print SYSCONFIG "MODULE_$i=$_\n"; + $i++; + } + close(SYSCONFIG); + + print "Copy prog/init/lm_sensors.init to /etc/init.d/lm_sensors\n". + "for initialization at boot time.\n" + unless -f "/etc/init.d/lm_sensors"; + + if (-x "/sbin/insserv" && -f "/etc/init.d/lm_sensors") { + system("/sbin/insserv", "/etc/init.d/lm_sensors"); + } elsif (-x "/sbin/chkconfig" && -f "/etc/init.d/lm_sensors") { + system("/sbin/chkconfig", "lm_sensors", "on"); + if (-x "/sbin/service") { + system("/sbin/service", "lm_sensors", "start"); + } + } else { + print "You should now start the lm_sensors service to load the required\n". + "kernel modules.\n\n"; + } + } else { + print "To load everything that is needed, add this to one of the system\n". + "initialization scripts (e.g. /etc/rc.d/rc.local):\n\n"; + print "#----cut here----\n"; + if (@{$bus_modules}) { + print "# Adapter drivers\n"; + print "modprobe $_\n" foreach (@{$bus_modules}); + } + print "# Chip drivers\n"; + print "modprobe $_\n" foreach (@{$hwmon_modules}); + print((-e '/usr/bin/sensors' ? + "/usr/bin/sensors -s\n" : + "/usr/local/bin/sensors -s\n"). + "#----cut here----\n\n"); + + print "If you have some drivers built into your kernel, the list above will\n". + "contain too many modules. Skip the appropriate ones! You really\n". + "should try these commands right now to make sure everything is\n". + "working properly. Monitoring programs won't work until the needed\n". + "modules are loaded.\n\n"; + } } sub main { - my (@adapters, $res, $did_adapter_detection, $adapter); + my ($input, $superio_features); - # We won't go very far if not root - unless ($> == 0) { - print "You need to be root to run this script.\n"; - exit -1; - } + # Handle special command line cases first + if (defined $ARGV[0] && $ARGV[0] eq "--stat") { + show_i2c_stats(); + exit 0; + } - if (-x "/sbin/service" && -f "/etc/init.d/lm_sensors" && - -f "/var/lock/subsys/lm_sensors") { - system("/sbin/service", "lm_sensors", "stop"); - } + # We won't go very far if not root + unless ($> == 0) { + print "You need to be root to run this script.\n"; + exit -1; + } - initialize_kernel_version(); - initialize_conf; - initialize_proc_pci; - initialize_modules_list; - # make sure any special case chips are added to the chip_ids list before - # making the support modules list - chip_special_cases(); - initialize_modules_supported; - initialize_cpu_list(); + if (-x "/sbin/service" && -f "/etc/init.d/lm_sensors" && + -f "/var/lock/subsys/lm_sensors") { + system("/sbin/service", "lm_sensors", "stop"); + } - print "# sensors-detect revision $revision\n\n"; + initialize_kernel_version(); + initialize_conf(); + initialize_pci(); + initialize_modules_list(); + # Make sure any special case chips are added to the chip_ids list + # before making the support modules list + chip_special_cases(); + initialize_modules_supported(); + initialize_cpu_list(); - print "This program will help you determine which kernel modules you need\n", - "to load to use lm_sensors most effectively. It is generally safe\n", - "and recommended to accept the default answers to all questions,\n", - "unless you know what you're doing.\n"; - print "You need to have i2c and lm_sensors installed before running this\n", - "program.\n" - unless kernel_version_at_least(2, 6, 0); - print "\n"; + print "# sensors-detect revision $revision\n"; + initialize_dmi_data(); + print_dmi_summary(); + print "\n"; + print "This program will help you determine which kernel modules you need\n", + "to load to use lm_sensors most effectively. It is generally safe\n", + "and recommended to accept the default answers to all questions,\n", + "unless you know what you're doing.\n\n"; - print "We can start with probing for (PCI) I2C or SMBus adapters.\n"; - print "Do you want to probe now? (YES/no): "; - @adapters = adapter_pci_detection - if ($did_adapter_detection = not =~ /\s*[Nn]/); - print "\n"; + print "Some south bridges, CPUs or memory controllers contain embedded sensors.\n". + "Do you want to scan for them? This is totally safe. (YES/no): "; + unless ( =~ /^\s*n/i) { + $| = 1; + foreach my $entry (@cpu_ids) { + scan_cpu($entry); + } + $| = 0; + } + print "\n"; - if (not $did_adapter_detection) { - print "As you skipped adapter detection, we will only scan already loaded\n". - "adapter modules.\n"; - } else { - print "We will now try to load each adapter module in turn.\n" - if (@adapters); - foreach $adapter (@adapters) { - if (exists($modules_list{$adapter})) { - print "Module `$adapter' already loaded.\n"; - } else { - print "Load `$adapter' (say NO if built into your kernel)? (YES/no): "; - unless ( =~ /^\s*[Nn]/) { - if (system ("modprobe", $adapter)) { - print "Loading failed... skipping.\n"; - } else { - print "Module loaded successfully.\n"; - } - } - } - } - } + $superio_features = 0; + # Skip "random" I/O port probing on PPC + if ($kernel_arch ne 'ppc' + && $kernel_arch ne 'ppc64') { + print "Some Super I/O chips contain embedded sensors. We have to write to\n". + "standard I/O ports to probe them. This is usually safe.\n"; + print "Do you want to scan for Super I/O sensors? (YES/no): "; + unless ( =~ /^\s*n/i) { + initialize_ioports(); + $superio_features |= scan_superio(0x2e, 0x2f); + $superio_features |= scan_superio(0x4e, 0x4f); + close_ioports(); + } + print "\n"; - print "If you have undetectable or unsupported I2C/SMBus adapters, you can have\n". - "them scanned by manually loading the modules before running this script.\n\n"; - initialize_i2c_adapters_list(); + unless (is_laptop()) { + print "Some systems (mainly servers) implement IPMI, a set of common interfaces\n". + "through which system health data may be retrieved, amongst other things.\n". + "We have to read from arbitrary I/O ports to probe for such interfaces.\n". + "This is normally safe. Do you want to scan for IPMI interfaces?\n". + "(YES/no): "; + unless ( =~ /^\s*n/i) { + initialize_ioports(); + scan_isa_bus(\@ipmi_ifs); + close_ioports(); + } + print "\n"; + } - if (!exists($modules_list{"i2c-dev"}) - && !(defined $sysfs_root && -e "$sysfs_root/class/i2c-dev")) { - print "To continue, we need module `i2c-dev' to be loaded.\n"; - print "If it is built-in into your kernel, you can safely skip this.\n" - unless kernel_version_at_least(2, 6, 0); - print "Do you want to load `i2c-dev' now? (YES/no): "; - if ( =~ /^\s*n/i) { - print "Well, you will know best.\n"; - } elsif (system "modprobe", "i2c-dev") { - print "Loading failed, expect problems later on.\n"; - } else { - print "Module loaded successfully.\n"; - } - print "\n"; - } + printf "Some hardware monitoring chips are accessible through the ISA I/O ports.\n". + "We have to write to arbitrary I/O ports to probe them. This is usually\n". + "safe though. Yes, you do have ISA I/O ports even if you do not have any\n". + "ISA slots! Do you want to scan the ISA I/O ports? (\%s): ", + $superio_features ? "yes/NO" : "YES/no"; + $input = ; + unless ($input =~ /^\s*n/i + || ($superio_features && $input !~ /^\s*y/i)) { + initialize_ioports(); + scan_isa_bus(\@chip_ids); + close_ioports(); + } + print "\n"; + } - $i2c_addresses_to_scan = i2c_addresses_to_scan(); + print "Lastly, we can probe the I2C/SMBus adapters for connected hardware\n". + "monitoring devices. This is the most risky part, and while it works\n". + "reasonably well on most systems, it has been reported to cause trouble\n". + "on some systems.\n". + "Do you want to probe the I2C/SMBus adapters now? (YES/no): "; - print "We are now going to do the I2C/SMBus adapter probings. Some chips may\n", - "be double detected; we choose the one with the highest confidence\n", - "value in that case.\n", - "If you found that the adapter hung after probing a certain address,\n", - "you can specify that address to remain unprobed.\n"; + unless ( =~ /^\s*n/i) { + adapter_pci_detection(); + load_module("i2c-dev") unless -e "$sysfs_root/class/i2c-dev"; + initialize_i2c_adapters_list(); + $i2c_addresses_to_scan = i2c_addresses_to_scan(); + print "\n"; - my ($inp, @not_to_scan, $inp2); - for (my $dev_nr = 0; $dev_nr < @i2c_adapters; $dev_nr++) { - next unless exists $i2c_adapters[$dev_nr]; - my $adap = $i2c_adapters[$dev_nr]->{'name'}; - print "\n"; - print "Next adapter: $adap (i2c-$dev_nr)\n"; - print "Do you want to scan it? (YES/no/selectively): "; + # Skip SMBus probing by default if Super-I/O has all the features + my $by_default = ~$superio_features & (FEAT_IN | FEAT_FAN | FEAT_TEMP); + # Except on Asus and Tyan boards which often have more than + # one hardware monitoring chip + $by_default = 1 if dmi_match('board_vendor', 'asustek', 'tyan', + 'supermicro'); - $inp = ; - if ($inp =~ /^\s*[Ss]/) { - print "Please enter one or more addresses not to scan. Separate them ", - "with comma's.\n", - "You can specify a range by using dashes. Addresses may be ", - "decimal (like 54)\n", - "or hexadecimal (like 0x33).\n", - "Addresses: "; - $inp2 = ; - chop $inp2; - @not_to_scan = parse_not_to_scan(0x03, 0x77, $inp2); - } - scan_adapter $dev_nr, $adap, $i2c_adapters[$dev_nr]->{'driver'}, - \@not_to_scan unless $inp =~ /^\s*[Nn]/; - } - print "\n"; + for (my $dev_nr = 0; $dev_nr < @i2c_adapters; $dev_nr++) { + next unless exists $i2c_adapters[$dev_nr]; + scan_i2c_adapter($dev_nr, $by_default); + } + } - # Skip "random" I/O port probing on PPC - if ($kernel_arch ne 'ppc' - && $kernel_arch ne 'ppc64') { - print "Some chips are also accessible through the ISA I/O ports. We have to\n". - "write to arbitrary I/O ports to probe them. This is usually safe though.\n". - "Yes, you do have ISA I/O ports even if you do not have any ISA slots!\n"; - print "Do you want to scan the ISA I/O ports? (YES/no): "; - unless ( =~ /^\s*n/i) { - initialize_ioports(); - scan_isa_bus(); - close_ioports(); - } - print "\n"; + if (!keys %chips_detected) { + print "Sorry, no sensors were detected.\n"; + if (is_laptop() && -d "$sysfs_root/firmware/acpi") { + print "This is relatively common on laptops, where thermal management is\n". + "handled by ACPI rather than the OS.\n"; + } else { + print "Either your system has no sensors, or they are not supported, or\n". + "they are connected to an I2C or SMBus adapter that is not\n". + "supported. If you find out what chips are on your board, check\n". + "http://www.lm-sensors.org/wiki/Devices for driver status.\n"; + } + exit; + } - print "Some Super I/O chips may also contain sensors. We have to write to\n". - "standard I/O ports to probe them. This is usually safe.\n"; - print "Do you want to scan for Super I/O sensors? (YES/no): "; - unless ( =~ /^\s*n/i) { - initialize_ioports(); - scan_superio(0x2e, 0x2f); - scan_superio(0x4e, 0x4f); - close_ioports(); - } - print "\n"; - } + print "Now follows a summary of the probes I have just done.\n". + "Just press ENTER to continue: "; + ; - print "Some south bridges, CPUs or memory controllers may also contain\n"; - print "embedded sensors. Do you want to scan for them? (YES/no): "; - unless ( =~ /^\s*n/i) { - $| = 1; - foreach my $entry (@cpu_ids) { - scan_cpu($entry); - } - $| = 0; - } - print "\n"; + foreach my $driver (keys %chips_detected) { + next unless @{$chips_detected{$driver}}; + find_aliases($chips_detected{$driver}); + print "\nDriver `$driver':\n"; + print_chips_report($chips_detected{$driver}); + } + print "\n"; - if (! @chips_detected) { - print "Sorry, no sensors were detected.\n", - "Either your sensors are not supported, or they are connected to an\n", - "I2C or SMBus adapter that is not supported. See doc/FAQ or\n", - "doc/lm_sensors-FAQ.html (FAQ #4.24.3) for further information.\n", - "If you find out what chips are on your board, check\n", - "http://www.lm-sensors.org/wiki/Devices for driver status.\n"; - exit; - } + my ($configfile, $bus_modules, $hwmon_modules) = generate_modprobes(); - print "Now follows a summary of the probes I have just done.\n". - "Just press ENTER to continue: "; - ; + if (@{$hwmon_modules}) { + write_config($configfile, $bus_modules, $hwmon_modules); + } else { + print "No modules to load, skipping modules configuration.\n\n"; + } - my ($chip, $data); - foreach $chip (@chips_detected) { - print "\nDriver `$chip->{driver}' "; - if (@{$chip->{detected}}) { - if (@{$chip->{misdetected}}) { - print "(should be inserted but causes problems):\n"; - } else { - print "(should be inserted):\n"; - } - } else { - if (@{$chip->{misdetected}}) { - print "(may not be inserted):\n"; - } else { - print "(should not be inserted, but is harmless):\n"; - } - } - if (@{$chip->{detected}}) { - print " Detects correctly:\n"; - print_chips_report $chip->{detected}; - } - if (@{$chip->{misdetected}}) { - print " Misdetects:\n"; - print_chips_report $chip->{misdetected}; - } - } - print "\n"; - - my ($modprobes, $configfile) = generate_modprobes(); - - if (defined $configfile) { - my $have_modprobe_d = -d '/etc/modprobe.d'; - printf "Do you want to \%s /etc/modprobe.d/lm_sensors? (\%s): ", - (-e '/etc/modprobe.d/lm_sensors' ? 'overwrite' : 'generate'), - ($have_modprobe_d ? 'YES/no' : 'yes/NO'); - $_ = ; - if (($have_modprobe_d and not m/^\s*n/i) or m/^\s*y/i) { - unless ($have_modprobe_d) { - mkdir '/etc/modprobe.d', 0777 - or die "Sorry, can't create /etc/modprobe.d ($!)"; - } - open(local *MODPROBE_D, ">/etc/modprobe.d/lm_sensors") - or die "Sorry, can't create /etc/modprobe.d/lm_sensors ($!)"; - print MODPROBE_D - "# Generated by sensors-detect on " . scalar localtime() . "\n"; - print MODPROBE_D $configfile; - close(MODPROBE_D); - } else { - print "To make the sensors modules behave correctly, add these lines to\n". - "$modules_conf:\n\n"; - print "#----cut here----\n". - $configfile. - "#----cut here----\n\n"; - } - } - - my $have_sysconfig = -d '/etc/sysconfig'; - printf "Do you want to \%s /etc/sysconfig/lm_sensors? (\%s): ", - (-e '/etc/sysconfig/lm_sensors' ? 'overwrite' : 'generate'), - ($have_sysconfig ? 'YES/no' : 'yes/NO'); - $_ = ; - if (($have_sysconfig and not m/^\s*n/i) or m/^\s*y/i) { - unless ($have_sysconfig) { - mkdir '/etc/sysconfig', 0777 - or die "Sorry, can't create /etc/sysconfig ($!)"; - } - open(local *SYSCONFIG, ">/etc/sysconfig/lm_sensors") - or die "Sorry, can't create /etc/sysconfig/lm_sensors ($!)"; - print SYSCONFIG <<'EOT'; -# /etc/sysconfig/lm_sensors - Defines modules loaded by -# /etc/init.d/lm_sensors -# Copyright (c) 1998 - 2001 Frodo Looijaard -# -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, -# MA 02110-1301 USA. -# -# -# See also the lm_sensors homepage at: -# http://www.lm-sensors.org/ -# -# This file is used by /etc/init.d/lm_sensors and defines the modules to -# be loaded/unloaded. This file is sourced into /etc/init.d/lm_sensors. -# -# The format of this file is a shell script that simply defines the modules -# in order as normal variables with the special names: -# MODULE_0, MODULE_1, MODULE_2, etc. -# -# List the modules that are to be loaded for your system -# -EOT - print SYSCONFIG - "# Generated by sensors-detect on " . scalar localtime() . "\n"; - my @modules = grep /^modprobe /, split "\n", $modprobes; - my $i = 0; - my $sysconfig = ""; - foreach (@modules) { - s/^modprobe //; - $sysconfig .= "MODULE_$i=$_\n"; - $i++; - } - print SYSCONFIG $sysconfig; - close(SYSCONFIG); - - print "Copy prog/init/lm_sensors.init to /etc/init.d/lm_sensors\n". - "for initialization at boot time.\n" - unless -f "/etc/init.d/lm_sensors"; - - if (-x "/sbin/insserv" && -f "/etc/init.d/lm_sensors") { - system("/sbin/insserv", "/etc/init.d/lm_sensors"); - } elsif (-x "/sbin/chkconfig" && -f "/etc/init.d/lm_sensors") { - system("/sbin/chkconfig", "lm_sensors", "on"); - if (-x "/sbin/service") { - system("/sbin/service", "lm_sensors", "start"); - } - } else { - print "You should now start the lm_sensors service to load the required\n". - "kernel modules.\n\n"; - } - } else { - print "To load everything that is needed, add this to one of the system\n". - "initialization scripts (e.g. /etc/rc.d/rc.local):\n\n"; - print "#----cut here----\n". - $modprobes. - (-e '/usr/bin/sensors' ? - "/usr/bin/sensors -s\n" : - "/usr/local/bin/sensors -s\n") . - "#----cut here----\n\n"; - - print "If you have some drivers built into your kernel, the list above will\n". - "contain too many modules. Skip the appropriate ones! You really\n". - "should try these commands right now to make sure everything is\n". - "working properly. Monitoring programs won't work until the needed\n". - "modules are loaded.\n\n"; - } + unload_modules(); } +sub cleanup_on_int +{ + print "\n"; + unload_modules(); + exit; +} + +$SIG{INT} = \&cleanup_on_int; + main; diff --git a/prog/detect/sensors-detect-stat.pl b/prog/detect/sensors-detect-stat.pl deleted file mode 100755 index f59454b5..00000000 --- a/prog/detect/sensors-detect-stat.pl +++ /dev/null @@ -1,101 +0,0 @@ -#!/usr/bin/perl -wT - -# sensors-detect-stat.pl -# Statistical analysis of sensors-detect i2c addresses scanner -# Part of the lm_sensors project -# Copyright (C) 2003-2008 Jean Delvare -# -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - -use strict; -use vars qw(%histo $chips $file $skip); - -# Where is sensors-detect? -# Use first argument, else try default locations. -if (defined($ARGV[0])) -{ - $file = $ARGV[0]; -} -elsif (-r '/usr/local/sbin/sensors-detect') -{ - $file = '/usr/local/sbin/sensors-detect'; -} -elsif (-r '/usr/sbin/sensors-detect') -{ - $file = '/usr/sbin/sensors-detect'; -} -else -{ - print "Usage: $0 /path/to/sensors-detect\n"; - exit 1; -} - -# Can we read that file? -if (! -r $file) -{ - print "Couldn't open $file for reading.\n"; - exit 2; -} - -# Get the data. -open (SD, $file) || die; -$skip = 0; -while () -{ - # Some chips are handled differently depending on the kernel - # version, avoid counting them twice. - if (m/^\@chip_kern24_ids\s*=/ || m/^\@chip_oldfsc_ids\s*=/) { - $skip = 1; - next; - } - if ($skip && m/^\);$/) { - $skip = 0; - next; - } - next if $skip; - - # The regular expression may seem a little bit complex, but we wouldn't - # want to exec malicious code. - next unless m/^\s*i2c_addrs\s*=>\s*(\[( *0x[\dA-Fa-f]{2}( *\.\. *0x[\dA-Fa-f]{2})? *,?)+\])\s*,/; - my $addresses = eval $1 || die "Failed to eval \"$1\""; - $chips++; - foreach my $a (@{$addresses}) - { - $histo{$a}++; - } -} -close SD; - -# Print the data. -printf "\%s knows \%d chips and scans \%d addresses.\n\n", - $file, $chips, scalar keys %histo; -print " 0 1 2 3 4 5 6 7 8 9 a b c d e f\n"; -for (my $i=0; $i<128; $i+=16) -{ - printf '%02x:', $i; - for (my $j=0; $j<16; $j++) - { - my $valid = ($i+$j >= 0x04 && $i+$j <= 0x77); - if (defined $histo{$i+$j}) - { - printf '%s%02d', ($valid?' ':'!'), $histo{$i+$j}; - } - else - { - printf ' %s', ($valid?'--':' '); - } - } - print "\n"; -} diff --git a/prog/detect/sensors-detect.8 b/prog/detect/sensors-detect.8 index f210ee07..a7eabfad 100644 --- a/prog/detect/sensors-detect.8 +++ b/prog/detect/sensors-detect.8 @@ -1,4 +1,4 @@ -.TH SENSORS-DETECT 8 "March 2004" +.TH SENSORS-DETECT 8 "December 2008" "lm-sensors 3" .SH NAME sensors-detect \- detect hardware monitoring chips @@ -11,15 +11,42 @@ process of scanning your system for various hardware monitoring chips, or sensors, supported by libsensors(3), or more generally by the lm_sensors tool suite. -.SH CONFORMING TO -lm_sensors-2.x +sensors-detect will look for the following devices, in order: +.IP \(bu +Sensors embedded in CPUs, south bridges and memory controllers. +.IP \(bu +Sensors embedded in Super I/O chips. +.IP \(bu +Hardware monitoring chips accessed through ISA I/O ports. +.IP \(bu +Hardware monitoring chips reachable over the SMBus or more generally +any I2C bus on your system. +.PP +As the last two detection steps can cause trouble on some systems, they +are normally not attempted if the second detection step led to the +discovery of a Super I/O chip with complete hardware monitoring features. +However, the user is always free to ask for all detection steps if so is +his/her wish. This can be useful if a given system has more than one +hardware monitoring chip. Some vendors are known to do this, most notably +Asus and Tyan. + +.SH WARNING +sensors-detect needs to access the hardware for most of the chip detections. +By definition, it doesn't know which chips are there before it manages to +identify them. This means that it can access chips in a way these chips do +not like, causing problems ranging from SMBus lockup to permanent hardware +damage (a rare case, thankfully.) + +The authors made their best to make the detection as safe as possible, and +it turns out to work just fine in most cases, however it is impossible to +guarantee that sensors-detect will not lock or kill a specific system. So, +as a rule of thumb, you should not run sensors-detect on production servers, +and you should not run sensors-detect if can't afford replacing a random +part of your system. Also, it is recommended to not force a detection step +which would have been skipped by default, unless you know what you are doing. .SH SEE ALSO -sensors(1), libsensors(3), i2cdetect(8) +sensors(1), libsensors(3) .SH AUTHOR -Frodo Looijaard and the lm_sensors group -http://www.lm-sensors.org/ -This manual page was written by Joey Hess , for -the Debian GNU/Linux system. It was then reviewed by the lm_sensors team and -is now part of the lm_sensors source distribution. +Frodo Looijaard and Jean Delvare diff --git a/prog/doc/doc-features.pl b/prog/doc/doc-features.pl deleted file mode 100755 index 986edec2..00000000 --- a/prog/doc/doc-features.pl +++ /dev/null @@ -1,357 +0,0 @@ -#!/usr/bin/perl -w - -# -# doc-features.pl - Generate module/library documentation -# Copyright (c) 1999 Frodo Looijaard -# Copyright (c) 2002 Jean Delvare -# -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -# - -use strict; - -# %prefix contains the SENSORS_*_PREFIX defines as found in lib/chips.h. -# It is generated by scan_chips_h(). It shouldn't have duplicated values. -# %arrayname contains the sensors_chip_features array as found in -# lib/chips.c. It is generated by scan_chips_c_1(). It may have duplicated -# values. -# %prefix and %arrayname are expected to have the same set of keys, and -# this is verified in scan_all(). -# -# %sysctl contains the sysctl filenames as found in kernel/chips/*.c. It -# is generated by scan_kernel_chip, which is called on each file. It has -# (of course) duplicated values. -# -# %features contains the features for all chips as found in lib/chips.c. -# They are stored as arrays of references to hashes, each containing the -# following fields: -# number: The preprocessor symbol for the number of this feature -# name: The name of this feature -# logical_mapping: The preprocessor symbol for the logical mapping -# feature -# compute_mapping: The preprocessor symbol for the compute mapping -# feature -# mode_read: 1 if the feature is readable, 0 if not -# mode_write: 1 if the feature is writable, 0 if not -# sysctl: Preprocessor name of the sysctl file -# offset: Offset (in longs) within the sysctl file -# magnitude: Magnitude of this feature -# -# %mapping contains the feature names. It is generated while parsing -# lib/chips.c and is later used to display the mappings. - -use vars qw(%prefix %arrayname %sysctl %features %mapping); - -# Scan chips.h to get all prefixes values. -# Store the results in %prefix. -# $_[0]: Path to chips.h -sub scan_chips_h -{ - my $chips_h = shift; - - open INPUTFILE, $chips_h - or die "Can't open $chips_h"; - - while () - { - if (m/^\s*#\s*define\s+(SENSORS_\w+_PREFIX)\s+"(\S+)"/) - { - die "Duplicate #define $1 in $chips_h" - if defined $prefix{$1}; - $prefix{$1} = $2; - } - } - - close INPUTFILE; -} - -# Scan chips.c to get the feature array names. -# Store the results in %arrayname. -# $_[0]: Path to chips.c -sub scan_chips_c_1 -{ - my $chips_c = shift; - open INPUTFILE, $chips_c - or die "Can't open $chips_c"; - - while ( !~ m/^\s*sensors_chip_features\s/) {} - while () - { - last if m/^\s*\{\s*0/; - if (m/^\s*\{\s*(SENSORS_\w+_PREFIX)\s*,\s*(\w+)\s*\}\s*,/) - { - die "Duplicate entry $1 in sensors_chip_features" - if defined $arrayname{$1}; - $arrayname{$1} = $2; - } - } - - close INPUTFILE; -} - -# Returns a list of tokens. -# Tokens are either '{', '}', ',', ';' or anything between them. Spaces on -# each side of a token are removed; spaces inside a token are not. -# Used by scan_kernel_chip() and scan_chips_c_2(). -# $_[0]: Line to tokenize -sub tokenize -{ - my $line = shift; - - my @res = (); - $line =~ s/^\s*//; - - while (length $line) - { - last if $line =~ s/^\s*$//; - $line =~ s/^([{};,])\s*// - or $line =~ s/^([^{},;]+?)\s*([{},;\n])/$2/; - die "Parse error" - unless defined $1; - push @res, $1; - } - - return @res; -} - -# Scan one chip file to get sysctl filenames. -# Store the results in %prefix. -# $_[0]: Kernel chip filename -sub scan_kernel_chip -{ - my $chip = shift; - my $line; - - open INPUTFILE, $chip - or die "Can't open $chip"; - - while ($line = ) - { - next unless $line =~ m/^\s*static\s+ctl_table/; - last if $line =~ m/;/; # Skip dynamic ctl_table - my @tokens = tokenize($line); - - while ($line = ) - { - push @tokens, tokenize($line); - last if $line =~ m/;/; - } - - while (shift @tokens ne '{') { die "Tokenization failed in $chip" unless @tokens } - for (;;) - { - while (shift @tokens ne '{') { die "Tokenization failed in $chip" unless @tokens } - my $val = shift @tokens; - last if $val eq '0'; - die "Parse error: ',' expected after '$val' within $chip" - if shift @tokens ne ','; - my $name = shift @tokens; - die "Parse error: invalid name '$name' within $chip" - unless ($sysctl{$val}) = $name =~ m/^"(.+)"$/; - } - } - - close INPUTFILE; -} - -# Scan chips.c to get the feature arrays. -# Store the results in %feature. -# $_[0]: Path to chips.c -sub scan_chips_c_2 -{ - my $chips_c = shift; - my $line; - - open INPUTFILE, $chips_c or - die "Can't open $chips_c"; - while () - { - next unless m/sensors_chip_feature\s+(\w+)\s*\[/; - my $name = $1; - - my @tokens = (); - while ($line = ) - { - push @tokens, tokenize($line); - last if $line =~ m/;/; - } - - $features{$name} = []; - die "Parse error: '{' expected for $name" - if shift @tokens ne '{'; - for(;;) - { - my $new = {}; - while (shift @tokens ne '{') { die unless @tokens } - $new->{number} = shift @tokens; - last if $new->{number} eq '0'; - die "Parse error: ',' expected for $name" - if shift @tokens ne ','; - ($new->{name}) = (shift @tokens) =~ m/^"(.*)"$/ - or die "Parse error: Bad name for $name"; - die "Parse error: ',' expected for $name" - if shift @tokens ne ','; - $new->{logical_mapping} = shift @tokens; - die "Parse error: ',' expected for $name" - if shift @tokens ne ','; - $new->{compute_mapping} = shift @tokens; - die "Parse error: ',' expected for $name" - if shift @tokens ne ','; - my $next = shift @tokens; - $new->{mode_read} = ($next =~ m/_RW?$/); - $new->{mode_write} = ($next =~ m/_R?W$/); - die "Parse error: ',' expected for $name" - if shift @tokens ne ','; - $new->{sysctl} = shift @tokens; - die "Parse error: ',' expected for $name" - if shift @tokens ne ','; - ($new->{offset}) = (shift @tokens) =~ m/^VALUE\s*\(\s*(\d+)\s*\)/ - or die "Parse error: Bad offset for $name"; - die "Parse error: ',' expected for $name" - if shift @tokens ne ','; - $new->{magnitude} = shift @tokens; - push @{$features{$name}}, $new; - $mapping{$new->{number}} = $new->{name}; - while (shift @tokens ne '}') { die unless @tokens } - die "Parse error: ',' expected after $name" - if shift @tokens ne ','; - } - } - - close INPUTFILE; -} - -# $_[0]: Base directory -sub scan_all -{ - my $basedir = shift; - - $basedir =~ s/\/*$//; - - # Generate %prefix - scan_chips_h("$basedir/lib/chips.h"); - # Generate %arrayname - scan_chips_c_1("$basedir/lib/chips.c"); - - # Check that %prefix and %arrayname have the same set of keys - foreach my $item (keys %prefix) - { - die "Missing array name for $item" - unless defined $arrayname{$item}; - } - foreach my $item (keys %arrayname) - { - die "Missing #define for $item" - unless defined $prefix{$item}; - } - - #Generate ?? - scan_chips_c_2("$basedir/lib/chips.c"); - # Generate %sysctl - foreach my $filename (glob "$basedir/kernel/chips/*.c") - { - scan_kernel_chip($filename); - } -} - -# $_[0]: Prefix -sub output_data -{ - my $index = shift; - - printf "Chip '\%s'\n", $prefix{$index}; - print "\n"; - - printf "\%-21s \%-21s \%-21s \%5s \%5s\n", 'LABEL', 'LABEL CLASS', - 'COMPUTE CLASS', 'MODE', 'MAGN'; - foreach my $data (@{$features{$arrayname{$index}}}) - { - print STDERR "Missing logical mapping for $data->{logical_mapping} (index = $index, name = $data->{name})\n" - unless defined $mapping{$data->{logical_mapping}}; - print STDERR "Missing compute mapping for $data->{compute_mapping} (index = $index, name = $data->{name})\n" - unless defined $mapping{$data->{compute_mapping}}; - - printf "\%-21s \%-21s \%-21s \%4s \%2d\n", $data->{name}, - $mapping{$data->{logical_mapping}} || '?', - $mapping{$data->{compute_mapping}} || '?', - ($data->{mode_read}?'R':'-').($data->{mode_write}?'W':'-'), - $data->{magnitude}; - } - print "\n"; - - printf "\%-21s \%-38s \%16s:\%1s\n", 'LABEL', 'FEATURE SYMBOL', - 'SYSCTL FILE', 'N'; - foreach my $data (@{$features{$arrayname{$index}}}) - { - print STDERR "Missing sysctl for $data->{sysctl} (index = $index, name = $data->{name})\n" - unless defined $sysctl{$data->{sysctl}}; - - printf "\%-21s \%-38s \%16s:\%1d\n",$data->{name}, $data->{number}, - $sysctl{$data->{sysctl}} || '?', $data->{offset}; - } - print "\n", "\n"; -} - -if (@ARGV < 1 or $ARGV[0] =~ m/^-/) -{ - print "Usage: $0 PATH [PREFIXES ...]\n", - " PATH is the path to the base directory of the lm_sensors tree.\n", - " PREFIXES are the chips that have to be output. If none are\n", - " specified, all chips are printed.\n"; - exit 0; -} - -%prefix = %arrayname = %sysctl = %features = (); -%mapping = (SENSORS_NO_MAPPING => '-'); - -scan_all(shift @ARGV); - -print "Chip Features\n", "-------------\n", "\n"; - -if (@ARGV) -{ - my %rprefix = reverse %prefix; - foreach my $prefix (@ARGV) - { - if (exists $rprefix{$prefix}) - { - output_data($rprefix{$prefix}) - } - else - { - my $lines = 0; - print "No chip named `$prefix' was found.\n", - "Suggestions:\n"; - foreach my $k (sort keys %rprefix) - { - if (grep /$prefix/, $k) - { - print " $k\n"; - $lines++; - } - } - print " (none)\n" - unless $lines; - print "\n"; - } - } -} -else -{ - foreach my $item (sort keys %prefix) - { - output_data($item); - } -} diff --git a/prog/doc/doc-insmod.pl b/prog/doc/doc-insmod.pl deleted file mode 100755 index 289ab5c4..00000000 --- a/prog/doc/doc-insmod.pl +++ /dev/null @@ -1,93 +0,0 @@ -#!/usr/bin/perl -w - -# -# doc-insmod.pl - Generate module parameters documentation -# Copyright (c) 1998, 1999 Frodo Looijaard -# Copyright (c) 2002 Jean Delvare -# -# Known to work with Linux modutils 2.3.10-pre1, 2.4.6, 2.4.15, 2.4.16 -# and 2.4.19. -# -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -# - - -use strict; -use Text::Wrap; -use vars qw($modinfo); - -$modinfo = 'modinfo'; -$ENV{PATH} = '/sbin'; - -sub get_modinfo_version -{ - my $line = `$modinfo -V`; - - return undef unless $line =~ m/\b(\d+)\.(\d+)\.(\d+)/; - return ($1<<16)+($2<<8)+$3; -} - -# @_[0]: name or full path of the kernel module -sub print_modinfo -{ - my $modname = shift; - my $version = get_modinfo_version(); - - unless ($modname =~ m/^([\w\d.\/-]+)$/) - { - print STDERR "Invalid module name.\n"; - return; - } - $modname = $1; - - my ($author, $license); - $author = `$modinfo -a $modname`; - $author =~ s/\n\s+/ /mg; # handle multiline authors - $author =~ s/^"//; - $author =~ s/"$//; - if (defined $version and $version >= (2<<16)+(4<<8)+15) - { - $license = `$modinfo -l $modname`; - $license =~ s/^"//; - $license =~ s/"$//; - } - - print wrap('Author: ', ' ', $author), "\n"; - print wrap('License: ', ' ', $license), "\n" - if defined $license; - print "\n", "Module Parameters\n", "-----------------\n", "\n"; - - my $lines = 0; - open OPTIONS, "$modinfo -p $modname |"; - while () - { - next unless m/^(parm:\s*)?(\S+) (.+), description "(.*)"$/; - print "* $2: $3\n", - wrap(' ', ' ', $4), "\n"; - $lines++; - } - close OPTIONS; - print "(none)\n" - unless $lines; -} - -if (@ARGV != 1 or $ARGV[0] =~ /^-/) -{ - print "Usage: $0 MODULE\n", - " MODULE is a module name or the full path to a module file.\n"; - exit 0; -} - -print_modinfo($ARGV[0]); diff --git a/prog/dump/Module.mk b/prog/dump/Module.mk index ee9c4f4f..5e522e3d 100644 --- a/prog/dump/Module.mk +++ b/prog/dump/Module.mk @@ -13,7 +13,8 @@ # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software -# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, +# MA 02110-1301 USA. # Note that MODULE_DIR (the directory in which this file resides) is a # 'simply expanded variable'. That means that its value is substituted @@ -22,27 +23,14 @@ MODULE_DIR := prog/dump PROGDUMPDIR := $(MODULE_DIR) PROGDUMPMAN8DIR := $(MANDIR)/man8 -PROGDUMPMAN8FILES := $(MODULE_DIR)/i2cdump.8 $(MODULE_DIR)/i2cset.8 \ - $(MODULE_DIR)/i2cget.8 +PROGDUMPMAN8FILES := $(MODULE_DIR)/isadump.8 $(MODULE_DIR)/isaset.8 # Regrettably, even 'simply expanded variables' will not put their currently # defined value verbatim into the command-list of rules... -PROGDUMPTARGETS := $(MODULE_DIR)/i2cdump $(MODULE_DIR)/i2cset \ - $(MODULE_DIR)/i2cget -PROGDUMPSOURCES := $(MODULE_DIR)/i2cdump.c $(MODULE_DIR)/i2cset.c \ - $(MODULE_DIR)/i2cget.c $(MODULE_DIR)/i2cbusses.c \ - $(MODULE_DIR)/util.c -PROGDUMPBININSTALL := $(MODULE_DIR)/i2cdump $(MODULE_DIR)/i2cset \ - $(MODULE_DIR)/i2cget - -# Only build isadump and isaset on x86 machines. -ifneq (,$(findstring $(MACHINE), i386 i486 i586 i686 x86_64)) -PROGDUMPMAN8FILES += $(MODULE_DIR)/isadump.8 $(MODULE_DIR)/isaset.8 -PROGDUMPTARGETS += $(MODULE_DIR)/isadump $(MODULE_DIR)/isaset -PROGDUMPSOURCES += $(MODULE_DIR)/isadump.c $(MODULE_DIR)/isaset.c \ - $(MODULE_DIR)/superio.c -PROGDUMPBININSTALL += $(MODULE_DIR)/isadump $(MODULE_DIR)/isaset -endif +PROGDUMPTARGETS := $(MODULE_DIR)/isadump $(MODULE_DIR)/isaset +PROGDUMPSOURCES := $(MODULE_DIR)/util.c $(MODULE_DIR)/isadump.c \ + $(MODULE_DIR)/isaset.c $(MODULE_DIR)/superio.c +PROGDUMPBININSTALL := $(MODULE_DIR)/isadump $(MODULE_DIR)/isaset # Include all dependency files. We use '.rd' to indicate this will create # executables. @@ -54,15 +42,6 @@ REMOVEDUMPMAN := $(patsubst $(MODULE_DIR)/%,$(DESTDIR)$(PROGDUMPMAN8DIR)/%,$(PRO all-prog-dump: $(PROGDUMPTARGETS) user :: all-prog-dump -$(MODULE_DIR)/i2cdump: $(MODULE_DIR)/i2cdump.ro $(MODULE_DIR)/i2cbusses.ro $(MODULE_DIR)/util.ro - $(CC) $(EXLDFLAGS) -o $@ $^ - -$(MODULE_DIR)/i2cset: $(MODULE_DIR)/i2cset.ro $(MODULE_DIR)/i2cbusses.ro $(MODULE_DIR)/util.ro - $(CC) $(EXLDFLAGS) -o $@ $^ - -$(MODULE_DIR)/i2cget: $(MODULE_DIR)/i2cget.ro $(MODULE_DIR)/i2cbusses.ro $(MODULE_DIR)/util.ro - $(CC) $(EXLDFLAGS) -o $@ $^ - $(MODULE_DIR)/isadump: $(MODULE_DIR)/isadump.ro $(MODULE_DIR)/superio.ro $(MODULE_DIR)/util.ro $(CC) $(EXLDFLAGS) -o $@ $^ diff --git a/prog/dump/i2cbusses.c b/prog/dump/i2cbusses.c deleted file mode 100644 index 0435ddf4..00000000 --- a/prog/dump/i2cbusses.c +++ /dev/null @@ -1,259 +0,0 @@ -/* - i2cbusses: Print the installed i2c busses for both 2.4 and 2.6 kernels. - Part of user-space programs to access for I2C - devices. - Copyright (c) 1999-2003 Frodo Looijaard and - Mark D. Studebaker - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "i2cbusses.h" -#include "i2c-dev.h" - -enum adt { adt_dummy, adt_isa, adt_i2c, adt_smbus, adt_unknown }; - -struct adap_type { - const char *funcs; - const char* algo; -}; - -static struct adap_type adap_types[5] = { - { .funcs = "dummy", - .algo = "Dummy bus", }, - { .funcs = "isa", - .algo = "ISA bus", }, - { .funcs = "i2c", - .algo = "I2C adapter", }, - { .funcs = "smbus", - .algo = "SMBus adapter", }, - { .funcs = "unknown", - .algo = "N/A", }, -}; - -static enum adt i2c_get_funcs(int i2cbus) -{ - unsigned long funcs; - int file; - char filename[20]; - enum adt ret; - - file = open_i2c_dev(i2cbus, filename, 1); - if (file < 0) - return adt_unknown; - - if (ioctl(file, I2C_FUNCS, &funcs) < 0) - ret = adt_unknown; - else if (funcs & I2C_FUNC_I2C) - ret = adt_i2c; - else if (funcs & (I2C_FUNC_SMBUS_BYTE | - I2C_FUNC_SMBUS_BYTE_DATA | - I2C_FUNC_SMBUS_WORD_DATA)) - ret = adt_smbus; - else - ret = adt_dummy; - - close(file); - return ret; -} - -/* - this just prints out the installed i2c busses in a consistent format, whether - on a 2.4 kernel using /proc or a 2.6 kernel using /sys. - If procfmt == 1, print out exactly /proc/bus/i2c format on stdout. - This allows this to be used in a program to emulate /proc/bus/i2c on a - sysfs system. -*/ -void print_i2c_busses(int procfmt) -{ - FILE *fptr; - char s[100]; - struct dirent *de, *dde; - DIR *dir, *ddir; - FILE *f; - char *border; - char dev[NAME_MAX], fstype[NAME_MAX], sysfs[NAME_MAX], n[NAME_MAX]; - int foundsysfs = 0; - int count=0; - - - /* look in /proc/bus/i2c */ - if((fptr = fopen("/proc/bus/i2c", "r"))) { - while(fgets(s, 100, fptr)) { - if(count++ == 0 && !procfmt) - fprintf(stderr," Installed I2C busses:\n"); - if(procfmt) - printf("%s", s); - else - fprintf(stderr, " %s", s); - } - fclose(fptr); - goto done; - } - - /* look in sysfs */ - /* First figure out where sysfs was mounted */ - if ((f = fopen("/proc/mounts", "r")) == NULL) { - goto done; - } - while (fgets(n, NAME_MAX, f)) { - sscanf(n, "%[^ ] %[^ ] %[^ ] %*s\n", dev, sysfs, fstype); - if (strcasecmp(fstype, "sysfs") == 0) { - foundsysfs++; - break; - } - } - fclose(f); - if (! foundsysfs) { - goto done; - } - - /* Bus numbers in i2c-adapter don't necessarily match those in - i2c-dev and what we really care about are the i2c-dev numbers. - Unfortunately the names are harder to get in i2c-dev */ - strcat(sysfs, "/class/i2c-dev"); - if(!(dir = opendir(sysfs))) - goto done; - /* go through the busses */ - while ((de = readdir(dir)) != NULL) { - if (!strcmp(de->d_name, ".")) - continue; - if (!strcmp(de->d_name, "..")) - continue; - - /* this should work for kernels 2.6.5 or higher and */ - /* is preferred because is unambiguous */ - sprintf(n, "%s/%s/name", sysfs, de->d_name); - f = fopen(n, "r"); - /* this seems to work for ISA */ - if(f == NULL) { - sprintf(n, "%s/%s/device/name", sysfs, de->d_name); - f = fopen(n, "r"); - } - /* non-ISA is much harder */ - /* and this won't find the correct bus name if a driver - has more than one bus */ - if(f == NULL) { - sprintf(n, "%s/%s/device", sysfs, de->d_name); - if(!(ddir = opendir(n))) - continue; - while ((dde = readdir(ddir)) != NULL) { - if (!strcmp(dde->d_name, ".")) - continue; - if (!strcmp(dde->d_name, "..")) - continue; - if ((!strncmp(dde->d_name, "i2c-", 4))) { - sprintf(n, "%s/%s/device/%s/name", - sysfs, de->d_name, dde->d_name); - if((f = fopen(n, "r"))) - goto found; - } - } - } - -found: - if (f != NULL) { - int i2cbus; - enum adt type; - char x[120]; - char *px; - - px = fgets(x, 120, f); - fclose(f); - if (!px) { - fprintf(stderr, "%s: read error\n", n); - continue; - } - if((border = strchr(x, '\n')) != NULL) - *border = 0; - if(count++ == 0 && !procfmt) - fprintf(stderr," Installed I2C busses:\n"); - /* match 2.4 /proc/bus/i2c format as closely as possible */ - if(!strncmp(x, "ISA ", 4)) { - type = adt_isa; - } else if(!sscanf(de->d_name, "i2c-%d", &i2cbus)) { - type = adt_dummy; - } else { - /* Attempt to probe for adapter capabilities */ - type = i2c_get_funcs(i2cbus); - } - - if (procfmt) - printf("%s\t%-10s\t%-32s\t%s\n", de->d_name, - adap_types[type].funcs, x, adap_types[type].algo); - else - fprintf(stderr, " %s\t%-10s\t%s\n", de->d_name, - adap_types[type].funcs, x); - } - } - closedir(dir); - -done: - if(count == 0 && !procfmt) - fprintf(stderr,"Error: No I2C busses found!\n" - "Be sure you have done 'modprobe i2c-dev'\n" - "and also modprobed your i2c bus drivers\n"); -} - -int open_i2c_dev(const int i2cbus, char *filename, const int quiet) -{ - int file; - - sprintf(filename, "/dev/i2c/%d", i2cbus); - file = open(filename, O_RDWR); - - if (file < 0 && errno == ENOENT) { - sprintf(filename, "/dev/i2c-%d", i2cbus); - file = open(filename, O_RDWR); - } - - if (file < 0 && !quiet) { - if (errno == ENOENT) { - fprintf(stderr, "Error: Could not open file " - "`/dev/i2c-%d' or `/dev/i2c/%d': %s\n", - i2cbus, i2cbus, strerror(ENOENT)); - } else { - fprintf(stderr, "Error: Could not open file " - "`%s': %s\n", filename, strerror(errno)); - if (errno == EACCES) - fprintf(stderr, "Run as root?\n"); - } - } - - return file; -} - -int set_slave_addr(int file, int address, int force) -{ - /* With force, let the user read from/write to the registers - even when a driver is also running */ - if (ioctl(file, force ? I2C_SLAVE_FORCE : I2C_SLAVE, address) < 0) { - fprintf(stderr, - "Error: Could not set address to 0x%02x: %s\n", - address, strerror(errno)); - return -errno; - } - - return 0; -} diff --git a/prog/dump/i2cdump.8 b/prog/dump/i2cdump.8 deleted file mode 100644 index 9a703e9a..00000000 --- a/prog/dump/i2cdump.8 +++ /dev/null @@ -1,80 +0,0 @@ -.TH I2CDUMP 8 "June 2007" -.SH NAME -i2cdump \- examine I2C registers - -.SH SYNOPSIS -.B i2cdump -.RB [ -f ] -.RB [ -y ] -.I i2cbus -.I address -.RI [ mode ] -.RI [ "bank " [ bankreg ]] -.br -.B i2cdump -.B -V - -.SH DESCRIPTION -i2cdump is a small helper program to examine registers -visible through the I2C bus. - -.SH OPTIONS -.TP -.B -V -Display the version and exit. -.TP -.B -f -Force access to the device even if it is already busy. By default, i2cdump -will refuse to access a device which is already under the control of a -kernel driver. Using this flag is dangerous, it can seriously confuse the -kernel driver in question. It can also cause i2cdump to return invalid -results. So use at your own risk and only if you know what you're doing. -.TP -.B -y -Disable interactive mode. By default, i2cdump will wait for a confirmation -from the user before messing with the I2C bus. When this flag is used, it -will perform the operation directly. This is mainly meant to be used in -scripts. -.PP -At least two options must be provided to i2cdump. \fIi2cbus\fR indicates the -number of the I2C bus to be scanned. This number should correspond to one -of the busses listed by \fIi2cdetect -l\fR. \fIaddress\fR indicates the -address to be scanned on that bus, and is an integer between 0x00 and 0x7F. -.PP -The \fImode\fR parameter, if specified, is one of the letters \fBb\fP, \fBw\fP, -\fBs\fP, or \fBi\fP, corresponding to a read size of a single byte, a 16-bit -word, an SMBus block, an I2C block, respectively. The \fBc\fP mode is a -little different, it reads all bytes consecutively, and is useful for chips that -have an address auto-increment feature, such as EEPROMs. The \fBW\fP mode is -also special, it is similar to \fBw\fP except that a read command will only -be issued on even register addresses; this is again mainly useful for EEPROMs. -.PP -A \fBp\fP can also be appended to the \fImode\fR parameter (except for -\fBi\fP and \fBW\fP) to enable PEC. If the \fImode\fR parameter is omitted, -i2cdump defaults to byte access without PEC. -.PP -The \fIbank\fR and \fIbankreg\fR parameters are useful on the W83781D and -similar chips (at the time of writing, all Winbond and Asus chips). -\fIbank\fR is an integer between 0 and 7, and \fIbankreg\fR is an integer -between 0x00 and 0xFF (default value: 0x4E). The W83781D data sheet has more -information on bank selection. - -.SH WARNING -i2cdump can be dangerous if used improperly. Most notably, the \fBc\fP mode -starts with WRITING a byte to the chip. On most chips it will be stored in the -address pointer register, which is OK, but some chips with a single register -or no (visible) register at all will most likely see this as a real WRITE, -resulting in possible misbehavior or corruption. Do not use i2cdump -on random addresses. Anyway, it is of little use unless you have an idea of -what you are looking for and have some general knowledge about hardware -monitoring chips internals. - -.SH SEE ALSO -i2cset(8), i2cdetect(8), isadump(8) - -.SH AUTHOR -Frodo Looijaard, Mark D. Studebaker, and the lm_sensors group -http://www.lm-sensors.org/ -This manual page was originally written by David Z Maze for -the Debian GNU/Linux system. It was then reviewed by the lm_sensors team and -is now part of the lm_sensors source distribution. diff --git a/prog/dump/i2cdump.c b/prog/dump/i2cdump.c deleted file mode 100644 index f677b58d..00000000 --- a/prog/dump/i2cdump.c +++ /dev/null @@ -1,428 +0,0 @@ -/* - i2cdump.c - a user-space program to dump I2C registers - Copyright (C) 2002-2003 Frodo Looijaard , and - Mark D. Studebaker - Copyright (C) 2004 The lm_sensors group - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#include -#include -#include -#include -#include -#include "util.h" -#include "i2cbusses.h" -#include "i2c-dev.h" -#include "version.h" - -void help(void) -{ - fprintf(stderr, "Syntax: i2cdump [-f] [-y] I2CBUS ADDRESS [MODE] " - "[BANK [BANKREG]]\n" - " i2cdump -V\n" - " MODE is one of:\n" - " b (byte, default)\n" - " w (word)\n" - " W (word on even register addresses)\n" - " s (SMBus block)\n" - " i (I2C block)\n" - " c (consecutive byte)\n" - " Append 'p' to 'b', 'w', 's' or 'c' for PEC checking\n" - " I2CBUS is an integer\n" - " ADDRESS is an integer 0x00 - 0x7f\n" - " BANK and BANKREG are for byte and word accesses (default " - "bank 0, reg 0x4e)\n" - " BANK is the command for smbusblock accesses (default 0)\n"); - print_i2c_busses(0); -} - -int main(int argc, char *argv[]) -{ - char *end; - int i, j, res, i2cbus, address, size, file; - int bank = 0, bankreg = 0x4E, old_bank = 0; - char filename[20]; - unsigned long funcs; - int block[256], s_length = 0; - int pec = 0, even = 0; - int flags = 0; - int force = 0, yes = 0, version = 0; - - /* handle (optional) flags first */ - while (1+flags < argc && argv[1+flags][0] == '-') { - switch (argv[1+flags][1]) { - case 'V': version = 1; break; - case 'f': force = 1; break; - case 'y': yes = 1; break; - default: - fprintf(stderr, "Warning: Unsupported flag " - "\"-%c\"!\n", argv[1+flags][1]); - help(); - exit(1); - } - flags++; - } - - if (version) { - fprintf(stderr, "i2cdump version %s\n", LM_VERSION); - exit(0); - } - - if (argc < flags + 2) { - fprintf(stderr, "Error: No i2c-bus specified!\n"); - help(); - exit(1); - } - i2cbus = strtol(argv[flags+1], &end, 0); - if (*end) { - fprintf(stderr, "Error: First argument not a number!\n"); - help(); - exit(1); - } - if (i2cbus < 0 || i2cbus > 0xff) { - fprintf(stderr, "Error: I2CBUS argument out of range!\n"); - help(); - exit(1); - } - - if (argc < flags + 3) { - fprintf(stderr, "Error: No address specified!\n"); - help(); - exit(1); - } - address = strtol(argv[flags+2], &end, 0); - if (*end) { - fprintf(stderr, "Error: Second argument not a number!\n"); - help(); - exit(1); - } - if (address < 0 || address > 0x7f) { - fprintf(stderr, "Error: Address out of range!\n"); - help(); - exit(1); - } - - if (argc < flags + 4) { - fprintf(stderr, "No size specified (using byte-data access)\n"); - size = I2C_SMBUS_BYTE_DATA; - } else if (!strncmp(argv[flags+3], "b", 1)) { - size = I2C_SMBUS_BYTE_DATA; - pec = argv[flags+3][1] == 'p'; - } else if (!strncmp(argv[flags+3], "w", 1)) { - size = I2C_SMBUS_WORD_DATA; - pec = argv[flags+3][1] == 'p'; - } else if (!strncmp(argv[flags+3], "W", 1)) { - size = I2C_SMBUS_WORD_DATA; - even = 1; - } else if (!strncmp(argv[flags+3], "s", 1)) { - size = I2C_SMBUS_BLOCK_DATA; - pec = argv[flags+3][1] == 'p'; - } else if (!strncmp(argv[flags+3], "c", 1)) { - size = I2C_SMBUS_BYTE; - pec = argv[flags+3][1] == 'p'; - } else if (!strcmp(argv[flags+3], "i")) - size = I2C_SMBUS_I2C_BLOCK_DATA; - else { - fprintf(stderr, "Error: Invalid mode!\n"); - help(); - exit(1); - } - - if (argc > flags + 4) { - bank = strtol(argv[flags+4], &end, 0); - if (*end || size == I2C_SMBUS_I2C_BLOCK_DATA) { - fprintf(stderr, "Error: Invalid bank number!\n"); - help(); - exit(1); - } - if ((size == I2C_SMBUS_BYTE_DATA || size == I2C_SMBUS_WORD_DATA) - && (bank < 0 || bank > 15)) { - fprintf(stderr, "Error: bank out of range!\n"); - help(); - exit(1); - } - if (size == I2C_SMBUS_BLOCK_DATA - && (bank < 0 || bank > 0xff)) { - fprintf(stderr, "Error: block command out of range!\n"); - help(); - exit(1); - } - - if (argc > flags + 5) { - bankreg = strtol(argv[flags+5], &end, 0); - if (*end || size == I2C_SMBUS_BLOCK_DATA) { - fprintf(stderr, "Error: Invalid bank register " - "number!\n"); - help(); - exit(1); - } - if (bankreg < 0 || bankreg > 0xff) { - fprintf(stderr, "Error: bank out of range " - "(0-0xff)!\n"); - help(); - exit(1); - } - } - } - - file = open_i2c_dev(i2cbus, filename, 0); - if (file < 0) { - exit(1); - } - - /* check adapter functionality */ - if (ioctl(file, I2C_FUNCS, &funcs) < 0) { - fprintf(stderr, "Error: Could not get the adapter " - "functionality matrix: %s\n", strerror(errno)); - exit(1); - } - - switch(size) { - case I2C_SMBUS_BYTE: - if (!((funcs & I2C_FUNC_SMBUS_BYTE) == I2C_FUNC_SMBUS_BYTE)) { - fprintf(stderr, "Error: Adapter for i2c bus %d does " - "not have byte capability\n", i2cbus); - exit(1); - } - break; - - case I2C_SMBUS_BYTE_DATA: - if (!(funcs & I2C_FUNC_SMBUS_READ_BYTE_DATA)) { - fprintf(stderr, "Error: Adapter for i2c bus %d does " - "not have byte read capability\n", i2cbus); - exit(1); - } - break; - - case I2C_SMBUS_WORD_DATA: - if (!(funcs & I2C_FUNC_SMBUS_READ_WORD_DATA)) { - fprintf(stderr, "Error: Adapter for i2c bus %d does " - "not have word read capability\n", i2cbus); - exit(1); - } - break; - - case I2C_SMBUS_BLOCK_DATA: - if (!(funcs & I2C_FUNC_SMBUS_READ_BLOCK_DATA)) { - fprintf(stderr, "Error: Adapter for i2c bus %d does " - "not have smbus block read capability\n", - i2cbus); - exit(1); - } - break; - - case I2C_SMBUS_I2C_BLOCK_DATA: - if (!(funcs & I2C_FUNC_SMBUS_READ_I2C_BLOCK)) { - fprintf(stderr, "Error: Adapter for i2c bus %d does " - "not have i2c block read capability\n", - i2cbus); - exit(1); - } - break; - } - - if (set_slave_addr(file, address, force) < 0) - exit(1); - - if (pec) { - if (ioctl(file, I2C_PEC, 1) < 0) { - fprintf(stderr, "Error: Could not set PEC: %s\n", - strerror(errno)); - exit(1); - } - if (!(funcs & (I2C_FUNC_SMBUS_PEC | I2C_FUNC_I2C))) { - fprintf(stderr, "Warning: Adapter for i2c bus %d does " - "not seem to actually support PEC\n", i2cbus); - } - } - - if (!yes) { - fprintf(stderr, "WARNING! This program can confuse your I2C " - "bus, cause data loss and worse!\n"); - - fprintf(stderr, "I will probe file %s, address 0x%x, mode " - "%s\n", filename, address, - size == I2C_SMBUS_BLOCK_DATA ? "smbus block" : - size == I2C_SMBUS_I2C_BLOCK_DATA ? "i2c block" : - size == I2C_SMBUS_BYTE ? "byte consecutive read" : - size == I2C_SMBUS_BYTE_DATA ? "byte" : "word"); - if (pec) - fprintf(stderr, "PEC checking enabled.\n"); - if (even) - fprintf(stderr, "Only probing even register " - "addresses.\n"); - if (bank) { - if (size == I2C_SMBUS_BLOCK_DATA) - fprintf(stderr, "Using command 0x%02x.\n", - bank); - else - fprintf(stderr, "Probing bank %d using bank " - "register 0x%02x.\n", bank, bankreg); - } - - fprintf(stderr, "Continue? [Y/n] "); - fflush(stderr); - if (!user_ack(1)) { - fprintf(stderr, "Aborting on user request.\n"); - exit(0); - } - } - - /* See Winbond w83781d data sheet for bank details */ - if (bank && size != I2C_SMBUS_BLOCK_DATA) { - res = i2c_smbus_read_byte_data(file, bankreg); - if (res >= 0) { - old_bank = res; - res = i2c_smbus_write_byte_data(file, bankreg, - bank | (old_bank & 0xf0)); - } - if (res < 0) { - fprintf(stderr, "Error: Bank switching failed\n"); - exit(1); - } - } - - /* handle all but word data */ - if (size != I2C_SMBUS_WORD_DATA || even) { - /* do the block transaction */ - if (size == I2C_SMBUS_BLOCK_DATA - || size == I2C_SMBUS_I2C_BLOCK_DATA) { - unsigned char cblock[288]; - - if (size == I2C_SMBUS_BLOCK_DATA) { - res = i2c_smbus_read_block_data(file, bank, - cblock); - /* Remember returned block length for a nicer - display later */ - s_length = res; - } else { - for (res = 0; res < 256; res += i) { - i = i2c_smbus_read_i2c_block_data(file, - res, 32, cblock + res); - if (i <= 0) { - res = i; - break; - } - } - } - if (res <= 0) { - fprintf(stderr, "Error: Block read failed, " - "return code %d\n", res); - exit(1); - } - if (res >= 256) - res = 256; - for (i = 0; i < res; i++) - block[i] = cblock[i]; - if (size != I2C_SMBUS_BLOCK_DATA) - for (i = res; i < 256; i++) - block[i] = -1; - } - - if (size == I2C_SMBUS_BYTE) { - res = i2c_smbus_write_byte(file, 0); - if(res != 0) { - fprintf(stderr, "Error: Write start address " - "failed, return code %d\n", res); - exit(1); - } - } - - printf(" 0 1 2 3 4 5 6 7 8 9 a b c d e f" - " 0123456789abcdef\n"); - for (i = 0; i < 256; i+=16) { - if (size == I2C_SMBUS_BLOCK_DATA && i >= s_length) - break; - printf("%02x: ", i); - for (j = 0; j < 16; j++) { - fflush(stdout); - if (size == I2C_SMBUS_BYTE_DATA) { - block[i+j] = res = - i2c_smbus_read_byte_data(file, i+j); - } else if (size == I2C_SMBUS_WORD_DATA) { - res = i2c_smbus_read_word_data(file, - i+j); - if (res < 0) { - block[i+j] = res; - block[i+j+1] = res; - } else { - block[i+j] = res & 0xff; - block[i+j+1] = res >> 8; - } - } else if (size == I2C_SMBUS_BYTE) { - block[i+j] = res = - i2c_smbus_read_byte(file); - } else - res = block[i+j]; - - if (size == I2C_SMBUS_BLOCK_DATA - && i+j >= s_length) { - printf(" "); - } else if (res < 0) { - printf("XX "); - if (size == I2C_SMBUS_WORD_DATA) - printf("XX "); - } else { - printf("%02x ", block[i+j]); - if (size == I2C_SMBUS_WORD_DATA) - printf("%02x ", block[i+j+1]); - } - if (size == I2C_SMBUS_WORD_DATA) - j++; - } - printf(" "); - - for (j = 0; j < 16; j++) { - if (size == I2C_SMBUS_BLOCK_DATA - && i+j >= s_length) - break; - - res = block[i+j]; - if (res < 0) - printf("X"); - else - if ((res & 0xff) == 0x00 - || (res & 0xff) == 0xff) - printf("."); - else - if ((res & 0xff) < 32 - || (res & 0xff) >= 127) - printf("?"); - else - printf("%c", res & 0xff); - } - printf("\n"); - } - } else { - printf(" 0,8 1,9 2,a 3,b 4,c 5,d 6,e 7,f\n"); - for (i = 0; i < 256; i+=8) { - printf("%02x: ", i); - for (j = 0; j < 8; j++) { - res = i2c_smbus_read_word_data(file, i+j); - if (res < 0) - printf("XXXX "); - else - printf("%04x ", res & 0xffff); - } - printf("\n"); - } - } - if (bank && size != I2C_SMBUS_BLOCK_DATA) { - i2c_smbus_write_byte_data(file, bankreg, old_bank); - } - exit(0); -} diff --git a/prog/dump/i2cget.8 b/prog/dump/i2cget.8 deleted file mode 100644 index 4b4b76e1..00000000 --- a/prog/dump/i2cget.8 +++ /dev/null @@ -1,68 +0,0 @@ -.TH I2CGET 8 "June 2007" -.SH "NAME" -i2cget \- read from I2C/SMBus chip registers - -.SH SYNOPSIS -.B i2cget -.RB [ -f ] -.RB [ -y ] -.I i2cbus -.I chip-address -.RI [ data-address " [" mode ]] -.br -.B i2cget -.B -V - -.SH DESCRIPTION -i2cget is a small helper program to read registers visible through the I2C -bus (or SMBus). - -.SH OPTIONS -.TP -.B -V -Display the version and exit. -.TP -.B -f -Force access to the device even if it is already busy. By default, i2cget -will refuse to access a device which is already under the control of a -kernel driver. Using this flag is dangerous, it can seriously confuse the -kernel driver in question. It can also cause i2cget to return an invalid -value. So use at your own risk and only if you know what you're doing. -.TP -.B -y -Disable interactive mode. By default, i2cget will wait for a confirmation -from the user before messing with the I2C bus. When this flag is used, it -will perform the operation directly. This is mainly meant to be used in -scripts. Use with caution. -.PP -There are two required options to i2cget. \fIi2cbus\fR indicates the number -of the I2C bus to be scanned. This number should correspond to one of -the busses listed by \fIi2cdetect -l\fR. \fIchip-address\fR specifies the -address of the chip on that bus, and is an integer between 0x03 and 0x77. -.PP -\fIdata-address\fR specifies the address on that chip to read from, and is -an integer between 0x00 and 0xFF. If omitted, the currently active register -will be read (if that makes sense for the considered chip). -.PP -The \fImode\fR parameter, if specified, is one of the letters \fBb\fP, -\fBw\fP or \fBc\fP, corresponding to a read byte data, a read word data or a -write byte/read byte transaction, respectively. A \fBp\fP can also be appended -to the \fImode\fR parameter to enable PEC. If the \fImode\fR parameter is omitted, -i2cget defaults to a read byte data transaction, unless \fIdata-address\fR is -also omitted, in which case the default (and only valid) transaction is a -single read byte. - -.SH WARNING -i2cget can be extremely dangerous if used improperly. I2C and SMBus are designed -in such a way that an SMBus read transaction can be seen as a write transaction by -certain chips. This is particularly true if setting \fImode\fR to \fBcp\fP (write byte/read -byte with PEC). Be extremely careful using this program. - -.SH SEE ALSO -i2cdump(8), i2cset(8) - -.SH AUTHOR -Jean Delvare -http://www.lm-sensors.org/ -This manual page was strongly inspired from those written by David Z Maze -for i2cset. diff --git a/prog/dump/i2cget.c b/prog/dump/i2cget.c deleted file mode 100644 index 31d759fa..00000000 --- a/prog/dump/i2cget.c +++ /dev/null @@ -1,263 +0,0 @@ -/* - i2cget.c - A user-space program to read an I2C register. - Copyright (C) 2005 Jean Delvare - - Based on i2cset.c: - Copyright (C) 2001-2003 Frodo Looijaard , and - Mark D. Studebaker - Copyright (C) 2004-2005 Jean Delvare - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#include -#include -#include -#include -#include -#include "util.h" -#include "i2cbusses.h" -#include "i2c-dev.h" -#include "version.h" - -void help(void) __attribute__ ((noreturn)); - -void help(void) -{ - fprintf(stderr, "Syntax: i2cget [-f] [-y] I2CBUS CHIP-ADDRESS " - "[DATA-ADDRESS [MODE]]\n" - " i2cget -V\n" - " MODE can be: 'b' (read byte data, default)\n" - " 'w' (read word data)\n" - " 'c' (write byte/read byte)\n" - " If DATA-ADDRESS is omitted, a single read byte command is " - "issued\n" - " Append 'p' to MODE for PEC checking\n" - " I2CBUS is an integer\n"); - print_i2c_busses(0); - exit(1); -} - -int check_funcs(int file, int i2cbus, int size, int daddress, int pec) -{ - unsigned long funcs; - - /* check adapter functionality */ - if (ioctl(file, I2C_FUNCS, &funcs) < 0) { - fprintf(stderr, "Error: Could not get the adapter " - "functionality matrix: %s\n", strerror(errno)); - return -1; - } - - switch (size) { - case I2C_SMBUS_BYTE: - if (!(funcs & I2C_FUNC_SMBUS_READ_BYTE)) { - fprintf(stderr, "Error: Adapter for i2c bus %d does " - "not have read byte capability\n", i2cbus); - return -1; - } - if (daddress >= 0 - && !(funcs & I2C_FUNC_SMBUS_WRITE_BYTE)) { - fprintf(stderr, "Error: Adapter for i2c bus %d does " - "not have write byte capability\n", i2cbus); - return -1; - } - break; - - case I2C_SMBUS_BYTE_DATA: - if (!(funcs & I2C_FUNC_SMBUS_READ_BYTE_DATA)) { - fprintf(stderr, "Error: Adapter for i2c bus %d does " - "not have read byte data capability\n", i2cbus); - return -1; - } - break; - - case I2C_SMBUS_WORD_DATA: - if (!(funcs & I2C_FUNC_SMBUS_READ_WORD_DATA)) { - fprintf(stderr, "Error: Adapter for i2c bus %d does " - "not have read word data capability\n", i2cbus); - return -1; - } - break; - } - - if (pec - && !(funcs & (I2C_FUNC_SMBUS_PEC | I2C_FUNC_I2C))) { - fprintf(stderr, "Warning: Adapter for i2c bus %d does " - "not seem to support PEC\n", i2cbus); - } - - return 0; -} - -int confirm(const char *filename, int address, int size, int daddress, int pec) -{ - int dont = 0; - - fprintf(stderr, "WARNING! This program can confuse your I2C " - "bus, cause data loss and worse!\n"); - - /* Don't let the user break his/her EEPROMs */ - if (address >= 0x50 && address <= 0x57 && pec) { - fprintf(stderr, "STOP! EEPROMs are I2C devices, not " - "SMBus devices. Using PEC\non I2C devices may " - "result in unexpected results, such as\n" - "trashing the contents of EEPROMs. We can't " - "let you do that, sorry.\n"); - return 0; - } - - if (size == I2C_SMBUS_BYTE && daddress >= 0 && pec) { - fprintf(stderr, "WARNING! All I2C chips and some SMBus chips " - "will interpret a write\nbyte command with PEC as a" - "write byte data command, effectively writing a\n" - "value into a register!\n"); - dont++; - } - - fprintf(stderr, "I will read from device file %s, chip " - "address 0x%02x, ", filename, address); - if (daddress < 0) - fprintf(stderr, "current data\naddress"); - else - fprintf(stderr, "data address\n0x%02x", daddress); - fprintf(stderr, ", using %s.\n", - size == I2C_SMBUS_BYTE ? (daddress < 0 ? - "read byte" : "write byte/read byte") : - size == I2C_SMBUS_BYTE_DATA ? "read byte data" : - "read word data"); - if (pec) - fprintf(stderr, "PEC checking enabled.\n"); - - fprintf(stderr, "Continue? [%s] ", dont ? "y/N" : "Y/n"); - fflush(stderr); - if (!user_ack(!dont)) { - fprintf(stderr, "Aborting on user request.\n"); - return 0; - } - - return 1; -} - -int main(int argc, char *argv[]) -{ - char *end; - int res, i2cbus, address, file; - int size = I2C_SMBUS_BYTE_DATA; - int daddress; - char filename[20]; - int pec = 0; - int flags = 0; - int force = 0, yes = 0, version = 0; - - /* handle (optional) flags first */ - while (1+flags < argc && argv[1+flags][0] == '-') { - switch (argv[1+flags][1]) { - case 'V': version = 1; break; - case 'f': force = 1; break; - case 'y': yes = 1; break; - default: - fprintf(stderr, "Warning: Unsupported flag " - "\"-%c\"!\n", argv[1+flags][1]); - help(); - exit(1); - } - flags++; - } - - if (version) { - fprintf(stderr, "i2cget version %s\n", LM_VERSION); - exit(0); - } - - if (argc - flags < 3) - help(); - - i2cbus = strtol(argv[flags+1], &end, 0); - if (*end || i2cbus < 0 || i2cbus > 0x3f) { - fprintf(stderr, "Error: I2CBUS argument invalid!\n"); - help(); - } - - address = strtol(argv[flags+2], &end, 0); - if (*end || address < 3 || address > 0x77) { - fprintf(stderr, "Error: Chip address invalid!\n"); - help(); - } - - if (!(flags+3 < argc)) { - size = I2C_SMBUS_BYTE; - daddress = -1; - } else { - daddress = strtol(argv[flags+3], &end, 0); - if (*end || daddress < 0 || daddress > 0xff) { - fprintf(stderr, "Error: Data address invalid!\n"); - help(); - } - } - - if (flags+4 < argc) { - switch (argv[flags+4][0]) { - case 'b': size = I2C_SMBUS_BYTE_DATA; break; - case 'w': size = I2C_SMBUS_WORD_DATA; break; - case 'c': size = I2C_SMBUS_BYTE; break; - default: - fprintf(stderr, "Error: Invalid mode!\n"); - help(); - } - pec = argv[flags+4][1] == 'p'; - } - - file = open_i2c_dev(i2cbus, filename, 0); - if (file < 0 - || check_funcs(file, i2cbus, size, daddress, pec) - || set_slave_addr(file, address, force)) - exit(1); - - if (!yes && !confirm(filename, address, size, daddress, pec)) - exit(0); - - if (pec && ioctl(file, I2C_PEC, 1) < 0) { - fprintf(stderr, "Error: Could not set PEC: %s\n", - strerror(errno)); - exit(1); - } - - switch (size) { - case I2C_SMBUS_BYTE: - if (daddress >= 0) { - res = i2c_smbus_write_byte(file, daddress); - if (res < 0) - fprintf(stderr, "Warning - write failed\n"); - } - res = i2c_smbus_read_byte(file); - break; - case I2C_SMBUS_WORD_DATA: - res = i2c_smbus_read_word_data(file, daddress); - break; - default: /* I2C_SMBUS_BYTE_DATA */ - res = i2c_smbus_read_byte_data(file, daddress); - } - close(file); - - if (res < 0) { - fprintf(stderr, "Error: Read failed\n"); - exit(2); - } - - printf("0x%0*x\n", size == I2C_SMBUS_WORD_DATA ? 4 : 2, res); - - exit(0); -} diff --git a/prog/dump/i2cset.8 b/prog/dump/i2cset.8 deleted file mode 100644 index de7971a6..00000000 --- a/prog/dump/i2cset.8 +++ /dev/null @@ -1,77 +0,0 @@ -.TH I2CSET 8 "June 2007" -.SH "NAME" -i2cset \- set I2C registers - -.SH SYNOPSIS -.B i2cset -.RB [ -f ] -.RB [ -y ] -.I i2cbus -.I chip-address -.I data-address -.I value -.RI [ mode ] -.RI [ mask ] -.br -.B i2cset -.B -V - -.SH DESCRIPTION -i2cset is a small helper program to set registers visible through the I2C -bus. - -.SH OPTIONS -.TP -.B -V -Display the version and exit. -.TP -.B -f -Force access to the device even if it is already busy. By default, i2cset -will refuse to access a device which is already under the control of a -kernel driver. Using this flag is dangerous, it can seriously confuse the -kernel driver in question. It can also cause i2cset to silently write to -the wrong register. So use at your own risk and only if you know what -you're doing. -.TP -.B -y -Disable interactive mode. By default, i2cset will wait for a confirmation -from the user before messing with the I2C bus. When this flag is used, it -will perform the operation directly. This is mainly meant to be used in -scripts. -.PP -There are four required options to i2cset. \fIi2cbus\fR indicates the number -of the I2C bus to be scanned. This number should correspond to one of -the busses listed by \fIi2cdetect -l\fR. \fIchip-address\fR specifies the -address of the chip on that bus, and is an integer between 0x00 and 0x7F. -\fIdata-address\fR specifies the address on that chip to write to, and is an -integer between 0x00 and 0xFF. \fIvalue\fR is the value to write to that -location on the chip. -.PP -The \fImode\fR parameter, if specified, is one of the letters \fBb\fP or -\fBw\fP, corresponding to a write size of a single byte or a 16-bit word, -respectively. A \fBp\fP can also be appended to the \fImode\fR parameter to -enable PEC. If the \fImode\fR parameter is omitted, i2cset defaults to byte -mode without PEC. The \fIvalue\fR provided must be within range for the -specified data type (0x00-0xFF for bytes, 0x0000-0xFFFF for words). -.PP -The \fImask\fR parameter, if specified, describes which bits of \fIvalue\fR -will be actually written to \fIdata-address\fR. Bits set to 1 in the mask -are taken from \fIvalue\fR, while bits set to 0 will be read from -\fIdata-address\fR and thus preserved by the operation. - -.SH WARNING -i2cset can be extremely dangerous if used improperly. It can confuse your -I2C bus, cause data loss, or have more serious side effects. Writing to -a serial EEPROM on a memory DIMM (chip addresses between 0x50 and 0x57) may -DESTROY your memory, leaving your system unbootable! Be extremely careful -using this program. - -.SH SEE ALSO -i2cdump(8), isaset(8) - -.SH AUTHOR -Frodo Looijaard, Mark D. Studebaker, and the lm_sensors group -http://www.lm-sensors.org/ -This manual page was originally written by David Z Maze for -the Debian GNU/Linux system. It was then reviewed by the lm_sensors team and -is now part of the lm_sensors source distribution. diff --git a/prog/dump/i2cset.c b/prog/dump/i2cset.c deleted file mode 100644 index a55adccc..00000000 --- a/prog/dump/i2cset.c +++ /dev/null @@ -1,286 +0,0 @@ -/* - i2cset.c - A user-space program to write an I2C register. - Copyright (C) 2001-2003 Frodo Looijaard , and - Mark D. Studebaker - Copyright (C) 2004-2005 Jean Delvare - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#include -#include -#include -#include -#include -#include "i2cbusses.h" -#include "util.h" -#include "i2c-dev.h" -#include "version.h" - -void help(void) __attribute__ ((noreturn)); - -void help(void) -{ - fprintf(stderr, "Syntax: i2cset [-f] [-y] I2CBUS CHIP-ADDRESS DATA-ADDRESS " - "VALUE [MODE] [MASK]\n" - " i2cset -V\n" - " MODE is 'b[yte]' or 'w[ord]' (default b)\n" - " Append 'p' to MODE for PEC checking\n" - " I2CBUS is an integer\n"); - print_i2c_busses(0); - exit(1); -} - -int main(int argc, char *argv[]) -{ - char *end; - int res, i2cbus, address, size, file; - int value, daddress, vmask = 0; - int e1; - char filename[20]; - unsigned long funcs; - int pec = 0; - int flags = 0; - int force = 0, yes = 0, version = 0; - - /* handle (optional) flags first */ - while (1+flags < argc && argv[1+flags][0] == '-') { - switch (argv[1+flags][1]) { - case 'V': version = 1; break; - case 'f': force = 1; break; - case 'y': yes = 1; break; - default: - fprintf(stderr, "Warning: Unsupported flag " - "\"-%c\"!\n", argv[1+flags][1]); - help(); - exit(1); - } - flags++; - } - - if (version) { - fprintf(stderr, "i2cset version %s\n", LM_VERSION); - exit(0); - } - - if (argc < flags + 5) - help(); - - i2cbus = strtol(argv[flags+1], &end, 0); - if (*end || i2cbus < 0 || i2cbus > 0x3f) { - fprintf(stderr, "Error: I2CBUS argument invalid!\n"); - help(); - } - - address = strtol(argv[flags+2], &end, 0); - if (*end || address < 0 || address > 0x7f) { - fprintf(stderr, "Error: Chip address invalid!\n"); - help(); - } - - daddress = strtol(argv[flags+3], &end, 0); - if (*end || daddress < 0 || daddress > 0xff) { - fprintf(stderr, "Error: Data address invalid!\n"); - help(); - } - - value = strtol(argv[flags+4], &end, 0); - if (*end) { - fprintf(stderr, "Error: Data value invalid!\n"); - help(); - } - - if (argc < flags + 6) { - fprintf(stderr, "No size specified (using byte-data access)\n"); - size = I2C_SMBUS_BYTE_DATA; - } else if (argv[flags+5][0] == 'b') { - size = I2C_SMBUS_BYTE_DATA; - pec = argv[flags+5][1] == 'p'; - } else if (argv[flags+5][0] == 'w') { - size = I2C_SMBUS_WORD_DATA; - pec = argv[flags+5][1] == 'p'; - } else { - fprintf(stderr, "Error: Invalid mode!\n"); - help(); - } - - if (argc >= flags + 7) { - vmask = strtol(argv[flags+6], &end, 0); - if (*end || vmask == 0) { - fprintf(stderr, "Error: Data value mask invalid!\n"); - help(); - } - } - - if (value < 0 - || (size == I2C_SMBUS_BYTE_DATA && value > 0xff) - || (size == I2C_SMBUS_WORD_DATA && value > 0xffff)) { - fprintf(stderr, "Error: Data value out of range!\n"); - help(); - } - - file = open_i2c_dev(i2cbus, filename, 0); - if (file < 0) { - exit(1); - } - - /* check adapter functionality */ - if (ioctl(file, I2C_FUNCS, &funcs) < 0) { - fprintf(stderr, "Error: Could not get the adapter " - "functionality matrix: %s\n", strerror(errno)); - exit(1); - } - - switch (size) { - case I2C_SMBUS_BYTE_DATA: - if (!(funcs & I2C_FUNC_SMBUS_WRITE_BYTE_DATA)) { - fprintf(stderr, "Error: Adapter for i2c bus %d does " - "not have byte write capability\n", i2cbus); - exit(1); - } - break; - - case I2C_SMBUS_WORD_DATA: - if (!(funcs & I2C_FUNC_SMBUS_WRITE_WORD_DATA)) { - fprintf(stderr, "Error: Adapter for i2c bus %d does " - "not have word write capability\n", i2cbus); - exit(1); - } - break; - } - - if (set_slave_addr(file, address, force) < 0) - exit(1); - - if (!yes) { - int dont = 0; - - fprintf(stderr, "WARNING! This program can confuse your I2C " - "bus, cause data loss and worse!\n"); - - if (address >= 0x50 && address <= 0x57) { - fprintf(stderr, "DANGEROUS! Writing to a serial " - "EEPROM on a memory DIMM\nmay render your " - "memory USELESS and make your system " - "UNBOOTABLE!\n"); - dont = 1; - } - - fprintf(stderr, "I will write to device file %s, chip address " - "0x%02x, data address\n0x%02x, data 0x%02x%s, mode " - "%s.\n", filename, address, daddress, value, - vmask ? " (masked)" : "", - size == I2C_SMBUS_BYTE_DATA ? "byte" : "word"); - if (pec) - fprintf(stderr, "PEC checking enabled.\n"); - - fprintf(stderr, "Continue? [%s] ", dont ? "y/N" : "Y/n"); - fflush(stderr); - if (!user_ack(!dont)) { - fprintf(stderr, "Aborting on user request.\n"); - exit(0); - } - } - - if (vmask) { - int oldvalue; - - if (size == I2C_SMBUS_WORD_DATA) { - oldvalue = i2c_smbus_read_word_data(file, daddress); - } else { - oldvalue = i2c_smbus_read_byte_data(file, daddress); - } - - if (oldvalue < 0) { - fprintf(stderr, "Error: Failed to read old value\n"); - exit(1); - } - - value = (value & vmask) | (oldvalue & ~vmask); - - if (!yes) { - fprintf(stderr, "Old value 0x%0*x, write mask " - "0x%0*x: Will write 0x%0*x to register " - "0x%02x\n", - size == I2C_SMBUS_WORD_DATA ? 4 : 2, oldvalue, - size == I2C_SMBUS_WORD_DATA ? 4 : 2, vmask, - size == I2C_SMBUS_WORD_DATA ? 4 : 2, value, - daddress); - - fprintf(stderr, "Continue? [Y/n] "); - fflush(stderr); - if (!user_ack(1)) { - fprintf(stderr, "Aborting on user request.\n"); - exit(0); - } - } - } - - if (pec) { - if (ioctl(file, I2C_PEC, 1) < 0) { - fprintf(stderr, "Error: Could not set PEC: %s\n", - strerror(errno)); - exit(1); - } - if (!(funcs & (I2C_FUNC_SMBUS_PEC | I2C_FUNC_I2C))) { - fprintf(stderr, "Warning: Adapter for i2c bus %d does " - "not seem to actually support PEC\n", i2cbus); - } - } - - e1 = 0; - if (size == I2C_SMBUS_WORD_DATA) { - res = i2c_smbus_write_word_data(file, daddress, value); - } else { - res = i2c_smbus_write_byte_data(file, daddress, value); - } - if (res < 0) { - fprintf(stderr, "Warning - write failed\n"); - e1++; - } - - if (pec) { - if (ioctl(file, I2C_PEC, 0) < 0) { - fprintf(stderr, "Error: Could not clear PEC: %s\n", - strerror(errno)); - close(file); - exit(e1); - } - } - - if (size == I2C_SMBUS_WORD_DATA) { - res = i2c_smbus_read_word_data(file, daddress); - } else { - res = i2c_smbus_read_byte_data(file, daddress); - } - close(file); - - if (res < 0) { - fprintf(stderr, "Warning - readback failed\n"); - e1++; - } else - if (res != value) { - e1++; - fprintf(stderr, "Warning - data mismatch - wrote " - "0x%0*x, read back 0x%0*x\n", - size == I2C_SMBUS_WORD_DATA ? 4 : 2, value, - size == I2C_SMBUS_WORD_DATA ? 4 : 2, res); - } else { - fprintf(stderr, "Value 0x%0*x written, readback matched\n", - size == I2C_SMBUS_WORD_DATA ? 4 : 2, value); - } - - exit(e1); -} diff --git a/prog/dump/isadump.c b/prog/dump/isadump.c index 968947a8..420e66d4 100644 --- a/prog/dump/isadump.c +++ b/prog/dump/isadump.c @@ -16,7 +16,8 @@ You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + MA 02110-1301 USA. */ /* diff --git a/prog/dump/isaset.c b/prog/dump/isaset.c index 66066e80..8d91c589 100644 --- a/prog/dump/isaset.c +++ b/prog/dump/isaset.c @@ -16,7 +16,8 @@ You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + MA 02110-1301 USA. */ /* @@ -43,7 +44,7 @@ unsigned long isa_io_base = 0; /* XXX for now */ #endif /* __powerpc__ */ -void help(void) +static void help(void) { fprintf(stderr, "Syntax for I2C-like access:\n" diff --git a/prog/dump/superio.c b/prog/dump/superio.c index ac092635..1af7358b 100644 --- a/prog/dump/superio.c +++ b/prog/dump/superio.c @@ -15,7 +15,8 @@ You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + MA 02110-1301 USA. */ #include diff --git a/prog/dump/superio.h b/prog/dump/superio.h index 44f6d25f..c44f2ac8 100644 --- a/prog/dump/superio.h +++ b/prog/dump/superio.h @@ -15,7 +15,8 @@ You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + MA 02110-1301 USA. */ #ifndef _SUPERIO_H diff --git a/prog/eeprom/Module.mk b/prog/eeprom/Module.mk deleted file mode 100644 index 126a650b..00000000 --- a/prog/eeprom/Module.mk +++ /dev/null @@ -1,35 +0,0 @@ -# Module.mk -# Copyright (c) 1998, 1999 Frodo Looijaard -# -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - -MODULE_DIR := prog/eeprom -PROGEEPROMDIR := $(MODULE_DIR) - -PROGEEPROMTARGETS := $(MODULE_DIR)/ddcmon \ - $(MODULE_DIR)/decode-dimms.pl \ - $(MODULE_DIR)/decode-edid.pl \ - $(MODULE_DIR)/decode-vaio.pl - -REMOVEEEPROMBIN := $(patsubst $(MODULE_DIR)/%,$(DESTDIR)$(BINDIR)/%,$(PROGEEPROMTARGETS)) - -install-prog-eeprom: $(PROGEEPROMTARGETS) - $(MKDIR) $(DESTDIR)$(BINDIR) - $(INSTALL) -m 755 $(PROGEEPROMTARGETS) $(DESTDIR)$(BINDIR) - -user_install :: install-prog-eeprom - -user_uninstall:: - $(RM) $(REMOVEEEPROMBIN) diff --git a/prog/eeprom/ddcmon b/prog/eeprom/ddcmon deleted file mode 100755 index 1adc6f16..00000000 --- a/prog/eeprom/ddcmon +++ /dev/null @@ -1,566 +0,0 @@ -#!/usr/bin/perl -w -# -# Copyright (C) 2004-2005 Jean Delvare -# -# Parts inspired from decode-edid.pl. -# Copyright (C) 2003-2004 Jean Delvare -# -# Parts inspired from the ddcmon driver and sensors' print_ddcmon function. -# Copyright (C) 1998-2004 The LM Sensors Group -# -# Parts inspired from the fbmon driver (Linux 2.6.10). -# Copyright (C) 2002 James Simmons -# -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -# -# Version 1.0 2005-01-04 Jean Delvare -# -# This script is a replacement for the now deprecated ddcmon kernel driver. -# Instead of having a dedicated driver, it is better to reuse the standard -# eeprom driver and implement the EDID-specific code in user-space. -# -# EDID (Extended Display Identification Data) is a VESA standard which -# allows storing (on manufacturer's side) and retrieving (on user's side) -# of configuration information about displays, such as manufacturer, -# serial number, physical dimensions and allowed horizontal and vertical -# refresh rates. -# -# Syntax: ddcmon [bus [address]] -# Address can be given in decimal or hexadecimal (with a 0x prefix). -# If no address is given, default is 0x50. -# Bus number must be given in decimal. If no bus number is given, -# try them all. - -use strict; -use Fcntl qw(:DEFAULT :seek); -use vars qw(@standard_scales); - -@standard_scales = ([1, 1], [3, 4], [4, 5], [16, 9]); - -# Make sure the eeprom module is loaded. -# For non-modular kernels, we can't help. -if (-r '/proc/modules') -{ - my $found = 0; - open(MODULES, '/proc/modules'); - while (!$found && defined ($_ = )) - { - $found++ if m/^eeprom\s+/; - } - close(MODULES); - - unless ($found) - { - print STDERR - "This script requires the eeprom module to be loaded.\n"; - exit 1; - } -} - -# Only used for sysfs -sub rawread -{ - my $filename = shift; - my $length = shift; - my $offset = shift || 0; - my $bytes = ''; - - sysopen(FH, $filename, O_RDONLY) - or die "Can't open $filename"; - if ($offset) - { - sysseek(FH, $offset, SEEK_SET) - or die "Can't seek in $filename"; - } - - $offset = 0; - while ($length) - { - my $r = sysread(FH, $bytes, $length, $offset); - die "Can't read $filename" - unless defined($r); - die "Unexpected EOF in $filename" - unless $r; - $offset += $r; - $length -= $r; - } - close(FH); - - return $bytes; -} - -sub get_edid_sysfs -{ - my ($bus, $addr) = @_; - - my @bytes = unpack("C*", rawread("/sys/bus/i2c/devices/$bus-00$addr/eeprom", 128)); - - return \@bytes; -} - -sub get_edid_procfs -{ - my ($bus, $addr) = @_; - - my @bytes; - - for (my $i = 0 ; $i < 0x80; $i += 0x10) - { - my $filename = sprintf("/proc/sys/dev/sensors/eeprom-i2c-\%s-\%s/\%02x", - $bus, $addr, $i); - open(EEDATA, $filename) - or die "Can't read $filename"; - push @bytes, split(/\s+/, ); - close(EEDATA); - } - - return \@bytes; -} - -sub print_line -{ - my $label = shift; - my $pattern = shift; - - printf("\%-24s$pattern\n", $label.':', @_); -} - -sub extract_byte -{ - my ($bytes, $offset) = @_; - - return $bytes->[$offset]; -} - -sub extract_word -{ - my ($bytes, $offset) = @_; - - return ($bytes->[$offset] - | ($bytes->[$offset+1] << 8)); -} - -sub extract_manufacturer -{ - my ($bytes, $offset) = @_; - my $i = ($bytes->[$offset+1] | ($bytes->[$offset] << 8)); - - return sprintf('%c%c%c', - (($i >> 10) & 0x1f) + ord('A') - 1, - (($i >> 5) & 0x1f) + ord('A') - 1, - ($i & 0x1f) + ord('A') - 1); -} - -sub extract_sesquiword -{ - my ($bytes, $offset) = @_; - - return ($bytes->[$offset] - | ($bytes->[$offset+1] << 8) - | ($bytes->[$offset+2] << 16)); -} - -sub extract_dword -{ - my ($bytes, $offset) = @_; - - return ($bytes->[$offset] - | ($bytes->[$offset+1] << 8) - | ($bytes->[$offset+2] << 16) - | ($bytes->[$offset+3] << 24)); -} - -sub extract_display_input -{ - my ($bytes, $offset) = @_; - - my @voltage = ('0.700V/0.300V', '0.714V/0.286V', - '1.000V/0.400V', '0.700V/0.000V'); - - return 'Digital' - if ($bytes->[$offset] & 0x80); - - return 'Analog ('.$voltage[($bytes->[$offset] & 0x60) >> 5].')'; -} - -sub extract_dpms -{ - my ($bytes, $offset) = @_; - - my @supported; - - push @supported, 'Active Off' if ($bytes->[$offset] & 0x20); - push @supported, 'Suspend' if ($bytes->[$offset] & 0x40); - push @supported, 'Standby' if ($bytes->[$offset] & 0x80); - - return join(', ', @supported) - if (@supported); - - return 'None supported'; -} - -sub extract_color_mode -{ - my ($bytes, $offset) = @_; - - my @mode = ('Monochrome', 'RGB Multicolor', 'Non-RGB Multicolor'); - - return $mode[($bytes->[$offset] >> 3) & 0x03]; -} - -sub good_signature -{ - my $bytes = shift; - - return $bytes->[0] == 0x00 - && $bytes->[1] == 0xff - && $bytes->[2] == 0xff - && $bytes->[3] == 0xff - && $bytes->[4] == 0xff - && $bytes->[5] == 0xff - && $bytes->[6] == 0xff - && $bytes->[7] == 0x00; -} - -sub verify_checksum -{ - my $bytes = shift; - my $cs; - - for (my $i = 0, $cs = 0; $i < 0x80; $i++) - { - $cs += $bytes->[$i]; - } - - return (($cs & 0xff) == 0 ? 'OK' : 'Not OK'); -} - -sub add_timing -{ - my ($timings, $new) = @_; - - my $mode = sprintf('%ux%u@%u%s', $new->[0], $new->[1], - $new->[2], defined ($new->[3]) && - $new->[3] eq 'interlaced' ? 'i' : ''); - - $timings->{$mode} = $new; -} - -sub add_standard_timing -{ - my ($timings, $byte0, $byte1) = @_; - - # Unused slot - return if ($byte0 == $byte1) - && ($byte0 == 0x01 || $byte0 == 0x00 || $byte0 == 0x20); - - my $width = ($byte0 + 31) * 8; - my $height = $width * $standard_scales[$byte1 >> 6]->[0] - / $standard_scales[$byte1 >> 6]->[1]; - my $refresh = 60 + ($byte1 & 0x3f); - - add_timing($timings, [$width, $height, $refresh]); -} - -sub sort_timings -{ - # First order by width - return -1 if $a->[0] < $b->[0]; - return 1 if $a->[0] > $b->[0]; - - # Second by height - return -1 if $a->[1] < $b->[1]; - return 1 if $a->[1] > $b->[1]; - - # Third by frequency - # Interlaced modes count for half their frequency - my $freq_a = $a->[2]; - my $freq_b = $b->[2]; - $freq_a /= 2 if defined $a->[3] && $a->[3] eq 'interlaced'; - $freq_b /= 2 if defined $b->[3] && $b->[3] eq 'interlaced'; - return -1 if $freq_a < $freq_b; - return 1 if $freq_a > $freq_b; - - return 0; -} - -sub print_timings -{ - my ($bytes, $timings) = @_; - - # Established Timings - my @established = - ( - [720, 400, 70], - [720, 400, 88], - [640, 480, 60], - [640, 480, 67], - [640, 480, 72], - [640, 480, 75], - [800, 600, 56], - [800, 600, 60], - [800, 600, 72], - [800, 600, 75], - [832, 624, 75], - [1024, 768, 87, 'interlaced'], - [1024, 768, 60], - [1024, 768, 70], - [1024, 768, 75], - [1280, 1024, 75], - undef, undef, undef, - [1152, 870, 75], - ); - my $temp = extract_sesquiword($bytes, 0x23); - for (my $i = 0; $i < 24; $i++) - { - next unless defined($established[$i]); - add_timing($timings, $established[$i]) - if ($temp & (1 << $i)); - } - - # Standard Timings - for (my $i = 0x26; $i < 0x36; $i += 2) - { - add_standard_timing($timings, $bytes->[$i], $bytes->[$i+1]); - } - - foreach my $v (sort sort_timings values(%{$timings})) - { - print_line("Timing", '%ux%u @ %u Hz%s', - $v->[0], $v->[1], $v->[2], - defined($v->[3]) ? ' ('.$v->[3].')' : ''); - } -} - -sub extract_string -{ - my ($bytes, $offset) = @_; - my $string = ''; - - for (my $i = 5; $i < 18; $i++) - { - last if $bytes->[$offset+$i] == 0x0a - || $bytes->[$offset+$i] == 0x00; - $string .= chr($bytes->[$offset+$i]) - if ($bytes->[$offset+$i] >= 32 - && $bytes->[$offset+$i] < 127); - } - $string =~ s/\s+$//; - - return $string; -} - -# Some blocks contain different information: -# 0x00, 0x00, 0x00, 0xfa: Additional standard timings block -# 0x00, 0x00, 0x00, 0xfc: Monitor block -# 0x00, 0x00, 0x00, 0xfd: Limits block -# 0x00, 0x00, 0x00, 0xfe: Ascii block -# 0x00, 0x00, 0x00, 0xff: Serial block -# Return a reference to a hash containing all information. -sub extract_detailed_timings -{ - my ($bytes) = @_; - - my %info = ('timings' => {}); - - for (my $offset = 0x36; $offset < 0x7e; $offset += 18) - { - if ($bytes->[$offset] == 0x00 - && $bytes->[$offset+1] == 0x00 - && $bytes->[$offset+2] == 0x00 - && $bytes->[$offset+4] == 0x00) - { - if ($bytes->[$offset+3] == 0xfa) - { - for (my $i = $offset + 5; $i < $offset + 17; $i += 2) - { - add_standard_timing($info{'timings'}, - $bytes->[$i], - $bytes->[$i+1]); - } - } - - elsif ($bytes->[$offset+3] == 0xfc) - { - $info{'monitor'} .= extract_string($bytes, $offset); - } - - elsif ($bytes->[$offset+3] == 0xfd) - { - $info{'limits'}{'vsync_min'} = $bytes->[$offset+5]; - $info{'limits'}{'vsync_max'} = $bytes->[$offset+6]; - $info{'limits'}{'hsync_min'} = $bytes->[$offset+7]; - $info{'limits'}{'hsync_max'} = $bytes->[$offset+8]; - $info{'limits'}{'clock_max'} = $bytes->[$offset+9]; - } - - elsif ($bytes->[$offset+3] == 0xfe) - { - $info{'ascii'} .= extract_string($bytes, $offset); - } - - elsif ($bytes->[$offset+3] == 0xff) - { - $info{'serial'} .= extract_string($bytes, $offset); - } - - next; - } - - # Detailed Timing - my $width = $bytes->[$offset+2] + (($bytes->[$offset+4] & 0xf0) << 4); - my $height = $bytes->[$offset+5] + (($bytes->[$offset+7] & 0xf0) << 4); - my $clock = extract_word($bytes, $offset) * 10000; - my $hblank = $bytes->[$offset+3] + (($bytes->[$offset+4] & 0x0f) << 8); - my $vblank = $bytes->[$offset+6] + (($bytes->[$offset+7] & 0x0f) << 8); - my $area = ($width + $hblank) * ($height + $vblank); - next unless $area; # Should not happen, but... - my $refresh = ($clock + $area / 2) / $area; # Proper rounding - add_timing($info{'timings'}, [$width, $height, $refresh]); - } - - return \%info; -} - -sub print_edid -{ - my ($bus, $address) = @_; - my $bytes; - - if (-r "/sys/bus/i2c/devices/$bus-00$address/eeprom") - { - $bytes = get_edid_sysfs($bus, $address); - } - elsif (-r "/proc/sys/dev/sensors/eeprom-i2c-$bus-$address/00") - { - $bytes = get_edid_procfs($bus, $address); - } - - return 1 unless defined $bytes; - return 2 unless good_signature($bytes); - - print_line('Checksum', '%s', verify_checksum($bytes)); - my $edid_version = extract_byte($bytes, 0x12); - my $edid_revision = extract_byte($bytes, 0x13); - print_line('EDID Version', '%u.%u', $edid_version, - $edid_revision); - if ($edid_version > 1 || $edid_revision > 2) - { - $standard_scales[0][0] = 16; - $standard_scales[0][1] = 10; - } - else - { - $standard_scales[0][0] = 1; - $standard_scales[0][1] = 1; - } - - my $info = extract_detailed_timings($bytes); - - print_line('Manufacturer ID', '%s', extract_manufacturer($bytes, 0x08)); - print_line('Model Number', '0x%04X', extract_word($bytes, 0x0A)); - print_line('Model Name', '%s', $info->{'monitor'}) - if defined $info->{'monitor'}; - - if ($info->{'serial'}) - { - print_line('Serial Number', '%s', $info->{'serial'}) - } - elsif ((my $temp = extract_dword($bytes, 0x0C))) - { - print_line('Serial Number', '%u', $temp) - } - - print_line('Manufacture Time', '%u-W%02u', - 1990 + extract_byte($bytes, 0x11), - extract_byte($bytes, 0x10)); - print_line('Display Input', '%s', extract_display_input($bytes, 0x14)); - print_line('Monitor Size (cm)', '%ux%u', extract_byte($bytes, 0x15), - extract_byte($bytes, 0x16)); - print_line('Gamma Factor', '%.2f', - 1 + extract_byte($bytes, 0x17) / 100.0); - print_line('DPMS Modes', '%s', extract_dpms($bytes, 0x18)); - print_line('Color Mode', '%s', extract_color_mode($bytes, 0x18)) - if (($bytes->[0x18] & 0x18) != 0x18); - print_line('Additional Info', '%s', $info->{'ascii'}) - if $info->{'ascii'}; - - if (defined($info->{'limits'})) - { - print_line('Vertical Sync (Hz)', '%u-%u', - $info->{'limits'}{'vsync_min'}, - $info->{'limits'}{'vsync_max'}); - print_line('Horizontal Sync (kHz)', '%u-%u', - $info->{'limits'}{'hsync_min'}, - $info->{'limits'}{'hsync_max'}); - print_line('Max Pixel Clock (MHz)', '%u', - $info->{'limits'}{'clock_max'} * 10) - unless $info->{'limits'}{'clock_max'} == 0xff; - } - - print_timings($bytes, $info->{'timings'}); - print("\n"); - return 0; -} - -# Get the address. Default to 0x50 if not given. -my $address; -if (defined($ARGV[1])) -{ - $address = $ARGV[1]; - # Convert to decimal, whatever the value. - $address = oct $address if $address =~ m/^0/; - # Convert to an hexadecimal string. - $address = sprintf '%02x', $address; -} -else -{ - $address = '50'; -} - -if (defined($ARGV[0])) -{ - my $error = print_edid($ARGV[0], $address); - - if ($error == 1) - { - print STDERR - "No EEPROM found at 0x$address on bus $ARGV[0].\n"; - exit 1; - } - elsif ($error == 2) - { - print STDERR - "EEPROM found at 0x$address on bus $ARGV[0], but is not an EDID EEPROM.\n"; - exit 1; - } -} -# If no bus is given, try them all. -else -{ - my $total = 0; - - for (my $i = 0; $i < 16; $i++) - { - $total++ unless print_edid($i, $address); - } - - unless ($total) - { - print STDERR - "No EDID EEPROM found.\n"; - exit 1; - } -} diff --git a/prog/eeprom/decode-dimms.pl b/prog/eeprom/decode-dimms.pl deleted file mode 100755 index fecc06f6..00000000 --- a/prog/eeprom/decode-dimms.pl +++ /dev/null @@ -1,1261 +0,0 @@ -#!/usr/bin/perl -w -# -# Copyright 1998, 1999 Philip Edelbrock -# modified by Christian Zuckschwerdt -# modified by Burkart Lingner -# -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -# -# Version 0.4 1999 Philip Edelbrock -# Version 0.5 2000-03-30 Christian Zuckschwerdt -# html output (selectable by commandline switches) -# Version 0.6 2000-09-16 Christian Zuckschwerdt -# updated according to SPD Spec Rev 1.2B -# see http://developer.intel.com/technology/memory/pc133sdram/spec/Spdsd12b.htm -# Version 0.7 2002-11-08 Jean Delvare -# pass -w and use strict -# valid HTML 3.2 output (--format mode) -# miscellaneous formatting enhancements and bug fixes -# clearer HTML output (original patch by Nick Kurshev ) -# stop decoding on checksum error by default (--checksum option forces) -# Version 0.8 2005-06-20 Burkart Lingner -# adapted to Kernel 2.6's /sys filesystem -# Version 0.9 2005-07-15 Jean Delvare -# fix perl warning -# fix typo -# refactor some code -# Version 1.0 2005-09-18 Jean Delvare -# add large lookup tables for manufacturer names, based on data -# provided by Rudolf Marek, taken from: -# http://www.jedec.org/download/search/JEP106r.pdf -# Version 1.1 2006-01-22 Jean Delvare -# improve the text output, making it hopefully clearer -# read eeprom by 64-byte blocks, this allows some code cleanups -# use sysopen/sysread instead of open/read for better performance -# verify checksum before decoding anything -# Version 1.2 2006-05-15 Jean Delvare -# implement per-memory-type decoding -# don't decode revision code, manufacturing date and assembly serial -# number where not set -# decode the manufacturing date to an ISO8601 date -# Version 1.3 2006-05-21 Jean Delvare -# detect undefined manufacturer code and handle it properly -# round up timing data -# minor display adjustments -# group cycle and access times, display the CAS value for each (SDRAM) -# refactor some bitfield tests into loops (SDRAM) -# display latencies and burst length on a single line (SDRAM) -# don't display manufacturing location when undefined -# check that the manufacturing date is proper BCD, else fall back to -# hexadecimal display -# Version 1.4 2006-05-26 Jean Delvare -# fix latencies decoding (SDRAM) -# fix CAS latency decoding (DDR SDRAM) -# decode latencies, timings and module height (DDR SDRAM) -# decode size (Direct Rambus, Rambus) -# decode latencies and timings (DDR2 SDRAM) -# SPD revision decoding depends on memory type -# use more user-friendly labels -# fix HTML formatted output on checksum error -# Version 1.5 2007-11-08 Jean Delvare -# fix module speed (DDR2 SDRAM) -# -# -# EEPROM data decoding for SDRAM DIMM modules. -# -# The eeprom driver must be loaded. For kernels older than 2.6.0, the -# eeprom driver can be found in the lm-sensors package. -# -# use the following command line switches -# -f, --format print nice html output -# -b, --bodyonly don't print html header -# (useful for postprocessing the output) -# -c, --checksum decode completely even if checksum fails -# -h, --help display this usage summary -# -# References: -# PC SDRAM Serial Presence -# Detect (SPD) Specification, Intel, -# 1997,1999, Rev 1.2B -# -# Jedec Standards 4.1.x & 4.5.x -# http://www.jedec.org -# - -require 5.004; - -use strict; -use POSIX qw(ceil); -use Fcntl qw(:DEFAULT :seek); -use vars qw($opt_html $opt_body $opt_bodyonly $opt_igncheck $use_sysfs - @vendors %decode_callback); - -@vendors = ( -["AMD", "AMI", "Fairchild", "Fujitsu", - "GTE", "Harris", "Hitachi", "Inmos", - "Intel", "I.T.T.", "Intersil", "Monolithic Memories", - "Mostek", "Freescale (former Motorola)", "National", "NEC", - "RCA", "Raytheon", "Conexant (Rockwell)", "Seeq", - "NXP (former Signetics, Philips Semi.)", "Synertek", "Texas Instruments", "Toshiba", - "Xicor", "Zilog", "Eurotechnique", "Mitsubishi", - "Lucent (AT&T)", "Exel", "Atmel", "SGS/Thomson", - "Lattice Semi.", "NCR", "Wafer Scale Integration", "IBM", - "Tristar", "Visic", "Intl. CMOS Technology", "SSSI", - "MicrochipTechnology", "Ricoh Ltd.", "VLSI", "Micron Technology", - "Hyundai Electronics", "OKI Semiconductor", "ACTEL", "Sharp", - "Catalyst", "Panasonic", "IDT", "Cypress", - "DEC", "LSI Logic", "Zarlink (former Plessey)", "UTMC", - "Thinking Machine", "Thomson CSF", "Integrated CMOS (Vertex)", "Honeywell", - "Tektronix", "Sun Microsystems", "SST", "ProMos/Mosel Vitelic", - "Infineon (former Siemens)", "Macronix", "Xerox", "Plus Logic", - "SunDisk", "Elan Circuit Tech.", "European Silicon Str.", "Apple Computer", - "Xilinx", "Compaq", "Protocol Engines", "SCI", - "Seiko Instruments", "Samsung", "I3 Design System", "Klic", - "Crosspoint Solutions", "Alliance Semiconductor", "Tandem", "Hewlett-Packard", - "Intg. Silicon Solutions", "Brooktree", "New Media", "MHS Electronic", - "Performance Semi.", "Winbond Electronic", "Kawasaki Steel", "Bright Micro", - "TECMAR", "Exar", "PCMCIA", "LG Semi (former Goldstar)", - "Northern Telecom", "Sanyo", "Array Microsystems", "Crystal Semiconductor", - "Analog Devices", "PMC-Sierra", "Asparix", "Convex Computer", - "Quality Semiconductor", "Nimbus Technology", "Transwitch", "Micronas (ITT Intermetall)", - "Cannon", "Altera", "NEXCOM", "QUALCOMM", - "Sony", "Cray Research", "AMS(Austria Micro)", "Vitesse", - "Aster Electronics", "Bay Networks (Synoptic)", "Zentrum or ZMD", "TRW", - "Thesys", "Solbourne Computer", "Allied-Signal", "Dialog", - "Media Vision", "Level One Communication"], -["Cirrus Logic", "National Instruments", "ILC Data Device", "Alcatel Mietec", - "Micro Linear", "Univ. of NC", "JTAG Technologies", "BAE Systems", - "Nchip", "Galileo Tech", "Bestlink Systems", "Graychip", - "GENNUM", "VideoLogic", "Robert Bosch", "Chip Express", - "DATARAM", "United Microelec Corp.", "TCSI", "Smart Modular", - "Hughes Aircraft", "Lanstar Semiconductor", "Qlogic", "Kingston", - "Music Semi", "Ericsson Components", "SpaSE", "Eon Silicon Devices", - "Programmable Micro Corp", "DoD", "Integ. Memories Tech.", "Corollary Inc.", - "Dallas Semiconductor", "Omnivision", "EIV(Switzerland)", "Novatel Wireless", - "Zarlink (former Mitel)", "Clearpoint", "Cabletron", "STEC (former Silicon Technology)", - "Vanguard", "Hagiwara Sys-Com", "Vantis", "Celestica", - "Century", "Hal Computers", "Rohm Company Ltd.", "Juniper Networks", - "Libit Signal Processing", "Mushkin Enhanced Memory", "Tundra Semiconductor", "Adaptec Inc.", - "LightSpeed Semi.", "ZSP Corp.", "AMIC Technology", "Adobe Systems", - "Dynachip", "PNY Electronics", "Newport Digital", "MMC Networks", - "T Square", "Seiko Epson", "Broadcom", "Viking Components", - "V3 Semiconductor", "Flextronics (former Orbit)", "Suwa Electronics", "Transmeta", - "Micron CMS", "American Computer & Digital Components Inc", "Enhance 3000 Inc", "Tower Semiconductor", - "CPU Design", "Price Point", "Maxim Integrated Product", "Tellabs", - "Centaur Technology", "Unigen Corporation", "Transcend Information", "Memory Card Technology", - "CKD Corporation Ltd.", "Capital Instruments, Inc.", "Aica Kogyo, Ltd.", "Linvex Technology", - "MSC Vertriebs GmbH", "AKM Company, Ltd.", "Dynamem, Inc.", "NERA ASA", - "GSI Technology", "Dane-Elec (C Memory)", "Acorn Computers", "Lara Technology", - "Oak Technology, Inc.", "Itec Memory", "Tanisys Technology", "Truevision", - "Wintec Industries", "Super PC Memory", "MGV Memory", "Galvantech", - "Gadzoox Nteworks", "Multi Dimensional Cons.", "GateField", "Integrated Memory System", - "Triscend", "XaQti", "Goldenram", "Clear Logic", - "Cimaron Communications", "Nippon Steel Semi. Corp.", "Advantage Memory", "AMCC", - "LeCroy", "Yamaha Corporation", "Digital Microwave", "NetLogic Microsystems", - "MIMOS Semiconductor", "Advanced Fibre", "BF Goodrich Data.", "Epigram", - "Acbel Polytech Inc.", "Apacer Technology", "Admor Memory", "FOXCONN", - "Quadratics Superconductor", "3COM"], -["Camintonn Corporation", "ISOA Incorporated", "Agate Semiconductor", "ADMtek Incorporated", - "HYPERTEC", "Adhoc Technologies", "MOSAID Technologies", "Ardent Technologies", - "Switchcore", "Cisco Systems, Inc.", "Allayer Technologies", "WorkX AG", - "Oasis Semiconductor", "Novanet Semiconductor", "E-M Solutions", "Power General", - "Advanced Hardware Arch.", "Inova Semiconductors GmbH", "Telocity", "Delkin Devices", - "Symagery Microsystems", "C-Port Corporation", "SiberCore Technologies", "Southland Microsystems", - "Malleable Technologies", "Kendin Communications", "Great Technology Microcomputer", "Sanmina Corporation", - "HADCO Corporation", "Corsair", "Actrans System Inc.", "ALPHA Technologies", - "Silicon Laboratories, Inc. (Cygnal)", "Artesyn Technologies", "Align Manufacturing", "Peregrine Semiconductor", - "Chameleon Systems", "Aplus Flash Technology", "MIPS Technologies", "Chrysalis ITS", - "ADTEC Corporation", "Kentron Technologies", "Win Technologies", "Tachyon Semiconductor (former ASIC Designs Inc.)", - "Extreme Packet Devices", "RF Micro Devices", "Siemens AG", "Sarnoff Corporation", - "Itautec Philco SA", "Radiata Inc.", "Benchmark Elect. (AVEX)", "Legend", - "SpecTek Incorporated", "Hi/fn", "Enikia Incorporated", "SwitchOn Networks", - "AANetcom Incorporated", "Micro Memory Bank", "ESS Technology", "Virata Corporation", - "Excess Bandwidth", "West Bay Semiconductor", "DSP Group", "Newport Communications", - "Chip2Chip Incorporated", "Phobos Corporation", "Intellitech Corporation", "Nordic VLSI ASA", - "Ishoni Networks", "Silicon Spice", "Alchemy Semiconductor", "Agilent Technologies", - "Centillium Communications", "W.L. Gore", "HanBit Electronics", "GlobeSpan", - "Element 14", "Pycon", "Saifun Semiconductors", "Sibyte, Incorporated", - "MetaLink Technologies", "Feiya Technology", "I & C Technology", "Shikatronics", - "Elektrobit", "Megic", "Com-Tier", "Malaysia Micro Solutions", - "Hyperchip", "Gemstone Communications", "Anadigm (former Anadyne)", "3ParData", - "Mellanox Technologies", "Tenx Technologies", "Helix AG", "Domosys", - "Skyup Technology", "HiNT Corporation", "Chiaro", "MDT Technologies GmbH (former MCI Computer GMBH)", - "Exbit Technology A/S", "Integrated Technology Express", "AVED Memory", "Legerity", - "Jasmine Networks", "Caspian Networks", "nCUBE", "Silicon Access Networks", - "FDK Corporation", "High Bandwidth Access", "MultiLink Technology", "BRECIS", - "World Wide Packets", "APW", "Chicory Systems", "Xstream Logic", - "Fast-Chip", "Zucotto Wireless", "Realchip", "Galaxy Power", - "eSilicon", "Morphics Technology", "Accelerant Networks", "Silicon Wave", - "SandCraft", "Elpida"], -["Solectron", "Optosys Technologies", "Buffalo (former Melco)", "TriMedia Technologies", - "Cyan Technologies", "Global Locate", "Optillion", "Terago Communications", - "Ikanos Communications", "Princeton Technology", "Nanya Technology", "Elite Flash Storage", - "Mysticom", "LightSand Communications", "ATI Technologies", "Agere Systems", - "NeoMagic", "AuroraNetics", "Golden Empire", "Mushkin", - "Tioga Technologies", "Netlist", "TeraLogic", "Cicada Semiconductor", - "Centon Electronics", "Tyco Electronics", "Magis Works", "Zettacom", - "Cogency Semiconductor", "Chipcon AS", "Aspex Technology", "F5 Networks", - "Programmable Silicon Solutions", "ChipWrights", "Acorn Networks", "Quicklogic", - "Kingmax Semiconductor", "BOPS", "Flasys", "BitBlitz Communications", - "eMemory Technology", "Procket Networks", "Purple Ray", "Trebia Networks", - "Delta Electronics", "Onex Communications", "Ample Communications", "Memory Experts Intl", - "Astute Networks", "Azanda Network Devices", "Dibcom", "Tekmos", - "API NetWorks", "Bay Microsystems", "Firecron Ltd", "Resonext Communications", - "Tachys Technologies", "Equator Technology", "Concept Computer", "SILCOM", - "3Dlabs", "c't Magazine", "Sanera Systems", "Silicon Packets", - "Viasystems Group", "Simtek", "Semicon Devices Singapore", "Satron Handelsges", - "Improv Systems", "INDUSYS GmbH", "Corrent", "Infrant Technologies", - "Ritek Corp", "empowerTel Networks", "Hypertec", "Cavium Networks", - "PLX Technology", "Massana Design", "Intrinsity", "Valence Semiconductor", - "Terawave Communications", "IceFyre Semiconductor", "Primarion", "Picochip Designs Ltd", - "Silverback Systems", "Jade Star Technologies", "Pijnenburg Securealink", - "TakeMS International AG", "Cambridge Silicon Radio", - "Swissbit", "Nazomi Communications", "eWave System", - "Rockwell Collins", "Picocel Co., Ltd.", "Alphamosaic Ltd", "Sandburst", - "SiCon Video", "NanoAmp Solutions", "Ericsson Technology", "PrairieComm", - "Mitac International", "Layer N Networks", "MtekVision", "Allegro Networks", - "Marvell Semiconductors", "Netergy Microelectronic", "NVIDIA", "Internet Machines", - "Peak Electronics", "Litchfield Communication", "Accton Technology", "Teradiant Networks", - "Europe Technologies", "Cortina Systems", "RAM Components", "Raqia Networks", - "ClearSpeed", "Matsushita Battery", "Xelerated", "SimpleTech", - "Utron Technology", "Astec International", "AVM gmbH", "Redux Communications", - "Dot Hill Systems", "TeraChip"], -["T-RAM Incorporated", "Innovics Wireless", "Teknovus", "KeyEye Communications", - "Runcom Technologies", "RedSwitch", "Dotcast", "Silicon Mountain Memory", - "Signia Technologies", "Pixim", "Galazar Networks", "White Electronic Designs", - "Patriot Scientific", "Neoaxiom Corporation", "3Y Power Technology", "Europe Technologies", - "Potentia Power Systems", "C-guys Incorporated", "Digital Communications Technology Incorporated", "Silicon-Based Technology", - "Fulcrum Microsystems", "Positivo Informatica Ltd", "XIOtech Corporation", "PortalPlayer", - "Zhiying Software", "Direct2Data", "Phonex Broadband", "Skyworks Solutions", - "Entropic Communications", "Pacific Force Technology", "Zensys A/S", "Legend Silicon Corp.", - "sci-worx GmbH", "SMSC (former Oasis Silicon Systems)", "Renesas Technology", "Raza Microelectronics", - "Phyworks", "MediaTek", "Non-cents Productions", "US Modular", - "Wintegra Ltd", "Mathstar", "StarCore", "Oplus Technologies", - "Mindspeed", "Just Young Computer", "Radia Communications", "OCZ", - "Emuzed", "LOGIC Devices", "Inphi Corporation", "Quake Technologies", - "Vixel", "SolusTek", "Kongsberg Maritime", "Faraday Technology", - "Altium Ltd.", "Insyte", "ARM Ltd.", "DigiVision", - "Vativ Technologies", "Endicott Interconnect Technologies", "Pericom", "Bandspeed", - "LeWiz Communications", "CPU Technology", "Ramaxel Technology", "DSP Group", - "Axis Communications", "Legacy Electronics", "Chrontel", "Powerchip Semiconductor", - "MobilEye Technologies", "Excel Semiconductor", "A-DATA Technology", "VirtualDigm", - "G Skill Intl", "Quanta Computer", "Yield Microelectronics", "Afa Technologies", - "KINGBOX Technology Co. Ltd.", "Ceva", "iStor Networks", "Advance Modules", - "Microsoft", "Open-Silicon", "Goal Semiconductor", "ARC International", - "Simmtec", "Metanoia", "Key Stream", "Lowrance Electronics", - "Adimos", "SiGe Semiconductor", "Fodus Communications", "Credence Systems Corp.", - "Genesis Microchip Inc.", "Vihana, Inc.", "WIS Technologies", "GateChange Technologies", - "High Density Devices AS", "Synopsys", "Gigaram", "Enigma Semiconductor Inc.", - "Century Micro Inc.", "Icera Semiconductor", "Mediaworks Integrated Systems", "O'Neil Product Development", - "Supreme Top Technology Ltd.", "MicroDisplay Corporation", "Team Group Inc.", "Sinett Corporation", - "Toshiba Corporation", "Tensilica", "SiRF Technology", "Bacoc Inc.", - "SMaL Camera Technologies", "Thomson SC", "Airgo Networks", "Wisair Ltd.", - "SigmaTel", "Arkados", "Compete IT gmbH Co. KG", "Eudar Technology Inc.", - "Focus Enhancements", "Xyratex"], -["Specular Networks", "Patriot Memory", "U-Chip Technology Corp.", "Silicon Optix", - "Greenfield Networks", "CompuRAM GmbH", "Stargen, Inc.", "NetCell Corporation", - "Excalibrus Technologies Ltd", "SCM Microsystems", "Xsigo Systems, Inc.", "CHIPS & Systems Inc", - "Tier 1 Multichip Solutions", "CWRL Labs", "Teradici", "Gigaram, Inc.", - "g2 Microsystems", "PowerFlash Semiconductor", "P.A. Semi, Inc.", "NovaTech Solutions, S.A.", - "c2 Microsystems, Inc.", "Level5 Networks", "COS Memory AG", "Innovasic Semiconductor", - "02IC Co. Ltd", "Tabula, Inc.", "Crucial Technology", "Chelsio Communications", - "Solarflare Communications", "Xambala Inc.", "EADS Astrium", "ATO Semicon Co. Ltd.", - "Imaging Works, Inc.", "Astute Networks, Inc.", "Tzero", "Emulex", - "Power-One", "Pulse~LINK Inc.", "Hon Hai Precision Industry", "White Rock Networks Inc.", - "Telegent Systems USA, Inc.", "Atrua Technologies, Inc.", "Acbel Polytech Inc.", - "eRide Inc.","ULi Electronics Inc.", "Magnum Semiconductor Inc.", "neoOne Technology, Inc.", - "Connex Technology, Inc.", "Stream Processors, Inc.", "Focus Enhancements", "Telecis Wireless, Inc.", - "uNav Microelectronics", "Tarari, Inc.", "Ambric, Inc.", "Newport Media, Inc.", "VMTS", - "Enuclia Semiconductor, Inc.", "Virtium Technology Inc.", "Solid State System Co., Ltd.", "Kian Tech LLC", - "Artimi", "Power Quotient International", "Avago Technologies", "ADTechnology", "Sigma Designs", - "SiCortex, Inc.", "Ventura Technology Group", "eASIC", "M.H.S. SAS", "Micro Star International", - "Rapport Inc.", "Makway International", "Broad Reach Engineering Co.", - "Semiconductor Mfg Intl Corp", "SiConnect", "FCI USA Inc.", "Validity Sensors", - "Coney Technology Co. Ltd.", "Spans Logic", "Neterion Inc.", "Qimonda", - "New Japan Radio Co. Ltd.", "Velogix", "Montalvo Systems", "iVivity Inc.", "Walton Chaintech", - "AENEON", "Lorom Industrial Co. Ltd.", "Radiospire Networks", "Sensio Technologies, Inc.", - "Nethra Imaging", "Hexon Technology Pte Ltd", "CompuStocx (CSX)", "Methode Electronics, Inc.", - "Connect One Ltd.", "Opulan Technologies", "Septentrio NV", "Goldenmars Technology Inc.", - "Kreton Corporation", "Cochlear Ltd.", "Altair Semiconductor", "NetEffect, Inc.", - "Spansion, Inc.", "Taiwan Semiconductor Mfg", "Emphany Systems Inc.", - "ApaceWave Technologies", "Mobilygen Corporation", "Tego", "Cswitch Corporation", - "Haier (Beijing) IC Design Co.", "MetaRAM", "Axel Electronics Co. Ltd.", "Tilera Corporation", - "Aquantia", "Vivace Semiconductor", "Redpine Signals", "Octalica", "InterDigital Communications", - "Avant Technology", "Asrock, Inc.", "Availink", "Quartics, Inc.", "Element CXI", - "Innovaciones Microelectronicas", "VeriSilicon Microelectronics", "W5 Networks"], -["MOVEKING", "Mavrix Technology, Inc.", "CellGuide Ltd.", "Faraday Technology", - "Diablo Technologies, Inc.", "Jennic", "Octasic", "Molex Incorporated", "3Leaf Networks", - "Bright Micron Technology", "Netxen", "NextWave Broadband Inc.", "DisplayLink", "ZMOS Technology", - "Tec-Hill", "Multigig, Inc.", "Amimon", "Euphonic Technologies, Inc.", "BRN Phoenix", - "InSilica", "Ember Corporation", "Avexir Technologies Corporation", "Echelon Corporation", - "Edgewater Computer Systems", "XMOS Semiconductor Ltd.", "GENUSION, Inc.", "Memory Corp NV", - "SiliconBlue Technologies", "Rambus Inc."]); - -$use_sysfs = -d '/sys/bus'; - -# We consider that no data was written to this area of the SPD EEPROM if -# all bytes read 0x00 or all bytes read 0xff -sub spd_written(@) -{ - my $all_00 = 1; - my $all_ff = 1; - - foreach my $b (@_) { - $all_00 = 0 unless $b == 0x00; - $all_ff = 0 unless $b == 0xff; - return 1 unless $all_00 or $all_ff; - } - - return 0; -} - -sub parity($) -{ - my $n = shift; - my $parity = 0; - - while ($n) { - $parity++ if ($n & 1); - $n >>= 1; - } - - return ($parity & 1); -} - -sub manufacturer(@) -{ - my @bytes = @_; - my $ai = 0; - my $first; - - return ("Undefined", []) unless spd_written(@bytes); - - while (defined($first = shift(@bytes)) && $first == 0x7F) { - $ai++; - } - - return ("Invalid", []) unless defined $first; - return ("Invalid", [$first, @bytes]) if parity($first) != 1; - return ("Unknown", \@bytes) unless (($first & 0x7F) - 1 <= $vendors[$ai]); - - return ($vendors[$ai][($first & 0x7F) - 1], \@bytes); -} - -sub manufacturer_data(@) -{ - my $hex = ""; - my $asc = ""; - - return unless spd_written(@_); - - foreach my $byte (@_) { - $hex .= sprintf("\%02X ", $byte); - $asc .= ($byte >= 32 && $byte < 127) ? chr($byte) : '?'; - } - - return "$hex(\"$asc\")"; -} - -sub part_number(@) -{ - my $asc = ""; - my $byte; - - while (defined ($byte = shift) && $byte >= 32 && $byte < 127) { - $asc .= chr($byte); - } - - return ($asc eq "") ? "Undefined" : $asc; -} - -sub printl ($$) # print a line w/ label and value -{ - my ($label, $value) = @_; - if ($opt_html) { - $label =~ s//\>/sg; - $label =~ s/\n/
\n/sg; - $value =~ s//\>/sg; - $value =~ s/\n/
\n/sg; - print "$label$value\n"; - } else { - my @values = split /\n/, $value; - printf "%-47s %s\n", $label, shift @values; - printf "%-47s %s\n", "", $_ foreach (@values); - } -} - -sub printl2 ($$) # print a line w/ label and value (outside a table) -{ - my ($label, $value) = @_; - if ($opt_html) { - $label =~ s//\>/sg; - $label =~ s/\n/
\n/sg; - $value =~ s//\>/sg; - $value =~ s/\n/
\n/sg; - } - print "$label: $value\n"; -} - -sub prints ($) # print separator w/ given text -{ - my ($label) = @_; - if ($opt_html) { - $label =~ s//\>/sg; - $label =~ s/\n/
\n/sg; - print "$label\n"; - } else { - print "\n---=== $label ===---\n"; - } -} - -sub printh ($$) # print header w/ given text -{ - my ($header, $sub) = @_; - if ($opt_html) { - $header =~ s//\>/sg; - $header =~ s/\n/
\n/sg; - $sub =~ s//\>/sg; - $sub =~ s/\n/
\n/sg; - print "

$header

\n"; - print "

$sub

\n"; - } else { - print "\n$header\n$sub\n"; - } -} - -# Parameter: bytes 0-63 -sub decode_sdr_sdram($) -{ - my $bytes = shift; - my ($l, $temp); - -# SPD revision - printl "SPD Revision", $bytes->[62]; - -#size computation - - prints "Memory Characteristics"; - - my $k=0; - my $ii=0; - - $ii = ($bytes->[3] & 0x0f) + ($bytes->[4] & 0x0f) - 17; - if (($bytes->[5] <= 8) && ($bytes->[17] <= 8)) { - $k = $bytes->[5] * $bytes->[17]; - } - - if($ii > 0 && $ii <= 12 && $k > 0) { - printl "Size", ((1 << $ii) * $k) . " MB"; } - else { - printl "INVALID SIZE", $bytes->[3] . "," . $bytes->[4] . "," . - $bytes->[5] . "," . $bytes->[17]; - } - - my @cas; - for ($ii = 0; $ii < 7; $ii++) { - push(@cas, $ii + 1) if ($bytes->[18] & (1 << $ii)); - } - - my $trcd; - my $trp; - my $tras; - my $ctime = ($bytes->[9] >> 4) + ($bytes->[9] & 0xf) * 0.1; - - $trcd =$bytes->[29]; - $trp =$bytes->[27];; - $tras =$bytes->[30]; - - printl "tCL-tRCD-tRP-tRAS", - $cas[$#cas] . "-" . - ceil($trcd/$ctime) . "-" . - ceil($trp/$ctime) . "-" . - ceil($tras/$ctime); - - $l = "Number of Row Address Bits"; - if ($bytes->[3] == 0) { printl $l, "Undefined!"; } - elsif ($bytes->[3] == 1) { printl $l, "1/16"; } - elsif ($bytes->[3] == 2) { printl $l, "2/17"; } - elsif ($bytes->[3] == 3) { printl $l, "3/18"; } - else { printl $l, $bytes->[3]; } - - $l = "Number of Col Address Bits"; - if ($bytes->[4] == 0) { printl $l, "Undefined!"; } - elsif ($bytes->[4] == 1) { printl $l, "1/16"; } - elsif ($bytes->[4] == 2) { printl $l, "2/17"; } - elsif ($bytes->[4] == 3) { printl $l, "3/18"; } - else { printl $l, $bytes->[4]; } - - $l = "Number of Module Rows"; - if ($bytes->[5] == 0 ) { printl $l, "Undefined!"; } - else { printl $l, $bytes->[5]; } - - $l = "Data Width"; - if ($bytes->[7] > 1) { - printl $l, "Undefined!" - } else { - $temp = ($bytes->[7] * 256) + $bytes->[6]; - printl $l, $temp; - } - - $l = "Module Interface Signal Levels"; - if ($bytes->[8] == 0) { printl $l, "5.0 Volt/TTL"; } - elsif ($bytes->[8] == 1) { printl $l, "LVTTL"; } - elsif ($bytes->[8] == 2) { printl $l, "HSTL 1.5"; } - elsif ($bytes->[8] == 3) { printl $l, "SSTL 3.3"; } - elsif ($bytes->[8] == 4) { printl $l, "SSTL 2.5"; } - elsif ($bytes->[8] == 255) { printl $l, "New Table"; } - else { printl $l, "Undefined!"; } - - $l = "Module Configuration Type"; - if ($bytes->[11] == 0) { printl $l, "No Parity"; } - elsif ($bytes->[11] == 1) { printl $l, "Parity"; } - elsif ($bytes->[11] == 2) { printl $l, "ECC"; } - else { printl $l, "Undefined!"; } - - $l = "Refresh Type"; - if ($bytes->[12] & 0x80) { printl $l, "Self Refreshing"; } - else { printl $l, "Not Self Refreshing"; } - - $l = "Refresh Rate"; - $temp = $bytes->[12] & 0x7f; - if ($temp == 0) { printl $l, "Normal (15.625 us)"; } - elsif ($temp == 1) { printl $l, "Reduced (3.9 us)"; } - elsif ($temp == 2) { printl $l, "Reduced (7.8 us)"; } - elsif ($temp == 3) { printl $l, "Extended (31.3 us)"; } - elsif ($temp == 4) { printl $l, "Extended (62.5 us)"; } - elsif ($temp == 5) { printl $l, "Extended (125 us)"; } - else { printl $l, "Undefined!"; } - - $l = "Primary SDRAM Component Bank Config"; - if ($bytes->[13] & 0x80) { printl $l, "Bank2 = 2 x Bank1"; } - else { printl $l, "No Bank2 OR Bank2 = Bank1 width"; } - - $l = "Primary SDRAM Component Widths"; - $temp = $bytes->[13] & 0x7f; - if ($temp == 0) { printl $l, "Undefined!\n"; } - else { printl $l, $temp; } - - $l = "Error Checking SDRAM Component Bank Config"; - if ($bytes->[14] & 0x80) { printl $l, "Bank2 = 2 x Bank1"; } - else { printl $l, "No Bank2 OR Bank2 = Bank1 width"; } - - $l = "Error Checking SDRAM Component Widths"; - $temp = $bytes->[14] & 0x7f; - if ($temp == 0) { printl $l, "Undefined!"; } - else { printl $l, $temp; } - - $l = "Min Clock Delay for Back to Back Random Access"; - if ($bytes->[15] == 0) { printl $l, "Undefined!"; } - else { printl $l, $bytes->[15]; } - - $l = "Burst lengths supported"; - my @array; - for ($ii = 0; $ii < 4; $ii++) { - push(@array, 1 << $ii) if ($bytes->[16] & (1 << $ii)); - } - push(@array, "Page") if ($bytes->[16] & 128); - if (@array) { $temp = join ', ', @array; } - else { $temp = "None"; } - printl $l, $temp; - - $l = "Number of Device Banks"; - if ($bytes->[17] == 0) { printl $l, "Undefined/Reserved!"; } - else { printl $l, $bytes->[17]; } - - $l = "Supported CAS Latencies"; - if (@cas) { $temp = join ', ', @cas; } - else { $temp = "None"; } - printl $l, $temp; - - $l = "Supported CS Latencies"; - @array = (); - for ($ii = 0; $ii < 7; $ii++) { - push(@array, $ii) if ($bytes->[19] & (1 << $ii)); - } - if (@array) { $temp = join ', ', @array; } - else { $temp = "None"; } - printl $l, $temp; - - $l = "Supported WE Latencies"; - @array = (); - for ($ii = 0; $ii < 7; $ii++) { - push(@array, $ii) if ($bytes->[20] & (1 << $ii)); - } - if (@array) { $temp = join ', ', @array; } - else { $temp = "None"; } - printl $l, $temp; - - if (@cas >= 1) { - $l = "Cycle Time (CAS ".$cas[$#cas].")"; - printl $l, "$ctime ns"; - - $l = "Access Time (CAS ".$cas[$#cas].")"; - $temp = ($bytes->[10] >> 4) + ($bytes->[10] & 0xf) * 0.1; - printl $l, "$temp ns"; - } - - if (@cas >= 2 && spd_written(@$bytes[23..24])) { - $l = "Cycle Time (CAS ".$cas[$#cas-1].")"; - $temp = $bytes->[23] >> 4; - if ($temp == 0) { printl $l, "Undefined!"; } - else { - if ($temp < 4 ) { $temp=$temp + 15; } - printl $l, $temp + (($bytes->[23] & 0xf) * 0.1) . " ns"; - } - - $l = "Access Time (CAS ".$cas[$#cas-1].")"; - $temp = $bytes->[24] >> 4; - if ($temp == 0) { printl $l, "Undefined!"; } - else { - if ($temp < 4 ) { $temp=$temp + 15; } - printl $l, $temp + (($bytes->[24] & 0xf) * 0.1) . " ns"; - } - } - - if (@cas >= 3 && spd_written(@$bytes[25..26])) { - $l = "Cycle Time (CAS ".$cas[$#cas-2].")"; - $temp = $bytes->[25] >> 2; - if ($temp == 0) { printl $l, "Undefined!"; } - else { printl $l, $temp + ($bytes->[25] & 0x3) * 0.25 . " ns"; } - - $l = "Access Time (CAS ".$cas[$#cas-2].")"; - $temp = $bytes->[26] >> 2; - if ($temp == 0) { printl $l, "Undefined!"; } - else { printl $l, $temp + ($bytes->[26] & 0x3) * 0.25 . " ns"; } - } - - $l = "SDRAM Module Attributes"; - $temp = ""; - if ($bytes->[21] & 1) { $temp .= "Buffered Address/Control Inputs\n"; } - if ($bytes->[21] & 2) { $temp .= "Registered Address/Control Inputs\n"; } - if ($bytes->[21] & 4) { $temp .= "On card PLL (clock)\n"; } - if ($bytes->[21] & 8) { $temp .= "Buffered DQMB Inputs\n"; } - if ($bytes->[21] & 16) { $temp .= "Registered DQMB Inputs\n"; } - if ($bytes->[21] & 32) { $temp .= "Differential Clock Input\n"; } - if ($bytes->[21] & 64) { $temp .= "Redundant Row Address\n"; } - if ($bytes->[21] & 128) { $temp .= "Undefined (bit 7)\n"; } - if ($bytes->[21] == 0) { $temp .= "(None Reported)\n"; } - printl $l, $temp; - - $l = "SDRAM Device Attributes (General)"; - $temp = ""; - if ($bytes->[22] & 1) { $temp .= "Supports Early RAS# Recharge\n"; } - if ($bytes->[22] & 2) { $temp .= "Supports Auto-Precharge\n"; } - if ($bytes->[22] & 4) { $temp .= "Supports Precharge All\n"; } - if ($bytes->[22] & 8) { $temp .= "Supports Write1/Read Burst\n"; } - if ($bytes->[22] & 16) { $temp .= "Lower VCC Tolerance: 5%\n"; } - else { $temp .= "Lower VCC Tolerance: 10%\n"; } - if ($bytes->[22] & 32) { $temp .= "Upper VCC Tolerance: 5%\n"; } - else { $temp .= "Upper VCC Tolerance: 10%\n"; } - if ($bytes->[22] & 64) { $temp .= "Undefined (bit 6)\n"; } - if ($bytes->[22] & 128) { $temp .= "Undefined (bit 7)\n"; } - printl $l, $temp; - - $l = "Minimum Row Precharge Time"; - if ($bytes->[27] == 0) { printl $l, "Undefined!"; } - else { printl $l, "$bytes->[27] ns"; } - - $l = "Row Active to Row Active Min"; - if ($bytes->[28] == 0) { printl $l, "Undefined!"; } - else { printl $l, "$bytes->[28] ns"; } - - $l = "RAS to CAS Delay"; - if ($bytes->[29] == 0) { printl $l, "Undefined!"; } - else { printl $l, "$bytes->[29] ns"; } - - $l = "Min RAS Pulse Width"; - if ($bytes->[30] == 0) { printl $l, "Undefined!"; } - else { printl $l, "$bytes->[30] ns"; } - - $l = "Row Densities"; - $temp = ""; - if ($bytes->[31] & 1) { $temp .= "4 MByte\n"; } - if ($bytes->[31] & 2) { $temp .= "8 MByte\n"; } - if ($bytes->[31] & 4) { $temp .= "16 MByte\n"; } - if ($bytes->[31] & 8) { $temp .= "32 MByte\n"; } - if ($bytes->[31] & 16) { $temp .= "64 MByte\n"; } - if ($bytes->[31] & 32) { $temp .= "128 MByte\n"; } - if ($bytes->[31] & 64) { $temp .= "256 MByte\n"; } - if ($bytes->[31] & 128) { $temp .= "512 MByte\n"; } - if ($bytes->[31] == 0) { $temp .= "(Undefined! -- None Reported!)\n"; } - printl $l, $temp; - - if (($bytes->[32] & 0xf) <= 9) { - $l = "Command and Address Signal Setup Time"; - $temp = (($bytes->[32] & 0x7f) >> 4) + ($bytes->[32] & 0xf) * 0.1; - printl $l, (($bytes->[32] >> 7) ? -$temp : $temp) . " ns"; - } - - if (($bytes->[33] & 0xf) <= 9) { - $l = "Command and Address Signal Hold Time"; - $temp = (($bytes->[33] & 0x7f) >> 4) + ($bytes->[33] & 0xf) * 0.1; - printl $l, (($bytes->[33] >> 7) ? -$temp : $temp) . " ns"; - } - - if (($bytes->[34] & 0xf) <= 9) { - $l = "Data Signal Setup Time"; - $temp = (($bytes->[34] & 0x7f) >> 4) + ($bytes->[34] & 0xf) * 0.1; - printl $l, (($bytes->[34] >> 7) ? -$temp : $temp) . " ns"; - } - - if (($bytes->[35] & 0xf) <= 9) { - $l = "Data Signal Hold Time"; - $temp = (($bytes->[35] & 0x7f) >> 4) + ($bytes->[35] & 0xf) * 0.1; - printl $l, (($bytes->[35] >> 7) ? -$temp : $temp) . " ns"; - } -} - -# Parameter: bytes 0-63 -sub decode_ddr_sdram($) -{ - my $bytes = shift; - my ($l, $temp); - -# SPD revision - if ($bytes->[62] != 0xff) { - printl "SPD Revision", ($bytes->[62] >> 4) . "." . - ($bytes->[62] & 0xf); - } - -# speed - prints "Memory Characteristics"; - - $l = "Maximum module speed"; - $temp = ($bytes->[9] >> 4) + ($bytes->[9] & 0xf) * 0.1; - my $ddrclk = 2 * (1000 / $temp); - my $tbits = ($bytes->[7] * 256) + $bytes->[6]; - if (($bytes->[11] == 2) || ($bytes->[11] == 1)) { $tbits = $tbits - 8; } - my $pcclk = int ($ddrclk * $tbits / 8); - $pcclk += 100 if ($pcclk % 100) >= 50; # Round properly - $pcclk = $pcclk - ($pcclk % 100); - $ddrclk = int ($ddrclk); - printl $l, "${ddrclk}MHz (PC${pcclk})"; - -#size computation - my $k=0; - my $ii=0; - - $ii = ($bytes->[3] & 0x0f) + ($bytes->[4] & 0x0f) - 17; - if (($bytes->[5] <= 8) && ($bytes->[17] <= 8)) { - $k = $bytes->[5] * $bytes->[17]; - } - - if($ii > 0 && $ii <= 12 && $k > 0) { - printl "Size", ((1 << $ii) * $k) . " MB"; } - else { - printl "INVALID SIZE", $bytes->[3] . ", " . $bytes->[4] . ", " . - $bytes->[5] . ", " . $bytes->[17]; - } - - my $highestCAS = 0; - my %cas; - for ($ii = 0; $ii < 7; $ii++) { - if ($bytes->[18] & (1 << $ii)) { - $highestCAS = 1+$ii*0.5; - $cas{$highestCAS}++; - } - } - - my $trcd; - my $trp; - my $tras; - my $ctime = ($bytes->[9] >> 4) + ($bytes->[9] & 0xf) * 0.1; - - $trcd =($bytes->[29] >> 2)+(($bytes->[29] & 3)*0.25); - $trp =($bytes->[27] >> 2)+(($bytes->[27] & 3)*0.25); - $tras = $bytes->[30]; - - printl "tCL-tRCD-tRP-tRAS", - $highestCAS . "-" . - ceil($trcd/$ctime) . "-" . - ceil($trp/$ctime) . "-" . - ceil($tras/$ctime); - -# latencies - if (keys %cas) { $temp = join ', ', sort { $b <=> $a } keys %cas; } - else { $temp = "None"; } - printl "Supported CAS Latencies", $temp; - - my @array; - for ($ii = 0; $ii < 7; $ii++) { - push(@array, $ii) if ($bytes->[19] & (1 << $ii)); - } - if (@array) { $temp = join ', ', @array; } - else { $temp = "None"; } - printl "Supported CS Latencies", $temp; - - @array = (); - for ($ii = 0; $ii < 7; $ii++) { - push(@array, $ii) if ($bytes->[20] & (1 << $ii)); - } - if (@array) { $temp = join ', ', @array; } - else { $temp = "None"; } - printl "Supported WE Latencies", $temp; - -# timings - if (exists $cas{$highestCAS}) { - printl "Minimum Cycle Time (CAS $highestCAS)", - "$ctime ns"; - - printl "Maximum Access Time (CAS $highestCAS)", - (($bytes->[10] >> 4) * 0.1 + ($bytes->[10] & 0xf) * 0.01) . " ns"; - } - - if (exists $cas{$highestCAS-0.5} && spd_written(@$bytes[23..24])) { - printl "Minimum Cycle Time (CAS ".($highestCAS-0.5).")", - (($bytes->[23] >> 4) + ($bytes->[23] & 0xf) * 0.1) . " ns"; - - printl "Maximum Access Time (CAS ".($highestCAS-0.5).")", - (($bytes->[24] >> 4) * 0.1 + ($bytes->[24] & 0xf) * 0.01) . " ns"; - } - - if (exists $cas{$highestCAS-1} && spd_written(@$bytes[25..26])) { - printl "Minimum Cycle Time (CAS ".($highestCAS-1).")", - (($bytes->[25] >> 4) + ($bytes->[25] & 0xf) * 0.1) . " ns"; - - printl "Maximum Access Time (CAS ".($highestCAS-1).")", - (($bytes->[26] >> 4) * 0.1 + ($bytes->[26] & 0xf) * 0.01) . " ns"; - } - -# module attributes - if ($bytes->[47] & 0x03) { - if (($bytes->[47] & 0x03) == 0x01) { $temp = "1.125\" to 1.25\""; } - elsif (($bytes->[47] & 0x03) == 0x02) { $temp = "1.7\""; } - elsif (($bytes->[47] & 0x03) == 0x03) { $temp = "Other"; } - printl "Module Height", $temp; - } -} - -sub ddr2_sdram_ctime($) -{ - my $byte = shift; - my $ctime; - - $ctime = $byte >> 4; - if (($byte & 0xf) <= 9) { $ctime += ($byte & 0xf) * 0.1; } - elsif (($byte & 0xf) == 10) { $ctime += 0.25; } - elsif (($byte & 0xf) == 11) { $ctime += 0.33; } - elsif (($byte & 0xf) == 12) { $ctime += 0.66; } - elsif (($byte & 0xf) == 13) { $ctime += 0.75; } - - return $ctime; -} - -sub ddr2_sdram_atime($) -{ - my $byte = shift; - my $atime; - - $atime = ($byte >> 4) * 0.1 + ($byte & 0xf) * 0.01; - - return $atime; -} - -# Parameter: bytes 0-63 -sub decode_ddr2_sdram($) -{ - my $bytes = shift; - my ($l, $temp); - my $ctime; - -# SPD revision - if ($bytes->[62] != 0xff) { - printl "SPD Revision", ($bytes->[62] >> 4) . "." . - ($bytes->[62] & 0xf); - } - -# speed - prints "Memory Characteristics"; - - $l = "Maximum module speed"; - $ctime = ddr2_sdram_ctime($bytes->[9]); - my $ddrclk = 2 * (1000 / $ctime); - my $tbits = ($bytes->[7] * 256) + $bytes->[6]; - if ($bytes->[11] & 0x03) { $tbits = $tbits - 8; } - my $pcclk = int ($ddrclk * $tbits / 8); - # Round down to comply with Jedec - $pcclk = $pcclk - ($pcclk % 100); - $ddrclk = int ($ddrclk); - printl $l, "${ddrclk}MHz (PC2-${pcclk})"; - -#size computation - my $k=0; - my $ii=0; - - $ii = ($bytes->[3] & 0x0f) + ($bytes->[4] & 0x0f) - 17; - $k = (($bytes->[5] & 0x7) + 1) * $bytes->[17]; - - if($ii > 0 && $ii <= 12 && $k > 0) { - printl "Size", ((1 << $ii) * $k) . " MB"; - } else { - printl "INVALID SIZE", $bytes->[3] . "," . $bytes->[4] . "," . - $bytes->[5] . "," . $bytes->[17]; - } - - my $highestCAS = 0; - my %cas; - for ($ii = 2; $ii < 7; $ii++) { - if ($bytes->[18] & (1 << $ii)) { - $highestCAS = $ii; - $cas{$highestCAS}++; - } - } - - my $trcd; - my $trp; - my $tras; - - $trcd =($bytes->[29] >> 2)+(($bytes->[29] & 3)*0.25); - $trp =($bytes->[27] >> 2)+(($bytes->[27] & 3)*0.25); - $tras =$bytes->[30]; - - printl "tCL-tRCD-tRP-tRAS", - $highestCAS . "-" . - ceil($trcd/$ctime) . "-" . - ceil($trp/$ctime) . "-" . - ceil($tras/$ctime); - -# latencies - if (keys %cas) { $temp = join ', ', sort { $b <=> $a } keys %cas; } - else { $temp = "None"; } - printl "Supported CAS Latencies", $temp; - -# timings - if (exists $cas{$highestCAS}) { - printl "Minimum Cycle Time (CAS $highestCAS)", - "$ctime ns"; - printl "Maximum Access Time (CAS $highestCAS)", - ddr2_sdram_atime($bytes->[10]) . " ns"; - } - - if (exists $cas{$highestCAS-1} && spd_written(@$bytes[23..24])) { - printl "Minimum Cycle Time (CAS ".($highestCAS-1).")", - ddr2_sdram_ctime($bytes->[23]) . " ns"; - printl "Maximum Access Time (CAS ".($highestCAS-1).")", - ddr2_sdram_atime($bytes->[24]) . " ns"; - } - - if (exists $cas{$highestCAS-2} && spd_written(@$bytes[25..26])) { - printl "Minimum Cycle Time (CAS ".($highestCAS-2).")", - ddr2_sdram_ctime($bytes->[25]) . " ns"; - printl "Maximum Access Time (CAS ".($highestCAS-2).")", - ddr2_sdram_atime($bytes->[26]) . " ns"; - } -} - -# Parameter: bytes 0-63 -sub decode_direct_rambus($) -{ - my $bytes = shift; - -#size computation - prints "Memory Characteristics"; - - my $ii; - - $ii = ($bytes->[4] & 0x0f) + ($bytes->[4] >> 4) + ($bytes->[5] & 0x07) - 13; - - if ($ii > 0 && $ii < 16) { - printl "Size", (1 << $ii) . " MB"; - } else { - printl "INVALID SIZE", sprintf("0x%02x, 0x%02x", - $bytes->[4], $bytes->[5]); - } -} - -# Parameter: bytes 0-63 -sub decode_rambus($) -{ - my $bytes = shift; - -#size computation - prints "Memory Characteristics"; - - my $ii; - - $ii = ($bytes->[3] & 0x0f) + ($bytes->[3] >> 4) + ($bytes->[5] & 0x07) - 13; - - if ($ii > 0 && $ii < 16) { - printl "Size", (1 << $ii) . " MB"; - } else { - printl "INVALID SIZE", sprintf("0x%02x, 0x%02x", - $bytes->[3], $bytes->[5]); - } -} - -%decode_callback = ( - "SDR SDRAM" => \&decode_sdr_sdram, - "DDR SDRAM" => \&decode_ddr_sdram, - "DDR2 SDRAM" => \&decode_ddr2_sdram, - "Direct Rambus" => \&decode_direct_rambus, - "Rambus" => \&decode_rambus, -); - -# Parameter: bytes 64-127 -sub decode_intel_spec_freq($) -{ - my $bytes = shift; - my ($l, $temp); - - prints "Intel Specification"; - - $l = "Frequency"; - if ($bytes->[62] == 0x66) { $temp = "66MHz\n"; } - elsif ($bytes->[62] == 100) { $temp = "100MHz or 133MHz\n"; } - elsif ($bytes->[62] == 133) { $temp = "133MHz\n"; } - else { $temp = "Undefined!\n"; } - printl $l, $temp; - - $l = "Details for 100MHz Support"; - $temp=""; - if ($bytes->[63] & 1) { $temp .= "Intel Concurrent Auto-precharge\n"; } - if ($bytes->[63] & 2) { $temp .= "CAS Latency = 2\n"; } - if ($bytes->[63] & 4) { $temp .= "CAS Latency = 3\n"; } - if ($bytes->[63] & 8) { $temp .= "Junction Temp A (100 degrees C)\n"; } - else { $temp .= "Junction Temp B (90 degrees C)\n"; } - if ($bytes->[63] & 16) { $temp .= "CLK 3 Connected\n"; } - if ($bytes->[63] & 32) { $temp .= "CLK 2 Connected\n"; } - if ($bytes->[63] & 64) { $temp .= "CLK 1 Connected\n"; } - if ($bytes->[63] & 128) { $temp .= "CLK 0 Connected\n"; } - if (($bytes->[63] & 192) == 192) { $temp .= "Double-sided DIMM\n"; } - elsif (($bytes->[63] & 192) != 0) { $temp .= "Single-sided DIMM\n"; } - printl $l, $temp; -} - -sub readspd64 ($$) { # reads 64 bytes from SPD-EEPROM - my ($offset, $dimm_i) = @_; - my @bytes; - if ($use_sysfs) { - # Kernel 2.6 with sysfs - sysopen(HANDLE, "/sys/bus/i2c/drivers/eeprom/$dimm_i/eeprom", O_RDONLY) - or die "Cannot open /sys/bus/i2c/drivers/eeprom/$dimm_i/eeprom"; - binmode HANDLE; - sysseek(HANDLE, $offset, SEEK_SET); - sysread(HANDLE, my $eeprom, 64); - close HANDLE; - @bytes = unpack("C64", $eeprom); - } else { - # Kernel 2.4 with procfs - for my $i (0 .. 3) { - my $hexoff = sprintf('%02x', $offset + $i * 16); - push @bytes, split(" ", `cat /proc/sys/dev/sensors/$dimm_i/$hexoff`); - } - } - return @bytes; -} - -for (@ARGV) { - if (/-h/) { - print "Usage: $0 [-c] [-f [-b]]\n", - " $0 -h\n\n", - " -f, --format print nice html output\n", - " -b, --bodyonly don't print html header\n", - " (useful for postprocessing the output)\n", - " -c, --checksum decode completely even if checksum fails\n", - " -h, --help display this usage summary\n"; - exit; - } - $opt_html = 1 if (/-f/); - $opt_bodyonly = 1 if (/-b/); - $opt_igncheck = 1 if (/-c/); -} -$opt_body = $opt_html && ! $opt_bodyonly; - -if ($opt_body) -{ - print "\n", - "\n", - "\t\n", - "\tPC DIMM Serial Presence Detect Tester/Decoder Output\n", - "\n"; -} - -printh 'Memory Serial Presence Detect Decoder', -'By Philip Edelbrock, Christian Zuckschwerdt, Burkart Lingner, -Jean Delvare and others -Version 2.10.8'; - - -my $dimm_count=0; -my @dimm_list; -my $dir; -if ($use_sysfs) { $dir = '/sys/bus/i2c/drivers/eeprom'; } -else { $dir = '/proc/sys/dev/sensors'; } -if (-d $dir) { - @dimm_list = split(/\s+/, `ls $dir`); -} elsif (! -d '/sys/module/eeprom') { - print "No EEPROM found, are you sure the eeprom module is loaded?\n"; - exit; -} - -for my $i ( 0 .. $#dimm_list ) { - $_=$dimm_list[$i]; - if (($use_sysfs && /^\d+-\d+$/) - || (!$use_sysfs && /^eeprom-/)) { - print "" if $opt_html; - printl2 "\n\nDecoding EEPROM", ($use_sysfs ? - "/sys/bus/i2c/drivers/eeprom/$dimm_list[$i]" : - "/proc/sys/dev/sensors/$dimm_list[$i]"); - print "" if $opt_html; - print "\n" if $opt_html; - if (($use_sysfs && /^[^-]+-([^-]+)$/) - || (!$use_sysfs && /^[^-]+-[^-]+-[^-]+-([^-]+)$/)) { - my $dimm_num=$1 - 49; - printl "Guessing DIMM is in", "bank $dimm_num"; - } - -# Decode first 3 bytes (0-2) - prints "SPD EEPROM Information"; - - my @bytes = readspd64(0, $dimm_list[$i]); - my $dimm_checksum = 0; - $dimm_checksum += $bytes[$_] foreach (0 .. 62); - $dimm_checksum &= 0xff; - - my $l = "EEPROM Checksum of bytes 0-62"; - printl $l, ($bytes[63] == $dimm_checksum ? - sprintf("OK (0x%.2X)", $bytes[63]): - sprintf("Bad\n(found 0x%.2X, calculated 0x%.2X)\n", - $bytes[63], $dimm_checksum)); - - unless ($bytes[63] == $dimm_checksum or $opt_igncheck) { - print "
\n" if $opt_html; - next; - } - - $dimm_count++; - # Simple heuristic to detect Rambus - my $is_rambus = $bytes[0] < 4; - my $temp; - if ($is_rambus) { - if ($bytes[0] == 1) { $temp = "0.7"; } - elsif ($bytes[0] == 2) { $temp = "1.0"; } - elsif ($bytes[0] == 0 || $bytes[0] == 255) { $temp = "Invalid"; } - else { $temp = "Reserved"; } - printl "SPD Revision", $temp; - } else { - printl "# of bytes written to SDRAM EEPROM", - $bytes[0]; - } - - $l = "Total number of bytes in EEPROM"; - if ($bytes[1] <= 14) { - printl $l, 2**$bytes[1]; - } elsif ($bytes[1] == 0) { - printl $l, "RFU"; - } else { printl $l, "ERROR!"; } - - $l = "Fundamental Memory type"; - my $type = "Unknown"; - if ($is_rambus) { - if ($bytes[2] == 1) { $type = "Direct Rambus"; } - elsif ($bytes[2] == 17) { $type = "Rambus"; } - } else { - if ($bytes[2] == 1) { $type = "FPM DRAM"; } - elsif ($bytes[2] == 2) { $type = "EDO"; } - elsif ($bytes[2] == 3) { $type = "Pipelined Nibble"; } - elsif ($bytes[2] == 4) { $type = "SDR SDRAM"; } - elsif ($bytes[2] == 5) { $type = "Multiplexed ROM"; } - elsif ($bytes[2] == 6) { $type = "DDR SGRAM"; } - elsif ($bytes[2] == 7) { $type = "DDR SDRAM"; } - elsif ($bytes[2] == 8) { $type = "DDR2 SDRAM"; } - } - printl $l, $type; - -# Decode next 61 bytes (3-63, depend on memory type) - $decode_callback{$type}->(\@bytes) - if exists $decode_callback{$type}; - -# Decode next 35 bytes (64-98, common to all memory types) - prints "Manufacturing Information"; - - @bytes = readspd64(64, $dimm_list[$i]); - - $l = "Manufacturer"; - # $extra is a reference to an array containing up to - # 7 extra bytes from the Manufacturer field. Sometimes - # these bytes are filled with interesting data. - ($temp, my $extra) = manufacturer(@bytes[0..7]); - printl $l, $temp; - $l = "Custom Manufacturer Data"; - $temp = manufacturer_data(@{$extra}); - printl $l, $temp if defined $temp; - - if (spd_written($bytes[8])) { - # Try the location code as ASCII first, as earlier specifications - # suggested this. As newer specifications don't mention it anymore, - # we still fall back to binary. - $l = "Manufacturing Location Code"; - $temp = (chr($bytes[8]) =~ m/^[\w\d]$/) ? chr($bytes[8]) - : sprintf("0x%.2X", $bytes[8]); - printl $l, $temp; - } - - $l = "Part Number"; - $temp = part_number(@bytes[9..26]); - printl $l, $temp; - - if (spd_written(@bytes[27..28])) { - $l = "Revision Code"; - $temp = sprintf("0x%02X%02X\n", @bytes[27..28]); - printl $l, $temp; - } - - if (spd_written(@bytes[29..30])) { - $l = "Manufacturing Date"; - # In theory the year and week are in BCD format, but - # this is not always true in practice :( - if (($bytes[29] & 0xf0) <= 0x90 - && ($bytes[29] & 0x0f) <= 0x09 - && ($bytes[30] & 0xf0) <= 0x90 - && ($bytes[30] & 0x0f) <= 0x09) { - # Note that this heuristic will break in year 2080 - $temp = sprintf("%d%02X-W%02X\n", - $bytes[29] >= 0x80 ? 19 : 20, - @bytes[29..30]); - } else { - $temp = sprintf("0x%02X%02X\n", - @bytes[29..30]); - } - printl $l, $temp; - } - - if (spd_written(@bytes[31..34])) { - $l = "Assembly Serial Number"; - $temp = sprintf("0x%02X%02X%02X%02X\n", - @bytes[31..34]); - printl $l, $temp; - } - -# Next 27 bytes (99-125) are manufacturer specific, can't decode - -# Last 2 bytes (126-127) are reserved, Intel used them as an extension - if ($type eq "SDR SDRAM") { - decode_intel_spec_freq(\@bytes); - } - - print "\n" if $opt_html; - } -} -printl2 "\n\nNumber of SDRAM DIMMs detected and decoded", $dimm_count; - -print "\n" if $opt_body; diff --git a/prog/eeprom/decode-edid.pl b/prog/eeprom/decode-edid.pl deleted file mode 100755 index dc793e72..00000000 --- a/prog/eeprom/decode-edid.pl +++ /dev/null @@ -1,224 +0,0 @@ -#!/usr/bin/perl -w -# -# Copyright (C) 2003-2006 Jean Delvare -# -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -# -# Version 0.1 2003-07-17 Jean Delvare -# Version 0.2 2003-07-22 Jean Delvare -# Use print instead of syswrite. -# Version 0.3 2003-08-24 Jean Delvare -# Fix data block length (128 bytes instead of 256). -# Version 1.0 2004-02-08 Jean Delvare -# Added support for Linux 2.5/2.6 (i.e. sysfs). -# Version 1.1 2006-09-01 Jean Delvare -# Append /usr/sbin or /usr/local/sbin to $PATH if needed. -# -# EEPROM data decoding for EDID. EDID (Extended Display Identification -# Data) is a VESA standard which allows storing (on manufacturer's side) -# and retrieving (on user's side) of configuration information about -# displays, such as manufacturer, serial number, physical dimensions and -# allowed horizontal and vertical refresh rates. -# -# Using the LM Sensors modules and tools, you have two possibilities to -# make use of these data: -# 1* Use the ddcmon driver and run sensors. -# 2* Use the eeprom driver and run this script. -# Both solutions will return a different kind of information. The first -# method will report user-interesting information, such as the model number -# or the year of manufacturing. The second method will report video-card- -# interesting information, such as video modes and refresh rates. -# -# Note that this script does almost nothing by itself. It simply converts -# what it finds in /proc to binary data to feed the parse-edid program. -# The parse-edid program was written by John Fremlin and is available at -# the following address: -# http://john.fremlin.de/programs/linux/read-edid/ - -use strict; -use Fcntl qw(:DEFAULT :seek); -use vars qw($bus $address); -use constant PROCFS => 1; -use constant SYSFS => 2; - -# parse-edid will typically be installed in /usr/sbin or /usr/local/sbin -# even though regular users can run it -$ENV{PATH} .= ':/usr/local/sbin' - if $ENV{PATH} !~ m,(^|:)/usr/local/sbin/?(:|$), - && -x '/usr/local/sbin/parse-edid'; -$ENV{PATH} .= ':/usr/sbin' - if $ENV{PATH} !~ m,(^|:)/usr/sbin/?(:|$), - && -x '/usr/sbin/parse-edid'; - -sub edid_valid_procfs -{ - my ($bus, $addr) = @_; - - open EEDATA, "/proc/sys/dev/sensors/eeprom-i2c-$bus-$addr/00"; - my $line = ; - close EEDATA; - return 1 - if $line =~ m/^0 255 255 255 255 255 255 0 /; - return 0; -} - -# Only used for sysfs -sub rawread -{ - my ($filename, $length, $offset) = @_; - my $bytes = ''; - - sysopen(FH, $filename, O_RDONLY) - or die "Can't open $filename"; - if ($offset) - { - sysseek(FH, $offset, SEEK_SET) - or die "Can't seek in $filename"; - } - - $offset = 0; - while ($length) - { - my $r = sysread(FH, $bytes, $length, $offset); - die "Can't read $filename" - unless defined($r); - die "Unexpected EOF in $filename" - unless $r; - $offset += $r; - $length -= $r; - } - close(FH); - - return $bytes; -} - -sub edid_valid_sysfs -{ - my ($bus, $addr) = @_; - my $bytes = rawread("/sys/bus/i2c/devices/$bus-00$addr/eeprom", 8, 0); - - return 1 - if $bytes eq "\x00\xFF\xFF\xFF\xFF\xFF\xFF\x00"; - return 0; -} - -sub bus_detect -{ - my $max = shift; - - for (my $i=0; $i<$max; $i++) - { - if (-r "/proc/sys/dev/sensors/eeprom-i2c-$i-50/00") - { - if (edid_valid_procfs($i, '50')) - { - print STDERR - "decode-edid: using bus $i (autodetected)\n"; - return $i; - } - } - elsif (-r "/sys/bus/i2c/devices/$i-0050/eeprom") - { - if (edid_valid_sysfs($i, '50')) - { - print STDERR - "decode-edid: using bus $i (autodetected)\n"; - return $i; - } - } - } - - return; # default -} - -sub edid_decode -{ - my ($bus, $addr, $mode) = @_; - - # Make sure it is an EDID EEPROM. - - unless (($mode == PROCFS && edid_valid_procfs ($bus, $addr)) - || ($mode == SYSFS && edid_valid_sysfs ($bus, $addr))) - { - print STDERR - "decode-edid: not an EDID EEPROM at $bus-$addr\n"; - return; - } - - $SIG{__WARN__} = sub { }; - open PIPE, "| parse-edid" - or die "Can't open parse-edid. Please install read-edid.\n"; - delete $SIG{__WARN__}; - binmode PIPE; - - if ($mode == PROCFS) - { - for (my $i=0; $i<=0x70; $i+=0x10) - { - my $file = sprintf '%02x', $i; - my $output = ''; - open EEDATA, "/proc/sys/dev/sensors/eeprom-i2c-$bus-$addr/$file" - or die "Can't read /proc/sys/dev/sensors/eeprom-i2c-$bus-$addr/$file"; - while() - { - foreach my $item (split) - { - $output .= pack "C", $item; - } - } - close EEDATA; - print PIPE $output; - } - } - elsif ($mode == SYSFS) - { - print PIPE rawread("/sys/bus/i2c/devices/$bus-00$address/eeprom", 128, 0); - } - - close PIPE; -} - -# Get the address. Default to 0x50 if not given. -$address = $ARGV[1] || 0x50; -# Convert to decimal, whatever the value. -$address = oct $address if $address =~ m/^0/; -# Convert to an hexadecimal string. -$address = sprintf '%02x', $address; - -# Get the bus. Try to autodetect if not given. -$bus = $ARGV[0] if defined $ARGV[0]; -$bus = bus_detect(8) unless defined $bus; - -if(defined $bus) -{ - print STDERR - "decode-edid: decode-edid version 1.1\n"; - if (-r "/proc/sys/dev/sensors/eeprom-i2c-$bus-$address") - { - edid_decode ($bus, $address, PROCFS); - exit 0; - } - elsif (-r "/sys/bus/i2c/devices/$bus-00$address") - { - edid_decode ($bus, $address, SYSFS); - exit 0; - } -} - -print STDERR - "EDID EEPROM not found. Please make sure that the eeprom module is loaded.\n"; -print STDERR - "Maybe your EDID EEPROM is on another bus. Try \"decode-edid ".($bus+1)."\".\n" - if defined $bus; diff --git a/prog/eeprom/decode-vaio.pl b/prog/eeprom/decode-vaio.pl deleted file mode 100755 index 107a13af..00000000 --- a/prog/eeprom/decode-vaio.pl +++ /dev/null @@ -1,272 +0,0 @@ -#!/usr/bin/perl -w -# -# Copyright (C) 2002-2007 Jean Delvare -# -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -# -# Version 0.1 2002-02-06 Jean Delvare -# Version 0.2 2002-02-16 Jean Delvare -# Fixed to work with the new, simplified /proc interface names of the eeprom -# driver (lm_sensors 2.6.3 and greater). -# Shifted data display by 4 columns left. -# Version 0.3 2002-02-17 Jean Delvare -# Added UUID field at 0x10 (added decode_uuid). -# Merged decode_string and decode_string32. -# Added unknown field at 0x20. -# Moved header and footer to BEGIN and END, respectively. -# Reformated history to match those of the other decode scripts. -# Deleted decode_char (made useless by decode_string). -# Reordered field display, changed some labels. -# Added old /proc interface check. -# Version 1.0 2002-11-15 Jean Delvare -# Gave the label "OEM Data" to the field at 0x20. -# Gave the label "Timestamp" to the field at 0xE0. -# Renamed "Model Number" to "Model Name". -# Added some documentation. -# Version 1.1 2004-01-17 Jean Delvare -# Added support for Linux 2.5/2.6 (i.e. sysfs). -# Version 1.2 2004-11-28 Jean Delvare -# Support bus number 0 to 4 instead of only 0. -# Version 1.3 2005-01-18 Jean Delvare -# Revision might be a Service Tag. -# Version 1.4 2006-09-20 Jean Delvare -# Detect and skip false positives (e.g. EDID EEPROMs). -# Version 1.5 2007-11-19 Jean Delvare -# UUID and serial number might be hidden -# The model name is actually the first half of the asset tag -# The timestamp is only 18-byte long -# -# EEPROM data decoding for Sony Vaio laptops. -# -# Two assumptions: lm_sensors-2.6.3 or greater installed, -# and Perl is at /usr/bin/perl -# -# Please note that this is a guess-only work. Sony support refused to help -# me, so if someone can provide information, please contact me. -# My knowledge is summarized on this page: -# http://khali.linux-fr.org/vaio/eeprom.html -# -# It seems that if present, the EEPROM is always at 0x57. -# -# Models tested so far: -# PCG-F403 : No EEPROM -# PCG-F707 : No EEPROM -# PCG-GR114EK : OK -# PCG-GR114SK : OK -# PCG-GR214EP : OK -# PCG-GRT955MP : OK -# PCG-GRX316G : OK -# PCG-GRX570 : OK -# PCG-GRX600K : OK -# PCG-U1 : OK -# PCG-Z600LEK : No EEPROM -# PCG-Z600NE : No EEPROM -# VGN-S260 : OK -# VGN-S4M/S : OK -# VGN-TZ11MN/N : OK -# Any feedback appreciated anyway. -# -# Thanks to Werner Heuser, Carsten Blume, Christian Gennerat, Joe Wreschnig, -# Xavier Roche, Sebastien Lefevre, Lars Heer, Steve Dobson, Kent Hunt, -# Timo Hoenig and others for their precious help. - - -use strict; -use Fcntl qw(:DEFAULT :seek); -use vars qw($sysfs $found); - -use constant ONLYROOT => "Readable only by root"; - -sub print_item -{ - my ($label,$value) = @_; - - printf("\%16s : \%s\n",$label,$value); -} - -# Abstract reads so that other functions don't have to care wether -# we need to use procfs or sysfs -sub read_eeprom_bytes -{ - my ($bus, $addr, $offset, $length) = @_; - my $filename; - - if ($sysfs) - { - $filename = "/sys/bus/i2c/devices/$bus-00$addr/eeprom"; - sysopen(FH, $filename, O_RDONLY) - or die "Can't open $filename"; - sysseek(FH, $offset, SEEK_SET) - or die "Can't seek in $filename"; - - my ($r, $bytes); - $bytes = ''; - $offset = 0; - while($length) - { - $r = sysread(FH, $bytes, $length, $offset); - die "Can't read $filename" - unless defined($r); - die "Unexpected EOF in $filename" - unless $r; - $offset += $r; - $length -= $r; - } - close(FH); - - return $bytes; - } - else - { - my $base = $offset & 0xf0; - $offset -= $base; - my $values = ''; - my $remains = $length + $offset; - - # Get all lines in a single string - while ($remains > 0) - { - $filename = "/proc/sys/dev/sensors/eeprom-i2c-$bus-$addr/" - . sprintf('%02x', $base); - open(FH, $filename) - or die "Can't open $filename"; - $values .= ; - close(FH); - $remains -= 16; - $base += 16; - } - - # Store the useful part in an array - my @bytes = split(/[ \n]/, $values); - @bytes = @bytes[$offset..$offset+$length-1]; - - # Back to a binary string - return pack('C*', @bytes); - } -} - -sub decode_string -{ - my ($bus, $addr, $offset, $length) = @_; - - my $string = read_eeprom_bytes($bus, $addr, $offset, $length); - $string =~ s/\x00.*$//; - - return($string); -} - -sub decode_hexa -{ - my ($bus, $addr, $offset, $length) = @_; - - my @bytes = unpack('C*', read_eeprom_bytes($bus, $addr, $offset, $length)); - my $string=''; - - for(my $i=0;$i<$length;$i++) - { - $string.=sprintf('%02X', shift(@bytes)); - } - - return($string); -} - -sub decode_uuid -{ - my ($bus,$addr,$base) = @_; - - my @bytes = unpack('C16', read_eeprom_bytes($bus, $addr, $base, 16)); - my $string=''; - - for(my $i=0;$i<16;$i++) - { - $string.=sprintf('%02x',shift(@bytes)); - if(($i==3)||($i==5)||($i==7)||($i==9)) - { - $string.='-'; - } - } - - if ($string eq '00000000-0000-0000-0000-000000000000') - { - return(ONLYROOT); - } - else - { - return($string); - } -} - -sub vaio_decode -{ - my ($bus,$addr) = @_; - - my $name = decode_string($bus, $addr, 128, 32); - # Simple heuristic to skip false positives - return 0 unless $name =~ m/^[A-Z-]{4}/; - - print_item('Machine Name', $name); - my $serial = decode_string($bus, $addr, 192, 32); - print_item('Serial Number', $serial ? $serial : ONLYROOT); - print_item('UUID', decode_uuid($bus, $addr, 16)); - my $revision = decode_string($bus, $addr, 160, 10); - print_item(length($revision) > 2 ? 'Service Tag' : 'Revision', - $revision); - print_item('Asset Tag', decode_string($bus, $addr, 170, 4). - decode_hexa($bus, $addr, 174, 12)); - print_item('OEM Data', decode_string($bus, $addr, 32, 16)); - print_item('Timestamp', decode_string($bus, $addr, 224, 18)); - return 1; -} - -BEGIN -{ - print("Sony Vaio EEPROM Decoder\n"); - print("Copyright (C) 2002-2007 Jean Delvare\n"); - print("Version 1.5\n\n"); -} - -END -{ - print("\n"); -} - -for (my $i = 0, $found=0; $i <= 4 && !$found; $i++) -{ - if (-r "/sys/bus/i2c/devices/$i-0057/eeprom") - { - $sysfs = 1; - $found += vaio_decode($i, '57'); - } - elsif (-r "/proc/sys/dev/sensors/eeprom-i2c-$i-57") - { - if (-r "/proc/sys/dev/sensors/eeprom-i2c-$i-57/data0-15") - { - print("Deprecated old interface found. Please upgrade to lm_sensors 2.6.3 or greater."); - exit; - } - else - { - $sysfs = 0; - $found += vaio_decode($i, '57'); - } - } -} - -if (!$found) -{ - print("Vaio EEPROM not found. Please make sure that the eeprom module is loaded.\n"); - print("If you believe this is an error, please contact me \n"); - print("so that we may see how to fix the problem.\n"); -} diff --git a/prog/eepromer/24cXX.c b/prog/eepromer/24cXX.c deleted file mode 100644 index 00a21fd7..00000000 --- a/prog/eepromer/24cXX.c +++ /dev/null @@ -1,182 +0,0 @@ -/*************************************************************************** - copyright : (C) by 2002-2003 Stefano Barbato - email : stefano@codesink.org - - $Id$ - ***************************************************************************/ - -/*************************************************************************** - * * - * This program is free software; you can redistribute it and/or modify * - * it under the terms of the GNU General Public License as published by * - * the Free Software Foundation; either version 2 of the License, or * - * (at your option) any later version. * - * * - ***************************************************************************/ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "24cXX.h" - -static int i2c_write_1b(struct eeprom *e, __u8 buf) -{ - int r; - // we must simulate a plain I2C byte write with SMBus functions - r = i2c_smbus_write_byte(e->fd, buf); - if(r < 0) - fprintf(stderr, "Error i2c_write_1b: %s\n", strerror(errno)); - usleep(10); - return r; -} - -static int i2c_write_2b(struct eeprom *e, __u8 buf[2]) -{ - int r; - // we must simulate a plain I2C byte write with SMBus functions - r = i2c_smbus_write_byte_data(e->fd, buf[0], buf[1]); - if(r < 0) - fprintf(stderr, "Error i2c_write_2b: %s\n", strerror(errno)); - usleep(10); - return r; -} - -static int i2c_write_3b(struct eeprom *e, __u8 buf[3]) -{ - int r; - // we must simulate a plain I2C byte write with SMBus functions - // the __u16 data field will be byte swapped by the SMBus protocol - r = i2c_smbus_write_word_data(e->fd, buf[0], buf[2] << 8 | buf[1]); - if(r < 0) - fprintf(stderr, "Error i2c_write_3b: %s\n", strerror(errno)); - usleep(10); - return r; -} - - -#define CHECK_I2C_FUNC( var, label ) \ - do { if(0 == (var & label)) { \ - fprintf(stderr, "\nError: " \ - #label " function is required. Program halted.\n\n"); \ - exit(1); } \ - } while(0); - -int eeprom_open(char *dev_fqn, int addr, int type, struct eeprom* e) -{ - int fd, r; - unsigned long funcs; - e->fd = e->addr = 0; - e->dev = 0; - - fd = open(dev_fqn, O_RDWR); - if(fd <= 0) - return -1; - - // get funcs list - if((r = ioctl(fd, I2C_FUNCS, &funcs) < 0)) - return r; - - - // check for req funcs - CHECK_I2C_FUNC( funcs, I2C_FUNC_SMBUS_READ_BYTE ); - CHECK_I2C_FUNC( funcs, I2C_FUNC_SMBUS_WRITE_BYTE ); - CHECK_I2C_FUNC( funcs, I2C_FUNC_SMBUS_READ_BYTE_DATA ); - CHECK_I2C_FUNC( funcs, I2C_FUNC_SMBUS_WRITE_BYTE_DATA ); - CHECK_I2C_FUNC( funcs, I2C_FUNC_SMBUS_READ_WORD_DATA ); - CHECK_I2C_FUNC( funcs, I2C_FUNC_SMBUS_WRITE_WORD_DATA ); - - // set working device - if( ( r = ioctl(fd, I2C_SLAVE, addr)) < 0) - return r; - e->fd = fd; - e->addr = addr; - e->dev = dev_fqn; - e->type = type; - return 0; -} - -int eeprom_close(struct eeprom *e) -{ - close(e->fd); - e->fd = -1; - e->dev = 0; - e->type = EEPROM_TYPE_UNKNOWN; - return 0; -} - -#if 0 -int eeprom_24c32_write_byte(struct eeprom *e, __u16 mem_addr, __u8 data) -{ - __u8 buf[3] = { (mem_addr >> 8) & 0x00ff, mem_addr & 0x00ff, data }; - return i2c_write_3b(e, buf); -} - - -int eeprom_24c32_read_current_byte(struct eeprom* e) -{ - ioctl(e->fd, BLKFLSBUF); // clear kernel read buffer - return i2c_smbus_read_byte(e->fd); -} - -int eeprom_24c32_read_byte(struct eeprom* e, __u16 mem_addr) -{ - int r; - ioctl(e->fd, BLKFLSBUF); // clear kernel read buffer - __u8 buf[2] = { (mem_addr >> 8) & 0x0ff, mem_addr & 0x0ff }; - r = i2c_write_2b(e, buf); - if (r < 0) - return r; - r = i2c_smbus_read_byte(e->fd); - return r; -} -#endif - - -int eeprom_read_current_byte(struct eeprom* e) -{ - ioctl(e->fd, BLKFLSBUF); // clear kernel read buffer - return i2c_smbus_read_byte(e->fd); -} - -int eeprom_read_byte(struct eeprom* e, __u16 mem_addr) -{ - int r; - ioctl(e->fd, BLKFLSBUF); // clear kernel read buffer - if(e->type == EEPROM_TYPE_8BIT_ADDR) - { - __u8 buf = mem_addr & 0x0ff; - r = i2c_write_1b(e, buf); - } else if(e->type == EEPROM_TYPE_16BIT_ADDR) { - __u8 buf[2] = { (mem_addr >> 8) & 0x0ff, mem_addr & 0x0ff }; - r = i2c_write_2b(e, buf); - } else { - fprintf(stderr, "ERR: unknown eeprom type\n"); - return -1; - } - if (r < 0) - return r; - r = i2c_smbus_read_byte(e->fd); - return r; -} - -int eeprom_write_byte(struct eeprom *e, __u16 mem_addr, __u8 data) -{ - if(e->type == EEPROM_TYPE_8BIT_ADDR) { - __u8 buf[2] = { mem_addr & 0x00ff, data }; - return i2c_write_2b(e, buf); - } else if(e->type == EEPROM_TYPE_16BIT_ADDR) { - __u8 buf[3] = - { (mem_addr >> 8) & 0x00ff, mem_addr & 0x00ff, data }; - return i2c_write_3b(e, buf); - } else { - fprintf(stderr, "ERR: unknown eeprom type\n"); - return -1; - } -} - diff --git a/prog/eepromer/24cXX.h b/prog/eepromer/24cXX.h deleted file mode 100644 index caac05b0..00000000 --- a/prog/eepromer/24cXX.h +++ /dev/null @@ -1,58 +0,0 @@ -/*************************************************************************** - copyright : (C) by 2002-2003 Stefano Barbato - email : stefano@codesink.org - - $Id$ - ***************************************************************************/ - -/*************************************************************************** - * * - * This program is free software; you can redistribute it and/or modify * - * it under the terms of the GNU General Public License as published by * - * the Free Software Foundation; either version 2 of the License, or * - * (at your option) any later version. * - * * - ***************************************************************************/ -#ifndef _24CXX_H_ -#define _24CXX_H_ -#include "i2c-dev.h" - -#define EEPROM_TYPE_UNKNOWN 0 -#define EEPROM_TYPE_8BIT_ADDR 1 -#define EEPROM_TYPE_16BIT_ADDR 2 - -struct eeprom -{ - char *dev; // device file i.e. /dev/i2c-N - int addr; // i2c address - int fd; // file descriptor - int type; // eeprom type -}; - -/* - * opens the eeprom device at [dev_fqn] (i.e. /dev/i2c-N) whose address is - * [addr] and set the eeprom_24c32 [e] - */ -int eeprom_open(char *dev_fqn, int addr, int type, struct eeprom*); -/* - * closees the eeprom device [e] - */ -int eeprom_close(struct eeprom *e); -/* - * read and returns the eeprom byte at memory address [mem_addr] - * Note: eeprom must have been selected by ioctl(fd,I2C_SLAVE,address) - */ -int eeprom_read_byte(struct eeprom* e, __u16 mem_addr); -/* - * read the current byte - * Note: eeprom must have been selected by ioctl(fd,I2C_SLAVE,address) - */ -int eeprom_read_current_byte(struct eeprom *e); -/* - * writes [data] at memory address [mem_addr] - * Note: eeprom must have been selected by ioctl(fd,I2C_SLAVE,address) - */ -int eeprom_write_byte(struct eeprom *e, __u16 mem_addr, __u8 data); - -#endif - diff --git a/prog/eepromer/Makefile b/prog/eepromer/Makefile deleted file mode 100644 index 2f6a9826..00000000 --- a/prog/eepromer/Makefile +++ /dev/null @@ -1,14 +0,0 @@ -#eepromer Makefile - -CFLAGS = -O2 -I../../kernel/include -Wall - -all: eepromer eeprom eeprog - -eepromer: eepromer.o - -eeprom: eeprom.o - -eeprog: eeprog.o 24cXX.o - -clean: - rm -rf *~ *.o eepromer eeprom eeprog diff --git a/prog/eepromer/README b/prog/eepromer/README deleted file mode 100644 index ff89c730..00000000 --- a/prog/eepromer/README +++ /dev/null @@ -1,31 +0,0 @@ -These programs are used to read and write eeproms. - -Use eeprom for small eeproms with one-byte addresses: - 24C01, 24C01A, 24C02, 24C04, 24C08, and 24C16 - It works only on true i2c bus adapters. - See README.eeprom for details. - -Use eepromer for large eeproms with two-byte addresses: - 24C32, 24C64, 24C128, 24C256, and 24C512 - It works only on true i2c bus adapters. - See README.eepromer for details. - -Use eeprog for either small or large eeproms. - Use the -16 switch for large eeproms. - It works on both i2c and smbus bus adapters. - See README.eeprog for details. - - -!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! Warning !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -!!! ! -!!! These programs should only be used on external busses such as i2c-pport ! -!!! unless you REALLY know what you are doing. ! -!!! ! -!!! Your computer probably contains eeproms for saving data vital to its ! -!!! operation. If you are not careful you might overwrite this data with ! -!!! this program and your computer may no longer boot! ! -!!! ! -!!! An example are the EEPROMS on your SDRAM DIMMs, your computer may no ! -!!! longer detect the RAM module rendering it essentially USELESS! ! -!!! ! -!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! Warning !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! diff --git a/prog/eepromer/README.eeprog b/prog/eepromer/README.eeprog deleted file mode 100644 index 6cccd004..00000000 --- a/prog/eepromer/README.eeprog +++ /dev/null @@ -1,12 +0,0 @@ -Important! See the README file for important warnings. - -eeprog reads and writes 24Cxx EEPROMs connected to I2C serial bus. - -It uses the SMBus protocol used by most of the recent chipsets. Don't forget to load -your i2c chipset and the i2c-dev drivers. - -Use -16 switch for EEPROM larger then 24C16 (16 bit addressing mode). - -Again, it's really important that you read the README file. - -Type "make" to compile. diff --git a/prog/eepromer/README.eeprom b/prog/eepromer/README.eeprom deleted file mode 100644 index 481d60bf..00000000 --- a/prog/eepromer/README.eeprom +++ /dev/null @@ -1,85 +0,0 @@ -You can use this program to read/write to i2c-eeproms -like the popular 24C16, 24C08, 24C04,.. In contrast to lm_sensor's eeprommer -which supports 24C256-type eeproms 24C16ss use 1-byte addresses! - -!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! Warning !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -!!! ! -!!! This program should only be used on external busses such as i2c-pport. ! -!!! ! -!!! Your computer may contain i2c-eeproms for saving data vital to its ! -!!! operation. If you are not careful you might overwrite this data with ! -!!! this program and your computer may no longer boot! ! -!!! ! -!!! An example are the EEPROMS on your SDRAM DIMMs, your computer may no ! -!!! longer detect the RAM module rendering it essentially USELESS! ! -!!! ! -!!! IBM Thinkpads are said to store their configuration data in a eeprom, ! -!!! if you manage to overwrite this eeprom you will have to send your ! -!!! computer to the manufacturer for a costly repair! ! -!!! ! -!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! Warning !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - -It has several options: - - -d devicenode - - set this to the device-node of the i2c-bus - you want to use like /dev/i2c-0. - Use /dev/i2c-1 for the second bus, i2c-2 for the third... - - The default /dev/i2c-0 should work most of the time. - - -a address - - set this to the device-address of your - eeprom. For a 24C16 the address is hardcoded to - 0x50, which is -you guessed it- the default. - - For a 24C08 and smaller types you can choose which - addresses they occupy by forcing the address-pins - of the chip to High or Low so here the address may differ. - - -p number_of_pages - - set this to the number of pages you want to read - from or write to the eeprom. The 24C16 maps it's - pages to consecutive addresses on the i2c-bus so - we will try to read 256 bytes from every i2c - address between 'address' (inclusive) and - 'address + number_of_pages' (exclusive)... - - A 24C16 has 8 pages so that's the default for this - parameter. - - -f filename - - read data from this file (when writing to eeprom) or - write data to this file (when reading from eeprom). - - When reading a file that's smaller than the - eeprom's storage size we will pad the eeprom - with zeroes. - - If no file is given we will just read the - eeprom (while in read-mode) and test it's presence - this way. In write-mode we will just write zeroes - to the eeprom. - - -w When '-w' is present we will *write* to the eeprom. - If you do not specify '-w' we will read the contents - of the eeprom. - - -y This flag will suppress the warning when you write to the - eeprom. You will not be required to enter 'yes' so be careful - when using this switch! - - -I wrote that program to clear a 24C16 eeprom that sit's in my crappy -satellite receiver because sometimes its Z80 processor likes to -write garbage to it and then crash.... - -No further testing besides writing a long series of "The quick brown -fox jumps over the lazy dog!" and reading it back has been done so -of course this comes without any warranty. - - Chris diff --git a/prog/eepromer/README.eepromer b/prog/eepromer/README.eepromer deleted file mode 100644 index 444103f3..00000000 --- a/prog/eepromer/README.eepromer +++ /dev/null @@ -1,27 +0,0 @@ -Simple program for storing data to I2C EEPROM. - -!!!!!!!!!!!!!!!!!!!!!!!!Warning!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - -The EEPROM must be a large EEPROM which uses a 2-byte address -field (24C32 or larger). It will NOT WORK on small EEPROMs -(24C01 - 24C16) such as those used on SDRAM DIMMs. - -Tested only on 24C256. - -!!!!!!!!!!!!!!!!!!!!!!!!Warning!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - -This program is intended for use on eeproms using external busses such as -i2c-pport. -Do not use this on your SDRAM DIMM EEPROMS, it won't work!!!!!!!!! -Doing so will render your SDRAM USELESS and leave your system UNBOOTABLE!!! - -!!!!!!!!!!!!!!!!!!!!!!!!Warning!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - -Options: - -r read - -w write - -e erase - -p print "super block of EEPROM" (date and size stored data) - -Daniel Smolik -marvin@sitour.cz diff --git a/prog/eepromer/eeprog.c b/prog/eepromer/eeprog.c deleted file mode 100644 index 95579b6f..00000000 --- a/prog/eepromer/eeprog.c +++ /dev/null @@ -1,283 +0,0 @@ -/*************************************************************************** - copyright : (C) by 2002-2003 Stefano Barbato - email : stefano@codesink.org - - $Id$ - ***************************************************************************/ - -/*************************************************************************** - * * - * This program is free software; you can redistribute it and/or modify * - * it under the terms of the GNU General Public License as published by * - * the Free Software Foundation; either version 2 of the License, or * - * (at your option) any later version. * - * * - ***************************************************************************/ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "24cXX.h" - -#define VERSION "0.7.5" - -#define ENV_DEV "EEPROG_DEV" -#define ENV_I2C_ADDR "EEPROG_I2C_ADDR" - -int g_quiet; - -#define usage_if(a) do { do_usage_if( a , __LINE__); } while(0); -void do_usage_if(int b, int line) -{ - static const char *eeprog_usage = -"eeprog " VERSION ", a 24Cxx EEPROM reader/writer\n" -"Copyright (c) 2003 by Stefano Barbato - All rights reserved.\n" -"Usage: eeprog [-fqxdh] [-16|-8] [ -r addr[:count] | -w addr ] /dev/i2c-N i2c-address\n" -"\n" -" Address modes:\n" -" -8 Use 8bit address mode for 24c0x...24C16 [default]\n" -" -16 Use 16bit address mode for 24c32...24C256\n" -" Actions:\n" -" -r addr[:count] Read [count] (1 if omitted) bytes from [addr]\n" -" and print them to the standard output\n" -" -w addr Write input (stdin) at address [addr] of the EEPROM\n" -" -h Print this help\n" -" Options:\n" -" -x Set hex output mode\n" -" -d Dummy mode, display what *would* have been done\n" -" -f Disable warnings and don't ask confirmation\n" -" -q Quiet mode\n" -"\n" -"The following environment variables could be set instead of the command\n" -"line arguments:\n" -" EEPROG_DEV device name(/dev/i2c-N)\n" -" EEPROG_I2C_ADDR i2c-address\n" -"\n" -" Examples\n" -" 1- read 64 bytes from the EEPROM at address 0x54 on bus 0 starting\n" -" at address 123 (decimal)\n" -" eeprog /dev/i2c-0 0x54 -r 123:64\n" -" 2- prints the hex codes of the first 32 bytes read from bus 1\n" -" at address 0x22\n" -" eeprog /dev/i2c-1 0x51 -x -r 0x22:0x20\n" -" 3- write the current timestamp at address 0x200 of the EEPROM on\n" -" bus 0 at address 0x33\n" -" date | eeprog /dev/i2c-0 0x33 -w 0x200\n"; - - if(!b) - return; - fprintf(stderr, "%s\n[line %d]\n", eeprog_usage, line); - exit(1); -} - - -#define die_if(a, msg) do { do_die_if( a , msg, __LINE__); } while(0); -void do_die_if(int b, char* msg, int line) -{ - if(!b) - return; - fprintf(stderr, "Error at line %d: %s\n", line, msg); - //fprintf(stderr, " sysmsg: %s\n", strerror(errno)); - exit(1); -} - -#define print_info(args...) do { if(!g_quiet) fprintf(stderr, args); } while(0); - -void parse_arg(char *arg, int* paddr, int *psize) -{ - char *end; - *paddr = strtoul(arg, &end, 0); - if(*end == ':') - *psize = strtoul(++end, 0, 0); -} - -int confirm_action() -{ - fprintf(stderr, - "\n" - "____________________________WARNING____________________________\n" - "Erroneously writing to a system EEPROM (like DIMM SPD modules)\n" - "can break your system. It will NOT boot anymore so you'll not\n" - "be able to fix it.\n" - "\n" - "Reading from 8bit EEPROMs (like that in your DIMM) without using\n" - "the -8 switch can also UNEXPECTEDLY write to them, so be sure to\n" - "use the -8 command param when required.\n" - "\n" - "Use -f to disable this warning message\n" - "\n" - "Press ENTER to continue or hit CTRL-C to exit\n" - "\n" - ); - getchar(); - return 1; -} - - -int read_from_eeprom(struct eeprom *e, int addr, int size, int hex) -{ - - int ch, i; - // hex print out - die_if((ch = eeprom_read_byte(e, addr)) < 0, "read error"); - i = 1; - if(hex) - printf("\n %.4x| %.2x ", addr, ch); - else - putchar(ch); - while(--size) - { - die_if((ch = eeprom_read_current_byte(e)) < 0, "read error"); - if(hex) - { - addr++; - if( (i % 16) == 0 ) - printf("\n %.4x| ", addr); - else if( (i % 8) == 0 ) - printf(" "); - i++; - printf("%.2x ", ch); - } else { - putchar(ch); - } - } - if(hex) - printf("\n\n"); - fflush(stdout); - return 0; -} - -int write_to_eeprom(struct eeprom *e, int addr) -{ - int c; - while((c = getchar()) != EOF) - { - print_info("."); - fflush(stdout); - die_if(eeprom_write_byte(e, addr++, c), "write error"); - } - print_info("\n\n"); - return 0; -} - -int main(int argc, char** argv) -{ - struct eeprom e; - int ret, op, i2c_addr, memaddr, size, want_hex, dummy, force, sixteen; - char *device, *arg = 0, *i2c_addr_s; - struct stat st; - int eeprom_type = 0; - - op = want_hex = dummy = force = sixteen = 0; - g_quiet = 0; - - while((ret = getopt(argc, argv, "1:8fr:qhw:xd")) != -1) - { - switch(ret) - { - case '1': - usage_if(*optarg != '6' || strlen(optarg) != 1); - die_if(eeprom_type, "EEPROM type switch (-8 or -16) used twice"); - eeprom_type = EEPROM_TYPE_16BIT_ADDR; - break; - case 'x': - want_hex++; - break; - case 'd': - dummy++; - break; - case '8': - die_if(eeprom_type, "EEPROM type switch (-8 or -16) used twice"); - eeprom_type = EEPROM_TYPE_8BIT_ADDR; - break; - case 'f': - force++; - break; - case 'q': - g_quiet++; - break; - case 'h': - usage_if(1); - break; - default: - die_if(op != 0, "Both read and write requested"); - arg = optarg; - op = ret; - } - } - if(!eeprom_type) - eeprom_type = EEPROM_TYPE_8BIT_ADDR; // default - - usage_if(op == 0); // no switches - // set device and i2c_addr reading from cmdline or env - device = i2c_addr_s = 0; - switch(argc - optind) - { - case 0: - device = getenv(ENV_DEV); - i2c_addr_s = getenv(ENV_I2C_ADDR); - break; - case 1: - if(stat(argv[optind], &st) != -1) - { - device = argv[optind]; - i2c_addr_s = getenv(ENV_I2C_ADDR); - } else { - device = getenv(ENV_DEV); - i2c_addr_s = argv[optind]; - } - break; - case 2: - device = argv[optind++]; - i2c_addr_s = argv[optind]; - break; - default: - usage_if(1); - } - usage_if(!device || !i2c_addr_s); - i2c_addr = strtoul(i2c_addr_s, 0, 0); - - print_info("eeprog %s, a 24Cxx EEPROM reader/writer\n", VERSION); - print_info("Copyright (c) 2003 by Stefano Barbato - All rights reserved.\n"); - print_info(" Bus: %s, Address: 0x%x, Mode: %dbit\n", - device, i2c_addr, - (eeprom_type == EEPROM_TYPE_8BIT_ADDR ? 8 : 16) ); - if(dummy) - { - fprintf(stderr, "Dummy mode selected, nothing done.\n"); - return 0; - } - die_if(eeprom_open(device, i2c_addr, eeprom_type, &e) < 0, - "unable to open eeprom device file (check that the file exists and that it's readable)"); - switch(op) - { - case 'r': - if(force == 0) - confirm_action(); - size = 1; // default - parse_arg(arg, &memaddr, &size); - print_info(" Reading %d bytes from 0x%x\n", size, memaddr); - read_from_eeprom(&e, memaddr, size, want_hex); - break; - case 'w': - if(force == 0) - confirm_action(); - parse_arg(arg, &memaddr, &size); - print_info(" Writing stdin starting at address 0x%x\n", - memaddr); - write_to_eeprom(&e, memaddr); - break; - default: - usage_if(1); - exit(1); - } - eeprom_close(&e); - - return 0; -} - diff --git a/prog/eepromer/eeprom.c b/prog/eepromer/eeprom.c deleted file mode 100644 index f72b0085..00000000 --- a/prog/eepromer/eeprom.c +++ /dev/null @@ -1,297 +0,0 @@ -/* -This program is hereby placed into the public domain. -Of course the program is provided without warranty of any kind. -*/ -#include -#include -#include -#include -#include -#include -#include -#include "i2c-dev.h" - -/* - this program can read 24C16 (and probably smaller ones, too) - I wrote it as a quick and dirty hack because my satellite receiver - hung again... so I had to reprogram the eeprom where is stores it's - settings. - */ - -#define DEFAULT_I2C_BUS "/dev/i2c-0" -#define DEFAULT_EEPROM_ADDR 0x50 /* the 24C16 sits on i2c address 0x50 */ -#define DEFAULT_NUM_PAGES 8 /* we default to a 24C16 eeprom which has 8 pages */ -#define BYTES_PER_PAGE 256 /* one eeprom page is 256 byte */ -#define MAX_BYTES 8 /* max number of bytes to write in one chunk */ - /* ... note: 24C02 and 24C01 only allow 8 bytes to be written in one chunk. * - * if you are going to write 24C04,8,16 you can change this to 16 */ - -/* write len bytes (stored in buf) to eeprom at address addr, page-offset offset */ -/* if len=0 (buf may be NULL in this case) you can reposition the eeprom's read-pointer */ -/* return 0 on success, -1 on failure */ -int eeprom_write(int fd, - unsigned int addr, - unsigned int offset, - unsigned char *buf, - unsigned char len -){ - struct i2c_rdwr_ioctl_data msg_rdwr; - struct i2c_msg i2cmsg; - int i; - char _buf[MAX_BYTES + 1]; - - if(len>MAX_BYTES){ - fprintf(stderr,"I can only write MAX_BYTES bytes at a time!\n"); - return -1; - } - - if(len+offset >256){ - fprintf(stderr,"Sorry, len(%d)+offset(%d) > 256 (page boundary)\n", - len,offset); - return -1; - } - - _buf[0]=offset; /* _buf[0] is the offset into the eeprom page! */ - for(i=0;i _buf[1..n+1] */ - _buf[1+i]=buf[i]; - - msg_rdwr.msgs = &i2cmsg; - msg_rdwr.nmsgs = 1; - - i2cmsg.addr = addr; - i2cmsg.flags = 0; - i2cmsg.len = 1+len; - i2cmsg.buf = _buf; - - if((i=ioctl(fd,I2C_RDWR,&msg_rdwr))<0){ - perror("ioctl()"); - fprintf(stderr,"ioctl returned %d\n",i); - return -1; - } - - if(len>0) - fprintf(stderr,"Wrote %d bytes to eeprom at 0x%02x, offset %08x\n", - len,addr,offset); - else - fprintf(stderr,"Positioned pointer in eeprom at 0x%02x to offset %08x\n", - addr,offset); - - return 0; -} - -/* read len bytes stored in eeprom at address addr, offset offset in array buf */ -/* return -1 on error, 0 on success */ -int eeprom_read(int fd, - unsigned int addr, - unsigned int offset, - unsigned char *buf, - unsigned char len -){ - struct i2c_rdwr_ioctl_data msg_rdwr; - struct i2c_msg i2cmsg; - int i; - - if(len>MAX_BYTES){ - fprintf(stderr,"I can only write MAX_BYTES bytes at a time!\n"); - return -1; - } - - if(eeprom_write(fd,addr,offset,NULL,0)<0) - return -1; - - msg_rdwr.msgs = &i2cmsg; - msg_rdwr.nmsgs = 1; - - i2cmsg.addr = addr; - i2cmsg.flags = I2C_M_RD; - i2cmsg.len = len; - i2cmsg.buf = buf; - - if((i=ioctl(fd,I2C_RDWR,&msg_rdwr))<0){ - perror("ioctl()"); - fprintf(stderr,"ioctl returned %d\n",i); - return -1; - } - - fprintf(stderr,"Read %d bytes from eeprom at 0x%02x, offset %08x\n", - len,addr,offset); - - return 0; -} - - - -int main(int argc, char **argv){ - int i,j; - - /* filedescriptor and name of device */ - int d; - char *dn=DEFAULT_I2C_BUS; - - /* filedescriptor and name of data file */ - int f=-1; - char *fn=NULL; - - unsigned int addr=DEFAULT_EEPROM_ADDR; - int rwmode=0; - int pages=DEFAULT_NUM_PAGES; - - int force=0; /* suppress warning on write! */ - - while((i=getopt(argc,argv,"d:a:p:wyf:h"))>=0){ - switch(i){ - case 'h': - fprintf(stderr,"%s [-d dev] [-a adr] [-p pgs] [-w] [-y] [-f file]\n",argv[0]); - fprintf(stderr,"\tdev: device, e.g. /dev/i2c-0 (def)\n"); - fprintf(stderr,"\tadr: base address of eeprom, eg 0xA0 (def)\n"); - fprintf(stderr,"\tpgs: number of pages to read, eg 8 (def)\n"); - fprintf(stderr,"\t-w : write to eeprom (default is reading!)\n"); - fprintf(stderr,"\t-y : suppress warning when writing (default is to warn!)\n"); - fprintf(stderr,"\t-f file: copy eeprom contents to/from file\n"); - fprintf(stderr,"\t (default for read is test only; for write is all zeros)\n"); - fprintf(stderr,"Note on pages/addresses:\n"); - fprintf(stderr,"\teeproms with more than 256 byte appear as if they\n"); - fprintf(stderr,"\twere several eeproms with consecutive addresses on the bus\n"); - fprintf(stderr,"\tso we might as well address several separate eeproms with\n"); - fprintf(stderr,"\tincreasing addresses....\n\n"); - exit(1); - break; - case 'd': - dn=optarg; - break; - case 'a': - if(sscanf(optarg,"0x%x",&addr)!=1){ - fprintf(stderr,"Cannot parse '%s' as addrs., example: 0xa0\n", - optarg); - exit(1); - } - break; - case 'p': - if(sscanf(optarg,"%d",&pages)!=1){ - fprintf(stderr,"Cannot parse '%s' as number of pages, example: 8\n", - optarg); - exit(1); - } - break; - case 'w': - rwmode++; - break; - case 'f': - fn=optarg; - break; - case 'y': - force++; - break; - } - - } - - fprintf(stderr,"base-address of eeproms : 0x%02x\n",addr); - fprintf(stderr,"number of pages to read : %d (0x%02x .. 0x%02x)\n", - pages,addr,addr+pages-1); - - if(fn){ - if(!rwmode) /* if we are reading, *WRITE* to file */ - f=open(fn,O_WRONLY|O_CREAT,0666); - else /* if we are writing to eeprom, *READ* from file */ - f=open(fn,O_RDONLY); - if(f<0){ - fprintf(stderr,"Could not open data-file %s for reading or writing\n",fn); - perror(fn); - exit(1); - } - fprintf(stderr,"file opened for %7s : %s\n",rwmode?"reading":"writing",fn); - fprintf(stderr," on filedescriptor : %d\n",f); - } - - if((d=open(dn,O_RDWR))<0){ - fprintf(stderr,"Could not open i2c at %s\n",dn); - perror(dn); - exit(1); - } - - fprintf(stderr,"i2c-devicenode is : %s\n",dn); - fprintf(stderr," on filedescriptor : %d\n\n",d); - - /*** - *** I'm not the one to blame of you screw your computer! - ***/ - if(rwmode && ! force){ - unsigned char warnbuf[4]; - fprintf(stderr,"**WARNING**\n"); - fprintf(stderr," - \tYou have chosen to WRITE to this eeprom.\n"); - fprintf(stderr,"\tMake sure that this tiny chip is *NOT* vital to the\n"); - fprintf(stderr,"\toperation of your computer as you can easily corrupt\n"); - fprintf(stderr,"\tthe configuration memory of your SDRAM-memory-module,\n"); - fprintf(stderr,"\tyour IBM ThinkPad or whatnot...! Fixing these errors can be\n"); - fprintf(stderr,"\ta time-consuming and very costly process!\n\n"); - fprintf(stderr,"Things to consider:\n"); - fprintf(stderr," - \tYou can have more than one i2c-bus, check in /proc/bus/i2c\n"); - fprintf(stderr,"\tand specify the correct one with -d\n"); - fprintf(stderr,"\tright now you have chosen to use '%s'\n",dn); - fprintf(stderr," - \tA eeprom can occupy several i2c-addresses (one per page)\n"); - fprintf(stderr,"\tso please make sure that there is no vital eeprom in your computer\n"); - fprintf(stderr,"\tsitting at addresses between 0x%02x and 0x%02x\n",addr,addr+pages-1); - - fprintf(stderr,"Enter 'yes' to continue:"); - fflush(stderr); - if(!fgets(warnbuf,sizeof(warnbuf),stdin)){ - fprintf(stderr,"\nCould not read confirmation from stdin!\n"); - exit(1); - } - if(strncmp(warnbuf,"yes",3)){ - fprintf(stderr,"\n** ABORTING WRITE! **, you did not answer 'yes'\n"); - exit(1); - } - } - - for(i=0;i=0){ - j=read(f,buf,sizeof(buf)); - if(j<0){ - fprintf(stderr,"Cannot read from file '%s'\n",fn); - perror(fn); - exit(1); - } - if(j!=sizeof(buf)){ - fprintf(stderr,"File '%s' is too small, padding eeprom with zeroes\n",fn); - while(j=0){ - j=write(f,buf,sizeof(buf)); - if(j!=sizeof(buf)){ - fprintf(stderr,"Cannot write to file '%s'\n",fn); - perror(fn); - exit(1); - } - } - - } - - if(f>=0) - close(f); - - close(d); - - exit(0); - -} diff --git a/prog/eepromer/eepromer.c b/prog/eepromer/eepromer.c deleted file mode 100644 index 8273b26c..00000000 --- a/prog/eepromer/eepromer.c +++ /dev/null @@ -1,718 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include "i2c-dev.h" - - -#define MAX_BLK_SIZE 64 -#define EEPROM_SIZE 32768 -#define READ 1 -#define WRITE 0 -#define ERASE 2 -#define PHEADER 3 -#define VER "eepromer v 0.4 (c) Daniel Smolik 2001\n" -#define HEAD_SIZE sizeof(struct mini_inode) -#define START_ADDR 0 -#define FORCE 1 -/* -To disable startup warning #undef WARNINC - - -*/ - -#define WARNINC - - -int block_write(int file,int dev_addr,int eeprom_addr,unsigned char *buf,int lenght);int block_write(int file,int dev_addr,int eeprom_addr,unsigned char *buf,int lenght); -int block_read(int file,int dev_addr,int eeprom_addr,unsigned char *buf); - -/* block_read read block 64 bytes length and returns actual length of data*/ -void help(void); -int init(char *device,int addr); -int content_write(int file, int addr); -int content_read(int file, int addr); -int inode_write(int file, int dev_addr, int lenght); -int inode_read(int file, int dev_addr, void *p_inode); -void pheader(int file, int addr); -void erase(int file,int addr,int eeprom_size); -void made_address(int addr,unsigned char *buf); -void warn(void); -void bar(void); - - -static int stav=0; - - - -static struct mini_inode { - - time_t timestamp; - int data_len; - char data[56]; - - } m_ind,*p_ind; - - - -void help(void) -{ - FILE *fptr; - char s[100]; - - fprintf(stderr,"Syntax: eepromer [-r|-w|-e|-p] -f /dev/i2c-X ADDRESS \n\n"); - fprintf(stderr," ADDRESS is address of i2c device eg. 0x51\n"); - - if((fptr = fopen("/proc/bus/i2c", "r"))) { - fprintf(stderr," Installed I2C busses:\n"); - while(fgets(s, 100, fptr)) - fprintf(stderr, " %s", s); - fclose(fptr); - } -} - - - - - -int main(int argc, char *argv[]){ - - int i, file, addr; - int action; //in this variable will be (-r,-w,-e) - char device[45]; - int force; - - p_ind=&m_ind; - force=0; - - - - - for(i=1; i < argc;i++){ - - - if(!strcmp("-r",argv[i])) { - action=READ; - break; - } - if(!strcmp("-e",argv[i])) { - action=ERASE; - break; - } - if(!strcmp("-w",argv[i])) { - action=WRITE; - break; - } - if(!strcmp("-p",argv[i])) { - action=PHEADER; - break; - } - if(!strcmp("-force",argv[i])) { - force=FORCE; - break; - } - if(!strcmp("-v",argv[i])) { - fprintf(stderr,VER); - exit(0); - break; - } - else { - - fprintf(stderr,"Error: No action specified !\n"); - help(); - exit(1); - } - - } - - -#ifdef WARNINC - - if(force!=FORCE) warn(); - -#endif - - - if(argc < 5) { - fprintf(stderr,"Error: No i2c address specified !\n"); - help(); - exit(1); - - } - - - for(i=1; i < argc;i++){ - - - if(!strcmp("-f",argv[i])) { - strcpy(device,argv[i+1]); - break; - } - - } - - if(!strlen(device)) { - - fprintf(stderr,"Error: No device specified !\n"); - help(); - exit(1); - } - - - if(! (addr=strtol(argv[4],NULL,16))) { - - fprintf(stderr,"Error: Bad device address !\n"); - help(); - exit(1); - } - - if(! (file=init(device,addr))){ - - fprintf(stderr,"Error: Init failed !\n"); - exit(1); - } - - - switch(action){ - - case READ: - content_read(file,addr); - break; - - case WRITE: - content_write(file,addr); - break; - - case ERASE: erase(file,addr,EEPROM_SIZE); - break; - case PHEADER: pheader(file,addr); - break; - - default: - fprintf(stderr,"Internal error!\n"); - exit(1); break; - - } - - - close(file); - exit(0); - -} - - - -/****************************************************************************/ -/* Low level function */ -/* */ -/****************************************************************************/ - - - - - -int block_write(int file,int dev_addr,int eeprom_addr,unsigned char *buf,int lenght){ - - unsigned char buff[2]; - struct i2c_msg msg[2]; - - struct i2c_ioctl_rdwr_data { - - struct i2c_msg *msgs; /* ptr to array of simple messages */ - int nmsgs; /* number of messages to exchange */ - } msgst; - - - - if ( lenght > (MAX_BLK_SIZE) ) { - - fprintf(stderr, - "Error: Block too large:\n"); - - } - - - //bar(); - - made_address(eeprom_addr,buff); - - - msg[0].addr = dev_addr; - msg[0].flags = 0; - msg[0].len = 2; - msg[0].buf = buff; - - - msg[1].addr = dev_addr; - msg[1].flags = I2C_M_NOSTART; - msg[1].len = lenght; - msg[1].buf = buf; - - - msgst.msgs = msg; - msgst.nmsgs = 2; - - - if (ioctl(file,I2C_RDWR,&msgst) < 0){ - - fprintf(stderr, - "Error: Transaction failed: %s\n", - strerror(errno)); - - return 1; - - } - - return 0; - -} - - - - -int block_read(int file,int dev_addr,int eeprom_addr,unsigned char *buf){ - - int ln; - char buff[2]; //={0x0,0x0}; - - struct i2c_msg msg[2]; - - struct i2c_ioctl_rdwr_data { - - struct i2c_msg *msgs; /* ptr to array of simple messages */ - int nmsgs; /* number of messages to exchange */ - } msgst; - - - - made_address(eeprom_addr,buff); - ln=0; - //bar(); - - msg[0].addr = dev_addr; - msg[0].flags = 0; - msg[0].len = 2; - msg[0].buf = buff; - - - msg[1].addr = dev_addr; - msg[1].flags = I2C_M_RD; - msg[1].len = MAX_BLK_SIZE; - msg[1].buf = buf; - - - - - msgst.msgs = msg; - msgst.nmsgs = 2; - - - - - if ((ln = ioctl(file, I2C_RDWR, &msgst)) < 0) { - - fprintf(stderr, - "Error: Read error:%d\n",ln); - return ln; - } - - return ln; - -} - - - - - - - - - - - - - - - - -void made_address(int addr,unsigned char *buf){ - - int k; - - //addr = addr & 0xFFFF; /*odstranim nepoterbne bity*/ - - k=addr; - buf[1]=(unsigned char) (k & 0xFF); //vyrobim druhy byte adresy - k=addr & 0xFF00 ; - buf[0]= ((unsigned char) (k >> 8)) & 0x7F; - - - return; -} - - -int init(char *device,int addr) { - - int file; - unsigned long funcs; - - if ((file = open(device,O_RDWR)) < 0) { - - fprintf(stderr,"Error: Could not open file %s\n", - device); - - return 0; - } - - - /* check adapter functionality */ - if (ioctl(file,I2C_FUNCS,&funcs) < 0) { - fprintf(stderr, - "Error: Could not get the adapter functionality matrix: %s\n", - strerror(errno)); - close(file); - return 0; - } - - /* The I2C address */ - if (ioctl(file,I2C_SLAVE,addr) < 0) { - /* ERROR HANDLING; you can check errno to see what went wrong */ - fprintf(stderr, - "Error: Cannot communicate with slave: %s\n", - strerror(errno)); - - close(file); - return 0; - } - - return file; -} - - -int content_write(int file, int addr){ - - unsigned char buf[MAX_BLK_SIZE]; - unsigned char pom; - int i, j, k, delka, addr_cnt; - - delka=0; - addr_cnt=HEAD_SIZE; - k=0; - - for(j=0;j<=MAX_BLK_SIZE;j++)buf[j]=0; - - - - i=0; - - for(;;) { - - delka=fread(&pom,1,1,stdin); - - if( delka > 0 ){ - buf[i]=pom; - } - - if(i==(MAX_BLK_SIZE-1) || (delka < 1)) { - - - - if(block_write(file,addr,addr_cnt,buf,delka<1?i:(i+1)) !=0) { - - fprintf(stderr,"Block write failed\n"); - return 1; - - } - //printf("i:%d\n",i); - addr_cnt=addr_cnt + i + (delka==1?1:0); //+i - - for(j=0;j<=MAX_BLK_SIZE;j++)buf[j]=0; - - i=0; - if(delka<1) { - - //pisu EOF - - - if(inode_write(file,addr,(addr_cnt-HEAD_SIZE)) !=0) { - - fprintf(stderr,"Inode write failed\n"); - return 1; - - } - break; - } - - - } else i++; - - } - - return 0; - -} - - -int content_read(int file, int addr){ - - unsigned char buf[MAX_BLK_SIZE]; - int i, j, k, delka; - - delka=0; - k=0; - - - inode_read(file,addr,p_ind ); - - - for(i=HEAD_SIZE;i<= (HEAD_SIZE + p_ind->data_len);i=i+MAX_BLK_SIZE ) { - - - if(block_read(file,addr,i,buf) !=0) { - - fprintf(stderr,"Block read failed\n"); - return 1; - - } - - if( (HEAD_SIZE + p_ind->data_len - i) < MAX_BLK_SIZE ) { - k= HEAD_SIZE + p_ind->data_len - i; - }else { - k=MAX_BLK_SIZE; - } - - - for(j=0;j 70 ) stav=0; - - - switch(stav) { - - - case 10: fwrite("\\",1,1,stderr); - fflush(stderr); - rewind(stderr); - break; - case 20: fwrite("|",1,1,stderr); - fflush(stderr); - rewind(stderr); - break; - case 30: fwrite("/",1,1,stderr); - fflush(stderr); - rewind(stderr); - break; - case 40: fwrite("-",1,1,stderr); - fflush(stderr); - rewind(stderr); - break; - case 50: fwrite("\\",1,1,stderr); - fflush(stderr); - rewind(stderr); - break; - case 60: fwrite("|",1,1,stderr); - fflush(stderr); - rewind(stderr); - break; - case 70: fwrite("/",1,1,stderr); - fflush(stderr); - rewind(stderr); - break; - } - stav++; - -} - - - - - -int inode_write(int file,int dev_addr,int lenght){ - - unsigned char buff[2]; - struct i2c_msg msg[2]; - - struct i2c_ioctl_rdwr_data { - - struct i2c_msg *msgs; /* ptr to array of simple messages */ - int nmsgs; /* number of messages to exchange */ - } msgst; - - - m_ind.timestamp=time(NULL); - m_ind.data_len=lenght; - - - - - - //bar(); - - made_address(START_ADDR,buff); - - - msg[0].addr = dev_addr; - msg[0].flags = 0; - msg[0].len = 2; - msg[0].buf = buff; - - - msg[1].addr = dev_addr; - msg[1].flags = I2C_M_NOSTART; - msg[1].len = sizeof(struct mini_inode); - msg[1].buf = (char *) &m_ind; - - - - msgst.msgs = msg; - msgst.nmsgs = 2; - - - if (ioctl(file,I2C_RDWR,&msgst) < 0){ - - fprintf(stderr, - "Error: Transaction failed: %s\n", - strerror(errno)); - - return 1; - - } - - return 0; - -} - - - -int inode_read(int file,int dev_addr,void *p_inode ){ - - - #define POK 32 - int ln; - char buff[2]; //={0x0,0x0}; - - struct i2c_msg msg[2]; - - struct i2c_ioctl_rdwr_data { - - struct i2c_msg *msgs; /* ptr to array of simple messages */ - int nmsgs; /* number of messages to exchange */ - } msgst; - - made_address(START_ADDR,buff); - - ln=0; - //bar(); - - msg[0].addr = dev_addr; - msg[0].flags = 0; - msg[0].len = 2; - msg[0].buf = buff; - - - msg[1].addr = dev_addr; - msg[1].flags = I2C_M_RD; - msg[1].len = sizeof(struct mini_inode); - msg[1].buf = p_inode; - - - - - msgst.msgs = msg; - msgst.nmsgs = 2; - - - if ((ln = ioctl(file, I2C_RDWR, &msgst)) < 0) { - - fprintf(stderr, - "Error: Read error:%d\n",ln); - return ln; - } - - - - return ln; - -} - - -void pheader(int file,int dev_addr){ - - struct tm *p_tm; - char time_buf[15],*p_buf; - - p_buf=time_buf; - inode_read(file,dev_addr,p_ind ); - p_tm=localtime(&p_ind->timestamp); - strftime(p_buf,sizeof(time_buf),"%Y%m%d%H%M%S",p_tm); - printf("LEN=%d,TIME=%s\n",p_ind->data_len,p_buf); - return; -} - - - - -#ifdef WARNINC -void warn(void) -{ - - fprintf(stderr,"\n\n!!!!!!!!!!!!!!!!!!!!!WARNING!!!!!!!!!!!!!!!!!!!!!\n"); - fprintf(stderr,"This program is intended for use on eeproms\nusing external busses such as i2c-pport.\n"); - fprintf(stderr,"Do not use this on your SDRAM DIMM EEPROMS\nunless you REALLY REALLY know what you are\ndoing!!! Doing so will render your SDRAM\nUSELESS and leave your system UNBOOTABLE!!!\n"); - fprintf(stderr,"To disable this warning use -force\n"); - fprintf(stderr,"\n\nPress ENTER to continue or hit Control-C NOW !!!!\n\n\n"); - - getchar(); -} -#endif diff --git a/prog/hotplug/Makefile b/prog/hotplug/Makefile deleted file mode 100644 index 1aa4b896..00000000 --- a/prog/hotplug/Makefile +++ /dev/null @@ -1,24 +0,0 @@ -INCLUDEDIR = /usr/include - -# Compile with Debugging turned on - watch out, lots of pci device infos. -CFLAGS = -D__KERNEL__ -DMODULE -DLINUX -DM7101_DEBUG -O2 -Wall -I$(INCLUDEDIR) -# CFLAGS := -D__KERNEL__ -DMODULE -DLINUX -O2 -Wall -I$(INCLUDEDIR) - -CC := gcc -LD := ld - -# extract versionnumber from version.h -VER = $(shell awk -F\" '/REL/ {print $$2}' $(INCLUDEDIR)/linux/version.h) - -OBJS = m7101.o - -all: $(OBJS) - -%.o: %.c - $(CC) $(CFLAGS) -c $< -o $@ - -install: all - install -m 644 $(OBJS) /lib/modules/$(VER)/kernel/drivers/i2c/busses - -clean: - rm -f $(OBJS) diff --git a/prog/hotplug/Makefile.p4b b/prog/hotplug/Makefile.p4b deleted file mode 100644 index 42242597..00000000 --- a/prog/hotplug/Makefile.p4b +++ /dev/null @@ -1,64 +0,0 @@ -# pcwd Kernel Module Makefile -# - -VERSION=1.40 - -# The currently running kernel version. This is used right below to -# determine where the kernel sources can be found. -KERNELVERSION := $(shell uname -r) - -# The location of linux itself. This is used to find the kernel headers -# and other things. -#LINUX := /usr/src/linux -LINUX := /lib/modules/$(KERNELVERSION)/build -LINUX_HEADERS := $(LINUX)/include - -# Uncomment the third line on SMP systems if the magic invocation fails. It -# is a bit complicated because SMP configuration changed around kernel 2.1.130 -SMP := $(shell if grep -q '^SMP[[:space:]]*=' $(LINUX)/Makefile || \ - grep -q '^[[:space:]]*\#define[[:space:]]*CONFIG_SMP[[:space:]]*1' $(LINUX_HEADERS)/linux/autoconf.h ; \ - then echo 1; else echo 0; fi) -#SMP := 0 -#SMP := 1 - -# Uncomment the second or third line if the magic invocation fails. -# We need to know whether CONFIG_MODVERSIONS is defined. -MODVER := $(shell if cat $(LINUX_HEADERS)/linux/config.h $(LINUX_HEADERS)/linux/autoconf.h 2>/dev/null | grep -q '^[[:space:]]*\#define[[:space:]]*CONFIG_MODVERSIONS[[:space:]]*1'; then echo 1; else echo 0; fi) -#MODVER := 0 -#MODVER := 1 - -MODCPPFLAGS := - -ifeq ($(SMP),1) -MODCPPFLAGS += -D__SMP__ -endif - -ifeq ($(MODVER),1) -MODCPPFLAGS += -DMODVERSIONS -include $(LINUX_HEADERS)/linux/modversions.h -endif - -CFLAGS := $(MODCPPFLAGS) -D__KERNEL__ -DMODULE -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer -fno-strict-aliasing -I$(LINUX_HEADERS) - -OBJS = p4b_smbus.o - -all: $(OBJS) - -install: all - install -d /lib/modules/$(KERNELVERSION)/kernel/drivers/i2c/busses - install -c p4b_smbus.o /lib/modules/$(KERNELVERSION)/kernel/drivers/i2c/busses -# test ! -x /dev/watchdog || mknod -m 600 /dev/watchdog c 10 130 -# test ! -x /dev/temperature || mknod -m 600 /dev/temperature c 10 131 - -inst: all - rmmod p4b_smbus - install -d /lib/modules/$(KERNELVERSION)/kernel/drivers/i2c/busses - install -c p4b_smbus.o /lib/modules/$(KERNEL)/kernel/drivers/i2c/busses - depmod -a -# modprobe p4b_smbus - -clean: - rm -f *.o *~ core - -cleandist: - rm -f *.o *~ core - diff --git a/prog/hotplug/README b/prog/hotplug/README deleted file mode 100644 index d0f9d7ca..00000000 --- a/prog/hotplug/README +++ /dev/null @@ -1,112 +0,0 @@ -Files in this directory: - -* m7101.c - M7101 - SMBus Support for ALi M15x3 based motherboards. - -* README.p4b - More detailed information for files below. - -* p4b_smbus.c - 2.4 Kernel module which unhides the bus for ASUS boards. - -* unhide_ICH_SMBus - Script which unhides the bus for 2.6 kernel. - --------------------------------------------------------- -Quick Start (2.4 kernels only): - - Verify that hotplug is enabled in your kernel (general setup) - and reconfigure/rebuild/reinstall kernel if not - "lspci" to verify that 7101 device is not present - "make" - (as root) "make install" - (as root) "insmod m7101" - "lspci" to verify that 7101 device is present - --------------------------------------------------------- --------------------------------------------------------- - -Version 0.2 for 2.4.0-testx kernels. -Mark D. Studebaker - -*** You must have 'Support for hot-pluggable devices' enabled -*** in your kernel (under 'general setup') for this module to work!! - -For 2.2 and early 2.3 kernels you must use version 0.1; -version 0.2 will not work. -Version 0.1 does not use the kernel hotplug facility. - --------------------------------------------------------- -Notes below for the 0.2 version, MDS. --------------------------------------------------------- -Default I/O addresses are 0xe800 for SMBus and 0xec00 for ACPI. - -These can be changed at module insertion. -For example: - insmod m7101 smb_io=0x5000 acpi_io=0x4000 - - --------------------------------------------------------- -Notes below from the 0.1 version, B. Kohl. --------------------------------------------------------- - -This module was written to enable SMBus support on ALi M15x3 chipset based -motherboards. Although it was written for and tested on Gigabytes GA-5AX -it should work on any M15x3 chipset based board. - -Probably most people trying this software on a GA-5AX will be utterly -disappointed. We have seen no sensor chips on this board - only DIMMs -were connected to the SMBus. If you are trying to make lm_sensors read -temperature and voltage values you will be pretty lost. - -CAVEAT: To perform it's task this module needs to manipulate PCI-config -data and device structures on a very low level. This bears the risk of -causing havoc to your system in case anything goes wrong. Use this soft- -ware absolutely at your own risk. - - -Installation: -Untar the m7101.tgz file into an appropriate location and cd into the -m7101 subdirectory. Then type "make" to build the module file 'm7101.o'. -To insert it type - $ insmod m7101.o -as root. - -If everything goes well (no error messages) you will see a description like -the following when doing 'lspci -v': - -00:03.0 Non-VGA unclassified device: Acer Laboratories Inc. [ALi] M7101 PMU - Flags: medium devsel - I/O ports at 4000 - I/O ports at 5000 - -and find an entry in the proc filesystem under /proc/bus/pci/00/03.0. - - -Removing the module removes the M7101 device from the proc file system -and switches the SMBus support off. - -The lm_sensors software now should be able to access devices on the -motherboard's SMBus through the M7101. - -Values for the ACPI-IO port (normally 0x4000) and the SMBus-IO port -(normally 0x5000) can be specified using the parameters acpi_io and -smbus_io respectively on the insmod command line. -The module defaults to ports 0xec00 and 0xe800. - -In case the module does not load you might want to switch on debugging -by uncommenting the second CFLAGS-line (with the -DM7101_DEBUG switch) -in the Makefile. - -This module was written to activate SMBus support. I don't know neither -have I tested wether it works with the software from the ACPI project. - -Note: Egcs compilers with versions below 2.95.2 do not compile properly. -Use either 2.95.2 or gcc 2.7.2.x. - -I have tested this module with 2.2 kernels up to version 2.2.14. - - -I wish to thank Frank Bauer for his help with this module. - -Burkhard Kohl (burkhard.kohl@gmx.de) diff --git a/prog/hotplug/README.p4b b/prog/hotplug/README.p4b index e3cf3c23..eb43a0e7 100644 --- a/prog/hotplug/README.p4b +++ b/prog/hotplug/README.p4b @@ -1,13 +1,15 @@ What is it? ----------- -It unhides the SMBus of Intel ICH southbridges hidden -on ASUS P4B series. It is implemented as a module (p4b_smbus.o), -or a shell script for the 2.6 kernel (unhide_ICH_SMBus). +It unhides the SMBus of Intel ICH southbridges hidden on Asus P4B series +and some other Asus and non-Asus systems. It is implemented as a shell +script for the 2.6 kernel: unhide_ICH_SMBus. It works with the following chips: * ICH2 (82801BA) * ICH2-M (82801BAM) + * ICH3 (82801CA) + * ICH3-M (82801CAM) * ICH4 (82801DB) * ICH4-M (82801DBM) * ICH5 (82801EB) @@ -17,13 +19,15 @@ with the German support and learned that: "We do not want the users to be irritated by just another PCI Device in the Win98 device manager." Really funny :-). -This module is for 2.4 kernels only. For 2.6 kernels, activation is -handled by the code in drivers/pci/quirks.c in the kernel source. If you -have the 2.6 kernel and the quirks code does not activate your SMBus, -you may: +For 2.6 kernels, activation is normally handled by the code in +drivers/pci/quirks.c in the kernel source. If you have the 2.6 kernel and +the quirks code does not activate your SMBus, you may: - * check if you have kernel version from 2.6.17 to 2.6.19 - If so you, need to disable ACPI sleep support and recompile kernel. + * first of all, read the paragraph "Hidden ICH SMBus" in + Documentation/i2c/busses/i2c-i801 in the kernel source. + + * check if you have kernel version from 2.6.16 to 2.6.19 + If so, you need to disable ACPI sleep support and recompile kernel. If you don't use suspend try below instead of recompilation. * run as root the ./unhide_ICH_SMBus script. It will unhide the bus @@ -33,77 +37,3 @@ you may: * if above script works and you have latest kernel, you may try to fix the quirks.c, recompile and test your new kernel, and then submit a patch to us. Contact us if you need assistance. - -Information for 2.4 users continues below. - -NOTE: As of kernel 2.4.23, the kernel activates the SMBus PCI device -on the following boards: - * Asus P4B - * Asus P4B533 - * Asus P4PE - * Asus P4T533 - * Asus P4G8X Deluxe -So this module is no longer required for these boards. For the other -affected boards, it still is. - -What does the module do? ------------------------- -(Note: the following instructions assume the ICH2. For the ICH4, -the PCI IDs are 24C0 and 24C3) - -It turnes off (!) the bits number 8 and 3 in the LPC register of the ICH2. -This you can also try as root with setpci and pcitweak. -First do a: - -setpci -d 8086:2440 f2.w - -You will get an hex number VAL - in my case 148 (Hex)-, where you have to -erase the two bits - in my case you get 40 (Hex). -Then do a: - -setpci -d 8086:2440 f2.w=VAL - -Running "lspci -n" you will not see any new device, but with "pcitweak -l" you -should get a line similar to this in the output: - -PCI: 00:1f:3: chip 8086,2443 card 1043,8028 rev 12 class 0c,05,00 hdr 00 - -The important thing is the "8086,2443" here. -The device is activated, but not included in /proc/pci and -/proc/bus/pci/devices. This is the reason for running the module. - -What are the system requirements? ---------------------------------- - -- Obviously a board with Intel i801BA/DB/EB ICH2/4/5 with broken BIOS. -- A linux working with a 2.4 kernel AND hotplug support in it! -- A installed kernel tree and gcc. -- i2c and sensor modules installed. - -How to install? ---------------- - -Simply do a: - -make -f Makefile.p4b -insmod p4b_smbus.o -modprobe i2c-core -modprobe i2c-i801 -modprobe i2c-dev -modprobe i2c-proc - -Then run your sensor: - -modprobe w83781d - -What should i never do? ------------------------ - -Do not try to do a "rmmod p4b_smbus" before a "rmmod i2c-i801". -The other way around should be okay. Otherwise you remove the PCI device -without notifying the i2c driver. - - -------------------------------- -Ilja Rauhut - diff --git a/prog/hotplug/m7101.c b/prog/hotplug/m7101.c deleted file mode 100644 index a7e4a977..00000000 --- a/prog/hotplug/m7101.c +++ /dev/null @@ -1,391 +0,0 @@ -/* - * m7101.c - * - * Initialize the M7101 device on ALi M15x3 Chipsets - */ -/* - Copyright (c) 2000 Burkhard Kohl , - Frank Bauer , and - Mark D. Studebaker - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ -/* CHANGES: - * 030799 FB: created this file - * frank.bauer@nikocity.de - * - * 110799 BK: messed it up to insert the M7101 dev after boot - * buk@buks.ipn.de - * - * 160799 BK: grouped portions of the code into functions - * - * June 21, 2000 MDS: Add Copyright and GPL comments, - * distribute as release 0.1. - * - * Sept 21, 2000 MDS: Rewrite to use kernel hotplug facility, - * (similar to drivers/pcmcia/cardbus.c), - * fix makefile so it will compile, - * distribute as release 0.2. - * - * This code is absolutely experimental - use it at your own - * risk. - * - * Warning, this module will work only with 2.4.x kernels. - * If it works with earlier kernels then it is by luck. - * - * Warning, this module does not work with egcs < 2.95.2, use - * gcc > 2.7.2 or egcs >= 2.95.2. - * - */ - - -#ifdef M7101_DEBUG -#define DBG(x...) printk(x) -#else -#define DBG(x...) -#endif - -#ifndef TRUE -#define TRUE 1 -#define FALSE !TRUE -#endif - -#include -#ifndef CONFIG_HOTPLUG -#error ERROR - You must have 'Support for hot-pluggable devices' enabled in your kernel (under 'general setup')!! -#endif - -/* Deal with CONFIG_MODVERSIONS */ -#ifdef CONFIG_MODVERSIONS -#define MODVERSIONS -#include -#endif - -#include -#include -#include -#include -#include -#include -#include -#include - -/* - from lm_sensors-2.3.3: - */ -#define SMBHSTCFG 0x0E0 -/* PCI Address Constants */ -#define SMBATPC 0x05B /* used to unlock xxxBA registers */ -/* ALI15X3 address lock bits */ -#define ALI15X3_LOCK 0x06 - -/* - addresses the i/o space gets mapped to, - for M1543C, Bits 16-31 are supposed to be zero - */ -#define ACPI_IO_SIZE 0x40 -#define SMB_IO_SIZE 0x20 -#define ACPI_BASE 0x0 -#define SMB_BASE 0x1 -static u32 acpi_io = 0xEC00; /* Set I/O Base defaults here */ -static u32 smb_io = 0xE800; -MODULE_PARM(acpi_io, "l"); -MODULE_PARM(smb_io, "l"); -#ifdef M7101_DEBUG -static int debug = 0; -MODULE_PARM(debug, "i"); -#endif - -/* status, used to indicate that io space needs to be freed */ -static struct pci_dev *m7101 = NULL; -static int m7101_inserted = FALSE; -extern void cleanup_module(); - -static rwlock_t m7101_lock = RW_LOCK_UNLOCKED; -static unsigned long m7101_lock_flags = 0; - - -#ifdef M7101_DEBUG -static void -dump_dev_data(struct pci_dev *dev, int address_data) -{ - if (dev != NULL) { - printk("m7101: devfn: 0x%4x class: 0x%4x\n", - dev->devfn, dev->class); - printk("m7101: vendor: 0x%4x device: 0x%4x\n", - dev->vendor, dev->device); - - if (address_data) { - printk("m7101: resource[0]: 0x%08lx resource[1]: 0x%08lx\n", - dev->resource[0].start, dev->resource[1].start); - printk("m7101: resource[2]: 0x%08lx resource[3]: 0x%08lx\n", - dev->resource[2].start, dev->resource[3].start); - printk("m7101: resource[4]: 0x%08lx resource[5]: 0x%08lx\n", - dev->resource[4].start, dev->resource[5].start); - printk("m7101: rom_address: 0x%08lx\n", - dev->resource[PCI_ROM_RESOURCE].start); - } - } -} -#endif - -/* - * Checks whether PMU and SMB are enabled and turns them on in case they are not. - * It's done by clearing Bit 2 in M1533 config space 5Fh. - * I/O - */ -static int -m7101_enable(struct pci_dev *dev){ - u8 val = 0; - - pci_read_config_byte(dev, 0x5F, &val); - DBG("m7101: M7101 config byte reading 0x%X.\n", val); - if (val & 0x4) { - pci_write_config_byte(dev, 0x5F, val & 0xFB); - pci_read_config_byte(dev, 0x5F, &val); - if(val & 0x4) { - DBG("m7101: Can't enable PMU/SMB, config byte locked:-(\n"); - return -EIO; - } - } - return 0; - -} - -/* - * Builds the basic pci_dev for the M7101 - */ -static int -m7101_build(struct pci_dev **m7101, struct pci_bus *bus) -{ - u32 devfn; - u16 id = 0; - u16 vid = 0; - int ret; - - DBG("m7101: requesting kernel space for the m7101 entry.\n"); - *m7101 = kmalloc(sizeof(**m7101), GFP_ATOMIC); - if(NULL == *m7101) { - printk("m7101: out of memory.\n"); - return -ENOMEM; - } - - /* minimally fill in structure for search */ - /* The device should be on the same bus as the M1533. */ - memset(*m7101, 0, sizeof(**m7101)); - (*m7101)->bus = bus; - (*m7101)->sysdata = bus->sysdata; - (*m7101)->hdr_type = PCI_HEADER_TYPE_NORMAL; - - DBG("m7101: now looking for M7101.\n"); - for (id = 0, devfn = 0; devfn < 0xFF; devfn++) { - (*m7101)->devfn = devfn; - ret = pci_read_config_word(*m7101, PCI_DEVICE_ID, &id); - if (ret == 0 && PCI_DEVICE_ID_AL_M7101 == id) { - pci_read_config_word(*m7101, PCI_VENDOR_ID, &vid); - if(vid == PCI_VENDOR_ID_AL) - break; - } - } - if (PCI_DEVICE_ID_AL_M7101 != id) { - DBG("m7101: M7101 not found although M1533 present - strange.\n"); - return -EACCES; - } else { - DBG("m7101: M7101 found and enabled. Devfn: 0x%X.\n", devfn); - } - /* We now have the devfn and bus of the M7101 device. - * let's put the rest of the device data together. - */ - - (*m7101)->vendor = PCI_VENDOR_ID_AL; - (*m7101)->hdr_type = PCI_HEADER_TYPE_NORMAL; - (*m7101)->device = PCI_DEVICE_ID_AL_M7101; - return(pci_setup_device(*m7101)); -} - -/* - * unlock the address registers if necessary - */ -static int -m7101_unlock_registers(struct pci_dev *m7101) -{ - u8 val = 0; - - if (pci_read_config_byte(m7101, SMBATPC, &val)) { - DBG("m7101: failed to read SMBATPC\n"); - return -EIO; - } else { - if(val & ALI15X3_LOCK) { - DBG("m7101: need to unlock the address registers\n"); - val &= ~ALI15X3_LOCK; - if (pci_write_config_byte(m7101, SMBATPC, val)) { - DBG("m7101: failed to write SMBATPC\n"); - return -EIO; - } - } - } - - return 0; -} - - -static int -m7101_set_io_address(struct pci_dev *m7101, u32 addr, int base_idx, int size) -{ - if (!addr) { - printk("m7101: Sorry - cannot assign address 0 to region.\n"); - return -EINVAL; - } - if (check_region(addr, size)) { - printk("m7101: Requested IO-region 0x%x already in use.\n", addr); - return -EBUSY; - } else { - m7101->resource[base_idx].start = addr; - } - - return 0; -} - - -/* Initialize the module */ -int init_module(void) -{ - struct pci_bus *bus = NULL; - struct pci_dev *dev = NULL; - u32 acpi_addr = 0, smb_addr = 0; - int ret = 0; - - DBG("m7101: init_module().\n"); - - /* Are we on a PCI-Board? */ - if (!pci_present()) { - printk("m7101: No PCI bus found - sorry.\n"); - return -ENODEV; - } - - /* We want to be sure that the M7101 is not present yet. */ - dev = pci_find_device(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M7101, NULL); - if (dev) { - printk("m7101: M7101 already present, no need to run this module.\n"); -#ifdef M7101_DEBUG - if(debug) - { - printk("m7101: removing device for testing\n"); - pci_remove_device(dev); - m7101_inserted = 0; - return 0; - } - else -#endif - return -EPERM; - } - - /* Are we operating a M15x3 chipset */ - dev = pci_find_device(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M1533, NULL); - if (NULL == dev) { - printk("m7101: ALi M15xx chipset not found.\n"); - return -ENODEV ; - } - /* we need the bus pointer later */ - bus = dev->bus; - - if ( (ret = m7101_enable(dev)) ) { - printk("m7101: Unable to turn on M7101 device - sorry!\n"); - return ret; - } - - if ( (ret = m7101_build(&m7101, bus)) ){ - return ret; - } - - /* thus, now we have a rudimentary dev for M7101 ... */ - /* check wether register need to be unlocked. */ - if ( (ret = m7101_unlock_registers(m7101)) ){ - return ret; - } - - /* - * Handle address assignment for ACPI_IO - * If address is already assigned do nothing. - */ - acpi_addr = m7101->resource[ACPI_BASE].start; - if (!acpi_addr) { - acpi_io |= PCI_BASE_ADDRESS_SPACE_IO; - ret = m7101_set_io_address(m7101, acpi_io,ACPI_BASE, ACPI_IO_SIZE); - if (ret) - return ret; - acpi_addr = acpi_io; - } - - /* - * Handle address assignment for SMB_IO - * If address is already assigned then do nothing. - */ - smb_addr = m7101->resource[SMB_BASE].start; - if (!smb_addr) { - smb_io |= PCI_BASE_ADDRESS_SPACE_IO; - ret = m7101_set_io_address(m7101, smb_io, SMB_BASE, SMB_IO_SIZE); - if (ret) - return ret; - smb_addr = smb_io; - } - -#ifdef M7101_DEBUG - dump_dev_data(m7101, 1); -#endif - - - if ( (ret = pci_enable_device(m7101)) ) { - printk("m7101: Unable to pci_enable M7101 device!\n"); - return ret; - } - - DBG("m7101: now inserting.\n"); - pci_insert_device(m7101, m7101->bus); - printk("m7101: Enabled with ACPI I/O address 0x%04X and SMB I/O address 0x%04X\n", - acpi_addr, smb_addr); - m7101_inserted = TRUE; - - return 0; -} - - -void cleanup_module() -{ - write_lock_irqsave(m7101_lock, m7101_lock_flags); - if (m7101_inserted) { - pci_remove_device(m7101); - m7101_inserted = FALSE; - } - write_unlock_irqrestore(m7101_lock, m7101_lock_flags); - - if (NULL != m7101) - kfree(m7101); - - printk("m7101: bye bye\n"); -} - -EXPORT_NO_SYMBOLS; - -#ifdef MODULE -#ifdef MODULE_LICENSE -MODULE_LICENSE("GPL"); -#endif -MODULE_AUTHOR("Burkhard Kohl , " - "Frank Bauer , " - "and Mark Studebaker "); -MODULE_DESCRIPTION("M7101 PCI Inserter"); - -#endif /* MODULE */ diff --git a/prog/hotplug/p4b_smbus.c b/prog/hotplug/p4b_smbus.c deleted file mode 100644 index 9f3e96c0..00000000 --- a/prog/hotplug/p4b_smbus.c +++ /dev/null @@ -1,340 +0,0 @@ -/* - * p4b_smbus.c - * - * Initialize the SMBus device on ICH2/2-M/4/4-M/5 (82801BA/BAM/DB/DBM/EB) - */ -/* - Copyright (c) 2002 Ilja Rauhut and - Klaus Woltereck , - - Based on the m7101.c hotplug example by: - - Copyright (c) 2000 Burkhard Kohl , - Frank Bauer , and - Mark D. Studebaker - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ -/* CHANGES: - * February 13,2002 IR First Version - * - * This code is absolutely experimental - use it at your own - * risk. - * - * Warning, this module will work only with 2.4.x kernels. - * If it works with earlier kernels then it is by luck. - * - * Warning, this module does not work with egcs < 2.95.2, use - * gcc > 2.7.2 or egcs >= 2.95.2. - * - * - * June 21, 2002, added support for the ICH4, code clean up -- Klaus - * - * Apr 13, 2004, modified for ICH4-M (82801DBM) -- Axel Thimm - * bugfix: register F2/bit 8 on ICH2* is bit 0 on ICH4* - * - * Jan 6, 2007, added support for the ICH5 -- Jean Delvare - */ - - -#ifdef P4Bsmbus_DEBUG -#define DBG(x...) printk(x) -#else -#define DBG(x...) -#endif - -#ifndef TRUE -#define TRUE 1 -#define FALSE !TRUE -#endif - -#include -#ifndef CONFIG_HOTPLUG -#error ERROR - You must have 'Support for hot-pluggable devices' enabled in your kernel (under 'general setup')!! -#endif - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -/* -rmm from lm_sensors-2.3.3: - */ - -#define SMB_IO_SIZE 0xF -#define SMB_BASE 0x20 - - -/* - * some shorter definitions for the ICHx PCI device IDs - */ - -#define ICH2 0x2440 -#define ICH2_M 0x244c -#define ICH2_SMBUS 0x2443 - -#define ICH4 0x24c0 -#define ICH4_M 0x24cc -#define ICH4_SMBUS 0x24c3 - -#define ICH5 0x24d0 -#define ICH5_SMBUS 0x24d3 - -#define is_supported_smbus(id) \ - ((id) == ICH2_SMBUS || \ - (id) == ICH4_SMBUS || \ - (id) == ICH5_SMBUS) - -/* status, used to indicate that io space needs to be freed */ -static struct pci_dev *i801smbus = NULL; -static int i801smbus_inserted = FALSE; -extern void cleanup_module(void); - -static rwlock_t i801smbus_lock = RW_LOCK_UNLOCKED; -static unsigned long i801smbus_lock_flags = 0; - -/* - * Checks whether SMBus is enabled and turns it on in case they are not. - * It's done by modifying the i801 function disable register, F2h. - * ICH2(-M): PCI-Device 0x8086:0x2440(0x244c) - * Bit 3: Disables SMBus Host Controller function. - * Bit 8: allows SMBus I/O space to be accessible when Bit 3 is set. - * ICH4(-M): PCI-Device 0x8086:0x24c0(0x24cc) - * Bit 3: Disables SMBus Host Controller function. - * Bit 0: allows SMBus I/O space to be accessible when Bit 3 is set. - * ICH5: PCI-Device 0x8086:0x24d0 - * Same as ICH4. - */ -static int -i801smbus_enable(struct pci_dev *dev, u16 testmask, u16 mask){ - u16 val = 0; - - pci_read_config_word(dev, 0xF2, &val); - DBG("i801smbus: i801smbus config byte reading 0x%X.\n", val); - if (val & testmask) { - pci_write_config_word(dev, 0xF2, val & mask); - pci_read_config_word(dev, 0xF2, &val); - if(val & testmask) - { - DBG("i801smbus: i801smbus config byte locked:-(\n"); - return -EIO; - } - else - printk("i801smbus: SMBus activated in LPC!\n"); - } - return 0; - -} - -/* - * Builds the basic pci_dev for the i801smbus - */ -static int i801smbus_build(struct pci_dev **i801smbus, struct pci_bus *bus) -{ - u32 devfn; - u16 id = 0; - u16 vid = 0; - int ret; - - DBG("i801smbus: requesting kernel space for the i801smbus entry.\n"); - *i801smbus = kmalloc(sizeof(**i801smbus), GFP_ATOMIC); - if(NULL == *i801smbus) { - printk("i801smbus: out of memory.\n"); - return -ENOMEM; - } - - /* minimally fill in structure for search */ - /* The device should be on the same bus as the i801. */ - memset(*i801smbus, 0, sizeof(**i801smbus)); - (*i801smbus)->bus = bus; - (*i801smbus)->sysdata = bus->sysdata; - (*i801smbus)->hdr_type = PCI_HEADER_TYPE_NORMAL; - - DBG("i801smbus: now looking for i801smbus.\n"); - for (id = 0, devfn = 0; devfn < 0xFF; devfn++) { - (*i801smbus)->devfn = devfn; - ret = pci_read_config_word(*i801smbus, PCI_DEVICE_ID, &id); - if (ret == 0 && is_supported_smbus(id)) { - pci_read_config_word(*i801smbus, PCI_VENDOR_ID, &vid); - if(vid == 0x8086) - break; - } - } - if (!is_supported_smbus(id)) { - DBG("i801smbus: i801smbus not found although i801 present - strange.\n"); - return -EACCES; - } else { - DBG("i801smbus: i801smbus found and enabled. Devfn: 0x%X.\n", devfn); - } - /* We now have the devfn and bus of the i801smbus device. - * let's put the rest of the device data together. - */ - - (*i801smbus)->vendor = 0x8086; - (*i801smbus)->hdr_type = PCI_HEADER_TYPE_NORMAL; - (*i801smbus)->device = id; - - return(pci_setup_device(*i801smbus)); -} - - - - -/* Initialize the module */ -int init_module(void) -{ - struct pci_bus *bus = NULL; - struct pci_dev *dev = NULL; - int ret = 0; - u16 testmask = 0, mask = 0; - - DBG("i801smbus: init_module().\n"); - - /* Are we on a PCI-Board? */ - if (!pci_present()) { - printk("i801smbus: No PCI bus found - sorry.\n"); - return -ENODEV; - } - - /* We want to be sure that the i801smbus is not present yet. */ - dev = pci_find_device(0x8086, ICH2_SMBUS, NULL); - - if (dev) - { - printk("i801smbus: SMBus already active\n"); - return -EPERM; - } - - dev = pci_find_device(0x8086, ICH4_SMBUS, NULL); - - if (dev) - { - printk("i801smbus: SMBus already active\n"); - return -EPERM; - } - - dev = pci_find_device(0x8086, ICH5_SMBUS, NULL); - - if (dev) - { - printk("i801smbus: SMBus already active\n"); - return -EPERM; - } - - /* Are we operating a i801 chipset */ - if ((dev = pci_find_device(0x8086, ICH2, NULL)) != 0) - { - printk("i801smbus: found Intel ICH2 (82801BA).\n"); - testmask = 0x008; - mask = 0xfef7; - } - else if ((dev = pci_find_device(0x8086, ICH2_M, NULL)) != 0) - { - printk("i801smbus: found Intel ICH2-M (82801BAM).\n"); - testmask = 0x008; - mask = 0xfef7; - } - else if ((dev = pci_find_device(0x8086, ICH4, NULL)) != 0) - { - printk("i801smbus: found Intel ICH4 (82801DB).\n"); - testmask = 0x008; - mask = 0xfff6; - } - else if ((dev = pci_find_device(0x8086, ICH4_M, NULL)) != 0) - { - printk("i801smbus: found Intel ICH4-M (82801DBM).\n"); - testmask = 0x008; - mask = 0xfff6; - } - else if ((dev = pci_find_device(0x8086, ICH5, NULL)) != 0) - { - printk(KERN_INFO "i801smbus: Found Intel ICH5 (82801EB)\n"); - testmask = 0x008; - mask = 0xfff6; - } - else - { - printk(KERN_NOTICE "i801smbus: No supported Intel ICH (82801) " - "chip found\n"); - return -ENODEV ; - } - - /* we need the bus pointer later */ - bus = dev->bus; - - - if ( (ret = i801smbus_enable(dev, testmask, mask)) ) - { - printk("i801smbus: Unable to turn on i801smbus device - sorry!\n"); - return ret; - } - - if ( (ret = i801smbus_build(&i801smbus, bus)) ) - return ret; - - - if ( (ret = pci_enable_device(i801smbus)) ) { - printk("i801smbus: Unable to pci_enable i801smbus device!\n"); - return ret; - } - - DBG("i801smbus: now inserting.\n"); - pci_insert_device(i801smbus, i801smbus->bus); - printk("i801smbus: Enabled\n"); - i801smbus_inserted = TRUE; - return 0; -} - - -void cleanup_module(void) -{ - write_lock_irqsave(&i801smbus_lock, i801smbus_lock_flags); - if (i801smbus_inserted) { - pci_remove_device(i801smbus); - i801smbus_inserted = FALSE; - } - write_unlock_irqrestore(&i801smbus_lock, i801smbus_lock_flags); - - if (NULL != i801smbus) - { - kfree(i801smbus); - } - printk("i801smbus: SMBus device removed\n"); -} - -EXPORT_NO_SYMBOLS; - -#ifdef MODULE -#ifdef MODULE_LICENSE -MODULE_LICENSE("GPL"); -#endif -MODULE_AUTHOR("Ilja Rauhut , " - "Burkhard Kohl , " - "Frank Bauer , " - "Mark Studebaker ," - "and Klaus Woltereck "); -MODULE_DESCRIPTION("i801smbus PCI Inserter"); - -#endif /* MODULE */ diff --git a/prog/init/README b/prog/init/README index f3392f00..aec8cb42 100644 --- a/prog/init/README +++ b/prog/init/README @@ -1,5 +1,5 @@ This directory contains files useful for initialization -scripts, especially for RedHat and SuSE. +scripts, especially for RedHat. There are two choices, lm_sensors.init and sensord.init. Use one or the other but not both! @@ -20,10 +20,6 @@ Once the script is done detecting the hardware monitoring devices, it will list all the required modules in that file, so that they can be loaded automatically at boot time. -SuSE users will want to use lm_sensors.init.suse instead, which is -more specifically designed for this distribution. Changes were contributed -by Marc Rieffel . - ---------------- The script sensord.init also loads the modules, and then diff --git a/prog/init/fancontrol.init b/prog/init/fancontrol.init index 38fce8e4..eabe734c 100755 --- a/prog/init/fancontrol.init +++ b/prog/init/fancontrol.init @@ -34,7 +34,6 @@ stop() echo -n "Stopping fancontrol daemon" killproc $FANCONTROL RETVAL=$? - rm -f $PIDFILE rm -f /var/lock/subsys/fancontrol echo } diff --git a/prog/init/lm_sensors.init b/prog/init/lm_sensors.init index 4a09bb5f..77172d24 100755 --- a/prog/init/lm_sensors.init +++ b/prog/init/lm_sensors.init @@ -16,7 +16,8 @@ # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software -# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, +# MA 02110-1301 USA. # See also the lm_sensors homepage at: # http://www.lm-sensors.org @@ -24,9 +25,9 @@ # It uses a config file /etc/sysconfig/lm_sensors that contains the modules # to be loaded/unloaded. That file is sourced into this one. -# The format of that file a shell script that simply defines the modules -# in order as normal shell variables with the special names: -# MODULE_1, MODULE_2, MODULE_3, etc. +# The format of this file is a shell script that simply defines variables: +# HWMON_MODULES for hardware monitoring driver modules, and optionally +# BUS_MODULES for any required bus driver module (for example for I2C or SPI). PSENSORS=/usr/local/bin/sensors @@ -43,31 +44,8 @@ prog="lm_sensors" # This functions checks if sensor support is compiled into the kernel, if # sensors are configured, and loads the config file check_sensors() { - if grep -q sysfs /proc/mounts; then - WITHSYS=1 - else - WITHSYS=0 - fi - - if [ $WITHSYS == "0" ]; then - # If sensors isn't supported by the kernel, try loading the module... - [ -e /proc/sys/dev/sensors ] || /sbin/modprobe i2c-proc >/dev/null 2>&1 - - # Don't bother if /proc/sensors still doesn't exist, kernel doesn't have - # support for sensors. - if ! [ -e /proc/sys/dev/sensors ]; then - echo -n "$1 $prog: kernel does not have sensors support" - echo_failure - echo - exit 5 - fi - - # If sensors was not already running, unload the module... - [ -e /var/lock/subsys/lm_sensors ] || /sbin/modprobe -r i2c-proc >/dev/null 2>&1 - fi - CONFIG=/etc/sysconfig/lm_sensors - if ! [ -r "$CONFIG" ] || ! grep '^MODULE_' $CONFIG >/dev/null 2>&1; then + if ! [ -r "$CONFIG" ] || ! grep '^HWMON_MODULES' $CONFIG >/dev/null 2>&1; then echo -n "$1 $prog: not configured, run sensors-detect" echo_warning echo @@ -83,13 +61,9 @@ start() { echo -n "Starting $prog: loading module " - modules=`grep \^MODULE_ $CONFIG | wc -l | tr -d ' '` - i=0 - while [ $i -lt $modules ] ; do - module=`eval echo '$'MODULE_$i` + for module in $BUS_MODULES $HWMON_MODULES ; do echo -n "${module} " /sbin/modprobe $module >/dev/null 2>&1 - i=`expr $i + 1` done $PSENSORS -s @@ -108,18 +82,10 @@ stop() { echo -n "Stopping $prog: " - modules=`grep \^MODULE_ $CONFIG | wc -l | tr -d ' '` - i=`expr $modules` - while [ $i -ge 0 ] ; do - module=`eval echo '$'MODULE_$i` + for module in $HWMON_MODULES $BUS_MODULES ; do /sbin/modprobe -r $module >/dev/null 2>&1 - i=`expr $i - 1` done - if [ $WITHSYS == "0" ]; then - /sbin/modprobe -r i2c-proc >/dev/null 2>&1 - fi - RETVAL=$? if [ $RETVAL -eq 0 ] && rm -f /var/lock/subsys/lm_sensors ; then echo_success diff --git a/prog/init/lm_sensors.init.suse b/prog/init/lm_sensors.init.suse deleted file mode 100755 index 60058c6e..00000000 --- a/prog/init/lm_sensors.init.suse +++ /dev/null @@ -1,174 +0,0 @@ -#!/bin/sh -# -### BEGIN INIT INFO -# Provides: lm_sensors -# Required-Start: $local_fs -# X-UnitedLinux-Should-Start: -# Required-Stop: $local_fs -# X-UnitedLinux-Should-Stop: -# Default-Start: 3 4 5 -# Default-Stop: 0 1 2 6 -# Short-Description: LM Sensors -# Description: LM Sensors for hardware monitoring -### END INIT INFO -# chkconfig: 2345 26 74 -# description: sensors is used for monitoring motherboard sensor values. -# config: /etc/sysconfig/lm_sensors -# -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - -# See also the lm_sensors homepage at: -# http://www.lm-sensors.org - -# It uses a config file /etc/sysconfig/lm_sensors that contains the modules -# to be loaded/unloaded. That file is sourced into this one. - -# The format of that file a shell script that simply defines the modules -# in order as normal shell variables with the special names: -# MODULE_1, MODULE_2, MODULE_3, etc. - -# If sensors isn't supported by the kernel, try loading the module... -[ -e /proc/sys/dev/sensors ] || /sbin/modprobe i2c-proc &>/dev/null - -# Don't bother if /proc/sensors still doesn't exist, kernel doesn't have -# support for sensors. -[ -e /proc/sys/dev/sensors ] || exit 0 - -# If sensors was not already running, unload the module... -[ -e /var/lock/subsys/lm_sensors ] || /sbin/modprobe -r i2c-proc &>/dev/null - -CONFIG=/etc/sysconfig/lm_sensors -PSENSORS=/usr/local/bin/sensors - -# Source function library. -#. /etc/init.d/functions - -# Shell functions sourced from /etc/rc.status: -# rc_check check and set local and overall rc status -# rc_status check and set local and overall rc status -# rc_status -v ditto but be verbose in local rc status -# rc_status -v -r ditto and clear the local rc status -# rc_status -s display "skipped" and exit with status 3 -# rc_status -u display "unused" and exit with status 3 -# rc_failed set local and overall rc status to failed -# rc_failed set local and overall rc status to -# rc_reset clear local rc status (overall remains) -# rc_exit exit appropriate to overall rc status -# rc_active checks whether a service is activated by symlinks -# rc_splash arg sets the boot splash screen to arg (if active) -. /etc/rc.status - -# Reset status of this service -rc_reset - -# Return values acc. to LSB for all commands but status: -# 0 - success -# 1 - generic or unspecified error -# 2 - invalid or excess argument(s) -# 3 - unimplemented feature (e.g. "reload") -# 4 - user had insufficient privileges -# 5 - program is not installed -# 6 - program is not configured -# 7 - program is not running -# 8--199 - reserved (8--99 LSB, 100--149 distrib, 150--199 appl) -# -# Note that starting an already running service, stopping -# or restarting a not-running service as well as the restart -# with force-reload (in case signaling is not supported) are -# considered a success. - -RETVAL=0 - -start() { - echo -n $"Starting up sensors: " - test -r "$CONFIG" && . "$CONFIG" - - modules=`grep \^MODULE_ $CONFIG | wc -l | tr -d ' '` - i=0 - while [ $i -lt $modules ] ; do - module=`eval echo '$'MODULE_$i` - echo starting module __${module}__ - /sbin/modprobe $module &>/dev/null - i=`expr $i + 1` - done - $PSENSORS -s - - RETVAL=$? - if [ $RETVAL -eq 0 ] && touch /var/lock/subsys/lm_sensors ; then - rc_status -v - else - rc_status -v - fi -} - -stop() { - echo -n $"Shutting down sensors: " - test -r "$CONFIG" && . "$CONFIG" - - modules=`grep \^MODULE_ $CONFIG | wc -l | tr -d ' '` - i=`expr $modules` - while [ $i -ge 0 ] ; do - module=`eval echo '$'MODULE_$i` - /sbin/modprobe -r $module &>/dev/null - i=`expr $i - 1` - done - /sbin/modprobe -r i2c-proc &>/dev/null - - RETVAL=$? - if [ $RETVAL -eq 0 ] && rm -f /var/lock/subsys/lm_sensors ; then - rc_status -v - else - rc_status -v - fi -} - -dostatus() { - $PSENSORS - RETVAL=$? -} - -restart() { - stop - start - RETVAL=$? -} - -condrestart() { - [ -e /var/lock/subsys/lm_sensors ] && restart || : -} - -# See how we were called. -case "$1" in - start) - start - ;; - stop) - stop - ;; - status) - dostatus - ;; - restart|reload) - restart - ;; - condrestart) - condrestart - ;; - *) - echo "Usage: sensors.init {start|stop|status|restart|reload|condrestart}" - exit 1 -esac - -exit $RETVAL diff --git a/prog/init/sysconfig-lm_sensors-convert b/prog/init/sysconfig-lm_sensors-convert new file mode 100755 index 00000000..f379d793 --- /dev/null +++ b/prog/init/sysconfig-lm_sensors-convert @@ -0,0 +1,30 @@ +#!/bin/sh + +# Convert an lm_sensors service configuration file from the old convention +# (MODULE_0, MODULE_1...) to the new convention (HWMON_MODULES). +# +# Copyright (C) 2009 Jean Delvare +# +# Released without a license on purpose. This is public domain code, so +# that package maintainers can include it in their post-install script. + +CONFIG=/etc/sysconfig/lm_sensors +test -r "$CONFIG" || exit + +unset ${!MODULE_*} $HWMON_MODULES +. "$CONFIG" +test -n "$HWMON_MODULES" && exit + +for i in ${!MODULE_*} ; do + eval module=\$$i + if test -z "$HWMON_MODULES" ; then + HWMON_MODULES="$module" + else + HWMON_MODULES="$HWMON_MODULES $module" + fi +done +test -z "$HWMON_MODULES" && exit + +echo >> "$CONFIG" +echo "# New configuration format generated by sysconfig-lm_sensors-convert" >> "$CONFIG" +echo "HWMON_MODULES=\"$HWMON_MODULES\"" >> "$CONFIG" diff --git a/prog/matorb/displayit.pl b/prog/matorb/displayit.pl deleted file mode 100755 index 0af5ce48..00000000 --- a/prog/matorb/displayit.pl +++ /dev/null @@ -1,32 +0,0 @@ -#!/usr/bin/perl - -# This is a simple perl script to display a 'screen' -# on a Matrix Orbital Display. In this case, this -# script will read the first four lines (up to 20 -# chars a line) and display them on the display. - -# Written and copywritten (C) by Philip Edelbrock, 1999. - - -# Turn off the blinking cursor -$temp=`echo "254 84" > /proc/sys/dev/sensors/matorb*/disp`; - -$linenum=1; - -while () { - # Reset the position of the cursor to the next line - $temp=`echo "254 71 1 $linenum" > /proc/sys/dev/sensors/matorb*/disp`; - chop; - $_="$_ "; - if (/^(.{1,20})/) { - $_=$1; - $line=""; - while (/(.)/gc) { - $temp=ord($1); - $line="$line $temp"; - } - $temp=`echo "$line" > /proc/sys/dev/sensors/matorb*/disp`; - } - $linenum+=1; - if ($linenum > 4) { exit; } -} diff --git a/prog/maxilife/sysinfo.sh b/prog/maxilife/sysinfo.sh deleted file mode 100644 index 237dd4bd..00000000 --- a/prog/maxilife/sysinfo.sh +++ /dev/null @@ -1,26 +0,0 @@ -#! /bin/sh - -lnxvers="`uname -s` `uname -r`" -#host="`hostname -s`" -host="`hostname`" -blink="o" - -writelcd=/home/rdm/src/lm_sensors-2.5.0/prog/maxilife/writelcd.sh - -$writelcd "$host" 3 - -i=0 -while true; do - $writelcd "$lnxvers $blink" 2 - if [ $[i == 5] = 1 ]; then - $writelcd "`awk '{ printf("%s %s %s", $1, $2, $3) }' < /proc/loadavg`" 4 - i=0 - fi - if [ $blink = "o" ]; then - blink=O - else - blink=o - fi - sleep 1 - i=$[i+1] -done diff --git a/prog/maxilife/writelcd.sh b/prog/maxilife/writelcd.sh deleted file mode 100644 index ccef350d..00000000 --- a/prog/maxilife/writelcd.sh +++ /dev/null @@ -1,26 +0,0 @@ -#! /bin/sh - -usage() { - echo "usage: $0 " - echo " must be <= 16 characters" - echo " lcd line number, between 1..4" -} - -if [ $# != 2 ]; then - usage - exit 1 -fi - -str=$1 -line=$2 - -if [ $[line < 1 || line > 4] = 1 ]; then - usage - exit 1 -fi - -sysctl=/proc/sys/dev/sensors/maxilife-nba-i2c-0-14/lcd - -printf "%-16.16s" "$str" | od -A n -l > $sysctl$line - -exit 0 diff --git a/prog/mkdev/mkdev.sh b/prog/mkdev/mkdev.sh deleted file mode 100755 index 8b29a37c..00000000 --- a/prog/mkdev/mkdev.sh +++ /dev/null @@ -1,32 +0,0 @@ -#!/bin/bash - -# Here you can set several defaults. - -# The number of devices to create (max: 256) -# If not provided on the command line, default to 32 -NUMBER=${1:-32} - -# The owner and group of the devices -OUSER=root -OGROUP=root -# The mode of the devices -MODE=600 - -# This script doesn't need to be run if devfs is used -if [ -r /proc/mounts ] ; then - if grep -q "/dev devfs" /proc/mounts ; then - echo "You do not need to run this script as your system uses devfs." - exit; - fi -fi - -i=0; - -while [ $i -lt $NUMBER ] ; do - if [ ! -c /dev/i2c-$i ] ; then - echo /dev/i2c-$i - mknod -m $MODE /dev/i2c-$i c 89 $i || exit - chown "$OUSER:$OGROUP" /dev/i2c-$i || exit - fi - i=$[$i + 1] -done diff --git a/prog/pwm/Module.mk b/prog/pwm/Module.mk index 034dfe76..30de1e31 100644 --- a/prog/pwm/Module.mk +++ b/prog/pwm/Module.mk @@ -13,7 +13,8 @@ # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software -# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, +# MA 02110-1301 USA. MODULE_DIR := prog/pwm PROGPWMDIR := $(MODULE_DIR) @@ -22,9 +23,15 @@ PROGPWMMAN8DIR := $(MANDIR)/man8 PROGPWMMAN8FILES := $(MODULE_DIR)/fancontrol.8 $(MODULE_DIR)/pwmconfig.8 PROGPWMTARGETS := $(MODULE_DIR)/fancontrol \ - $(MODULE_DIR)/fancontrol.pl \ $(MODULE_DIR)/pwmconfig +# The vt1211_pwm script is not installed by default, pass VT1211_PWM=1 +# to get it +ifeq ($(VT1211_PWM),1) +PROGPWMMAN8FILES += $(MODULE_DIR)/vt1211_pwm.8 +PROGPWMTARGETS += $(MODULE_DIR)/vt1211_pwm +endif + REMOVEPWMBIN := $(patsubst $(MODULE_DIR)/%,$(DESTDIR)$(SBINDIR)/%,$(PROGPWMTARGETS)) REMOVEPWMMAN := $(patsubst $(MODULE_DIR)/%,$(DESTDIR)$(PROGPWMMAN8DIR)/%,$(PROGPWMMAN8FILES)) diff --git a/prog/pwm/fancontrol b/prog/pwm/fancontrol index 00837538..aca7b2c9 100755 --- a/prog/pwm/fancontrol +++ b/prog/pwm/fancontrol @@ -2,7 +2,7 @@ # # Simple script implementing a temperature dependent fan speed control # -# Version 0.66 +# Version 0.67 # # Usage: fancontrol [CONFIGFILE] # @@ -13,16 +13,12 @@ # marius.reiner@hdev.de # Thanks! # -# The latest version of this script is available at: -# http://www.hdev.de/fancontrol/fancontrol.html -# or in the SVN version of lm_sensors -# # For configuration instructions and warnings please see fancontrol.txt, which # can be found in the doc/ directory or at the website mentioned above. # # # Copyright 2003 Marius Reiner -# Copyright (C) 2007 Jean Delvare +# Copyright (C) 2007-2008 Jean Delvare # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -36,14 +32,22 @@ # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software -# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, +# MA 02110-1301 USA. # # +PIDFILE="/var/run/fancontrol.pid" + #DEBUG=1 MAX=255 -echo $$ > /var/run/fancontrol.pid +if [ -f "$PIDFILE" ] +then + echo "File $PIDFILE exists, is fancontrol already running?" + exit 1 +fi +echo $$ > "$PIDFILE" declare -i pwmval @@ -247,6 +251,7 @@ function restorefans() let fcvcount=$fcvcount+1 done echo 'Verify fans have returned to full speed' + rm -f "$PIDFILE" exit $status } diff --git a/prog/pwm/fancontrol.8 b/prog/pwm/fancontrol.8 index 45074465..6a47fb9e 100644 --- a/prog/pwm/fancontrol.8 +++ b/prog/pwm/fancontrol.8 @@ -1,4 +1,4 @@ -.TH FANCONTROL 8 "June 2007" +.TH FANCONTROL 8 "June 2007" "lm-sensors 3" .SH NAME fancontrol \- automated software based fan speed regulation @@ -102,9 +102,6 @@ new values are written to the PWM outputs. Currently the speed increases quadratically with rising temperature. This way you won't hear your fans most of the time at best. -.SH CONFORMING TO -lm_sensors-2.x - .SH SEE ALSO pwmconfig(8), sensors(1). diff --git a/prog/pwm/fancontrol.pl b/prog/pwm/fancontrol.pl deleted file mode 100755 index 2e67acca..00000000 --- a/prog/pwm/fancontrol.pl +++ /dev/null @@ -1,428 +0,0 @@ -#!/usr/bin/perl -wT -# $Id$ -# -# Perl script for temperature dependent fan speed control. -# -# Copyright 2004 dean takemori -# -# This is a reimplementation in perl of Marius Reiner's bash script for -# fan speed control. It has advantages in that it can daemonize itself -# and needn't spawn subprocesses for grep, sleep etc. Much of the structure -# of the bash script is preserved to make mirroring changes easier, so -# this is seriously non-idiomatic perl but at the same time it should not -# be considered a a direct bash to perl translation. -# -# Usage: fancontrol [CONFIGFILE] -# -# For configuration instructions and warnings please see fancontrol.txt, -# which can be found in the doc/ directory or at the website mentioned -# elsewhere. -# -# This script is derived from Marius Reiner's bash version, so it is -# hereby placed under the GPL. -# -# Copyright 2003 Marius Reiner -# -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -# - -use warnings; -use strict; -use IO::Handle; -use Getopt::Std; -use POSIX; - -$ENV{PATH} = "/bin:/usr/bin"; - -##### Configuration ##### -use constant DEBUG => 0; -use constant MAX => 255; - -use constant PIDFILE => '/var/run/fancontrol.pid'; -use constant CONFFILE => '/etc/fancontrol'; -use constant LOGFILE => '/var/log/fancontrol/fancontrol.log'; -use constant ERRFILE => '/var/log/fancontrol/fancontrol.err'; -### End Configuration ### - -our $interval; -our $pwmo; -our @afcpwm; -our @afctemp; -our @afcfan; -our @afcmaxtemp; -our @afcmintemp; -our @afcminstart; -our @afcminstop; - -sub loadconfig($); -sub pwmdisable($); -sub pwmenable($); -sub restorefans(); -sub calc(@); -sub UpdateFanSpeeds(); -END { restorefans(); } - -our $opt_d; -getopts('d'); - -my $config = shift; -if (defined($config)) - { loadconfig($config); } -else - { loadconfig(CONFFILE); } - -### Daemonize -if ( defined($opt_d) && ($opt_d == 1) ) - { - my $pid = fork; - POSIX::_exit(0) if $pid; - - unless (defined($pid)) - { die("Couldn't fork: $!"); } - - open(*STDERR, '>', ERRFILE); - IO::Handle::autoflush(*STDERR); - open(*STDOUT, '>>', LOGFILE); - IO::Handle::autoflush(*STDOUT); - - unless (POSIX::setsid()) - { die("Couldn't open new session: $!"); } - - } - -### Pidfile -if (open(FILE, ">" . PIDFILE)) - { - print(FILE "$$\n"); - close(FILE); - } -else - { print(PIDFILE . ": $!\n"); } - - -### What kind of interface? -our $sysfs = 0; -our $dir = '/proc/sys/dev/sensors'; -if (!(-d $dir)) - { - if ($afcpwm[0] =~ m/^hwmon\d/) - { - $dir = '/sys/class/hwmon'; - } - else - { - $dir = '/sys/bus/i2c/devices'; - } - - if (!(-d $dir)) - { die("No sensors found! (are the necessary modules loaded?) : -$!\n"); } - else - { - $sysfs = 1; - } - } - -### Trap signals -$SIG{TERM} = \&restorefans; -$SIG{HUP} = \&restorefans; -$SIG{INT} = \&restorefans; -$SIG{QUIT} = \&restorefans; - -### Enable PWM -print("Enabling PWM on fans...\n"); -my $fcvcount = 0; -while ($fcvcount < $#afcpwm+1) - { - $pwmo = $afcpwm[$fcvcount]; - unless (pwmenable($pwmo)) - { die("Error enabling PWM on $dir/$pwmo : $!\n"); } - $fcvcount++; - } - -print("Starting automatic fan control...\n"); - -while(1) - { - UpdateFanSpeeds(); - sleep($interval); - } - -1; - -################################################################ -sub loadconfig($) -{ - my $file = shift; - - print("Loading configuration from $file ...\n"); - - unless ( (-e $file) && (-r $file) ) - { die("Unable to read config file $file: $!"); } - - open(F, $file); - - our ($interval, $fctemps, $fcfans, $mintemp, $maxtemp, $minstart, -$minstop); - while($_ = ) - { - if ($_ =~ /^\s+$/) { next; } - elsif ($_ =~ /^INTERVAL=\s*(.*)$/) { $interval = $1; next; } - elsif ($_ =~ /^FCTEMPS=\s*(.*)$/) { $fctemps = $1; next; } - elsif ($_ =~ /^FCFANS=\s*(.*)$/) { $fcfans = $1; next; } - elsif ($_ =~ /^MINTEMP=\s*(.*)$/) { $mintemp = $1; next; } - elsif ($_ =~ /^MAXTEMP=\s*(.*)$/) { $maxtemp = $1; next; } - elsif ($_ =~ /^MINSTART=\s*(.*)$/) { $minstart = $1; next; } - elsif ($_ =~ /^MINSTOP=\s*(.*)$/) { $minstop = $1; next; } - } - close(F); - - unless (defined($interval)) - { die("Some settings missing ..."); } - - print("\nCommon settings:\n"); - print(" INTERVAL=$interval\n"); - - my $fcvcount = 0; - foreach my $fcv (split(/\s+/, $fctemps)) - { - ($afcpwm[$fcvcount], $afctemp[$fcvcount]) = split(/=/, $fcv); - - $fcfans =~ s/^\S*=(\S+)\s*//; $afcfan[$fcvcount] = $1; - $mintemp =~ s/^\S*=(\S+)\s*//; $afcmintemp[$fcvcount] = $1; - $maxtemp =~ s/^\S*=(\S+)\s*//; $afcmaxtemp[$fcvcount] = $1; - $minstart =~ s/^\S*=(\S+)\s*//; $afcminstart[$fcvcount] = $1; - $minstop =~ s/^\S*=(\S+)\s*//; $afcminstop[$fcvcount] = $1; - - print("\nSettings for $afcpwm[$fcvcount]:\n"); - print(" Depends on $afctemp[$fcvcount]\n"); - print(" Controls $afcfan[$fcvcount]\n"); - print(" MINTEMP = $afcmintemp[$fcvcount]\n"); - print(" MAXTEMP = $afcmaxtemp[$fcvcount]\n"); - print(" MINSTART = $afcminstart[$fcvcount]\n"); - print(" MINSTOP = $afcminstop[$fcvcount]\n"); - - $fcvcount++; - } -} - - -################################################################ -sub pwmdisable($) -{ - my $p = shift; - - if ($sysfs == 1) - { - if (open(F, ">$dir/$p")) - { - print(F MAX . '\n'); - close(F); - } - else - { die("$dir/$p : $!"); } - - my $enable = "$dir/${p}_enable"; - if (-f $enable) - { - if (open(F, ">$enable")) - { - print(F '0'); - close(F); - } - else - { die("$enable : $!"); } - } - } - else - { - if (open(F, ">$dir/$p")) - { - print(F MAX . ' 0'); - close(F); - } - else - { die("$dir/$p : $!"); } - } - return(1); -} - - -################################################################# -sub pwmenable($) -{ - my $p = shift; - - if ($sysfs == 1) - { - my $enable = "$dir/${p}_enable"; - if (-f $enable) - { - if (open(F, ">$enable")) - { - print(F "1\n"); - close(F); - } - else - { die("$enable : $!\n"); } - } - } - else - { - if (open(F, ">$dir/$p")) - { - print(F MAX . " 1\n"); - close(F); - } - else - { die("$dir/$p : $!\n"); } - } - return(1); -} - - -################################################################ -sub restorefans() -{ - $SIG{TERM} = 'IGNORE'; - $SIG{HUP} = 'IGNORE'; - $SIG{INT} = 'IGNORE'; - $SIG{QUIT} = 'IGNORE'; - - print("Aborting, restoring fans...\n"); - my $fcvcount = 0; - - while ( $fcvcount < $#afcpwm+1) - { - my $pwmo = $afcpwm[$fcvcount]; - &pwmdisable($afcpwm[$fcvcount]); - $fcvcount++; - } - print("Verify fans have returned to full speed\n"); - POSIX:_exit(-1); -} - - -############################################################ -sub UpdateFanSpeeds() -{ - my $fcvcount = 0; - - while ($fcvcount < $#afcpwm+1) - { - my $pwmo = $afcpwm[$fcvcount]; - my $tsens = $afctemp[$fcvcount]; - my $fan = $afcfan[$fcvcount]; - my $mint = $afcmintemp[$fcvcount]; - my $maxt = $afcmaxtemp[$fcvcount]; - my $minsa = $afcminstart[$fcvcount]; - my $minso = $afcminstop[$fcvcount]; - - ### tval - my $tval = 0; - if (open(F, "$dir/$tsens")) - { - $tval = ; - close(F); - } - else - { die("Error reading temperature from $dir/$tsens"); } - $tval =~ /([.\d]+)\s*$/; - $tval = int($1); - if ($sysfs == 1) - { $tval /= 1000; } - - ### pwmpval - my $pwmpval = 0; - if (open(F, "$dir/$pwmo")) - { - $pwmpval = ; - close(F); - } - else - { die("Error reading PWM value from $dir/$pwmo"); } - ($pwmpval) = split(/\s/, $pwmpval); - - ### fanval - my $fanval = 0; - if (open(F, "$dir/$fan")) - { - $fanval = ; - close(F); - } - else - { die("Error reading Fan value from $dir/$fan"); } - $fanval =~ /(\d+)\s$/; - $fanval = $1; - - ### DEBUG - if (DEBUG == 1) - { - print("pwmo=$pwmo\n"); - print("tsens=$tsens\n"); - print("fan=$fan\n"); - print("mint=$mint\n"); - print("maxt=$maxt\n"); - print("minsa=$minsa\n"); - print("minso=$minso\n"); - print("tval=$tval\n"); - print("pwmpval=$pwmpval\n"); - print("fanval=$fanval\n"); - print("\n"); - } - - my $pwmval; - if ($tval <= $mint) - { $pwmval = 0; } - elsif ($tval >= $maxt) - { $pwmval = MAX; } - else - { - $pwmval = eval ( ($tval - $mint) / ($maxt - $mint) ); - $pwmval *= (255 - $minso); - $pwmval += $minso; - $pwmval = int($pwmval); - if ( ($pwmval == 0) || ($fanval == 0) ) - { - if (open(F, ">$dir/$pwmo")) - { - print(F "$minsa\n"); - close(F); - } - else - { die("Error writing PWM value to $dir/$pwmo : $!\n"); } - sleep 1; - } - } - - if (open(F, ">$dir/$pwmo")) - { - print(F "$pwmval\n"); - close(F); - } - else - { die("Error writing PWM value to $dir/$pwmo : $!\n"); } - - if (DEBUG == 1) - { print("new pwmval = $pwmval\n"); } - - $fcvcount++; - } - -} - -1; - - diff --git a/prog/pwm/pwmconfig b/prog/pwm/pwmconfig index e0db0e69..c705f3e8 100755 --- a/prog/pwm/pwmconfig +++ b/prog/pwm/pwmconfig @@ -1,6 +1,6 @@ #!/bin/bash # -# pwmconfig v0.10 +# pwmconfig # Tests the pwm outputs of sensors and configures fancontrol # # Warning!!! This program will stop your fans, one at a time, @@ -9,7 +9,7 @@ # Verify that all fans are running at normal speed after this # program has exited!!! # -# Copyright (C) 2007, 2008 Jean Delvare +# Copyright (C) 2007-2008 Jean Delvare # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -23,9 +23,25 @@ # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software -# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, +# MA 02110-1301 USA. # # + +REVISION=$(echo '$Revision$' | cut -d' ' -f2) +REVDATE=$(echo '$Date$' | cut -d' ' -f2) +PIDFILE="/var/run/fancontrol.pid" + +if [ -f "$PIDFILE" ] +then + echo "File $PIDFILE exists. This typically means that the" + echo "fancontrol deamon is running. You should stop it before running pwmconfig." + echo "If you are certain that fancontrol is not running, then you can delete" + echo "$PIDFILE manually." + exit 1 +fi + +echo "# pwmconfig revision $REVISION ($REVDATE)" echo 'This program will search your sensors for pulse width modulation (pwm)' echo 'controls, and test each one to see if it controls a fan on' echo 'your motherboard. Note that many motherboards do not have pwm' @@ -61,7 +77,7 @@ fi cd $DIR if [ "$SYSFS" = "2" ] then - PREFIX='hwmon*/device' + PREFIX='hwmon*' else PREFIX='*-*' fi @@ -72,28 +88,60 @@ then exit 1 fi -MATCH=$PREFIX/'pwm[1-9]' -PWM=`echo $MATCH` -if [ "$SYSFS" = "1" -a "$MATCH" = "$PWM" ] +# For sysfs, we may need to adjust the device path +if [ "$SYSFS" = "2" ] then - # Deprecated naming scheme (used in kernels 2.6.5 to 2.6.9) - MATCH=$PREFIX/'fan[1-9]_pwm' - PWM=`echo $MATCH` + OLD_DEVICES="$DEVICES" + DEVICES="" + + for device in $OLD_DEVICES + do + if [ ! -r "$device/name" ] + then + device="$device/device" + fi + + DEVICES="$DEVICES $device" + done fi -if [ "$MATCH" = "$PWM" ] + + +for device in $DEVICES +do + # Find available fan control outputs + MATCH=$device/'pwm[1-9]' + device_pwm=`echo $MATCH` + if [ "$SYSFS" = "1" -a "$MATCH" = "$device_pwm" ] + then + # Deprecated naming scheme (used in kernels 2.6.5 to 2.6.9) + MATCH=$device/'fan[1-9]_pwm' + device_pwm=`echo $MATCH` + fi + if [ "$MATCH" != "$device_pwm" ] + then + PWM="$PWM $device_pwm" + fi + + # Find available fan monitoring inputs + if [ -n "$SYSFS" ] + then + MATCH=$device/'fan[1-9]_input' + else + MATCH=$device/'fan[1-9]' + fi + device_fan=`echo $MATCH` + if [ "$MATCH" != "$device_fan" ] + then + FAN="$FAN $device_fan" + fi +done + +if [ -z "$PWM" ] then echo $0: 'There are no pwm-capable sensor modules installed' exit 1 fi - -if [ -n "$SYSFS" ] -then - MATCH=$PREFIX/'fan[1-9]_input' -else - MATCH=$PREFIX/'fan[1-9]' -fi -FAN=`echo $MATCH` -if [ "$MATCH" = "$FAN" ] +if [ -z "$FAN" ] then echo $0: 'There are no fan-capable sensor modules installed' exit 1 @@ -103,9 +151,13 @@ fi # Only works with Linux 2.6 function print_devices() { + local name + for device in $DEVICES do - echo "$1$device is `cat $device/name`" + name=`cat $device/name 2> /dev/null` + [ -z "$name" ] && name="unknown (no name attribute)" + echo "$1$device is $name" done } @@ -317,6 +369,11 @@ function pwmdetail() then PLOT=y fi + else + if [ -n "$DISPLAY" ] + then + echo "Note: If you had $PLOTTER installed, I could generate a graphical plot." + fi fi if [ "$PLOT" = "y" ] @@ -332,6 +389,7 @@ function pwmdetail() > $TMP2 fi + local threshold=100000 let pwm=$MAX pwmenable $P while [ $pwm -ge 0 ] @@ -347,7 +405,15 @@ function pwmdetail() fi # this will return the first field if there's only one (sysfs) S=`cat $F | cut -d' ' -f2` - echo " PWM $pwm FAN $S" + # Fan speed should never increase significantly + if [ $S -gt $threshold ] + then + echo " PWM $pwm FAN $S (probably incorrect)" + else + echo " PWM $pwm FAN $S" + let threshold=S*6/5 + fi + if [ "$PLOT" = "y" ] then echo "$pwm $S" >> $TMP2 @@ -423,8 +489,10 @@ do let pwmactivecount=1 pwmactive="$i ${pwmactive}" fanactive="$j ${fanactive}" + fanactive_min="$S ${fanactive_min}" else fanactive="$j+${fanactive}" #not supported yet by fancontrol + fanactive_min="$S+${fanactive_min}" fi sleep $DELAY if [ $? -ne 0 ] @@ -484,48 +552,62 @@ then exit fi -if [ -n "$SYSFS" ] -then - MATCH=$PREFIX/'temp[1-9]_input' -else - MATCH=$PREFIX/'temp[1-9]' -fi -TEMPS=`echo $MATCH` -if [ "$MATCH" = "$TEMPS" ] +for device in $DEVICES +do + # Find available temperature monitoring inputs + if [ -n "$SYSFS" ] + then + MATCH=$device/'temp[1-9]_input' + else + MATCH=$device/'temp[1-9]' + fi + device_temp=`echo $MATCH` + if [ "$MATCH" != "$device_temp" ] + then + TEMPS="$TEMPS $device_temp" + fi +done + +if [ -z "$TEMPS" ] then echo $0: 'There are no temperature-capable sensor modules installed' exit 1 fi -function AskPath { +function AskPath() +{ echo -n 'What should be the path to your fancontrol config file (/etc/fancontrol)? ' - read X - if [ "$X" = "y" -o "$X" = "Y" -o "$X" = "" ] + read FCCONFIG + if [ "$FCCONFIG" = "" ] then - X=/etc/fancontrol - fi - if [ -f $X ] - then - FCCONFIG=$X - else - echo -n "$X does not exist, shall I create it now (y)? " - read Y - if [ "$Y" = "y" -o "$Y" = "Y" -o "$Y" = "" ] - then - touch $X - chmod 0660 $X - chown root.root $X - FCCONFIG=$X - else - AskPath - fi + FCCONFIG="/etc/fancontrol" fi } AskPath -function LoadConfig { +function ClearConfig() +{ + FCTEMPS="" + FCFANS="" + MINTEMP="" + MAXTEMP="" + MINSTART="" + MINSTOP="" + MINPWM="" + MAXPWM="" +} + +function LoadConfig() +{ + # Nothing to do + if [ ! -f "$1" ] + then + ClearConfig + return 0 + fi + echo "Loading configuration from $1 ..." INTERVAL=`egrep '^INTERVAL=.*$' $1 | sed -e 's/INTERVAL= *//g'` FCTEMPS=`egrep '^FCTEMPS=.*$' $1 | sed -e 's/FCTEMPS= *//g'` @@ -544,14 +626,7 @@ function LoadConfig { if [ ! -f "`echo $item | sed -e 's/=.*$//'`" ] then echo "Configuration appears to be outdated, discarded" - FCTEMPS="" - FCFANS="" - MINTEMP="" - MAXTEMP="" - MINSTART="" - MINSTOP="" - MINPWM="" - MAXPWM="" + ClearConfig return 0 fi done @@ -559,24 +634,26 @@ function LoadConfig { LoadConfig $FCCONFIG -function TestMinStart { +# $1 = pwm value below which the fan is stopped +function TestMinStart() +{ echo echo 'Now we increase the PWM value in 10-unit-steps.' echo 'Let the fan stop completely, then press return until the' echo "fan starts spinning. Then enter 'y'." echo 'We will use this value +20 as the starting speed.' let fanok=0 - let fanval=0 + let fanval="$1" pwmenable $pwms until [ "$fanok" = "1" ] do - let fanval=fanval+10 if [ $fanval -gt 240 ] ; then let fanval=$MAX ; let fanok=1 ; fi echo -n "Setting $pwms to $fanval..." pwmset $pwms $fanval read FANTEST if [ "$FANTEST" != "" ] ; then let fanok=1 ; fi + let fanval=fanval+10 done pwmdisable $pwms @@ -585,42 +662,66 @@ function TestMinStart { echo "OK, using $fanval" } -function TestMinStop { +# $1 = fan input to read the fan speed from +function TestMinStop() +{ + local faninput=$1 + local threshold=100000 + local fanspeed + echo - echo 'Now we decrease the PWM value in 10-unit-steps.' - echo 'Let the fan reach full speed, then press return until the' - echo "fan stops spinning. Then enter 'y'." - echo 'We will use this value +20 as the minimum speed.' - let fanok=0 + echo 'Now we decrease the PWM value to figure out the lowest usable value.' + echo 'We will use a slightly greater value as the minimum speed.' let fanval=$MAX pwmenable $pwms - until [ "$fanok" = "1" ] + while [ $fanval -ge 0 ] do - let fanval=fanval-10 - if [ $fanval -lt 0 ] ; then let fanval=0 ; let fanok=1 ; fi - echo -n "Setting $pwms to $fanval..." pwmset $pwms $fanval - read FANTEST - if [ "$FANTEST" != "" ] ; then let fanok=1 ; fi + sleep $PDELAY + fanspeed=`cat $faninput | cut -d' ' -f2` + if [ $fanspeed -gt $threshold ] + then + echo " PWM $fanval -> $fanspeed RPM (probably incorrect)" + break + else + echo " PWM $fanval -> $fanspeed RPM" + if [ $fanspeed = "0" -o $fanspeed = "-1" ] + then + break + fi + let threshold=fanspeed*6/5 + fi + if [ $fanval -lt $STEP2_BELOW ] + then + let fanval=$fanval-$STEP2 + else + let fanval=$fanval-$STEP + fi done pwmdisable $pwms - let fanval=fanval+20 - if [ $fanval -gt $MAX ] ; then let fanval=$MAX ; fi + if [ $fanval -lt $STEP2_BELOW ] + then + let 'fanval=fanval+2*STEP2' + else + let 'fanval=fanval+STEP' + fi echo "OK, using $fanval" } -function SaveConfig { +function SaveConfig() +{ echo echo "Saving configuration to $FCCONFIG..." tmpfile=`mktemp -t pwmcfg.XXXXXXXXXX` || { echo "$0: Cannot create temporary file" >&2; exit 1; } trap " [ -f \"$tmpfile\" ] && /bin/rm -f -- \"$tmpfile\"" 0 1 2 3 13 15 - egrep -v '(INTERVAL|FCTEMPS|FCFANS|MAXTEMP|MINTEMP|MINSTART|MINSTOP|MINPWM|MAXPWM)' $FCCONFIG >$tmpfile + echo "# Configuration file generated by pwmconfig, changes will be lost" >$tmpfile echo -e "INTERVAL=$INTERVAL\nFCTEMPS=$FCTEMPS\nFCFANS=$FCFANS\nMINTEMP=$MINTEMP\nMAXTEMP=$MAXTEMP\nMINSTART=$MINSTART\nMINSTOP=$MINSTOP" >>$tmpfile [ -n "$MINPWM" ] && echo "MINPWM=$MINPWM" >>$tmpfile [ -n "$MAXPWM" ] && echo "MAXPWM=$MAXPWM" >>$tmpfile mv $tmpfile $FCCONFIG + chmod +r $FCCONFIG #check if file was written correctly echo 'Configuration saved' } @@ -632,7 +733,18 @@ DEFMAXTEMP=60 DEFMINSTART=150 DEFMINSTOP=100 -#the section below has a high potential for usability improvements +function filter_cfgvar() +{ + echo "$1" | sed -e 's/ /\n/g' \ + | egrep "$2" \ + | sed -e 's/.*=//g' +} + +# "select" won't repeat the list of options, so we enclose it in a +# never-ending loop so that it starts over again with each iteration. +# I admit it's not exactly nice, but I do not have a better idea to +# keep usability at an acceptable level. +while [ 1 ] ; do echo echo 'Select fan output to configure, or other action:' select pwms in $pwmactive "Change INTERVAL" "Just quit" "Save and quit" "Show configuration"; do @@ -640,8 +752,9 @@ select pwms in $pwmactive "Change INTERVAL" "Just quit" "Save and quit" "Show co "Change INTERVAL") echo echo "Current interval is $INTERVAL seconds." - echo -n "Enter the interval at which fancontrol should update PWM values (in s):" - read INTERVAL ;; #check user input here + echo -n "Enter the interval at which fancontrol should update PWM values (in s): " + read INTERVAL #check user input here + break ;; "Just quit") exit ;; "Save and quit") @@ -655,20 +768,21 @@ select pwms in $pwmactive "Change INTERVAL" "Just quit" "Save and quit" "Show co do echo echo "Settings of ${pwmo}:" - echo " Depends on `echo $FCTEMPS |sed -e 's/ /\n/g' |egrep \"${pwmo}\" |sed -e 's/.*=//g'`" - echo " Controls `echo $FCFANS |sed -e 's/ /\n/g' |egrep \"${pwmo}\" |sed -e 's/.*=//g'`" - echo " MINTEMP=`echo $MINTEMP |sed -e \"s/ /\n/g\" |egrep \"${pwmo}\" |sed -e \"s/.*=//g\"`" - echo " MAXTEMP=`echo $MAXTEMP |sed -e \"s/ /\n/g\" |egrep \"${pwmo}\" |sed -e \"s/.*=//g\"`" - echo " MINSTART=`echo $MINSTART |sed -e \"s/ /\n/g\" |egrep \"${pwmo}\" |sed -e \"s/.*=//g\"`" - echo " MINSTOP=`echo $MINSTOP |sed -e \"s/ /\n/g\" |egrep \"${pwmo}\" |sed -e \"s/.*=//g\"`" - XMINP=`echo $MINPWM | sed -e "s/ /\n/g" | egrep "${pwmo}" | sed -e "s/.*=//g"` + echo " Depends on `filter_cfgvar "$FCTEMPS" "$pwmo"`" + echo " Controls `filter_cfgvar "$FCFANS" "$pwmo"`" + echo " MINTEMP=`filter_cfgvar "$MINTEMP" $pwmo`" + echo " MAXTEMP=`filter_cfgvar "$MAXTEMP" "$pwmo"`" + echo " MINSTART=`filter_cfgvar "$MINSTART" "$pwmo"`" + echo " MINSTOP=`filter_cfgvar "$MINSTOP" "$pwmo"`" + XMINP=`filter_cfgvar "$MINPWM" "$pwmo"` [ -n "$XMINP" ] && echo " MINPWM=$XMINP" - XMAXP=`echo $MAXPWM | sed -e "s/ /\n/g" | egrep "${pwmo}" | sed -e "s/.*=//g"` + XMAXP=`filter_cfgvar "$MAXPWM" "$pwmo"` [ -n "$XMAXP" ] && echo " MAXPWM=$XMAXP" done - echo ;; + echo + break ;; - "`echo ${pwmactive} |sed -e 's/ /\n/g' | egrep \"${pwms}\"`" ) + "`echo ${pwmactive} |sed -e 's/ /\n/g' | egrep "${pwms}"`" ) pwmsed=`echo ${pwms} | sed -e 's/\//\\\\\//g'` #escape / for sed echo if [ -n "$SYSFS" ] @@ -689,7 +803,8 @@ select pwms in $pwmactive "Change INTERVAL" "Just quit" "Save and quit" "Show co echo "$j $S" done FAN=`echo $fanactive|cut -d' ' -f$REPLY` - FCFANS="`echo $FCFANS | sed -e "s/${pwmsed}[^ ]* *//g\"` ${pwms}=$FAN" + FAN_MIN=`echo $fanactive_min|cut -d' ' -f$REPLY` + FCFANS="`echo $FCFANS | sed -e "s/${pwmsed}[^ ]* *//g"` ${pwms}=$FAN" echo echo "Select a temperature sensor as source for ${pwms}:" select tempss in $TEMPS "None (Do not affect this PWM output)"; do @@ -702,7 +817,7 @@ select pwms in $pwmactive "Change INTERVAL" "Just quit" "Save and quit" "Show co then FCTEMPS="${pwms}=${tempss}" else - FCTEMPS="`echo $FCTEMPS | sed -e "s/${pwmsed}[^ ]* *//g\"` ${pwms}=${tempss}" + FCTEMPS="`echo $FCTEMPS | sed -e "s/${pwmsed}[^ ]* *//g"` ${pwms}=${tempss}" fi fi echo @@ -717,7 +832,7 @@ select pwms in $pwmactive "Change INTERVAL" "Just quit" "Save and quit" "Show co then MINTEMP="${pwms}=${XMT}" else - MINTEMP="`echo $MINTEMP | sed -e \"s/${pwmsed}[^ ]* *//g\"` ${pwms}=${XMT}" + MINTEMP="`echo $MINTEMP | sed -e "s/${pwmsed}[^ ]* *//g"` ${pwms}=${XMT}" fi echo echo 'Enter the high temperature (degree C)' @@ -731,61 +846,81 @@ select pwms in $pwmactive "Change INTERVAL" "Just quit" "Save and quit" "Show co then MAXTEMP="${pwms}=${XMT}" else - MAXTEMP="`echo $MAXTEMP | sed -e \"s/${pwmsed}[^ ]* *//g\"` ${pwms}=${XMT}" + MAXTEMP="`echo $MAXTEMP | sed -e "s/${pwmsed}[^ ]* *//g"` ${pwms}=${XMT}" fi - echo - echo "Enter the minimum PWM value (0-$MAX)" - echo -n "at which the fan STARTS spinning (press t to test) ($DEFMINSTART): " - read XMV - if [ "$XMV" = "" ] + + if [ $FAN_MIN -eq 0 ] then - XMV=$DEFMINSTART - fi - if [ "$XMV" = "t" -o "$XMV" = "T" ] - then - TestMinStart - XMV=$fanval - fi - if [ "$MINSTART" = "" ] - then - MINSTART="${pwms}=${XMV}" + echo + echo "Enter the minimum PWM value (0-$MAX)" + echo -n "at which the fan STOPS spinning (press t to test) ($DEFMINSTOP): " + read XMSTOP + + if [ "$XMSTOP" = "" ] + then + XMSTOP=$DEFMINSTOP + fi + if [ "$XMSTOP" = "t" -o "$XMSTOP" = "T" ] + then + TestMinStop $FAN + XMSTOP=$fanval + fi else - MINSTART="`echo $MINSTART | sed -e \"s/${pwmsed}[^ ]* *//g\"` ${pwms}=${XMV}" - fi - echo - echo "Enter the minimum PWM value (0-$MAX)" - echo -n "at which the fan STOPS spinning (press t to test) ($DEFMINSTOP): " - read XMV - if [ "$XMV" = "" ] - then - XMV=$DEFMINSTOP - fi - if [ "$XMV" = "t" -o "$XMV" = "T" ] - then - TestMinStop - XMV=$fanval + XMSTOP=0 fi if [ "$MINSTOP" = "" ] then - MINSTOP="${pwms}=${XMV}" + MINSTOP="${pwms}=${XMSTOP}" else - MINSTOP="`echo $MINSTOP | sed -e \"s/${pwmsed}[^ ]* *//g\"` ${pwms}=${XMV}" + MINSTOP="`echo $MINSTOP | sed -e "s/${pwmsed}[^ ]* *//g"` ${pwms}=${XMSTOP}" + fi + + if [ $FAN_MIN -eq 0 ] + then + echo + echo "Enter the minimum PWM value ($XMSTOP-$MAX)" + echo -n "at which the fan STARTS spinning (press t to test) ($DEFMINSTART): " + read XMSTART + + if [ "$XMSTART" = "" ] + then + XMSTART=$DEFMINSTART + fi + if [ "$XMSTART" = "t" -o "$XMSTART" = "T" ] + then + TestMinStart $XMSTOP + XMSTART=$fanval + fi + else + XMSTART=$DEFMINSTART + fi + if [ "$MINSTART" = "" ] + then + MINSTART="${pwms}=${XMSTART}" + else + MINSTART="`echo $MINSTART | sed -e "s/${pwmsed}[^ ]* *//g"` ${pwms}=${XMSTART}" + fi + + if [ $XMSTOP -gt 0 ] + then + echo + echo "Enter the PWM value (0-$XMSTOP) to use when the temperature" + echo -n "is below the low temperature limit (0): " + read XMINP + else + XMINP="" fi - echo - echo "Enter the PWM value (0-$XMV) to use when the temperature" - echo -n "is below the low temperature limit (0): " - read XMINP if [ -n "$XMINP" ] then if [ "$MINPWM" = "" ] then MINPWM="${pwms}=${XMINP}" else - MINPWM="`echo $MINPWM | sed -e \"s/${pwmsed}[^ ]* *//g\"` ${pwms}=${XMINP}" + MINPWM="`echo $MINPWM | sed -e "s/${pwmsed}[^ ]* *//g"` ${pwms}=${XMINP}" fi fi echo - echo "Enter the PWM value ($XMV-$MAX) to use when the temperature" + echo "Enter the PWM value ($XMSTOP-$MAX) to use when the temperature" echo -n "is over the high temperature limit ($MAX): " read XMAXP if [ -n "$XMAXP" ] @@ -794,16 +929,17 @@ select pwms in $pwmactive "Change INTERVAL" "Just quit" "Save and quit" "Show co then MAXPWM="${pwms}=${XMAXP}" else - MAXPWM="`echo $MAXPWM | sed -e \"s/${pwmsed}[^ ]* *//g\"` ${pwms}=${XMAXP}" + MAXPWM="`echo $MAXPWM | sed -e "s/${pwmsed}[^ ]* *//g"` ${pwms}=${XMAXP}" fi fi echo break; - done ;; + done + break ;; *) - grep $pwm - - echo "No such option. Enter a number." ;; + echo "No such option. Enter a number." + break ;; esac done +done diff --git a/prog/pwm/pwmconfig.8 b/prog/pwm/pwmconfig.8 index 42bc4a0d..9e5201e1 100644 --- a/prog/pwm/pwmconfig.8 +++ b/prog/pwm/pwmconfig.8 @@ -1,10 +1,23 @@ -.TH PWMCONFIG 8 "January 27, 2005" +.TH PWMCONFIG 8 "September 28, 2008" "lm-sensors 3" .SH NAME pwmconfig \- tests the PWM outputs of sensors and configures fancontrol .SH SYNOPSIS .B pwmconfig +.SH WARNING +\fBpwmconfig\fR will attempt to stop your fans, one at a time, for +approximately 5 seconds each. This may cause your processor +temperature to rise. Verify that all fans are running at normal speed +after this program has exited. +\fBpwmconfig\fR does its best to check that the fans are spinning when +they are supposed to, but due to the diversity of available +motherboards and fans, it shouldn't be blindly trusted. Always verify +by yourself. + +It is strongly recommended to run \fBpwmconfig\fR at a time when there +is no significant system load, to minimize the risk of overheating. + .SH DESCRIPTION .B pwmconfig searches your sensors for pulse width modulation (PWM) @@ -12,22 +25,31 @@ controls, and tests each one to see if it controls a fan on your motherboard. Note that many motherboards do not have PWM circuitry installed, even if your sensor chip supports PWM. -It attempts to briefly stop each fan using the PWM controls. It then -attempts to restore each fan to full speed after testing. However, it -is \fBvery important\fP that you physically verify that the fans have -been returned to full speed after the program has completed. +When a connection is established between a PWM control and a fan, +\fBpwmconfig\fR can generate a detailed correlation, to show how a +given fan is responding to various PWM duty cycles. -.SH WARNING -This program will stop your fans, one at a time, for approximately 5 seconds each. -This may cause your processor temperature to rise. Verify that all fans are running -at normal speed after this program has exited. +Lastly, \fBpwmconfig\fR will enter in \fBfancontrol\fR configuration +mode (unless you decide to skip that part.) In this mode, you are +invited to enter several parameters which will determine how the +\fBfancontrol\fR daemon regulates the speed of one or more fans in +your system based on temperature measurements. In particular, you will +have the opportunity to establish mappings between fans and +temperature inputs, define the temperature range over which the speed +of the fan should be adjusted dynamically, the minimum speed at which +the fan should spin, etc. See fancontrol(8) for additional +information. -.SH CONFORMING TO -lm_sensors-2.x +.SH BUGS +The term "PWM" is used because most fan control systems in computers +are based on pulse width modulation. Some motherboards however use DC +variation instead. So, the term "PWM" should be seen as a generic term +for "fan speed control", regardless of the actual method used. .SH SEE ALSO fancontrol(8), sensors(1). -.SH AUTHOR +.SH AUTHORS .PP -Marius Reiner +Marius Reiner , +Jean Delvare diff --git a/prog/pwm/vt1211_pwm b/prog/pwm/vt1211_pwm new file mode 100755 index 00000000..e03a65da --- /dev/null +++ b/prog/pwm/vt1211_pwm @@ -0,0 +1,179 @@ +#!/bin/sh +# +# vt1211_pwm - Manually control the PWM outputs of the VIA vt1211 Super-I/O +# +# Copyright (C) 2008 Juerg Haefliger (juergh at gmail.com> +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +# + +function usage +{ + echo "Usage: vt1211_pwm -i | -r | -s ," + echo + echo "DESCRIPTION" + echo " This tool provides manual control of the PWM outputs of the VIA " + echo " vt1211 Super-I/O." + echo + echo "OPTIONS" + echo " -d Display the current PWM settings of the vt1211." + echo " -i Initialize the PWM output for manual control." + echo " -r Restore the PWM output to the original settings." + echo " -s , Set the PWM output duty-cycle. " + echo + echo "WITH" + echo " PWM output (1-2)." + echo " PWM duty-cycle (0-255)." + echo + exit 2 +} + +function set_attr +{ + local tmp + read tmp < $1 + echo "echo $tmp > $1" + echo $2 > $1 +} + +# check if we have the right permissions to run +if [ `whoami` != "root" ] ; then + echo "You must be root to run this script." + exit 1 +fi + +# parse the command line options +action= +nr=1 +val=0 +while getopts di:r:s: opt ; do + [ -z "$action" ] || usage + case $opt in + d) action="display" + ;; + i) action="init" + nr=$OPTARG + ;; + r) action="restore" + nr=$OPTARG + ;; + s) action="set" + nr=${OPTARG%,*} + val=${OPTARG#*,} + ;; + ?) usage + ;; + esac +done + +[ -z "$action" ] && usage +[ $nr -lt 1 -o $nr -gt 2 ] && usage +[ $val -lt 0 -o $val -gt 255 ] && usage + +# check hwmon device +dev=`ls -d /sys/devices/platform/vt1211.*` +if [ -z "$dev" ] ; then + echo "Platform device vt1211 not found. Did you load the vt1211 module?" + exit 1 +fi + +# init file +initfile="/root/.vt1211_pwm${nr}" + +# ACTION: display +if [ $action = "display" ] ; then + for nr in 1 2 ; do + read mode < ${dev}/pwm${nr}_enable + if [ $mode -eq 0 ] ; then + mode_txt="(disabled)" + elif [ $mode -eq 2 ] ; then + mode_txt="(auto) " + else + mode_txt="(unknown) " + fi + read val < ${dev}/pwm${nr} + dc=$((val * 100 / 255)) + echo "pwm${nr}: mode = ${mode} ${mode_txt}, val = ${val} (${dc}%)" + done +fi + +# ACTION: init +if [ $action = "init" ] ; then + # check for an init file + if [ -e $initfile ] ; then + echo " $initfile exists. Did you already initialize this PWM?" + exit 1 + fi + + ( + # set the pwm-to-temp mapping + # use the internal temp as a reference + set_attr ${dev}/pwm${nr}_auto_channels_temp 2 + + # enable the pwm auto controller + set_attr ${dev}/pwm${nr}_enable 2 + + # set the PWM duty-cycle + set_attr ${dev}/pwm${nr}_auto_point2_pwm 0 + set_attr ${dev}/pwm${nr}_auto_point3_pwm 255 + + # set the temp boundaries to extrem values + set_attr ${dev}/pwm1_auto_point1_temp 0 + set_attr ${dev}/pwm1_auto_point2_temp 0 + set_attr ${dev}/pwm1_auto_point3_temp 1000000 + set_attr ${dev}/pwm1_auto_point4_temp 1000000 + + ) > $initfile + + exit 0 +fi + +# ACTION: restore +if [ $action = "restore" ] ; then + # check for an init file + if [ ! -e $initfile ] ; then + echo " $initfile not found. Nothing to restore." + exit 1 + fi + + sh $initfile + rm $initfile + + exit 0 +fi + +# ACTION: set +if [ $action = "set" ] ; then + # check for an init file + if [ ! -e $initfile ] ; then + echo "$initfile not found. Did you initialize this PWM?" + exit 1 + fi + + # set the PWM duty-cycle + echo $val > ${dev}/pwm${nr}_auto_point3_pwm + + # fool the vt1211 into believing there is a temp change + # otherwise the new PWM duty-cycle doesn't take effect + echo 0 > ${dev}/pwm1_auto_point3_temp + echo 1000000 > ${dev}/pwm1_auto_point3_temp + + # read the new PWM duty-cycle back and print it + read val < ${dev}/pwm${nr} + dc=$((val * 100 / 255)) + echo "pwm${nr} is now at ${val} (${dc}%)." + + exit 0 +fi diff --git a/prog/pwm/vt1211_pwm.8 b/prog/pwm/vt1211_pwm.8 new file mode 100644 index 00000000..f4a3c5e1 --- /dev/null +++ b/prog/pwm/vt1211_pwm.8 @@ -0,0 +1,52 @@ +.TH VT1211_PWM 8 "July 2008" "lm-sensors 3" +.SH NAME +vt1211_pwm \- manual control of VIA vt1211 PWM outputs + +.SH SYNOPSIS +.B vt1211_pwm +.B -d | -i | -r | -s , + +.SH DESCRIPTION +\fBvt1211_pwm\fP is a shell script that provides manual control of the two PWM +outputs of the VIA vt1211 Super-I/O device. + +.SH OPTIONS +.TP +.B -d +Display the current settings of the two PWM outputs. +.TP +.B -i +Initialize PWM \fB\fP for manual control. Valid numbers for \fB\fP +are 1 or 2. This option also writes the original vt1211 register values to +~/.vt1211_pwm\fB\fP which is used for restoring the original settings. +.TP +.B -r +Restore PWM \fB\fP to the orignal settings. Valid numbers for \fB\fP +are 1 or 2. This options reads the original settings from +~/.vt1211_pwm\fB\fP and writes them to the vt1211. +.TP +.B -s , +Set PMW \fB\fP output to \fB\fP. Valid numbers for \fB\fP are 1 +or 2 and valid numbers for \fB\fP are 0 to 255. The \fB\fP range of +0-255 maps to an output duty-cycle of 0%-100%, i.e., output duty-cycle = +\fB\fP * 100 / 255. + +.SH REQUIREMENTS +You need root privileges to execute the vt1211_pwm script and the vt1211 kernel +module needs to be loaded and you obviously need to have fans connected to the +PWM outputs of the vt1211 :-) + +.SH WARNING +This script puts the PWM controller of the vt1211 into automatic mode and +toggles the thermal thresholds between extrem values to fool the chip into +believing that there is a temperature change and thus forcing the PWM outputs +to change to the specified values. Since there is only a single PWM controller +that controls both PWM outputs, setting the duty-cycle of one PWM output could +affect the duty-cycle of the other PWM output. Use at you own risk! + +.SH SEE ALSO +sensors(1) + +.SH AUTHOR +.PP +Juerg Haefliger diff --git a/prog/py-smbus/README b/prog/py-smbus/README deleted file mode 100644 index b97801d4..00000000 --- a/prog/py-smbus/README +++ /dev/null @@ -1,28 +0,0 @@ - -README: py-smbus - -Prerequisites: -Be sure to build and install the lm-sensors userspace first. This package -requires one of the header files from that. - -To build: - $ python setup.py build - -To install (will also build if necessary): - $ python setup.py install - -For general build/install help: - $ python setup.py --help-commands - -Frequently Answered Question: - -Q: It's throwing exceptions, nothing works, what's wrong? - - A1: You need write permissions to the i2c-dev devices. Try running as root. - - A2: Addresses in Linux/I2C are the most-sig 7 bits, right-justified. E.g. - if your device uses address 0xc0 to write and 0xc1 to read, then use - address 0x60 with this module. - - A3: Some other kernel driver has claimed that I2C address. Unload it first. - diff --git a/prog/py-smbus/setup.py b/prog/py-smbus/setup.py deleted file mode 100644 index d85c8083..00000000 --- a/prog/py-smbus/setup.py +++ /dev/null @@ -1,14 +0,0 @@ -#!/usr/bin/env python - -from distutils.core import setup, Extension - -setup( name="smbus", - version="1.1", - description="Python bindings for Linux SMBus access through i2c-dev", - author="Mark M. Hoffman", - author_email="mhoffman@lightlink.com", - maintainer="Mark M. Hoffman", - maintainer_email="lm-sensors@lm-sensors.org", - license="GPLv2", - url="http://lm-sensors.org/", - ext_modules=[Extension("smbus", ["smbusmodule.c"])]) diff --git a/prog/py-smbus/smbusmodule.c b/prog/py-smbus/smbusmodule.c deleted file mode 100644 index afc54a41..00000000 --- a/prog/py-smbus/smbusmodule.c +++ /dev/null @@ -1,697 +0,0 @@ -/* - * smbusmodule.c - Python bindings for Linux SMBus access through i2c-dev - * Copyright (C) 2005-2007 Mark M. Hoffman - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#include -#include "structmember.h" -#include -#include -#include -#include - -/* -** These are required to build this module against Linux older than 2.6.23. -*/ -#ifndef I2C_SMBUS_I2C_BLOCK_BROKEN -#undef I2C_SMBUS_I2C_BLOCK_DATA -#define I2C_SMBUS_I2C_BLOCK_BROKEN 6 -#define I2C_SMBUS_I2C_BLOCK_DATA 8 -#endif - -PyDoc_STRVAR(SMBus_module_doc, - "This module defines an object type that allows SMBus transactions\n" - "on Linux hosts. The host kernel must have I2C support, I2C device\n" - "interface support, and a bus adapter driver. All of these can be\n" - "either built-in to the kernel, or loaded from modules.\n" - "\n" - "Because the I2C device interface is opened R/W, users of this\n" - "module usually must have root permissions.\n"); - -typedef struct { - PyObject_HEAD - - int fd; /* open file descriptor: /dev/i2c-?, or -1 */ - int addr; /* current client SMBus address */ - int pec; /* !0 => Packet Error Codes enabled */ -} SMBus; - -static PyObject * -SMBus_new(PyTypeObject *type, PyObject *args, PyObject *kwds) -{ - SMBus *self; - - if ((self = (SMBus *)type->tp_alloc(type, 0)) == NULL) - return NULL; - - self->fd = -1; - self->addr = -1; - self->pec = 0; - - return (PyObject *)self; -} - -PyDoc_STRVAR(SMBus_close_doc, - "close()\n\n" - "Disconnects the object from the bus.\n"); - -static PyObject * -SMBus_close(SMBus *self) -{ - if ((self->fd != -1) && (close(self->fd) == -1)) { - PyErr_SetFromErrno(PyExc_IOError); - return NULL; - } - - self->fd = -1; - self->addr = -1; - self->pec = 0; - - Py_INCREF(Py_None); - return Py_None; -} - -static void -SMBus_dealloc(SMBus *self) -{ - PyObject *ref = SMBus_close(self); - Py_XDECREF(ref); - - self->ob_type->tp_free((PyObject *)self); -} - -#define MAXPATH 16 - -PyDoc_STRVAR(SMBus_open_doc, - "open(bus)\n\n" - "Connects the object to the specified SMBus.\n"); - -static PyObject * -SMBus_open(SMBus *self, PyObject *args, PyObject *kwds) -{ - int bus; - char path[MAXPATH]; - - static char *kwlist[] = {"bus", NULL}; - - if (!PyArg_ParseTupleAndKeywords(args, kwds, "i:open", kwlist, &bus)) - return NULL; - - if (snprintf(path, MAXPATH, "/dev/i2c-%d", bus) >= MAXPATH) { - PyErr_SetString(PyExc_OverflowError, - "Bus number is invalid."); - return NULL; - } - - if ((self->fd = open(path, O_RDWR, 0)) == -1) { - PyErr_SetFromErrno(PyExc_IOError); - return NULL; - } - - Py_INCREF(Py_None); - return Py_None; -} - -static int -SMBus_init(SMBus *self, PyObject *args, PyObject *kwds) -{ - int bus = -1; - - static char *kwlist[] = {"bus", NULL}; - - if (!PyArg_ParseTupleAndKeywords(args, kwds, "|i:__init__", - kwlist, &bus)) - return -1; - - if (bus >= 0) { - SMBus_open(self, args, kwds); - if (PyErr_Occurred()) - return -1; - } - - return 0; -} - -/* - * private helper function, 0 => success, !0 => error - */ -static int -SMBus_set_addr(SMBus *self, int addr) -{ - int ret = 0; - - if (self->addr != addr) { - ret = ioctl(self->fd, I2C_SLAVE, addr); - self->addr = addr; - } - - return ret; -} - -#define SMBus_SET_ADDR(self, addr) do { \ - if (SMBus_set_addr(self, addr)) { \ - PyErr_SetFromErrno(PyExc_IOError); \ - return NULL; \ - } \ -} while(0) - -PyDoc_STRVAR(SMBus_write_quick_doc, - "write_quick(addr)\n\n" - "Perform SMBus Quick transaction.\n"); - -static PyObject * -SMBus_write_quick(SMBus *self, PyObject *args) -{ - int addr; - __s32 result; - - if (!PyArg_ParseTuple(args, "i:write_quick", &addr)) - return NULL; - - SMBus_SET_ADDR(self, addr); - - if ((result = i2c_smbus_write_quick(self->fd, I2C_SMBUS_WRITE))) { - PyErr_SetFromErrno(PyExc_IOError); - return NULL; - } - - Py_INCREF(Py_None); - return Py_None; -} - -PyDoc_STRVAR(SMBus_read_byte_doc, - "read_byte(addr) -> result\n\n" - "Perform SMBus Read Byte transaction.\n"); - -static PyObject * -SMBus_read_byte(SMBus *self, PyObject *args) -{ - int addr; - __s32 result; - - if (!PyArg_ParseTuple(args, "i:read_byte", &addr)) - return NULL; - - SMBus_SET_ADDR(self, addr); - - if ((result = i2c_smbus_read_byte(self->fd)) == -1) { - PyErr_SetFromErrno(PyExc_IOError); - return NULL; - } - - return Py_BuildValue("l", (long)result); -} - -PyDoc_STRVAR(SMBus_write_byte_doc, - "write_byte(addr, val)\n\n" - "Perform SMBus Write Byte transaction.\n"); - -static PyObject * -SMBus_write_byte(SMBus *self, PyObject *args) -{ - int addr, val; - __s32 result; - - if (!PyArg_ParseTuple(args, "ii:write_byte", &addr, &val)) - return NULL; - - SMBus_SET_ADDR(self, addr); - - if ((result = i2c_smbus_write_byte(self->fd, (__u8)val)) == -1) { - PyErr_SetFromErrno(PyExc_IOError); - return NULL; - } - - Py_INCREF(Py_None); - return Py_None; -} - -PyDoc_STRVAR(SMBus_read_byte_data_doc, - "read_byte_data(addr, cmd) -> result\n\n" - "Perform SMBus Read Byte Data transaction.\n"); - -static PyObject * -SMBus_read_byte_data(SMBus *self, PyObject *args) -{ - int addr, cmd; - __s32 result; - - if (!PyArg_ParseTuple(args, "ii:read_byte_data", &addr, &cmd)) - return NULL; - - SMBus_SET_ADDR(self, addr); - - if ((result = i2c_smbus_read_byte_data(self->fd, (__u8)cmd)) == -1) { - PyErr_SetFromErrno(PyExc_IOError); - return NULL; - } - - return Py_BuildValue("l", (long)result); -} - -PyDoc_STRVAR(SMBus_write_byte_data_doc, - "write_byte_data(addr, cmd, val)\n\n" - "Perform SMBus Write Byte Data transaction.\n"); - -static PyObject * -SMBus_write_byte_data(SMBus *self, PyObject *args) -{ - int addr, cmd, val; - __s32 result; - - if (!PyArg_ParseTuple(args, "iii:write_byte_data", &addr, &cmd, &val)) - return NULL; - - SMBus_SET_ADDR(self, addr); - - if ((result = i2c_smbus_write_byte_data(self->fd, - (__u8)cmd, (__u8)val)) == -1) { - PyErr_SetFromErrno(PyExc_IOError); - return NULL; - } - - Py_INCREF(Py_None); - return Py_None; -} - -PyDoc_STRVAR(SMBus_read_word_data_doc, - "read_word_data(addr, cmd) -> result\n\n" - "Perform SMBus Read Word Data transaction.\n"); - -static PyObject * -SMBus_read_word_data(SMBus *self, PyObject *args) -{ - int addr, cmd; - __s32 result; - - if (!PyArg_ParseTuple(args, "ii:read_word_data", &addr, &cmd)) - return NULL; - - SMBus_SET_ADDR(self, addr); - - if ((result = i2c_smbus_read_word_data(self->fd, (__u8)cmd)) == -1) { - PyErr_SetFromErrno(PyExc_IOError); - return NULL; - } - - return Py_BuildValue("l", (long)result); -} - -PyDoc_STRVAR(SMBus_write_word_data_doc, - "write_word_data(addr, cmd, val)\n\n" - "Perform SMBus Write Word Data transaction.\n"); - -static PyObject * -SMBus_write_word_data(SMBus *self, PyObject *args) -{ - int addr, cmd, val; - __s32 result; - - if (!PyArg_ParseTuple(args, "iii:write_word_data", &addr, &cmd, &val)) - return NULL; - - SMBus_SET_ADDR(self, addr); - - if ((result = i2c_smbus_write_word_data(self->fd, - (__u8)cmd, (__u16)val)) == -1) { - PyErr_SetFromErrno(PyExc_IOError); - return NULL; - } - - Py_INCREF(Py_None); - return Py_None; -} - -PyDoc_STRVAR(SMBus_process_call_doc, - "process_call(addr, cmd, val)\n\n" - "Perform SMBus Process Call transaction.\n"); - -static PyObject * -SMBus_process_call(SMBus *self, PyObject *args) -{ - int addr, cmd, val; - __s32 result; - - if (!PyArg_ParseTuple(args, "iii:process_call", &addr, &cmd, &val)) - return NULL; - - SMBus_SET_ADDR(self, addr); - - if ((result = i2c_smbus_process_call(self->fd, - (__u8)cmd, (__u16)val)) == -1) { - PyErr_SetFromErrno(PyExc_IOError); - return NULL; - } - - Py_INCREF(Py_None); - return Py_None; -} - -/* - * private helper function; returns a new list of integers - */ -static PyObject * -SMBus_buf_to_list(__u8 const *buf, int len) -{ - PyObject *list = PyList_New(len); - int ii; - - if (list == NULL) - return NULL; - - for (ii = 0; ii < len; ii++) { - PyObject *val = Py_BuildValue("l", (long)buf[ii]); - PyList_SET_ITEM(list, ii, val); - } - return list; -} - -PyDoc_STRVAR(SMBus_read_block_data_doc, - "read_block_data(addr, cmd) -> results\n\n" - "Perform SMBus Read Block Data transaction.\n"); - -static PyObject * -SMBus_read_block_data(SMBus *self, PyObject *args) -{ - int addr, cmd; - union i2c_smbus_data data; - - if (!PyArg_ParseTuple(args, "ii:read_block_data", &addr, &cmd)) - return NULL; - - SMBus_SET_ADDR(self, addr); - - /* save a bit of code by calling the access function directly */ - if (i2c_smbus_access(self->fd, I2C_SMBUS_READ, (__u8)cmd, - I2C_SMBUS_BLOCK_DATA, &data)) { - PyErr_SetFromErrno(PyExc_IOError); - return NULL; - } - - /* first byte of the block contains (remaining) data length */ - return SMBus_buf_to_list(&data.block[1], data.block[0]); -} - -/* - * private helper function: convert an integer list to union i2c_smbus_data - */ -static int -SMBus_list_to_data(PyObject *list, union i2c_smbus_data *data) -{ - static char *msg = "Third argument must be a list of at least one, " - "but not more than 32 integers"; - int ii, len; - - if (!PyList_Check(list)) { - PyErr_SetString(PyExc_TypeError, msg); - return 0; /* fail */ - } - - if ((len = PyList_GET_SIZE(list)) > 32) { - PyErr_SetString(PyExc_OverflowError, msg); - return 0; /* fail */ - } - - /* first byte is the length */ - data->block[0] = (__u8)len; - - for (ii = 0; ii < len; ii++) { - PyObject *val = PyList_GET_ITEM(list, ii); - if (!PyInt_Check(val)) { - PyErr_SetString(PyExc_TypeError, msg); - return 0; /* fail */ - } - data->block[ii+1] = (__u8)PyInt_AS_LONG(val); - } - - return 1; /* success */ -} - -PyDoc_STRVAR(SMBus_write_block_data_doc, - "write_block_data(addr, cmd, [vals])\n\n" - "Perform SMBus Write Block Data transaction.\n"); - -static PyObject * -SMBus_write_block_data(SMBus *self, PyObject *args) -{ - int addr, cmd; - union i2c_smbus_data data; - - if (!PyArg_ParseTuple(args, "iiO&:write_block_data", &addr, &cmd, - SMBus_list_to_data, &data)) - return NULL; - - SMBus_SET_ADDR(self, addr); - - /* save a bit of code by calling the access function directly */ - if (i2c_smbus_access(self->fd, I2C_SMBUS_WRITE, (__u8)cmd, - I2C_SMBUS_BLOCK_DATA, &data)) { - PyErr_SetFromErrno(PyExc_IOError); - return NULL; - } - - Py_INCREF(Py_None); - return Py_None; -} - -PyDoc_STRVAR(SMBus_block_process_call_doc, - "block_process_call(addr, cmd, [vals]) -> results\n\n" - "Perform SMBus Block Process Call transaction.\n"); - -static PyObject * -SMBus_block_process_call(SMBus *self, PyObject *args) -{ - int addr, cmd; - union i2c_smbus_data data; - - if (!PyArg_ParseTuple(args, "iiO&:block_process_call", &addr, &cmd, - SMBus_list_to_data, &data)) - return NULL; - - SMBus_SET_ADDR(self, addr); - - /* save a bit of code by calling the access function directly */ - if (i2c_smbus_access(self->fd, I2C_SMBUS_WRITE, (__u8)cmd, - I2C_SMBUS_BLOCK_PROC_CALL, &data)) { - PyErr_SetFromErrno(PyExc_IOError); - return NULL; - } - - /* first byte of the block contains (remaining) data length */ - return SMBus_buf_to_list(&data.block[1], data.block[0]); -} - -PyDoc_STRVAR(SMBus_read_i2c_block_data_doc, - "read_i2c_block_data(addr, cmd, len=32) -> results\n\n" - "Perform I2C Block Read transaction.\n"); - -static PyObject * -SMBus_read_i2c_block_data(SMBus *self, PyObject *args) -{ - int addr, cmd, len=32; - union i2c_smbus_data data; - - if (!PyArg_ParseTuple(args, "ii|i:read_i2c_block_data", &addr, &cmd, - &len)) - return NULL; - - SMBus_SET_ADDR(self, addr); - - data.block[0] = len; - /* save a bit of code by calling the access function directly */ - if (i2c_smbus_access(self->fd, I2C_SMBUS_READ, (__u8)cmd, - len == 32 ? I2C_SMBUS_I2C_BLOCK_BROKEN: - I2C_SMBUS_I2C_BLOCK_DATA, &data)) { - PyErr_SetFromErrno(PyExc_IOError); - return NULL; - } - - /* first byte of the block contains (remaining) data length */ - return SMBus_buf_to_list(&data.block[1], data.block[0]); -} - -PyDoc_STRVAR(SMBus_write_i2c_block_data_doc, - "write_i2c_block_data(addr, cmd, [vals])\n\n" - "Perform I2C Block Write transaction.\n"); - -static PyObject * -SMBus_write_i2c_block_data(SMBus *self, PyObject *args) -{ - int addr, cmd; - union i2c_smbus_data data; - - if (!PyArg_ParseTuple(args, "iiO&:write_i2c_block_data", &addr, &cmd, - SMBus_list_to_data, &data)) - return NULL; - - SMBus_SET_ADDR(self, addr); - - /* save a bit of code by calling the access function directly */ - if (i2c_smbus_access(self->fd, I2C_SMBUS_WRITE, (__u8)cmd, - I2C_SMBUS_I2C_BLOCK_BROKEN, &data)) { - PyErr_SetFromErrno(PyExc_IOError); - return NULL; - } - - Py_INCREF(Py_None); - return Py_None; -} - -PyDoc_STRVAR(SMBus_type_doc, - "SMBus([bus]) -> SMBus\n\n" - "Return a new SMBus object that is (optionally) connected to the\n" - "specified I2C device interface.\n"); - -static PyMethodDef SMBus_methods[] = { - {"open", (PyCFunction)SMBus_open, METH_VARARGS | METH_KEYWORDS, - SMBus_open_doc}, - {"close", (PyCFunction)SMBus_close, METH_NOARGS, - SMBus_close_doc}, - {"write_quick", (PyCFunction)SMBus_write_quick, METH_VARARGS, - SMBus_write_quick_doc}, - {"read_byte", (PyCFunction)SMBus_read_byte, METH_VARARGS, - SMBus_read_byte_doc}, - {"write_byte", (PyCFunction)SMBus_write_byte, METH_VARARGS, - SMBus_write_byte_doc}, - {"read_byte_data", (PyCFunction)SMBus_read_byte_data, METH_VARARGS, - SMBus_read_byte_data_doc}, - {"write_byte_data", (PyCFunction)SMBus_write_byte_data, METH_VARARGS, - SMBus_write_byte_data_doc}, - {"read_word_data", (PyCFunction)SMBus_read_word_data, METH_VARARGS, - SMBus_read_word_data_doc}, - {"write_word_data", (PyCFunction)SMBus_write_word_data, METH_VARARGS, - SMBus_write_word_data_doc}, - {"process_call", (PyCFunction)SMBus_process_call, METH_VARARGS, - SMBus_process_call_doc}, - {"read_block_data", (PyCFunction)SMBus_read_block_data, METH_VARARGS, - SMBus_read_block_data_doc}, - {"write_block_data", (PyCFunction)SMBus_write_block_data, METH_VARARGS, - SMBus_write_block_data_doc}, - {"block_process_call", (PyCFunction)SMBus_block_process_call, - METH_VARARGS, SMBus_block_process_call_doc}, - {"read_i2c_block_data", (PyCFunction)SMBus_read_i2c_block_data, - METH_VARARGS, SMBus_read_i2c_block_data_doc}, - {"write_i2c_block_data", (PyCFunction)SMBus_write_i2c_block_data, - METH_VARARGS, SMBus_write_i2c_block_data_doc}, - {NULL}, -}; - -static PyObject * -SMBus_get_pec(SMBus *self, void *closure) -{ - PyObject *result = self->pec ? Py_True : Py_False; - Py_INCREF(result); - return result; -} - -static int -SMBus_set_pec(SMBus *self, PyObject *val, void *closure) -{ - int pec; - - pec = PyObject_IsTrue(val); - - if (val == NULL) { - PyErr_SetString(PyExc_TypeError, - "Cannot delete attribute"); - return -1; - } - else if (pec == -1) { - PyErr_SetString(PyExc_TypeError, - "The pec attribute must be a boolean."); - return -1; - } - - if (self->pec != pec) { - if (ioctl(self->fd, I2C_PEC, pec)) { - PyErr_SetFromErrno(PyExc_IOError); - return -1; - } - self->pec = pec; - } - - return 0; -} - -static PyGetSetDef SMBus_getset[] = { - {"pec", (getter)SMBus_get_pec, (setter)SMBus_set_pec, - "True if Packet Error Codes (PEC) are enabled"}, - {NULL}, -}; - -static PyTypeObject SMBus_type = { - PyObject_HEAD_INIT(NULL) - 0, /* ob_size */ - "SMBus", /* tp_name */ - sizeof(SMBus), /* tp_basicsize */ - 0, /* tp_itemsize */ - (destructor)SMBus_dealloc, /* tp_dealloc */ - 0, /* tp_print */ - 0, /* tp_getattr */ - 0, /* tp_setattr */ - 0, /* tp_compare */ - 0, /* tp_repr */ - 0, /* tp_as_number */ - 0, /* tp_as_sequence */ - 0, /* tp_as_mapping */ - 0, /* tp_hash */ - 0, /* tp_call */ - 0, /* tp_str */ - 0, /* tp_getattro */ - 0, /* tp_setattro */ - 0, /* tp_as_buffer */ - Py_TPFLAGS_DEFAULT, /* tp_flags */ - SMBus_type_doc, /* tp_doc */ - 0, /* tp_traverse */ - 0, /* tp_clear */ - 0, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ - 0, /* tp_iter */ - 0, /* tp_iternext */ - SMBus_methods, /* tp_methods */ - 0, /* tp_members */ - SMBus_getset, /* tp_getset */ - 0, /* tp_base */ - 0, /* tp_dict */ - 0, /* tp_descr_get */ - 0, /* tp_descr_set */ - 0, /* tp_dictoffset */ - (initproc)SMBus_init, /* tp_init */ - 0, /* tp_alloc */ - SMBus_new, /* tp_new */ -}; - -static PyMethodDef SMBus_module_methods[] = { - {NULL} -}; - -#ifndef PyMODINIT_FUNC /* declarations for DLL import/export */ -#define PyMODINIT_FUNC void -#endif -PyMODINIT_FUNC -initsmbus(void) -{ - PyObject* m; - - if (PyType_Ready(&SMBus_type) < 0) - return; - - m = Py_InitModule3("smbus", SMBus_module_methods, SMBus_module_doc); - - Py_INCREF(&SMBus_type); - PyModule_AddObject(m, "SMBus", (PyObject *)&SMBus_type); -} - diff --git a/prog/rrd/Makefile b/prog/rrd/Makefile index 0f817707..87554293 100644 --- a/prog/rrd/Makefile +++ b/prog/rrd/Makefile @@ -4,19 +4,12 @@ USER=apache # CRONTAB not used #CRONTAB=/var/spool/cron/tabs/$(USER) -RRDPATH=/usr/local/rrdtool/bin +RRDPATH=/usr/bin BINPATH=/usr/local/bin RRDDIR=/var/lib/sensors-rrd APACHE=/var/www/html APACHDIR=$(APACHE)/senspix MACH=`uname -n` -# 2.4 kernels -#SENSDEV=w83781d-isa-0290 -#SENSDIR=/proc/sys/dev/sensors/$(SENSDEV) -# 2.6 kernels up to 2.6.13 -#SENSDEV=0-0290 -#SENSDIR=/sys/bus/i2c/devices/$(SENSDEV) -# 2.6.14 and later kernels SENSDEV=hwmon0 SENSDIR=/sys/class/hwmon/$(SENSDEV)/device ################################################ diff --git a/prog/rrd/README b/prog/rrd/README index 3717f086..89ab85c4 100644 --- a/prog/rrd/README +++ b/prog/rrd/README @@ -6,7 +6,7 @@ graphs of sensor data. The RRD (Round Robin Database) package is REQUIRED. Get this package from - http://oss.oetiker.ch/rrdtool + http://oss.oetiker.ch/rrdtool/ A web server with CGI support is required. @@ -26,7 +26,7 @@ following advantages: If you are looking for something a little simpler, that does not require RRD, try ../tellerstats. -The RRD scripts read /proc or /sys entries and do not use libsensors. +The RRD scripts read /sys entries and do not use libsensors. Therefore the scale factors in /etc/sensors.conf are not used, and you may have to change the scale factors in the cgi scripts. @@ -51,7 +51,7 @@ INSTALLATION INSTRUCTIONS Cron user USER=httpd Path to rrdtool and rrdcgi - RRDPATH=/usr/local/rrdtool/bin + RRDPATH=/usr/bin Place to install sens_update_rrd script BINPATH=/usr/local/bin Place to store the database @@ -61,12 +61,7 @@ INSTALLATION INSTRUCTIONS APACHDIR=$(APACHE)/senspix The sensor device in your system (isa recommended over i2c if both are available) - 2.4 kernel - look in /proc/sys/dev/sensors: - SENSDEV=w83781d-isa-0290 - 2.6 kernel up to 2.6.13 - look in /sys/i2c/bus/devices: - SENSDEV=0-0290 - 2.6.14+ kernel - look in /sys/class/hwmon: - SENSDEV=hwmon0 + SENSDEV=hwmon0 (look in /sys/class/hwmon) - make - (as root) make install, which does the following. If you don't want it to do this, install by hand!!! @@ -76,7 +71,7 @@ INSTALLATION INSTRUCTIONS - Manually add the following line to the crontab for the user specified above, which will call the data gathering script every 5 minutes (adjust paths as necessary) - */5 * * * * /usr/local/bin/sens_update_rrd /var/lib/sensors-rrd/sensors.rrd w83781d-isa-0290 + */5 * * * * /usr/local/bin/sens_update_rrd /var/lib/sensors-rrd/sensors.rrd hwmon0 - Load http://localhost/senspix/sens_day.cgi in your web browser to test diff --git a/prog/rrd/sens_create_rrd b/prog/rrd/sens_create_rrd index 0051005f..09ef1f83 100755 --- a/prog/rrd/sens_create_rrd +++ b/prog/rrd/sens_create_rrd @@ -18,9 +18,10 @@ # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software -# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, +# MA 02110-1301 USA. # -RRDPATH=/usr/local/rrdtool/bin +RRDPATH=/usr/bin RRDB=$1 #Heartbeat 15 minutes HB=900 diff --git a/prog/rrd/sens_update_rrd b/prog/rrd/sens_update_rrd index c1f37433..6be365b1 100755 --- a/prog/rrd/sens_update_rrd +++ b/prog/rrd/sens_update_rrd @@ -3,9 +3,9 @@ # sens_update_rrd - # Update a sensors rrd database. # Sample usage: -# sens_update_rrd /var/lib/database.rrd w83781d-isa-0290 +# sens_update_rrd /var/lib/database.rrd hwmon0 # Sample cron entry: -# */5 * * * * /usr/local/bin/sens_update_rrd /var/lib/sensors-rrd/sensors.rrd w83781d-isa-0290 +# */5 * * * * /usr/local/bin/sens_update_rrd /var/lib/sensors-rrd/sensors.rrd hwmon0 # ################################################################# # @@ -23,112 +23,65 @@ # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software -# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, +# MA 02110-1301 USA. # ################################################################# # -if [ $# -ne 2 ] +if [ $# -lt 1 -o $# -gt 2 ] then - echo "usage: $0 database.rrd sensor" - echo " sensor example: w83781d-isa-0290 (2.4 kernel)" - echo " 0-0290 (early 2.6 kernel)" - echo " hwmon0 (kernel 2.6.14 or later)" + echo "usage: $0 database.rrd [hwmonN]" exit 1 +elif [ $# -eq 2 ] +then + HWMON=$2 +else + HWMON=hwmon0 fi # -RRDPATH=/usr/local/rrdtool/bin +RRDPATH=/usr/bin RRDB=$1 -SENSDIR=/proc/sys/dev/sensors -SDIR=/sys/bus/i2c/devices -HWMONDIR=/sys/class/hwmon -SENSDEV=$2 -if [ -d $HWMONDIR ] -then - SYSFS=1 - SENSDIR=$HWMONDIR - SENSDEV=$SENSDEV/device -elif [ -d $SDIR ] -then - SYSFS=1 - SENSDIR=$SDIR -elif [ ! -d $SENSDIR] -then - echo $0: 'No sensors found! (modprobe sensor modules?)' - exit 1 -fi +SENSDIR=/sys/class/hwmon +SENS=$SENSDIR/$HWMON/device -SENS=$SENSDIR/$SENSDEV -if [ ! -r $SENS ] +if [ ! -d $SENS ] then - echo $0: 'No sensors found! (modprobe sensor modules?)' + echo "No sensors found in: $SENS" + echo "(modprobe sensor modules?)" exit 1 fi STRING=N -if [ "$SYSFS" = "1" ] -then - # - # Get the value from these sensor files (/sys) - # - SENSORS="fan1 fan2 fan3" - for i in $SENSORS - do - V="`cat $SENSDIR/$SENSDEV/${i}_input 2> /dev/null`" - if [ $? -ne 0 ] - then - STRING="${STRING}:U" - else - STRING="${STRING}:${V}" - fi - done - # - # Get the value from these sensor files (/sys) and divide by 1000 - # - SENSORS="temp1 temp2 temp3 in0 in1 in2 in3 in4 in5 in6" - for i in $SENSORS - do - V="`cat $SENSDIR/$SENSDEV/${i}_input 2> /dev/null`" - if [ $? -ne 0 ] - then - STRING="${STRING}:U" - else - V=`echo "3k0 ${V/-/_} 1000/p"|dc` - STRING="${STRING}:${V}" - fi - done -else - # - # Get the second value from these sensor files (/proc) - # - SENSORS="fan1 fan2 fan3" - for i in $SENSORS - do - V="`cat $SENSDIR/$SENSDEV/$i 2> /dev/null`" - if [ $? -ne 0 ] - then - STRING="${STRING}:U" - else - V="`echo $V | cut -d ' ' -f 2`" - STRING="${STRING}:${V}" - fi - done - # - # Get the third value from these sensor files (/proc) - # - SENSORS="temp1 temp2 temp3 in0 in1 in2 in3 in4 in5 in6" - for i in $SENSORS - do - V="`cat $SENSDIR/$SENSDEV/$i 2> /dev/null`" - if [ $? -ne 0 ] - then - STRING="${STRING}:U" - else - V="`echo $V | cut -d ' ' -f 3`" - STRING="${STRING}:${V}" - fi - done -fi +# +# Get the value from these sensor files (/sys) +# +SENSORS="fan1 fan2 fan3" +for i in $SENSORS +do + V="`cat $SENS/${i}_input 2> /dev/null`" + if [ $? -ne 0 ] + then + STRING="${STRING}:U" + else + STRING="${STRING}:${V}" + fi +done +# +# Get the value from these sensor files (/sys) and divide by 1000 +# +SENSORS="temp1 temp2 temp3 in0 in1 in2 in3 in4 in5 in6" +for i in $SENSORS +do + V="`cat $SENS/${i}_input 2> /dev/null`" + if [ $? -ne 0 ] + then + STRING="${STRING}:U" + else + V=`echo "3k0 ${V/-/_} 1000/p"|dc` + STRING="${STRING}:${V}" + fi +done # # Get the first value from these /proc files diff --git a/prog/sensord/Module.mk b/prog/sensord/Module.mk index e744858e..9dcf9d27 100644 --- a/prog/sensord/Module.mk +++ b/prog/sensord/Module.mk @@ -13,7 +13,8 @@ # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software -# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, +# MA 02110-1301 USA. # The round robin database (RRD) development headers and libraries are # REQUIRED. Get this package from: diff --git a/prog/sensord/args.c b/prog/sensord/args.c index d54816ae..3d3b1562 100644 --- a/prog/sensord/args.c +++ b/prog/sensord/args.c @@ -17,7 +17,8 @@ * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301 USA. */ #include @@ -33,7 +34,7 @@ #define MAX_CHIP_NAMES 32 int isDaemon = 0; -const char *sensorsCfgFile = "sensors.conf"; +const char *sensorsCfgFile = NULL; const char *pidFile = "/var/run/sensord.pid"; const char *rrdFile = NULL; const char *cgiDir = NULL; @@ -102,7 +103,7 @@ static const char *daemonSyntax = " -t, --rrd-interval