#!/bin/sh
# tlp - adjust power settings
#
# Copyright (c) 2016 Thomas Koch <linrunner at gmx.net>
# This software is licensed under the GPL v2 or later.

# --- Constants
readonly LIBDIR="/usr/share/tlp-pm"
readonly LIBS="tlp-functions tlp-rf-func"

# --- Source libraries
for lib in $LIBS; do
    if [ ! -f $LIBDIR/$lib ]; then
        echo "Error: missing function library \'$LIBDIR/$lib\'." 1>&2
        exit 1
    fi
    . $LIBDIR/$lib
done

# --- Subroutines
apply_common_settings () { # apply settings common to all modes
                           # $1: 0=ac mode, 1=battery mode
    set_laptopmode $1
    set_dirty_parms $1
    set_scaling_governor $1
    set_scaling_min_max_freq $1
    set_cpu_perf_pct $1
    set_cpu_boost_all $1
    set_sched_powersave $1
    set_nmi_watchdog
    set_phc_controls $1
    set_energy_perf_policy $1
    set_disk_apm_level $1
    set_disk_spindown_timeout $1
    set_disk_io_sched
    set_sata_link_power $1
    set_ahci_runtime_pm $1
    set_pcie_aspm $1
    set_radeon_profile $1
    set_wifi_power_mode $1
    disable_wake_on_lan
    set_sound_power_mode $1
    set_runtime_pm $1

    return 0
}

# --- MAIN
read_defaults
check_tlp_enabled || exit 1
add_sbin2path

check_laptop_mode_tools

# get cmd line args
mode=$(echo $1 | tr "[:upper:]" "[:lower:]")
mode2=$(echo $2 | tr "[:upper:]" "[:lower:]")

# inhibit trace output for tlp stat
[ "$mode" = "stat" ] && nodebug=1

# get current power state
get_power_state
pwrmode=$?

modedebug=$mode
[ -n "$mode2" ] && modedebug="$modedebug $mode2"
echo_debug "run" "+++ mode=$modedebug ($TLPVER) ++++++++++++++++++++++++++++++++++++++++"

if [ -n "$addpath" ]; then
    echo_debug "path" "PATH=$oldpath[$addpath]"
else
    echo_debug "path" "PATH=$oldpath"
fi

if [ $pwrmode -eq 1 ]; then
    echo_debug "run" "power_source=bat"
else
    echo_debug "run" "power_source=ac"
fi

exitcode=0

