root/lm-sensors/trunk/prog/pwm/pwmconfig @ 4153

Revision 4153, 15.3 KB (checked in by khali, 7 years ago)

Use mktemp instead of tempfile to create the temporary config file.
We are already using mktemp elsewhere in the script, and it seems to be
more widely available than tempfile.

  • 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# pwmconfig v0.7
4# Tests the pwm outputs of sensors and configures fancontrol
5#
6#    Warning!!! This program will stop your fans, one at a time,
7#    for approximately 5 seconds each!!!
8#    This may cause your processor temperature to rise!!!
9#    Verify that all fans are running at normal speed after this
10#    program has exited!!!
11#
12#    Copyright 2003-2005 The lm_sensors project
13#
14#    This program is free software; you can redistribute it and/or modify
15#    it under the terms of the GNU General Public License as published by
16#    the Free Software Foundation; either version 2 of the License, or
17#    (at your option) any later version.
18#
19#    This program is distributed in the hope that it will be useful,
20#    but WITHOUT ANY WARRANTY; without even the implied warranty of
21#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
22#    GNU General Public License for more details.
23#
24#    You should have received a copy of the GNU General Public License
25#    along with this program; if not, write to the Free Software
26#    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
27#
28#
29echo 'This program will search your sensors for pulse width modulation (pwm)'
30echo 'controls, and test each one to see if it controls a fan on'
31echo 'your motherboard. Note that many motherboards do not have pwm'
32echo 'circuitry installed, even if your sensor chip supports pwm.'
33echo
34echo 'We will attempt to briefly stop each fan using the pwm controls.'
35echo 'The program will attempt to restore each fan to full speed'
36echo 'after testing. However, it is ** very important ** that you'
37echo 'physically verify that the fans have been to full speed'
38echo 'after the program has completed.'
39echo
40
41DELAY=5 # 3 seconds delay is too short for large fans, thus I increased it to 5
42MAX=255
43
44DIR=/proc/sys/dev/sensors
45SDIR=/sys/bus/i2c/devices
46if [ ! -d $DIR ]
47then
48        if [ ! -d $SDIR ]
49        then
50                echo $0: 'No sensors found! (modprobe sensor modules?)'
51                exit 1
52        else
53                SYSFS=1
54                DIR=$SDIR
55        fi     
56fi
57
58cd $DIR
59DRIVERS=`echo *-*`
60if [ "*-*" = "$DRIVERS" ]
61then
62        echo $0: 'No sensors found! (modprobe sensor modules?)'
63        exit 1
64fi
65
66MATCH='*/pwm[1-9]'
67PWM=`echo $MATCH`
68if [ "$SYSFS" = "1" -a "$MATCH" = "$PWM" ]
69then
70        # Deprecated naming scheme (used in kernels 2.6.5 to 2.6.9)
71        MATCH='*/fan[1-9]_pwm'
72        PWM=`echo $MATCH`
73fi
74if [ "$MATCH" = "$PWM" ]
75then
76        echo $0: 'There are no pwm-capable sensor modules installed'
77        exit 1
78fi
79
80if [ "$SYSFS" = "1" ]
81then
82        MATCH='*/fan[1-9]_input'
83else
84        MATCH='*/fan[1-9]'
85fi
86FAN=`echo $MATCH`
87if [ "$MATCH" = "$FAN" ]
88then
89        echo $0: 'There are no fan-capable sensor modules installed'
90        exit 1
91fi
92
93# $1 = pwm file name
94function pwmdisable()
95{
96        if [ "$SYSFS" = "1" ]
97        then
98                echo $MAX > $1
99                ENABLE=${1}_enable
100                if [ -w $ENABLE ]
101                then
102                        echo 0 > $ENABLE
103                fi
104        else
105                echo $MAX 0 > $1
106        fi
107}
108
109# $1 = pwm file name
110function pwmenable()
111{
112        if [ "$SYSFS" = "1" ]
113        then
114                ENABLE=${1}_enable
115                if [ -w $ENABLE ]
116                then
117                        echo 1 > $ENABLE
118                fi
119        else
120                echo $MAX 1 > $1
121        fi
122}
123
124# $1 = pwm file name; $2 = pwm value 0-255
125function pwmset()
126{
127        echo $2 > $1
128}
129
130echo 'Found the following PWM controls:'
131for i in $PWM
132do
133        echo "   $i"
134        if [ -w $i ]
135        then
136                pwmdisable $i
137        else
138                NOTROOT=1
139        fi
140done
141
142echo
143echo 'Found the following fan sensors:'
144for i in $FAN
145do
146        # this will return the first field if there's only one (sysfs)
147        S=`cat $i | cut -d' ' -f2`
148        if [ "$S" = "0" -o "$S" = "-1" ]
149        then
150                echo "   $i     current speed: 0 ... skipping!"
151        else
152                echo "   $i     current speed: $S RPM"
153                if [ "$GOODFAN" = "" ]
154                then
155                        GOODFAN=$i
156                        SPEEDS=$S
157                else
158                        GOODFAN="$GOODFAN $i"
159                        SPEEDS="$SPEEDS $S"
160                fi
161        fi
162done
163echo
164
165if [ "$GOODFAN" = "" ]
166then
167        echo 'There are no working fan sensors, all readings are 0.'
168        echo 'Make sure you have a 3-wire fan connected.'
169        echo 'You may also need to increase the fan divisors.'
170        echo 'See doc/fan-divisors for more information.'
171        exit 1
172fi
173
174if [ "$NOTROOT" = "1" ]
175then
176        echo 'As you are not root, we cannot write the PWM settings.'
177        echo 'Please run as root to continue.'
178        exit 1
179fi
180
181echo 'Warning!!! This program will stop your fans, one at a time,'
182echo "for approximately $DELAY seconds each!!!"
183echo 'This may cause your processor temperature to rise!!!'
184echo 'If you do not want to do this hit control-C now!!!'
185echo -n 'Hit return to continue: '
186read X
187echo
188
189PLOTTER=gnuplot
190STEP=15
191PDELAY=2
192
193function pwmdetail()
194{
195        P=$1
196        F=$2
197        PLOT=
198
199        type $PLOTTER > /dev/null 2>&1
200        if [ $? -eq 0 ]
201        then
202                echo -n "Would you like to generate a graphical plot using $PLOTTER (y)? "
203                read X
204                if [ "$X" = "y" -o "$X" = "Y" -o "$X" = "" ]
205                then
206                        PLOT=y         
207                fi
208        fi
209
210        if [ "$PLOT" = "y" ]
211        then
212                TMP1=`mktemp -t pwmtest1.XXXXXXXXXX` || { echo "$0: Cannot create temporary file" >&2; exit 1; }
213                TMP2=`mktemp -t pwmtest2.XXXXXXXXXX` || { rm -f $TMP1 ; echo "$0: Cannot create temporary file" >&2; exit 1; }
214                echo "set xlabel \"PWM: $P\"" > $TMP1
215                echo "set ylabel \"FAN: $F (RPM)\"" >> $TMP1
216                echo 'set nokey' >> $TMP1
217                echo 'set xrange [0:255]' >> $TMP1
218                echo "plot \"$TMP2\" with lines" >> $TMP1
219                echo 'pause -1 "    Hit return to continue..."' >> $TMP1
220                > $TMP2
221        fi
222
223        let pwm=$MAX
224        pwmenable $P
225        while [ $pwm -ge 0 ]
226        do
227                pwmset $P $pwm 
228                sleep $PDELAY
229                if [ $? -ne 0 ]
230                then
231                        pwmdisable $P   
232                        echo '^C received, aborting...'
233                        rm -f $TMP1 $TMP2
234                        exit 1
235                fi             
236                # this will return the first field if there's only one (sysfs)
237                S=`cat $F | cut -d' ' -f2`
238                echo "    PWM $pwm FAN $S"
239                if [ "$PLOT" = "y" ]
240                then
241                        echo "$pwm $S" >> $TMP2
242                fi
243                if [ "$S" = "0" -o "$S" = "-1" ]
244                then
245                        pwmdisable $P   
246                        echo "    Fan Stopped at PWM = $pwm"
247                        if [ $pwm -eq $MAX ]
248                        then
249                                echo "    This fan appears to stop when the PWM is enabled;"
250                                echo "    perhaps the fan input shares a pin with the PWM output"
251                                echo "    on the sensor chip."
252                                echo "    You cannot control this fan with this PWM output."
253                                rm -f $TMP1 $TMP2
254                                echo
255                                return 0
256                        fi
257                        break
258                fi
259                let pwm=$pwm-$STEP
260        done
261        pwmdisable $P   
262        if [ "$PLOT" = "y" ]
263        then
264                $PLOTTER  $TMP1
265                rm -f $TMP1 $TMP2
266        fi
267        echo
268}
269
270for i in $PWM
271do
272        echo Testing pwm control $i ...
273        pwmenable $i
274        pwmset $i 0
275        sleep $DELAY
276        if [ $? -ne 0 ]
277        then
278                pwmdisable $i
279                echo '^C received, restoring PWM and aborting...'
280                exit 1
281        fi             
282        let pwmactivecount=0
283        let count=1
284        for j in $GOODFAN
285        do
286                OS=`echo $SPEEDS | cut -d' ' -f$count`
287                # this will return the first field if there's only one (sysfs)
288                S=`cat $j | cut -d' ' -f2`
289                echo "  $j ... speed was $OS now $S"
290                pwmdisable $i
291                let threshold=2*$OS/3
292                if [ $S -lt $threshold ]
293                then
294                        echo "    It appears that fan $j"
295                        echo "    is controlled by pwm $i"
296#
297# a PWM can control more than one fan....
298#
299                        if [ $pwmactivecount -eq 0 ]
300                        then
301                                let pwmactivecount=1
302                                pwmactive="$i ${pwmactive}"
303                                fanactive="$j ${fanactive}"
304                        else
305                                fanactive="$j+${fanactive}" #not supported yet by fancontrol
306                        fi
307                        sleep $DELAY
308                        if [ $? -ne 0 ]
309                        then
310                                echo '^C received, aborting...'
311                                exit 1
312                        fi             
313                        # this will return the first field if there's only one (sysfs)
314                        S=`cat $j | cut -d' ' -f2`
315                        if [ $S -lt $threshold ]
316                        then
317                                echo "    Fan $j has not returned to speed, please investigate!"
318                        else
319                                echo -n "Would you like to generate a detailed correlation (y)? "
320                                read X
321                                if [ "$X" = "y" -o "$X" = "Y" -o "$X" = "" ]
322                                then
323                                        pwmdetail $i $j
324                                fi
325                        fi
326                else
327                        echo "    no correlation"
328                fi
329                let count=count+1
330        done
331        echo
332        if [ "$pwmactivecount" = "0" ]
333        then
334                echo "No correlations were detected."
335                echo "There is either no fan connected to the output of $i,"
336                echo "or the connected fan has no rpm-signal connected to one of"
337                echo "the tested fan sensors. (Note: not all motherboards have"
338                echo "the pwm outputs connected to the fan connectors,"
339                echo "check out the hardware database on http://www.almico.com/forumindex.php)"
340                echo
341                echo -n "Did you see/hear a fan stopping during the above test (n)? "
342                read X
343                if [ "$X" = "y" -o "$X" = "Y" ]
344                then
345                        pwmactive="$i ${pwmactive}"
346                fi
347                echo
348        fi
349done
350
351
352echo 'Testing is complete.'
353echo 'Please verify that all fans have returned to their normal speed.'
354echo
355echo 'The fancontrol script can automatically respond to temperature changes'
356echo 'of your system by changing fanspeeds.'
357echo -n 'Do you want to set up its configuration file now (y)? '
358
359read X
360if [ "$X" = "n" -o "$X" = "N" ]
361then
362        exit
363fi
364
365if [ "$SYSFS" = "1" ]
366then
367        MATCH='*/temp[1-9]_input'
368else
369        MATCH='*/temp[1-9]'
370fi
371TEMPS=`echo $MATCH`
372if [ "$MATCH" = "$TEMPS" ]
373then
374        echo $0: 'There are no temperature-capable sensor modules installed'
375        exit 1
376fi
377
378function AskPath {
379        echo -n 'What should be the path to your fancontrol config file (/etc/fancontrol)? '
380
381        read X
382        if [ "$X" = "y" -o "$X" = "Y" -o "$X" = "" ]
383        then
384                X=/etc/fancontrol
385        fi
386        if [ -f $X ]
387        then
388                FCCONFIG=$X
389        else
390                echo -n "$X does not exist, shall I create it now (y)? "
391                read Y
392                if [ "$Y" = "y" -o "$Y" = "Y" -o "$Y" = "" ]
393                then
394                        touch $X
395                        chmod 0660 $X
396                        chown root.root $X
397                        FCCONFIG=$X
398                else
399                        AskPath
400                fi
401        fi
402}
403
404AskPath
405
406function LoadConfig {
407        echo "Loading configuration from $1 ..."
408        INTERVAL=`egrep '^INTERVAL=.*$' $1 | sed -e 's/INTERVAL=//g'`
409        FCTEMPS=`egrep '^FCTEMPS=.*$' $1 | sed -e 's/FCTEMPS=//g'`
410        FCFANS=`egrep '^FCFANS=.*$' $1 | sed -e 's/FCFANS=//g'`
411        MINTEMP=`egrep '^MINTEMP=.*$' $1 | sed -e 's/MINTEMP=//g'`
412        MAXTEMP=`egrep '^MAXTEMP=.*$' $1 | sed -e 's/MAXTEMP=//g'`
413        MINSTART=`egrep '^MINSTART=.*$' $1 | sed -e 's/MINSTART=//g'`
414        MINSTOP=`egrep '^MINSTOP=.*$' $1 | sed -e 's/MINSTOP=//g'`
415}
416
417LoadConfig $FCCONFIG
418
419function TestMinStart {
420        echo
421        echo 'Now we increase the PWM value in 10-unit-steps.'
422        echo 'Let the fan stop completely, then press return until the'
423        echo "fan starts spinning. Then enter 'y'."
424        echo 'We will use this value +20 as the starting speed.'
425        let fanok=0
426        let fanval=0
427        until [ "$fanok" = "1" ]
428        do
429                let fanval=fanval+10
430                if [ $fanval -gt 240 ] ; then let fanval=$MAX ; let fanok=1 ; fi
431                echo -n "Setting $pwms to $fanval..."
432                echo $fanval > $pwms
433                read FANTEST
434                if [ "$FANTEST" != "" ] ; then let fanok=1 ; fi
435        done
436        let fanval=fanval+20
437        if [ $fanval -gt 240 ] ; then let fanval=$MAX ; fi
438        echo "OK, using $fanval"
439        echo $MAX > $pwms
440}
441
442function TestMinStop {
443        echo
444        echo 'Now we decrease the PWM value in 10-unit-steps.'
445        echo 'Let the fan reach full speed, then press return until the'
446        echo "fan stops spinning. Then enter 'y'."
447        echo 'We will use this value +20 as the minimum speed.'
448        let fanok=0
449        let fanval=$MAX
450        until [ "$fanok" = "1" ]
451        do
452                let fanval=fanval-10
453                if [ $fanval -lt 0 ] ; then let fanval=0 ; let fanok=1 ; fi
454                echo -n "Setting $pwms to $fanval..."
455                echo $fanval > $pwms
456                read FANTEST
457                if [ "$FANTEST" != "" ] ; then let fanok=1 ; fi
458        done
459        let fanval=fanval+20
460        if [ $fanval -gt $MAX ] ; then let fanval=$MAX ; fi
461        echo "OK, using $fanval"
462        echo $MAX > $pwms
463}
464
465function SaveConfig {
466        echo
467        echo "Saving configuration to $FCCONFIG..."
468        tmpfile=`mktemp -t pwmcfg.XXXXXXXXXX` || { echo "$0: Cannot create temporary file" >&2; exit 1;  }
469        trap " [ -f \"$tmpfile\" ] && /bin/rm -f -- \"$tmpfile\"" 0 1 2 3 13 15
470        egrep -v '(INTERVAL|FCTEMPS|FCFANS|MAXTEMP|MINTEMP|MINSTART|MINSTOP)' $FCCONFIG >$tmpfile
471        echo -e "INTERVAL=$INTERVAL\nFCTEMPS=$FCTEMPS\nFCFANS=$FCFANS\nMINTEMP=$MINTEMP\nMAXTEMP=$MAXTEMP\nMINSTART=$MINSTART\nMINSTOP=$MINSTOP" >>$tmpfile
472        mv $tmpfile $FCCONFIG
473        #check if file was written correctly
474        echo 'Configuration saved'
475}
476
477#function LoadConfig {
478#}
479
480INTERVAL=10
481PS3='select (1-n): '
482DEFMINTEMP=0
483DEFMAXTEMP=60
484DEFMINSTART=150
485DEFMINSTOP=100
486
487#the section below has a high potential for usability improvements
488echo
489echo 'Select fan output to configure, or other action:'
490select pwms in $pwmactive "Change INTERVAL" "Just quit" "Save and quit" "Show configuration"; do
491        case $pwms in
492        "Change INTERVAL")
493                echo
494                echo "Current interval is $INTERVAL seconds."
495                echo -n "Enter the interval at which fancontrol should update PWM values (in s):"
496                read INTERVAL ;; #check user input here
497        "Just quit")
498                exit ;;
499        "Save and quit")
500                SaveConfig
501                exit ;;
502        "Show configuration")
503                echo
504                echo "Common Settings:"
505                echo "INTERVAL=$INTERVAL"
506                for pwmo in $pwmactive
507                do
508                        echo
509                        echo "Settings of ${pwmo}:"
510                        echo "  Depends on `echo $FCTEMPS |sed -e 's/ /\n/g' |egrep \"${pwmo}\" |sed -e 's/.*=//g'`"
511                        echo "  Controls `echo $FCFANS |sed -e 's/ /\n/g' |egrep \"${pwmo}\" |sed -e 's/.*=//g'`"
512                        echo "  MINTEMP=`echo $MINTEMP |sed -e \"s/ /\n/g\" |egrep \"${pwmo}\" |sed -e \"s/.*=//g\"`"
513                        echo "  MAXTEMP=`echo $MAXTEMP |sed -e \"s/ /\n/g\" |egrep \"${pwmo}\" |sed -e \"s/.*=//g\"`"
514                        echo "  MINSTART=`echo $MINSTART |sed -e \"s/ /\n/g\" |egrep \"${pwmo}\" |sed -e \"s/.*=//g\"`"
515                        echo "  MINSTOP=`echo $MINSTOP |sed -e \"s/ /\n/g\" |egrep \"${pwmo}\" |sed -e \"s/.*=//g\"`"
516                done
517                echo ;;
518
519        "`echo ${pwmactive} |sed -e 's/ /\n/g' | egrep \"${pwms}\"`" )
520                pwmsed=`echo ${pwms} | sed -e 's/\//\\\\\//g'` #escape / for sed
521                echo
522                echo 'Current temperature readings are as follows:'
523                for j in $TEMPS
524                do
525                        # this will return the first field if there's only one (sysfs)
526                        S=`cat $j | cut -d' ' -f3`
527                        if [ "$SYSFS" = "1" ]
528                        then
529                                let S="$S / 1000"
530                        fi
531                        echo "$j        $S"
532                done
533                FAN=`echo $fanactive|cut -d' ' -f$REPLY`
534                FCFANS="`echo $FCFANS | sed -e "s/${pwmsed}[^ ]* *//g\"` ${pwms}=$FAN"
535                echo
536                echo "Select a temperature sensor as source for ${pwms}:"
537                select tempss in $TEMPS "None (Do not affect this PWM output)"; do
538                        if [ "$tempss" = "None (Do not affect this PWM output)" ]
539                        then
540                       
541                                break;
542                        else
543                                if [ "$FCTEMPS" = "" ]
544                                then
545                                        FCTEMPS="${pwms}=${tempss}"
546                                else
547                                        FCTEMPS="`echo $FCTEMPS | sed -e "s/${pwmsed}[^ ]* *//g\"` ${pwms}=${tempss}"
548                                fi
549                        fi
550                        echo
551                        echo 'Enter the low temperature (C)'
552                        echo -n "at which the fan should be switched off ($DEFMINTEMP): "
553                        read XMT
554                        if [ "$XMT" = "" ]
555                        then
556                                XMT=$DEFMINTEMP
557                        fi
558                        if [ "$MINTEMP" = "" ]
559                        then
560                                MINTEMP="${pwms}=${XMT}"
561                        else
562                                MINTEMP="`echo $MINTEMP | sed -e \"s/${pwmsed}[^ ]* *//g\"` ${pwms}=${XMT}"
563                        fi
564                        echo
565                        echo 'Enter the high temperature (C)'
566                        echo -n "at which the fan should be switched to full speed ($DEFMAXTEMP): "
567                        read XMT
568                        if [ "$XMT" = "" ]
569                        then
570                                XMT=$DEFMAXTEMP
571                        fi
572                        if [ "$MAXTEMP" = "" ]
573                        then
574                                MAXTEMP="${pwms}=${XMT}"
575                        else
576                                MAXTEMP="`echo $MAXTEMP | sed -e \"s/${pwmsed}[^ ]* *//g\"` ${pwms}=${XMT}"
577                        fi
578                        echo
579                        echo "Enter the minimum PWM value (0-$MAX)"
580                        echo -n "at which the fan STARTS spinning (press t to test) ($DEFMINSTART): "
581                        read XMV
582                        if [ "$XMV" = "" ]
583                        then
584                                XMV=$DEFMINSTART
585                        fi
586                        if [ "$XMV" = "t" -o "$XMV" = "T" ]
587                        then
588                                TestMinStart
589                                XMV=$fanval
590                        fi
591                        if [ "$MINSTART" = "" ]
592                        then
593                                MINSTART="${pwms}=${XMV}"
594                        else
595                                MINSTART="`echo $MINSTART | sed -e \"s/${pwmsed}[^ ]* *//g\"` ${pwms}=${XMV}"
596                        fi
597                        echo
598                        echo "Enter the minimum PWM value (0-$MAX)"
599                        echo -n "at which the fan STOPS spinning (press t to test) ($DEFMINSTOP): "
600                        read XMV
601                        if [ "$XMV" = "" ]
602                        then
603                                XMV=$DEFMINSTOP
604                        fi
605                        if [ "$XMV" = "t" -o "$XMV" = "T" ]
606                        then
607                                TestMinStop
608                                XMV=$fanval
609                        fi
610                        if [ "$MINSTOP" = "" ]
611                        then
612                                MINSTOP="${pwms}=${XMV}"
613                        else
614                                MINSTOP="`echo $MINSTOP | sed -e \"s/${pwmsed}[^ ]* *//g\"` ${pwms}=${XMV}"
615                        fi
616                        echo
617                        break;
618                done ;;
619       
620        *)
621                grep $pwm
622
623                echo "No such option. Enter a number." ;;
624        esac
625done
Note: See TracBrowser for help on using the browser.