--- fancontrol.orig	2008-12-04 02:53:06.000000000 +1300
+++ fancontrol	2009-01-03 10:36:12.000000000 +1300
@@ -1,387 +1,446 @@
 #!/bin/bash
 #
-# Simple script implementing a temperature dependent fan speed control
-#
-# Version 0.67
+# Script implementing a temperature dependent fan speed control.
 #
 # Usage: fancontrol [CONFIGFILE]
 #
-# Dependencies:
-#   bash, egrep, sed, cut, sleep, lm_sensors :)
+# Version 1.1
 #
-# Please send any questions, comments or success stories to
-# marius.reiner@hdev.de
-# Thanks!
+# Dependencies:
+#   * awk (for the math expression evaluation)
+#   * lm_sensors :)
+#   * A correctly configured config file, default /etc/fancontrol, see pwmconfig
+#     for creating an initial version.
 #
 # For configuration instructions and warnings please see fancontrol.txt, which
-# can be found in the doc/ directory or at the website mentioned above.
-#
+# can be found in the lm_sensors package.
 #
-#    Copyright 2003 Marius Reiner <marius.reiner@hdev.de>
-#    Copyright (C) 2007-2008 Jean Delvare <khali@linux-fr.org>
+#   Copyright 2003 Marius Reiner <marius.reiner@hdev.de>
+#   http://www.hdev.de/fancontrol/  up to version 0.63
 #
-#    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.
+#   Copyright 2006, 2009 Volker Kuhlmann <VolkerKuhlmann@gmx.de>
+#   http://volker.top.geek.nz/  versions 1.0, 1.1
 #
-#    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.
+#   Copyright (C) 2007-2008 Jean Delvare <khali@linux-fr.org>
+#
+#   Changelog:
+#   1.1, 03 Jan 2009, by Volker Kuhlmann:
+#     * Added changes from Jean Delvare's 0.67.
+#     * Kept temp threshold and curve calculations.
+#     * Using bash string functions instead of calling awk/sed/cut/egrep.
+#     * This improved script is upwards compatible with lm-sensor's.
+#     * TODO: re-write calc expressions for bash's integer arithmetic.
+#   0.67, 2007-2008:
+#     * by Jean Delvare
+#   1.0, 24 Jan 2006, by Volker Kuhlmann:
+#     * Added hysteresis when turning fan on/off, preventing the fan from going
+#       between off and minimum every $INTERVAL seconds.
+#       This change is upwards compatible; the script's behaviour is unchanged
+#       with older config files.
+#       TODO: add hysteresis handling to pwmconfig
+#     * Fixed the sleep constructs to be usable with system service scripts.
+#     * Rudimentary provision for multiple (different) control curves.
+#     * Tidied up script, replacing sub-optimal shell constructs.
+#   0.63, 2003:
+#     * by 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.
 #
-#    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.
-#
-#
-
-PIDFILE="/var/run/fancontrol.pid"
 
 #DEBUG=1
 MAX=255
+PIDFILE=/var/run/fancontrol.pid
+SENSDIR=/proc/sys/dev/sensors
+SSENSDIR=/sys/bus/i2c/devices
+HWMONDIR=/sys/class/hwmon
 
-if [ -f "$PIDFILE" ]
-then
-	echo "File $PIDFILE exists, is fancontrol already running?"
-	exit 1
-fi
-echo $$ > "$PIDFILE"
-
-declare -i pwmval
 