case "$mode" in
    init) # system initialization/shutdown: sysv, upstart, systemd, ...
        check_root

        # try to obtain lock (with timeout)
        locked=0
        if lock_tlp; then
            locked=1
        else
            echo "Failed to get lock, continuing anyway." 1>&2
        fi

        # do init business ...
        case $mode2 in
            start)
                # apply radio states
                set_radio_device_states start

                # apply power save settings -- but only if not previously run
                # (by the udev rule) for the same power state
                if compare_and_save_power_state $pwrmode; then
                    echo -n "Applying power save settings..."
                    apply_common_settings $pwrmode
                    [ "$pwrmode" = "1" ] && poweroff_drivebay 0
                    [ "$X_TLP_USB_MODE" = "1" ] && set_usb_suspend 0 auto
                    echo "done."
                fi

                # apply battery settings
                echo -n "Setting battery charge thresholds..."
                set_charge_thresholds
                echo "done."
                ;;

            restart|force-reload)
                # apply power save settings
                compare_and_save_power_state $pwrmode
                echo -n "Applying power save settings..."
                apply_common_settings $pwrmode
                [ "$pwrmode" = "1" ] && poweroff_drivebay 0
                [ "$X_TLP_USB_MODE" = "1" ] && set_usb_suspend 0 auto
                echo "done."

                # apply battery settings
                echo -n "Setting battery charge thresholds..."
                set_charge_thresholds
                echo "done."
                ;;

            stop)
                set_radio_device_states stop

                if [ "$USB_AUTOSUSPEND_DISABLE_ON_SHUTDOWN" = "1" ]; then
                    echo -n "Disabling usb autosuspend..."
                    set_usb_suspend 0 on
                    echo "done."
                fi

                # remove usb startup flag
                [ -f $USB_DONE ] && rm $USB_DONE

                # clear saved power state
                clear_saved_power_state

                # apply ac settings for faster shutdown
                echo -n "Applying power save settings..."
                apply_common_settings 0
                echo "done."
                ;;

            *)
                echo "Usage: tlp init {start|stop|restart|force-reload}" >&2
                exit 3
                ;;
        esac

        # unlock if necessary
        [ $locked -eq 0 ] || unlock_tlp
        ;;

    auto) # set mode depending on state (called by udev rule)
          # -- but only if not previously run for the same power state
          # rationale: filter out duplicate power_supply udev events
        check_root
        if lock_tlp_nb; then
            if compare_and_save_power_state $pwrmode; then
                apply_common_settings $pwrmode
                [ "$pwrmode" = "1" ] && poweroff_drivebay 0
                set_radio_device_states $pwrmode
            fi
            unlock_tlp
        else
            exitcode=4
        fi
        ;;

    start) # set mode depending on state (interactive mode)
        check_root
        if lock_tlp; then
            compare_and_save_power_state $pwrmode
            apply_common_settings $pwrmode
            [ "$pwrmode" = "1" ] && poweroff_drivebay 0
            set_usb_suspend 0 auto
            set_charge_thresholds
            set_radio_device_states $pwrmode
            unlock_tlp

            echo_started_mode $pwrmode
        else
            echo_tlp_locked
            exitcode=4
        fi
        ;;

    true|bat*) # set battery power mode
        check_root
        if lock_tlp; then
            compare_and_save_power_state 1
            apply_common_settings 1
            poweroff_drivebay 0
            [ "$X_TLP_USB_MODE" = "1" ] && set_usb_suspend 0 auto
            set_radio_device_states 1
            unlock_tlp

            echo_started_mode 1
        else
            echo_tlp_locked
            exitcode=4
        fi
        ;;

    false|ac) # set ac power mode
        check_root
        if lock_tlp; then
            compare_and_save_power_state 0
            apply_common_settings 0
            [ "$X_TLP_USB_MODE" = "1" ] && set_usb_suspend 0 auto
            set_radio_device_states 0
            unlock_tlp

            echo_started_mode 0
        else
            echo_tlp_locked
            exitcode=4
        fi
        ;;

    suspend) # handle suspend/hibernate
        check_root
        if lock_tlp; then
            save_device_states "bluetooth wwan"

            apply_common_settings 0
            suspend_drivebay $pwrmode
            unlock_tlp
        else
            exitcode=4
        fi
        ;;

    resume) # handle resume
        check_root
        if lock_tlp; then
            restore_device_states

            compare_and_save_power_state $pwrmode
            apply_common_settings $pwrmode
            resume_drivebay
            unlock_tlp
        else
            exitcode=4
        fi
        ;;

    usb) # Enable usb autosuspend
        check_root
        set_usb_suspend 1 auto
        ;;

    bayoff) # power off drive bay
        check_root
        poweroff_drivebay 1
        ;;

    setcharge) # set charge thresholds (temporarily)
        check_root
        setcharge_battery $2 $3 $4
        exitcode=$?
        ;;

    fullcharge) # charge battery up to 100% (temporarily)
        if check_ac_power fullcharge; then
            check_root
            setcharge_battery 96 100 $2
            exitcode=$?
        else
            exitcode=2
        fi
        ;;

    chargeonce) # charge battery to upper threshold once
        if check_ac_power chargeonce; then
            check_root
            chargeonce_battery $2
            exitcode=$?
        else
            exitcode=2
        fi
        ;;

    discharge) # discharge battery completely (to recalibrate)
        if check_ac_power discharge; then
            check_root
            discharge_battery $2
            exitcode=$?
        else
            exitcode=2
        fi
        ;;

    recalibrate) # recalibrate battery, i.e. discharge and charge to 100%
        if check_ac_power recalibrate; then
            check_root
            setcharge_battery 96 100 $2
            sleep 1
            discharge_battery $2
            exitcode=$?
            if [ $exitcode -eq 0 ]; then
                echo "      The battery starts charging now. For a complete recalibration"
                echo "      keep AC connected until the battery is fully charged."
            fi
        else
            exitcode=2
        fi
        ;;

    stat) # show status
        shift
        tlp-stat $*
        exitcode=$?
        ;;

    diskid) # show disk-by-id
        { for dev in $(ls /dev/disk/by-id/ | egrep '^ata' | egrep -v '\-part[1-9]+'); do
            if [ -n "$dev" ]; then
                get_disk_dev $dev
                echo "$disk_dev: $disk_id"
            fi
        done } | sort
        ;;

    *)
        echo "Error: unknown command \"$mode\"."  1>&2
        echo "Usage: tlp start|true|bat|false|ac|usb|bayoff|discharge|setcharge|fullcharge|recalibrate|stat|diskid" 1>&2
        exitcode=3
        ;;
esac

exit $exitcode


