#!/bin/bash
#
# powersave    Set some energy saving stuff
#
# chkconfig: 345 15 90
# description: This Script is trying to detect your hardware \
#              and trying to enable powersave for it. 
# probe: true

###
# Author: Jean-Michel Bruenn <himself@jeanbruenn.info>
# License: Free for everyone as long as you don't add
#          any license to this script.
# Important: This Script comes without any warranty,
#            you're using this script on your own risk.
#            by using this script you agree to this.
# Version: 0.1
###

shopt -s extglob

HDP=`which hdparm`;
CFI=`which cpufreq-info`;
CFS=`which cpufreq-set`;
ETT=`which ethtool`;
IWC=`which iwconfig`;

if [ ! -f $HDP ]; then
  echo "Please install hdparm";
  NOHDD=1;
fi

if [ ! -f $CFI ]; then
  echo "Please install cpufreq-utils";
  NOCPU=1;
fi

if [ ! -f $CFS ]; then
  echo "Please install cpufreq-utils";
  NOCFS=1;
fi

if [ ! -f $ETT ]; then
  echo "Please install ethtool";
  NONET=1;
fi

if [ ! -f $IWC ]; then
  NOWLA=1;
fi

chkresult()
{
  if [ $? -eq "-1" ] ; then
    echo  -e $RESULT_FAIL
  elif [ $? -eq "-3" ]; then
    echo  -e $RESULT_WARN
  else
    echo  -e $RESULT_OK
  fi
}