+# $1: config file to load
 function LoadConfig {
-	echo "Loading configuration from $1 ..."
-	# grep configuration from file
-	INTERVAL=`egrep '^INTERVAL=.*$' $1 | sed -e 's/INTERVAL=//g'`
-	FCTEMPS=`egrep '^FCTEMPS=.*$' $1 | sed -e 's/FCTEMPS=//g'`
-	MINTEMP=`egrep '^MINTEMP=.*$' $1 | sed -e 's/MINTEMP=//g'`
-	MAXTEMP=`egrep '^MAXTEMP=.*$' $1 | sed -e 's/MAXTEMP=//g'`
-	MINSTART=`egrep '^MINSTART=.*$' $1 | sed -e 's/MINSTART=//g'`
-	MINSTOP=`egrep '^MINSTOP=.*$' $1 | sed -e 's/MINSTOP=//g'`
-	# optional settings:
-	FCFANS=`egrep '^FCFANS=.*$' $1 | sed -e 's/FCFANS=//g'`
-	MINPWM=`egrep '^MINPWM=.*$' $1 | sed -e 's/MINPWM=//g'`
-	MAXPWM=`egrep '^MAXPWM=.*$' $1 | sed -e 's/MAXPWM=//g'`
+    echo "Loading configuration from $1 ..."
+    while read -r; do
+	case "$REPLY" in
+	    INTERVAL=*)   INTERVAL="${REPLY#*=}";;
+	    FCTEMPS=*)    FCTEMPS="${REPLY#*=}";;
+	    MINTEMP=*)    MINTEMP="${REPLY#*=}";;
+	    MAXTEMP=*)    MAXTEMP="${REPLY#*=}";;
+	    MINSTART=*)   MINSTART="${REPLY#*=}";;
+	    MINSTOP=*)    MINSTOP="${REPLY#*=}";;
+	    # Optional settings:
+	    FCFANS=*)     FCFANS="${REPLY#*=}";;
+	    THRESHTEMP=*) THRTEMP="${REPLY#*=}";;
+	    MINPWM=*)     MINPWM="${REPLY#*=}";;
+	    MAXPWM=*)     MAXPWM="${REPLY#*=}";;
+	esac
+    done < "$1"
+
+    # Check whether all mandatory settings are set.
+    if [[ -z ${INTERVAL} || -z ${FCTEMPS} || -z ${MINTEMP} || -z ${MAXTEMP} || -z ${MINSTART} || -z ${MINSTOP} ]]
+    then
+	echo "Some mandatory settings missing, please check your config file!"
+	exit 1
+    fi
+    if [ "$INTERVAL" -le 0 ]; then
+	echo "Error in configuration file:"
+	echo "INTERVAL must be at least 1"
+	exit 1
+    fi
 
-	# Check whether all mandatory settings are set
-	if [[ -z ${INTERVAL} || -z ${FCTEMPS} || -z ${MINTEMP} || -z ${MAXTEMP} || -z ${MINSTART} || -z ${MINSTOP} ]]
-	then
-		echo "Some mandatory settings missing, please check your config file!"
-		exit 1
+    # Write settings to arrays for easier use and print them.
+    getpwmval() {
+	local pwm
+	for pwm in $1; do
+	    case "$pwm" in
+		*$2=*)   echo "${pwm#*=}"; break;;
+	    esac
+	done
+    }
+    echo
+    echo "Common settings:"
+    echo "  INTERVAL=$INTERVAL"
+    let fcvcount=0
+    for fcv in $FCTEMPS; do
+    	case "$fcv" in
+	    *=*)    : ;;
+	    *)	    echo "Error in configuration file:"
+		    echo "FCTEMPS value is improperly formatted."
+		    exit 1;;
+	esac
+	
+	AFCPWM[$fcvcount]="${fcv%%=*}"  # field 1
+	AFCTEMP[$fcvcount]="${fcv#*=}"  # field 2
+	AFCFAN[$fcvcount]=`getpwmval "$FCFANS" "${AFCPWM[$fcvcount]}"`
+	AFCMINTEMP[$fcvcount]=`getpwmval "$MINTEMP" "${AFCPWM[$fcvcount]}"`
+	AFCMAXTEMP[$fcvcount]=`getpwmval "$MAXTEMP" "${AFCPWM[$fcvcount]}"`
+	AFCTHRTEMP[$fcvcount]=`getpwmval "$THRTEMP" "${AFCPWM[$fcvcount]}"`
+	AFCMINSTART[$fcvcount]=`getpwmval "$MINSTART" "${AFCPWM[$fcvcount]}"`
+	AFCMINSTOP[$fcvcount]=`getpwmval "$MINSTOP" "${AFCPWM[$fcvcount]}"`
+	AFCMINPWM[$fcvcount]=`getpwmval "$MINPWM" "${AFCPWM[$fcvcount]}"`
+	AFCMAXPWM[$fcvcount]=`getpwmval "$MAXPWM" "${AFCPWM[$fcvcount]}"`
+
+	# Defaults:
+	test -z "${AFCTHRTEMP[$fcvcount]}" && AFCTHRTEMP[$fcvcount]=0
+	test -z "${AFCMINPWM[$fcvcount]}" && AFCMINPWM[$fcvcount]=0
+	test -z "${AFCMAXPWM[$fcvcount]}" && AFCMAXPWM[$fcvcount]=255
+
+	# Verify the validity of the settings.
+	if [ "${AFCMINTEMP[$fcvcount]}" -ge "${AFCMAXTEMP[$fcvcount]}" ]; then
+	    echo "Error in configuration file (${AFCPWM[$fcvcount]}):"
+	    echo "MINTEMP must be less than MAXTEMP"
+	    exit 1
 	fi
