root/lm-sensors/branches/lm-sensors-3.0.0/prog/pwm/fancontrol @ 5330

Revision 5330, 9.6 KB (checked in by khali, 6 years ago)

Strip trailing whitespace.

  • Property svn:eol-style set to native
  • Property svn:executable set to *
  • Property svn:keywords set to Author Date Id Revision
Line 
1#!/bin/bash
2#
3# Simple script implementing a temperature dependent fan speed control
4#
5# Version 0.67
6#
7# Usage: fancontrol [CONFIGFILE]
8#
9# Dependencies:
10#   bash, egrep, sed, cut, sleep, lm_sensors :)
11#
12# Please send any questions, comments or success stories to
13# marius.reiner@hdev.de
14# Thanks!
15#
16# For configuration instructions and warnings please see fancontrol.txt, which
17# can be found in the doc/ directory or at the website mentioned above.
18#
19#
20#    Copyright 2003 Marius Reiner <marius.reiner@hdev.de>
21#    Copyright (C) 2007-2008 Jean Delvare <khali@linux-fr.org>
22#
23#    This program is free software; you can redistribute it and/or modify
24#    it under the terms of the GNU General Public License as published by
25#    the Free Software Foundation; either version 2 of the License, or
26#    (at your option) any later version.
27#
28#    This program is distributed in the hope that it will be useful,
29#    but WITHOUT ANY WARRANTY; without even the implied warranty of
30#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
31#    GNU General Public License for more details.
32#
33#    You should have received a copy of the GNU General Public License
34#    along with this program; if not, write to the Free Software
35#    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
36#    MA 02110-1301 USA.
37#
38#
39
40PIDFILE="/var/run/fancontrol.pid"
41
42#DEBUG=1
43MAX=255
44
45if [ -f "$PIDFILE" ]
46then
47        echo "File $PIDFILE exists, is fancontrol already running?"
48        exit 1
49fi
50echo $$ > "$PIDFILE"
51
52declare -i pwmval
53
54function LoadConfig {
55        echo "Loading configuration from $1 ..."
56        # grep configuration from file
57        INTERVAL=`egrep '^INTERVAL=.*$' $1 | sed -e 's/INTERVAL=//g'`
58        FCTEMPS=`egrep '^FCTEMPS=.*$' $1 | sed -e 's/FCTEMPS=//g'`
59        MINTEMP=`egrep '^MINTEMP=.*$' $1 | sed -e 's/MINTEMP=//g'`
60        MAXTEMP=`egrep '^MAXTEMP=.*$' $1 | sed -e 's/MAXTEMP=//g'`
61        MINSTART=`egrep '^MINSTART=.*$' $1 | sed -e 's/MINSTART=//g'`
62        MINSTOP=`egrep '^MINSTOP=.*$' $1 | sed -e 's/MINSTOP=//g'`
63        # optional settings:
64        FCFANS=`egrep '^FCFANS=.*$' $1 | sed -e 's/FCFANS=//g'`
65        MINPWM=`egrep '^MINPWM=.*$' $1 | sed -e 's/MINPWM=//g'`
66        MAXPWM=`egrep '^MAXPWM=.*$' $1 | sed -e 's/MAXPWM=//g'`
67
68        # Check whether all mandatory settings are set
69        if [[ -z ${INTERVAL} || -z ${FCTEMPS} || -z ${MINTEMP} || -z ${MAXTEMP} || -z ${MINSTART} || -z ${MINSTOP} ]]
70        then
71                echo "Some mandatory settings missing, please check your config file!"
72                exit 1
73        fi
74        if [ "$INTERVAL" -le 0 ]
75        then
76                echo "Error in configuration file:"
77                echo "INTERVAL must be at least 1"
78                exit 1
79        fi
80
81        # write settings to arrays for easier use and print them
82        echo
83        echo "Common settings:"
84        echo "  INTERVAL=$INTERVAL"
85
86        let fcvcount=0
87        for fcv in $FCTEMPS
88        do
89                if ! echo $fcv | egrep -q '='
90                then
91                        echo "Error in configuration file:"
92                        echo "FCTEMPS value is improperly formatted"
93                        exit 1
94                fi
95
96                AFCPWM[$fcvcount]=`echo $fcv |cut -d'=' -f1`
97                AFCTEMP[$fcvcount]=`echo $fcv |cut -d'=' -f2`
98                AFCFAN[$fcvcount]=`echo $FCFANS |sed -e 's/ /\n/g' |egrep "${AFCPWM[$fcvcount]}" |cut -d'=' -f2`
99                AFCMINTEMP[$fcvcount]=`echo $MINTEMP |sed -e 's/ /\n/g' |egrep "${AFCPWM[$fcvcount]}" |cut -d'=' -f2`
100                AFCMAXTEMP[$fcvcount]=`echo $MAXTEMP |sed -e 's/ /\n/g' |egrep "${AFCPWM[$fcvcount]}" |cut -d'=' -f2`
101                AFCMINSTART[$fcvcount]=`echo $MINSTART |sed -e 's/ /\n/g' |egrep "${AFCPWM[$fcvcount]}" |cut -d'=' -f2`
102                AFCMINSTOP[$fcvcount]=`echo $MINSTOP |sed -e 's/ /\n/g' |egrep "${AFCPWM[$fcvcount]}" |cut -d'=' -f2`
103                AFCMINPWM[$fcvcount]=`echo $MINPWM |sed -e 's/ /\n/g' |egrep "${AFCPWM[$fcvcount]}" |cut -d'=' -f2`
104                [ -z "${AFCMINPWM[$fcvcount]}" ] && AFCMINPWM[$fcvcount]=0
105                AFCMAXPWM[$fcvcount]=`echo $MAXPWM |sed -e 's/ /\n/g' |egrep "${AFCPWM[$fcvcount]}" |cut -d'=' -f2`
106                [ -z "${AFCMAXPWM[$fcvcount]}" ] && AFCMAXPWM[$fcvcount]=255
107
108                # verify the validity of the settings
109                if [ "${AFCMINTEMP[$fcvcount]}" -ge "${AFCMAXTEMP[$fcvcount]}" ]
110                then
111                        echo "Error in configuration file (${AFCPWM[$fcvcount]}):"
112                        echo "MINTEMP must be less than MAXTEMP"
113                        exit 1
114                fi
115                if [ "${AFCMAXPWM[$fcvcount]}" -gt 255 ]
116                then
117                        echo "Error in configuration file (${AFCPWM[$fcvcount]}):"
118                        echo "MAXPWM must be at most 255"
119                        exit 1
120                fi
121                if [ "${AFCMINSTOP[$fcvcount]}" -ge "${AFCMAXPWM[$fcvcount]}" ]
122                then
123                        echo "Error in configuration file (${AFCPWM[$fcvcount]}):"
124                        echo "MINSTOP must be less than MAXPWM"
125                        exit 1
126                fi
127                if [ "${AFCMINSTOP[$fcvcount]}" -lt "${AFCMINPWM[$fcvcount]}" ]
128                then
129                        echo "Error in configuration file (${AFCPWM[$fcvcount]}):"
130                        echo "MINSTOP must be greater than or equal to MINPWM"
131                        exit 1
132                fi
133                if [ "${AFCMINPWM[$fcvcount]}" -lt 0 ]
134                then
135                        echo "Error in configuration file (${AFCPWM[$fcvcount]}):"
136                        echo "MINPWM must be at least 0"
137                        exit 1
138                fi
139
140                echo
141                echo "Settings for ${AFCPWM[$fcvcount]}:"
142                echo "  Depends on ${AFCTEMP[$fcvcount]}"
143                echo "  Controls ${AFCFAN[$fcvcount]}"
144                echo "  MINTEMP=${AFCMINTEMP[$fcvcount]}"
145                echo "  MAXTEMP=${AFCMAXTEMP[$fcvcount]}"
146                echo "  MINSTART=${AFCMINSTART[$fcvcount]}"
147                echo "  MINSTOP=${AFCMINSTOP[$fcvcount]}"
148                echo "  MINPWM=${AFCMINPWM[$fcvcount]}"
149                echo "  MAXPWM=${AFCMAXPWM[$fcvcount]}"
150                let fcvcount=fcvcount+1
151        done
152        echo
153}
154
155if [ -f "$1" ]
156then
157        LoadConfig $1
158else
159        LoadConfig /etc/fancontrol
160fi
161
162DIR=/proc/sys/dev/sensors
163if [ ! -d $DIR ]
164then
165        # For Linux 2.6, detect if config file uses the hwmon class or not yet
166        if echo "${AFCPWM[0]}" | egrep -q '^hwmon[0-9]'
167        then
168                SDIR=/sys/class/hwmon
169        else
170                SDIR=/sys/bus/i2c/devices
171        fi
172
173        if [ ! -d $SDIR ]
174        then
175                echo $0: 'No sensors found! (did you load the necessary modules?)'
176                exit 1
177        else
178                SYSFS=1
179                DIR=$SDIR
180        fi
181fi
182cd $DIR
183
184# $1 = pwm file name
185function pwmdisable()
186{
187        if [ -n "$SYSFS" ]
188        then
189                ENABLE=${1}_enable
190                # No enable file? Just set to max
191                if [ ! -f $ENABLE ]
192                then
193                        echo $MAX > $1
194                        return 0
195                fi
196
197                # Try pwmN_enable=0
198                echo 0 > $ENABLE 2> /dev/null
199                if [ `cat $ENABLE` -eq 0 ]
200                then
201                        # Success
202                        return 0
203                fi
204
205                # It didn't work, try pwmN_enable=1 pwmN=255
206                echo 1 > $ENABLE 2> /dev/null
207                echo $MAX > $1
208                if [ `cat $ENABLE` -eq 1 -a `cat $1` -ge 190 ]
209                then
210                        # Success
211                        return 0
212                fi
213
214                # Nothing worked
215                echo "$ENABLE stuck to" `cat $ENABLE` >&2
216                return 1
217        else
218                echo $MAX 0 > $1
219        fi
220}
221
222# $1 = pwm file name
223function pwmenable()
224{
225        if [ "$SYSFS" = "1" ]
226        then
227                ENABLE=${1}_enable
228                if [ -f $ENABLE ]
229                then
230                        echo 1 > $ENABLE 2> /dev/null
231                        if [ $? -ne 0 ]
232                        then
233                                return 1
234                        fi
235                fi
236                echo $MAX > $1
237        else
238                echo $MAX 1 > $1
239        fi
240}
241
242function restorefans()
243{
244        local status=$1
245        echo 'Aborting, restoring fans...'
246        let fcvcount=0
247        while (( $fcvcount < ${#AFCPWM[@]} )) # go through all pwm outputs
248        do
249                pwmo=${AFCPWM[$fcvcount]}
250                pwmdisable $pwmo
251                let fcvcount=$fcvcount+1
252        done
253        echo 'Verify fans have returned to full speed'
254        rm -f "$PIDFILE"
255        exit $status
256}
257
258trap 'restorefans 0' SIGQUIT SIGTERM
259trap 'restorefans 1' SIGHUP SIGINT
260
261# main function
262function UpdateFanSpeeds {
263        let fcvcount=0
264        while (( $fcvcount < ${#AFCPWM[@]} )) # go through all pwm outputs
265        do
266                #hopefully shorter vars will improve readability:
267                pwmo=${AFCPWM[$fcvcount]}
268                tsens=${AFCTEMP[$fcvcount]}
269                fan=${AFCFAN[$fcvcount]}
270                mint=${AFCMINTEMP[$fcvcount]}
271                maxt=${AFCMAXTEMP[$fcvcount]}
272                minsa=${AFCMINSTART[$fcvcount]}
273                minso=${AFCMINSTOP[$fcvcount]}
274                minpwm=${AFCMINPWM[$fcvcount]}
275                maxpwm=${AFCMAXPWM[$fcvcount]}
276
277                read tval < ${tsens}
278                if [ $? -ne 0 ]
279                then
280                        echo "Error reading temperature from $DIR/$tsens"
281                        restorefans 1
282                fi
283                if [ "$SYSFS" = "1" ]
284                then
285                        let tval="($tval+500)/1000"
286                else
287                        tval=`echo ${tval} | cut -d' ' -f3 | cut -d'.' -f1`
288                fi
289
290                read pwmpval < ${pwmo}
291                if [ $? -ne 0 ]
292                then
293                        echo "Error reading PWM value from $DIR/$pwmo"
294                        restorefans 1
295                fi
296                if [ "$SYSFS" != "1" ]
297                then
298                        pwmpval=`echo ${pwmpval} | cut -d' ' -f1`
299                fi
300
301                # If fanspeed-sensor output shall be used, do it
302                if [[ -n ${fan} ]]
303                then
304                        read fanval < ${fan}
305                        if [ $? -ne 0 ]
306                        then
307                                echo "Error reading Fan value from $DIR/$fan"
308                                restorefans 1
309                        fi
310                        if [ "$SYSFS" != "1" ]
311                        then
312                                fanval=`echo ${fanval} | cut -d' ' -f2`
313                        fi
314                else
315                        fanval=1  # set it to a non zero value, so the rest of the script still works
316                fi
317
318                # debug info
319                if [ "$DEBUG" != "" ]
320                then
321                        echo "pwmo=$pwmo"
322                        echo "tsens=$tsens"
323                        echo "fan=$fan"
324                        echo "mint=$mint"
325                        echo "maxt=$maxt"
326                        echo "minsa=$minsa"
327                        echo "minso=$minso"
328                        echo "minpwm=$minpwm"
329                        echo "maxpwm=$maxpwm"
330                        echo "tval=$tval"
331                        echo "pwmpval=$pwmpval"
332                        echo "fanval=$fanval"
333                fi
334
335                if (( $tval <= $mint ))
336                  then pwmval=$minpwm # below min temp, use defined min pwm
337                elif (( $tval >= $maxt ))
338                  then pwmval=$maxpwm # over max temp, use defined max pwm
339                else
340                  # calculate the new value from temperature and settings
341                  pwmval="(${tval}-${mint})*(${maxpwm}-${minso})/(${maxt}-${mint})+${minso}"
342                  if [ $pwmpval -eq 0 -o $fanval -eq 0 ]
343                  then # if fan was stopped start it using a safe value
344                        echo $minsa > $pwmo
345                        # Sleep while still handling signals
346                        sleep 1 &
347                        wait $!
348                  fi
349                fi
350                echo $pwmval > $pwmo # write new value to pwm output
351                if [ $? -ne 0 ]
352                then
353                        echo "Error writing PWM value to $DIR/$pwmo"
354                        restorefans 1
355                fi
356                if [ "$DEBUG" != "" ]
357                then
358                        echo "new pwmval=$pwmval"
359                fi
360                let fcvcount=$fcvcount+1
361        done
362}
363
364echo 'Enabling PWM on fans...'
365let fcvcount=0
366while (( $fcvcount < ${#AFCPWM[@]} )) # go through all pwm outputs
367do
368        pwmo=${AFCPWM[$fcvcount]}
369        pwmenable $pwmo
370        if [ $? -ne 0 ]
371        then
372                echo "Error enabling PWM on $DIR/$pwmo"
373                restorefans 1
374        fi
375        let fcvcount=$fcvcount+1
376done
377
378echo 'Starting automatic fan control...'
379
380# main loop calling the main function at specified intervals
381while true
382do
383        UpdateFanSpeeds
384        # Sleep while still handling signals
385        sleep $INTERVAL &
386        wait $!
387done
Note: See TracBrowser for help on using the browser.