case "$1" in
  start)
    echo "Starting...";
 
    if [ ! $NOCPU ]; then
      ###
      # CPU Governor
      ###
      echo "== CPU Governor ==";

      
    fi

    ###
    # CPU Scheduling
    ###
    echo  "== CPU Scheduling ==";
    if [ -f /sys/devices/system/cpu/sched_mc_power_savings ]; then
      echo  " + Enabling Multicore-Scheduler-Power-Saving...";
      echo  1 > /sys/devices/system/cpu/sched_mc_power_savings
    else
      echo  " - Not possible to set sched_mc_power_savings";
    fi

    if [ -f /sys/devices/system/cpu/sched_smt_power_savings ]; then
      echo  " + Enabling Multithread-Scheduler-Power-Saving...";
      echo  1 > /sys/devices/system/cpu/sched_smt_power_savings
    else
      echo  " - Not possible to set sched_smt_power_savings";
    fi

    if [ ! $NOHDD ]; then
      ###
      # Harddisk
      ###
      echo  "== Harddisk Powersavings ==";
      RAM=$(free -m | awk 'NR == 2 { print $2; }');
      VALUE=$(bc <<< "$RAM / 1.75");
      if [ $VALUE -lt 255 ]; then
      	VALUE=256
      elif [ $VALUE -gt 2047 ]; then
      	VALUE=2048
      fi
      for i in /dev/[sh]d*; do
        TEST=$(echo $i | egrep '[0-9]');
        if [ ! "$TEST" ]; then
          DEV=$(echo $i | sed 's_/dev/__g');
          CDROM=$(dmesg | grep $DEV | egrep "CD|DVD");
          if [ ! "$CDROM" ]; then
            PRE=${DEV:0:1}
            if [ $PRE == "s" ]; then
            	DISKTYPE="SATA";
            else
            	DISKTYPE="IDE";
            fi
            CURRRA=$($HDP -a $i | egrep '[0-9]' | cut -d"=" -f2 | cut -d" " -f2);
            if [ $VALUE -gt $CURRRA ]; then
              echo  " + ($DISKTYPE) Setting Readahead from $CURRRA to $VALUE for drive $DEV...";
              $HDP -a $VALUE /dev/$DEV;
            else
              echo  " - ($DISKTYPE) No need to higher the Readahead for $DEV";
            fi

            APM=$($HDP -i $i | grep AdvancedPM | sed 's/WriteCache=.*//' | sed 's/\s//g');
            if [ "$APM" = "AdvancedPM=no" ]; then
              echo  " - ($DISKTYPE) Drive $DEV does not Support Powermanagement";
            else
              echo  " + ($DISKTYPE) Enabling Powermanagement for drive $DEV...";
              $HDP -B 15 -S 2 /dev/$DEV;
            fi
          fi
        fi
      done
    fi

    ###
    # SATA Aggresive Link Powermanagement
    ###
    echo  "== SATA Aggresive Link Powermanagement ==";
    for i in `ls /sys/class/scsi_host/`; do
      if [ -f /sys/class/scsi_host/$i/link_power_management_policy ]; then
        echo " + Setting SATA Link of $i to medium_power...";
        echo "medium_power" > /sys/class/scsi_host/$i/link_power_management_policy
      else
        echo " - SATA Link of $i does not support ALPM or no ALPM Support at all";
      fi
    done    

    ###
    # Vm Writeback
    ###
    echo "== VM Writeback Time ==";
    if [ `cat /proc/sys/vm/dirty_writeback_centisecs` -le 501 ]; then
      echo " + Setting VM Writeback to 1500...";
      echo 1500 > /proc/sys/vm/dirty_writeback_centisecs
    else
      echo " - Already set to a higher value than the default one";
    fi

    ###
    # Laptop Mode
    ###
    echo "== Laptop Mode ==";
    if [ `cat /proc/sys/vm/laptop_mode` > 0 ]; then
      echo " - Already enabled";
    else
      echo " + Enabling Laptop-Mode...";
      echo 5 > /proc/sys/vm/laptop_mode
    fi

    if [ ! $NONET ]; then
      ###
      # Networking
      ###
      echo "== Networking ==";
      for i in `ifconfig | grep "Ethernet" | cut -d" " -f1`; do
        WOL=$($ETT $i | grep "Supports Wake-on" | sed 's/\s+/ /' | sed 's/\t//');
        if [ ! "$WOL" ]; then
          echo " - The NIC $i does not support wake on lan";
        else
          WOD=$($ETT $i | grep "Wake-on: d" | sed 's/\s+/ /' | sed 's/\t//');
          if [ ! "$WOD" ]; then
            echo " + Disabling Wake-on-Lan for $i...";
            ethtool -s $i wol d
          else
            echo " - Wake-on-Lan already disabled for $i";
          fi
        fi

        # wanted to disable nics when not in use
        # though dunno how.
        #LNK=$(ethtool $i | grep "Link detected:" | sed 's/\s+/ /' | sed 's/\t//');
        #if [ "$LNK" = "Link detected: yes" ]; then
        #  echo " - Link detected, not disabling $i";
        #else
        #  echo " - No Link detected, disabling $i";
        #fi  

        WLN=$(ethtool $i | grep "No data");
        if [ "$WLN" = "No data available" ]; then
          echo " + Maybe WLAN ($i) detected, trying to tune...";
          # not all wlan cards support these commands.. however
          # its not causing any problems, power management is
          # just not working as the cards doesnt support it
          $IWC $i txpower auto
          $IWC $i power min period 2 power max period 4 power saving 5
        fi
      done
    fi

    ###
    # Soundcards
    ###
    echo "== Soundcards ==";
    if [ -f /sys/module/snd_hda_intel/parameters/power_save ]; then
      echo " + Managing snd-hda-intel soundcard...";
      SHI=$(cat /sys/module/snd_hda_intel/parameters/power_save);
      if [ $SHI -ge 0 ]; then
        echo " - Powersaving already enabled";
      else
        echo " + Enabling power-saving for snd-hda-intel...";
        echo 5 > /sys/module/snd_hda_intel/parameters/power_save
      fi
    fi

    if [ -f /sys/module/snd_ac97_codec/parameters/power_save ]; then
      echo " + Managing ac97 soundcard...";
      SHI=$(cat /sys/module/snd_ac97_codec/parameters/power_save);
      if [ $SHI -ge 0 ]; then
        echo " - Powersaving already enabled";
      else
        echo " + Enabling power-saving for ac97...";
        echo 1 > /sys/module/snd_ac97_codec/parameters/power_save
        echo 1 > /dev/dsp
      fi 
    fi

    ###
    # USB
    ###
    echo "== USB ==";
    if [ -f /sys/module/usbcore/parameters/autosuspend ]; then
      USB=$(cat /sys/module/usbcore/parameters/autosuspend);
      if [ $USB -ge 0 ]; then
        echo " - Auto-Suspend already enabled";
      else
        echo " + Enabling Auto-Suspend...";
        echo 2 > /sys/module/usbcore/parameters/autosuspend
      fi
    else
      echo " - No USB Support or Auto-Suspend not in Kernel";
    fi
    ;;

  stop)
    echo "Stopping...";

    if [ ! $NOCPU ]; then
      ###
      # CPU Governor
      ###
      echo "== CPU Governor ==";
    fi

    ###
    # CPU Scheduling
    ###
    echo  "== CPU Scheduling ==";
    if [ -f /sys/devices/system/cpu/sched_mc_power_savings ]; then
      echo  " + Disabling Multicore-Scheduler-Power-Saving...";
      echo  0 > /sys/devices/system/cpu/sched_mc_power_savings
    fi

    if [ -f /sys/devices/system/cpu/sched_smt_power_savings ]; then
      echo  " + Disabling Multithread-Scheduler-Power-Saving...";
      echo  0 > /sys/devices/system/cpu/sched_smt_power_savings
    fi

    if [ ! $NOHDD ]; then
      ###
      # Harddisk
      ###
      echo  "== Harddisk Powersavings ==";
      VALUE=256
      for i in /dev/[sh]d*; do
        TEST=$(echo $i | egrep '[0-9]');
        if [ ! "$TEST" ]; then
          DEV=$(echo $i | sed 's_/dev/__g');
          CDROM=$(dmesg | grep $DEV | egrep "CD|DVD");
          if [ ! "$CDROM" ]; then
            PRE=${DEV:0:1}
            if [ $PRE == "s" ]; then
            	DISKTYPE="SATA";
            else
            	DISKTYPE="IDE";
            fi
            CURRRA=$($HDP -a $i | egrep '[0-9]' | cut -d"=" -f2 | cut -d" " -f2);
            if [ $VALUE -lt $CURRRA ]; then
              echo  " + ($DISKTYPE) Setting Readahead back from $CURRRA to $VALUE for drive $DEV...";
              $HDP -a $VALUE /dev/$DEV;
            else
              echo  " - ($DISKTYPE) No need to alter the Readahead for $DEV";
            fi

            APM=$($HDP -i $i | grep AdvancedPM | sed 's/WriteCache=.*//' | sed 's/\s//g');
            if [ "$APM" = "AdvancedPM=no" ]; then
              echo  " - ($DISKTYPE) Drive $DEV does not Support Powermanagement";
            else
              echo  " + ($DISKTYPE) Disabling Powermanagement for drive $DEV...";
              $HDP -B 0 -S 0 /dev/$DEV;
            fi
          fi
        fi
      done
    fi

    ###
    # SATA Aggresive Link Powermanagement
    ###
    echo  "== SATA Aggresive Link Powermanagement ==";
    for i in `ls /sys/class/scsi_host/`; do
      if [ -f /sys/class/scsi_host/$i/link_power_management_policy ]; then
        echo " + Setting SATA Link of $i back to max_performance...";
        echo "max_performance" > /sys/class/scsi_host/$i/link_power_management_policy
      fi
    done    

    ###
    # Vm Writeback
    ###
    echo "== VM Writeback Time ==";
    if [ `cat /proc/sys/vm/dirty_writeback_centisecs` -gt 501 ]; then
      echo " + Setting VM Writeback back to 500...";
      echo 500 > /proc/sys/vm/dirty_writeback_centisecs
    else
      echo " - Already set to a higher value than the default one";
    fi

    ###
    # Laptop Mode
    ###
    echo "== Laptop Mode ==";
    if [ `cat /proc/sys/vm/laptop_mode` -gt 0 ]; then
    	echo " + Disabling Laptop-Mode...";
      echo 0 > /proc/sys/vm/laptop_mode
    fi

    if [ ! $NONET ]; then
      ###
      # Networking
      ###
      echo "== Networking ==";
      for i in `ifconfig | grep "Ethernet" | cut -d" " -f1`; do
        WOL=$($ETT $i | grep "Supports Wake-on" | sed 's/\s+/ /' | sed 's/\t//');
        if [ ! "$WOL" ]; then
          echo " - The NIC $i does not support wake on lan";
        else
          WOD=$($ETT $i | grep "Wake-on: d" | sed 's/\s+/ /' | sed 's/\t//');
          if [ "$WOD" == "Wake-on: d" ]; then
            echo " + Re-Enabling Wake-on-Lan for $i...";
            ethtool -s $i wol g
          fi
        fi

        # wanted to disable nics when not in use
        # though dunno how.
        #LNK=$(ethtool $i | grep "Link detected:" | sed 's/\s+/ /' | sed 's/\t//');
        #if [ "$LNK" = "Link detected: yes" ]; then
        #  echo " - Link detected, not disabling $i";
        #else
        #  echo " - No Link detected, disabling $i";
        #fi  

        WLN=$(ethtool $i | grep "No data");
        if [ "$WLN" = "No data available" ]; then
          echo " + Maybe WLAN ($i) detected, trying to tune...";
          # not all wlan cards support these commands.. however
          # its not causing any problems, power management is
          # just not working as the cards doesnt support it
          $IWC $i txpower auto
          $IWC $i power off
        fi
      done
    fi

    ###
    # Soundcards
    ###
    echo "== Soundcards ==";
    if [ -f /sys/module/snd_hda_intel/parameters/power_save ]; then
      echo " + Managing snd-hda-intel soundcard...";
      SHI=$(cat /sys/module/snd_hda_intel/parameters/power_save);
      if [ $SHI -gt 0 ]; then
        echo " + Disabling power-saving for snd-hda-intel...";
        echo 0 > /sys/module/snd_hda_intel/parameters/power_save
      fi
    fi

    if [ -f /sys/module/snd_ac97_codec/parameters/power_save ]; then
      echo " + Managing ac97 soundcard...";
      SHI=$(cat /sys/module/snd_ac97_codec/parameters/power_save);
      if [ $SHI -ge 0 ]; then
        echo " + Disabling power-saving for ac97...";
        echo 0 > /sys/module/snd_ac97_codec/parameters/power_save
        echo 1 > /dev/dsp
      fi 
    fi

    ###
    # USB
    ###
    echo "== USB ==";
    if [ -f /sys/module/usbcore/parameters/autosuspend ]; then
      USB=$(cat /sys/module/usbcore/parameters/autosuspend);
      if [ $USB -ge 0 ]; then
        echo " + Disabling Auto-Suspend...";
        echo 0 > /sys/module/usbcore/parameters/autosuspend
      fi
    else
      echo " - No USB Support or Auto-Suspend not in Kernel";
    fi
    ;;

  restart)
    $0 stop
    $0 start
    ;;

  *)
    echo  "Usage: $0 {start|stop}"
    exit 0
    ;;
esac