-	if [ "$INTERVAL" -le 0 ]
-	then
-		echo "Error in configuration file:"
-		echo "INTERVAL must be at least 1"
-		exit 1
+	if [ "${AFCMINPWM[$fcvcount]}" -ge "${AFCMAXPWM[$fcvcount]}" ]; then
+	    echo "Error in configuration file (${AFCPWM[$fcvcount]}):"
+	    echo "MINPWM must be less than MAXPWM"
+	    exit 1
+	fi
+	if [ "${AFCMINPWM[$fcvcount]}" -lt 0 ]; then
+	    echo "Error in configuration file (${AFCPWM[$fcvcount]}):"
+	    echo "MINPWM must be at least 0"
+	    exit 1
+	fi
+	if [ "${AFCMAXPWM[$fcvcount]}" -gt 255 ]; then
+	    echo "Error in configuration file (${AFCPWM[$fcvcount]}):"
+	    echo "MAXPWM must be at most 255"
+	    exit 1
+	fi
+	if [ "${AFCMINSTOP[$fcvcount]}" -ge "${AFCMAXPWM[$fcvcount]}" ]; then
+	    echo "Error in configuration file (${AFCPWM[$fcvcount]}):"
+	    echo "MINSTOP must be less than MAXPWM"
+	    exit 1
+	fi
+	if [ "${AFCMINSTOP[$fcvcount]}" -lt "${AFCMINPWM[$fcvcount]}" ]; then
+	    echo "Error in configuration file (${AFCPWM[$fcvcount]}):"
+	    echo "MINSTOP must be greater than or equal to MINPWM"
+	    exit 1
 	fi
 
