#!/bin/sh
###############################################################################
#                                   fancond 
#
# An example service, using eee.ko, that allows us to control the fan and CPU
# throttle independently.  This script is written for my Eee PC 900 (16GB),
# and as such your mileage WILL vary.  This script is public domain, and no
# warranties, expressed or implied, are granted for the usability of this
# software or the damage it may cause to your hardware.  
#
#                                                               Josef Chessor
###############################################################################

#######################################
#               Globals
#######################################

# You will have to alter these for your
# own machine's foibles.

# INTERVAL - How often does the script
#            check the temperature,
#            in seconds.
export INTERVAL=5

# MAXFSB  - The highest we dare push the
#           FSB when cool.
export MAXFSB=110

# MAXTEMP - Temperature after which we
#           shut down
export MAXTEMP=70

# MINFAN  - How low are you willing to 
#           let the fan go down?
export MINFAN=20

# MINFSB  - How low we dare underclock
#           the processor if we have to.
export MINFSB=70

# MINTEMP - Temperature that we can safely
#           run the processor at full and
#           the fan at minimum.
export MINTEMP=47

# SHIFTEMP - Temperature at which we shift
#            from increasing the fan to
#            throttling the FSB.
export SHIFTEMP=65

#######################################
#              Functions
#######################################

# 
# pthrottle - Change our FSB incrementally
#             to the indicated speed.  
# 
function pthrottle ()
{
   # Save the current speed.
   current=`cat /proc/eee/fsb | cut -f1 -d" "`

   # Check our parameters, and make sure we
   # stay within limits.  Defaults to full
   # speed.

   if [ -n $1 ]; then
     desired=$1
   else
     desired=$MAXFSB
   fi

   if [ $desired -lt $MINFSB ]; then
     desired=$MINFSB
   fi
   
   if [ $desired -gt $MAXFSB ]; then
     desired=$MAXFSB
   fi
   
   # Why do we need this?!
   if [ $current -lt $desired ]; then
     increment=1
   else
     increment=-1
   fi
   
   # Cycle the front side bus.   
   if [ $current -ne $desired ]; then 
     for i in `seq $current $increment $desired`; do
       echo $i 24 1 > /proc/eee/fsb
     done
   fi
}

#
# fthrottle - Incrementally increase or
#             decrease fan speed.  It
#             works for the FSB, so why
#             not?
#
function fthrottle ()
{
   # Save the current speed.
   current=`cat /proc/eee/fan_speed`

   # Check our parameters, and assume
   # full speed otherwise.
   if [ -n $1 ]; then
     desired=$1
   else
     desired=100
   fi

   if [ $desired -lt $MINFAN ]; then
     desired=$MINFAN
   fi
  
   # Why do we need this?!
   if [ $current -lt $desired ]; then
     increment=1
   else
     increment=-1
   fi
   
   # Cycle the fan RPM.   
   if [ $current -ne $desired ]; then 
     for i in `seq $current $increment $desired`; do
       echo $i > /proc/eee/fan_speed
     done
   fi
}

# Decide what to do with the environmental data.
function monitor 
{
  # Fetch the current temperature.
  temp=`cat /proc/eee/temperature`

  # Here, we check for the worst conditions:  
  #
  #   At MAXTEMP - 2, we should pop up a warning dialog, 
  #   informing our user that we're overheating.
  # 
  #   At MAXTEMP + 1, we pop up a final warning, and grace-
  #   fully shutdown the Eee PC.
  #

  let adjtemp=MAXTEMP-2
  if [ $temp -eq $adjtemp ]; then
    # Do this only if we haven't already warned the user.
    if [ ! -e /tmp/.tempwarning ]; then
      touch /tmp/.tempwarning
      kdialog --msgbox "The temperature of the netbook is too high.  Please reduce your activity levels, or move to a place with better ventilation.\n\nThe current temperature is $temp""C." &
      return;
    fi
  fi
    
  let adjtemp=MAXTEMP+1
  if [ $temp -ge $adjtemp ]; then
      kdialog --error "The temperature of the netbook has reached a critical high.  The laptop will shutdown in thirty seconds.  Please save as much as your work as you can.\n\nThe current temperature is $temp""C." &
      sleep 30
      /sbin/fastshutdown.sh 
  fi


  # Here's where it gets complicated.
  #  
  # If we're below the shift temperature, 
  # ensure the FSB is at max, and adjust
  # only the fan speed proportionate to 
  # the current temperature.  If we're
  # over the threshold, then adjust the
  # fsb downward according to temperature.
  
  if [ $temp -le $SHIFTEMP ]; then

    # Clean the temperature warning, if it exists.
    rm -f /tmp/.tempwarning

    # FSB at full speed
    pthrottle $MAXFSB;

    # Compute how far over the ideal we are.
    let deviation=$temp-$MINTEMP

    # This is how we determine fan speed:
    # speed = deviation * scalar
    let range=$SHIFTEMP-$MINTEMP
    let scale=100/$range

    let speed=$deviation*$scale

    fthrottle $speed

  else

    # Fan at full speed
    fthrottle 100;

    # Compute how far over the threshold we are.
    let deviation=$temp-$SHIFTEMP

    # This is how we throttle down the FSB:
    let range=$MAXTEMP-$SHIFTEMP
    let scalar=$MAXFSB-$MINFSB
    let scale=$scalar/$range
    let speed=$deviation*$scale
    let newfsb=$MAXFSB-$speed
    
    pthrottle $newfsb
   
  fi  
      
}

#######################################
#                Setup
#######################################

# We use kdialog to integrate into either desktop for user warnings.
export DISPLAY=:0.0


#######################################
#              Main Loop
#######################################

while [ "" = "" ]; do 

  # This could be placed in Setup, but if you load/unload
  # eeecontrol, it takes the module and manual flag with it.
  
  # Check for the eee.ko module, and load it if needed.
  if [ `lsmod | grep -c eee` = '0' ]; then
    sudo /sbin/modprobe i2c_i801
    sudo /sbin/modprobe eee
  fi

  # Enable fan control if it isn't already.
  echo 1 >/proc/eee/fan_manual

  monitor $1
  sleep $INTERVAL

done

#######################################
#             Thank You
#######################################