-	# write settings to arrays for easier use and print them
-	echo
-	echo "Common settings:"
-	echo "  INTERVAL=$INTERVAL"
-
-	let fcvcount=0
-	for fcv in $FCTEMPS
-	do
-		if ! echo $fcv | egrep -q '='
-		then
-			echo "Error in configuration file:"
-			echo "FCTEMPS value is improperly formatted"
-			exit 1
-		fi
-
-		AFCPWM[$fcvcount]=`echo $fcv |cut -d'=' -f1`
-		AFCTEMP[$fcvcount]=`echo $fcv |cut -d'=' -f2`
-		AFCFAN[$fcvcount]=`echo $FCFANS |sed -e 's/ /\n/g' |egrep "${AFCPWM[$fcvcount]}" |cut -d'=' -f2`
-		AFCMINTEMP[$fcvcount]=`echo $MINTEMP |sed -e 's/ /\n/g' |egrep "${AFCPWM[$fcvcount]}" |cut -d'=' -f2`
-		AFCMAXTEMP[$fcvcount]=`echo $MAXTEMP |sed -e 's/ /\n/g' |egrep "${AFCPWM[$fcvcount]}" |cut -d'=' -f2`
-		AFCMINSTART[$fcvcount]=`echo $MINSTART |sed -e 's/ /\n/g' |egrep "${AFCPWM[$fcvcount]}" |cut -d'=' -f2`
-		AFCMINSTOP[$fcvcount]=`echo $MINSTOP |sed -e 's/ /\n/g' |egrep "${AFCPWM[$fcvcount]}" |cut -d'=' -f2`
-		AFCMINPWM[$fcvcount]=`echo $MINPWM |sed -e 's/ /\n/g' |egrep "${AFCPWM[$fcvcount]}" |cut -d'=' -f2`
-		[ -z "${AFCMINPWM[$fcvcount]}" ] && AFCMINPWM[$fcvcount]=0
-		AFCMAXPWM[$fcvcount]=`echo $MAXPWM |sed -e 's/ /\n/g' |egrep "${AFCPWM[$fcvcount]}" |cut -d'=' -f2`
-		[ -z "${AFCMAXPWM[$fcvcount]}" ] && AFCMAXPWM[$fcvcount]=255
-
-		# verify the validity of the settings
-		if [ "${AFCMINTEMP[$fcvcount]}" -ge "${AFCMAXTEMP[$fcvcount]}" ]
-		then
-			echo "Error in configuration file (${AFCPWM[$fcvcount]}):"
-			echo "MINTEMP must be less than MAXTEMP"
-			exit 1
-		fi
-		if [ "${AFCMAXPWM[$fcvcount]}" -gt 255 ]
-		then
-			echo "Error in configuration file (${AFCPWM[$fcvcount]}):"
-			echo "MAXPWM must be at most 255"
-			exit 1
-		fi
-		if [ "${AFCMINSTOP[$fcvcount]}" -ge "${AFCMAXPWM[$fcvcount]}" ]
-		then
-			echo "Error in configuration file (${AFCPWM[$fcvcount]}):"
-			echo "MINSTOP must be less than MAXPWM"
-			exit 1
-		fi
-		if [ "${AFCMINSTOP[$fcvcount]}" -lt "${AFCMINPWM[$fcvcount]}" ]
-		then
-			echo "Error in configuration file (${AFCPWM[$fcvcount]}):"
-			echo "MINSTOP must be greater than or equal to MINPWM"
-			exit 1
-		fi
-		if [ "${AFCMINPWM[$fcvcount]}" -lt 0 ]
-		then
-			echo "Error in configuration file (${AFCPWM[$fcvcount]}):"
-			echo "MINPWM must be at least 0"
-			exit 1
-		fi
-
-		echo
-		echo "Settings for ${AFCPWM[$fcvcount]}:"
-		echo "  Depends on ${AFCTEMP[$fcvcount]}"
-		echo "  Controls ${AFCFAN[$fcvcount]}"
-		echo "  MINTEMP=${AFCMINTEMP[$fcvcount]}"
-		echo "  MAXTEMP=${AFCMAXTEMP[$fcvcount]}"
-		echo "  MINSTART=${AFCMINSTART[$fcvcount]}"
-		echo "  MINSTOP=${AFCMINSTOP[$fcvcount]}"
-		echo "  MINPWM=${AFCMINPWM[$fcvcount]}"
-		echo "  MAXPWM=${AFCMAXPWM[$fcvcount]}"
-		let fcvcount=fcvcount+1
-	done
 	echo
+	echo "Settings for ${AFCPWM[$fcvcount]}:"
+	echo "  Depends on ${AFCTEMP[$fcvcount]}"
+	echo "  Controls ${AFCFAN[$fcvcount]}"
+	echo "  MINTEMP=${AFCMINTEMP[$fcvcount]}"
+	echo "  MAXTEMP=${AFCMAXTEMP[$fcvcount]}"
+	echo "  THRESHTEMP=${AFCTHRTEMP[$fcvcount]}"
+	echo "  MINSTART=${AFCMINSTART[$fcvcount]}"
+	echo "  MINSTOP=${AFCMINSTOP[$fcvcount]}"
+	echo "  MINPWM=${AFCMINPWM[$fcvcount]}"
+	echo "  MAXPWM=${AFCMAXPWM[$fcvcount]}"
+	let fcvcount=fcvcount+1
+    done
+    echo
 }
 
-if [ -f "$1" ]
-then
-	LoadConfig $1
-else
-	LoadConfig /etc/fancontrol
-fi
-
-DIR=/proc/sys/dev/sensors
-if [ ! -d $DIR ]
-then
-	# For Linux 2.6, detect if config file uses the hwmon class or not yet
-	if echo "${AFCPWM[0]}" | egrep -q '^hwmon[0-9]'
-	then
-		SDIR=/sys/class/hwmon
-	else
-		SDIR=/sys/bus/i2c/devices
-	fi
-
-	if [ ! -d $SDIR ]
-	then
-		echo $0: 'No sensors found! (did you load the necessary modules?)'
-		exit 1
-	else
-		SYSFS=1
-		DIR=$SDIR
-	fi
-fi
-cd $DIR
-
-# $1 = pwm file name
+# $1 = full pwm file name
 function pwmdisable()
 {
-	if [ -n "$SYSFS" ]
-	then
-		ENABLE=${1}_enable
-		# No enable file? Just set to max
-		if [ ! -f $ENABLE ]
-		then
-			echo $MAX > $1
-			return 0
-		fi
+    if [ "$SYSFS" = "1" ]; then
+	ENABLE=${1}_enable
 
-		# Try pwmN_enable=0
-		echo 0 > $ENABLE 2> /dev/null
-		if [ `cat $ENABLE` -eq 0 ]
-		then
-			# Success
-			return 0
-		fi
-
-		# It didn't work, try pwmN_enable=1 pwmN=255
-		echo 1 > $ENABLE 2> /dev/null
-		echo $MAX > $1
-		if [ `cat $ENABLE` -eq 1 -a `cat $1` -ge 190 ]
-		then
-			# Success
-			return 0
-		fi
+    	# Without enable file, just set to max.
+	if [ ! -f $ENABLE ]; then
+	    echo $MAX > $1
+	    return 0
+	fi
+	
+	# Try pwmN_enable=0
+	echo 0 > $ENABLE 2>/dev/null
+	if [ `cat $ENABLE` -eq 0 ]; then
+	    # Success
+	    return 0
+	fi
 
-		# Nothing worked
-		echo "$ENABLE stuck to" `cat $ENABLE` >&2
-		return 1
-	else
-		echo $MAX 0 > $1
+	# It didn't work, try pwmN_enable=1 pwmN=255
+	echo 1 > $ENABLE 2>/dev/null
+	echo $MAX > $1
+	if [ `cat $ENABLE` -eq 1 -a `cat $1` -ge 190 ]; then
+	    # Success
+	    return 0
 	fi
+
+	# Nothing worked
+	echo "$ENABLE stuck to" `cat $ENABLE` >&2
+	return 1
+    else
+	echo $MAX 0 > $1
+    fi
 }
 
-# $1 = pwm file name
+# $1 = full pwm file name
 function pwmenable()
 {
-	if [ "$SYSFS" = "1" ]
-	then
-		ENABLE=${1}_enable
-		if [ -f $ENABLE ]
-		then
-			echo 1 > $ENABLE 2> /dev/null
-			if [ $? -ne 0 ]
-			then
-				return 1
-			fi
-		fi
-		echo $MAX > $1
-	else
-		echo $MAX 1 > $1
+    if [ "$SYSFS" = "1" ]; then
+	ENABLE=${1}_enable
+	if [ -f $ENABLE ]; then
+	    echo 1 > $ENABLE 2>/dev/null
+	    if [ $? -ne 0 ]; then
+	    	return 1
+	    fi
 	fi
+	echo $MAX > $1
+    else
+	echo $MAX 1 > $1
+    fi
 }
 
+# Set fans to maximum and exit.
 function restorefans()
 {
-	local status=$1
-	echo 'Aborting, restoring fans...'
-	let fcvcount=0
-	while (( $fcvcount < ${#AFCPWM[@]} )) # go through all pwm outputs
-	do
-		pwmo=${AFCPWM[$fcvcount]}
-		pwmdisable $pwmo
-		let fcvcount=$fcvcount+1
-	done
-	echo 'Verify fans have returned to full speed'
-	rm -f "$PIDFILE"
-	exit $status
+    local status="$1"
+
+    echo "Aborting, restoring fans..."
+    let fcvcount=0
+    while (( $fcvcount < ${#AFCPWM[@]} )); do # go through all pwm outputs
+	pwmo=${AFCPWM[$fcvcount]}
+	pwmdisable $SENSDIR/$pwmo
+	let fcvcount=$fcvcount+1
+    done
+    echo "Verify fans have returned to full speed."
+    rm -f "$PIDFILE"
+    exit "$status"
+}
+
+# Function evaluating the mathematical expression.
+function calc () {
+    awk "BEGIN { print $@ }"
+    # Alternatives: bc, or bc -l, or let (for internal integer arithmetic).
+}
+
+# Calculate the new value from temperature and settings; quadratic function.
+# Sets variables pwmval and func!
+calc_quadratic() {
+    func="((${tval}-${mint})/(${maxt}-${mint}))^2*(255-${minso})+${minso}"
+    pwmval=`calc "$func"`
+    pwmval="${pwmval%%.*}"
+}
+
+# Calculate the new value from temperature and settings; "quad" function?
+# Sets variables pwmval and func!
+calc_quad() {
+    func="((10/(${maxt}-${mint})*(${temp}-${mint}))^2/1000*(${maxt}-${mint})*(255-${minspeed})+${minspeed})"
+    pwmval=`calc "$func"`
+    pwmval="${pwmval%%.*}"
 }
 
-trap 'restorefans 0' SIGQUIT SIGTERM
-trap 'restorefans 1' SIGHUP SIGINT
+# Calculate the new value from temperature and settings; exponential function.
+# Sets variables pwmval and func!
+calc_exponential() {
+    func="..."
+    pwmval=`calc "$func"`
+    pwmval="${pwmval%%.*}"
+}
 
 # main function
 function UpdateFanSpeeds {
-	let fcvcount=0
-	while (( $fcvcount < ${#AFCPWM[@]} )) # go through all pwm outputs
-	do
-		#hopefully shorter vars will improve readability:
-		pwmo=${AFCPWM[$fcvcount]}
-		tsens=${AFCTEMP[$fcvcount]}
-		fan=${AFCFAN[$fcvcount]}
-		mint=${AFCMINTEMP[$fcvcount]}
-		maxt=${AFCMAXTEMP[$fcvcount]}
-		minsa=${AFCMINSTART[$fcvcount]}
-		minso=${AFCMINSTOP[$fcvcount]}
-		minpwm=${AFCMINPWM[$fcvcount]}
-		maxpwm=${AFCMAXPWM[$fcvcount]}
-
-		read tval < ${tsens}
-		if [ $? -ne 0 ]
-		then
-			echo "Error reading temperature from $DIR/$tsens"
-			restorefans 1
-		fi
-		if [ "$SYSFS" = "1" ]
-		then
-			let tval="($tval+500)/1000"
-		else
-			tval=`echo ${tval} | cut -d' ' -f3 | cut -d'.' -f1`
-		fi
+    local filler filler2
+    let fcvcount=0
+    while (( $fcvcount < ${#AFCPWM[@]} )); do # Go through all pwm outputs.
+	#Hopefully shorter vars will improve readability:
+	pwmo=${AFCPWM[$fcvcount]}
+	tsens=${AFCTEMP[$fcvcount]}
+	fan=${AFCFAN[$fcvcount]}
+	mint=${AFCMINTEMP[$fcvcount]}
+	maxt=${AFCMAXTEMP[$fcvcount]}
+	minsa=${AFCMINSTART[$fcvcount]}
+	minso=${AFCMINSTOP[$fcvcount]}
+	thresht=${AFCTHRTEMP[$fcvcount]}
+	minpwm=${AFCMINPWM[$fcvcount]}
+	maxpwm=${AFCMAXPWM[$fcvcount]}
+
+	read tval < $SENSDIR/${tsens} || {
+	    echo "Error reading temperature from $SENSDIR/$tsens"
+	    restorefans 1
+	}
+	if [ "$SYSFS" = "1" ]; then
+	    let tval="($tval + 500) / 1000"
+	else
+	    tval=`echo ${tval} |cut -d' ' -f3 |cut -d'.' -f1`
+	fi
 
-		read pwmpval < ${pwmo}
-		if [ $? -ne 0 ]
-		then
-			echo "Error reading PWM value from $DIR/$pwmo"
-			restorefans 1
-		fi
-		if [ "$SYSFS" != "1" ]
-		then
-			pwmpval=`echo ${pwmpval} | cut -d' ' -f1`
-		fi
+	read pwmpval filler < $SENSDIR/${pwmo} || {
+	    echo "Error reading PWM value from $SENSDIR/$pwmo"
+	    restorefans 1
+	}
+	if [ "$SYSFS" != "1" ]
+	then
+	    pwmpval=`echo ${pwmpval} | cut -d' ' -f1`
+	fi
 
-		# If fanspeed-sensor output shall be used, do it
-		if [[ -n ${fan} ]]
-		then
-			read fanval < ${fan}
-			if [ $? -ne 0 ]
-			then
-				echo "Error reading Fan value from $DIR/$fan"
-				restorefans 1
-			fi
-			if [ "$SYSFS" != "1" ]
-			then
-				fanval=`echo ${fanval} | cut -d' ' -f2`
-			fi
-		else
-			fanval=1  # set it to a non zero value, so the rest of the script still works
-		fi
+	# If fanspeed-sensor output shall be used, do it.
+	if [[ -n ${fan} ]]; then
+	    read filler fanval filler2 < $SENSDIR/${fan} || {
+		echo "Error reading Fan value from $SENSDIR/$fan"
+		restorefans 1
+	    }
+	    test "$fanval" || fanval=$filler  # field 2, or first field
+	    if [ "$SYSFS" != "1" ]
+	    then
+		fanval=`echo ${fanval} | cut -d' ' -f2`
+	    fi
+	else
+	    # Set to a non zero value, so the rest of the script still works.
+	    fanval=1
+	fi
 
-		# debug info
-		if [ "$DEBUG" != "" ]
-		then
-			echo "pwmo=$pwmo"
-			echo "tsens=$tsens"
-			echo "fan=$fan"
-			echo "mint=$mint"
-			echo "maxt=$maxt"
-			echo "minsa=$minsa"
-			echo "minso=$minso"
-			echo "minpwm=$minpwm"
-			echo "maxpwm=$maxpwm"
-			echo "tval=$tval"
-			echo "pwmpval=$pwmpval"
-			echo "fanval=$fanval"
-		fi
+	# debug info
+	if [ -n "$DEBUG" ]; then
+	    echo ""
+	    echo "pwmo=$pwmo"
+	    echo "tsens=$tsens"
+	    echo "fan=$fan"
+	    echo "mint=$mint"
+	    echo "maxt=$maxt"
+	    echo "thresht=$thresht"
+	    echo "minsa=$minsa"
+	    echo "minso=$minso"
+	    echo "minpwm=$minpwm"
+	    echo "maxpwm=$maxpwm"
+	    echo "tval=$tval"
+	    echo "pwmpval=$pwmpval"
+	    echo "fanval=$fanval"
+	fi
 
-		if (( $tval <= $mint ))
-		  then pwmval=$minpwm # below min temp, use defined min pwm
-		elif (( $tval >= $maxt ))
-		  then pwmval=$maxpwm # over max temp, use defined max pwm
+    	if (( $tval <= $mint ))
+	    then pwmval=$minpwm # at specified mintemp shut fan off
+	elif (( $tval >= $maxt ))
+	    then pwmval=$maxpwm # at specified maxtemp switch to 100%
+	else
+	    # Calculate the new value from temperature and settings.
+	    # (Sets variables pwmval and func.)
+	    calc_quadratic
+	    
+	    # If fan was stopped, start it using a safe value,
+	    # but only start it if temp is at least the threshold over minimum.
+	    if [ $pwmpval -eq 0 -o $fanval -eq 0 ]; then
+		if (( $tval >= (( $mint + $thresht )) )); then
+		    if [ -n "$DEBUG" ]; then
+			echo "starting fan with pwmval=$minsa"
+		    fi
+		    echo $minsa > $SENSDIR/$pwmo
+		    # ignore possible error
+		    #sleep 1  # not killable
+		    read < <(exec sleep 1)
 		else
-		  # calculate the new value from temperature and settings
-		  pwmval="(${tval}-${mint})*(${maxpwm}-${minso})/(${maxt}-${mint})+${minso}"
-		  if [ $pwmpval -eq 0 -o $fanval -eq 0 ]
-		  then # if fan was stopped start it using a safe value
-		  	echo $minsa > $pwmo
-			# Sleep while still handling signals
-			sleep 1 &
-			wait $!
-		  fi
-		fi
-		echo $pwmval > $pwmo # write new value to pwm output
-		if [ $? -ne 0 ]
-		then
-			echo "Error writing PWM value to $DIR/$pwmo"
-			restorefans 1
-		fi
-		if [ "$DEBUG" != "" ]
-		then
-			echo "new pwmval=$pwmval"
+		    pwmval=0
 		fi
-		let fcvcount=$fcvcount+1
-	done
-}
+	    fi
+	fi
 
-echo 'Enabling PWM on fans...'
-let fcvcount=0
-while (( $fcvcount < ${#AFCPWM[@]} )) # go through all pwm outputs
-do
-	pwmo=${AFCPWM[$fcvcount]}
-	pwmenable $pwmo
-	if [ $? -ne 0 ]
-	then
-		echo "Error enabling PWM on $DIR/$pwmo"
-		restorefans 1
+	# write new value to pwm output
+	echo $pwmval > $SENSDIR/$pwmo || {
+	    echo "Error writing PWM value to $SENSDIR/$pwmo"
+	    restorefans 1
+	}
+	if [ -n "$DEBUG" ]; then
+    	    echo "func=$func"
+	    echo "new pwmval=$pwmval"
 	fi
 	let fcvcount=$fcvcount+1
-done
+    done
+}
+
 
-echo 'Starting automatic fan control...'
+## MAIN
+
+if [ -e "$PIDFILE" ]; then
+    echo 1>&2 "$0: Error: PID file already exists: $PIDFILE"
+    exit 1
+fi
+
+LoadConfig "${1-/etc/fancontrol}"
+
+if [ ! -d $SENSDIR ]; then
+    # For Linux 2.6, detect if config file uses the hwmon class yet.
+    case "${AFCPWM[0]}" in
+    	hwmon[0-9]*)
+	    SSENSDIR=$HWMONDIR;;
+    esac
+
+    if [ ! -d $SSENSDIR ]; then
+	echo $0: "No sensors found! (did you load the necessary modules?)"
+	exit 1
+    else
+	SYSFS=1
+	SENSDIR=$SSENSDIR
+    fi	
+fi
+# cd $SENSDIR   # Let's not stand in procfs or sysfs!
+
+trap "restorefans 0" SIGQUIT SIGTERM
+trap "restorefans 1" SIGHUP SIGINT
+
+echo $$ > "$PIDFILE"
+
+echo "Enabling PWM on fans..."
+let fcvcount=0
+while (( $fcvcount < ${#AFCPWM[@]} )); do # go through all pwm outputs
+    pwmo=${AFCPWM[$fcvcount]}
+    pwmenable $SENSDIR/$pwmo
+    if [ $? -ne 0 ]; then
+	echo "Error enabling PWM on $SENSDIR/$pwmo"
+	restorefans 1
+    fi
+    let fcvcount=$fcvcount+1
+done
 
+echo "Starting automatic fan control..."
 # main loop calling the main function at specified intervals
-while true
-do
-	UpdateFanSpeeds
-	# Sleep while still handling signals
-	sleep $INTERVAL &
-	wait $!
+while true; do
+    UpdateFanSpeeds
+    # The sleep in the foreground isn't interruptible by kill, which is
+    # unsuitable for system service scripts.
+    # Werner@suse doesn't like  sleep $INTERVAL &; wait $! although it works.
+    read < <(exec sleep $INTERVAL)
 done
