#!/bin/sh -eu

MODPROBE="modprobe -qb"
MODULE=
CPUFREQ=/sys/devices/system/cpu/cpu0/cpufreq

CPU=
GOVERNOR_AC_ON=
GOVERNOR_AC_OFF=
DEFAULT_GOVERNOR_AC_ON=ondemand
DEFAULT_GOVERNOR_AC_OFF=ondemand
# Dirk Brandewie stated that in case of intel_pstate driver
# "powersave roughly equal to ondemand".
# See https://bugzilla.kernel.org/show_bug.cgi?id=73421#c1
# for details.
DEFAULT_INTEL_PSTATE_GOVERNOR_AC_ON=powersave
DEFAULT_INTEL_PSTATE_GOVERNOR_AC_OFF=powersave

DEFAULT_AMD_PSTATE_EPP_GOVERNOR_AC_ON=powersave
DEFAULT_AMD_PSTATE_EPP_GOVERNOR_AC_OFF=powersave

. shell-error

[ -f /etc/sysconfig/cpufreq-simple ] && . /etc/sysconfig/cpufreq-simple

PATH='/sbin:/usr/sbin:/usr/local/sbin:/bin:/usr/bin:/usr/local/bin'
CPUFREQ=/sys/devices/system/cpu/cpu0/cpufreq
GOVERNORS="$CPUFREQ/scaling_available_governors"
SCALING_DRIVER="$CPUFREQ/scaling_driver"
cmd="${1-}"

is_module_loaded()
{
	[ -f "$CPUFREQ/scaling_governor" ] && [ -f "$CPUFREQ/scaling_available_governors" ]
}

load_module()
{
	# Don't try to load already loaded module
	if is_module_loaded; then
		return 0
	fi

	# try autodetecting if not specified already
	if [ -z "$MODULE" ]; then
		MODULE="$(detect-cpufreq-module)"

		# check whether still none
		if [ -z "$MODULE" ]; then
			echo "No cpufreq module specified or detected" 1>&2
			# don't treat this as error
			return 0
		fi
	fi

	if ! $MODPROBE "$MODULE"; then
		echo "Loading cpufreq module $MODULE failed" 1>&2
		return 1
	fi

	return 0
}

get_ac_state()
{
	local state="off-line"

	# Treat error as on-line state
	if /usr/libexec/cpufreq-simple/on_ac_power || [ $? -eq 255 ]; then
		state="on-line"
	fi

	echo "$state"
}

get_scaling_driver()
{
	if [ -f "$SCALING_DRIVER" ]; then
		cat "$SCALING_DRIVER"
	fi
}

init_command()
{
	local ac_state="$(get_ac_state)"
	[ -n "$ac_state" ] && echo "ac-$ac_state"
}

set_cpufreq()
{
	local cpu_list=

	# getopt seems overkill right now
	if [ "$1" = "-g" -a -n "$2" ]; then
		grep -Fq -- "$2" "$GOVERNORS" || $MODPROBE "cpufreq_$2"
	fi
	for i in $CPU; do
		cpu_list="$cpu_list${cpu_list:+,}$i"
	done

	[ -n "$cpu_list" ] || cpu_list="all"

	cpupower --cpu "$cpu_list" frequency-set "$@"
}

status()
{
	cpupower frequency-info -d | grep --color=never -o 'driver: .*$'
	cpupower frequency-info -o
}

[ -n "$cmd" ] || cmd="$(init_command)"

if [ -z "$cmd" ]; then
	fatal "couldn't apply initial settings"
fi

if load_module; then
	# If cpufreq module not detected then exit
	if ! is_module_loaded; then
		exit 0
	fi
else
	exit 1
fi

case "$cmd" in
	ac-on-line)
		if [ -z "$GOVERNOR_AC_ON" ]; then
			case "$(get_scaling_driver)" in
				intel_pstate) GOVERNOR_AC_ON="$DEFAULT_INTEL_PSTATE_GOVERNOR_AC_ON" ;;
				amd-pstate-epp) GOVERNOR_AC_ON="$DEFAULT_AMD_PSTATE_EPP_GOVERNOR_AC_ON" ;;
				*) GOVERNOR_AC_ON="$DEFAULT_GOVERNOR_AC_ON" ;;
			esac
		fi
		set_cpufreq -g "$GOVERNOR_AC_ON"
		;;
	ac-off-line)
		if [ -z "$GOVERNOR_AC_OFF" ]; then
			case "$(get_scaling_driver)" in
				intel_pstate) GOVERNOR_AC_OFF="$DEFAULT_INTEL_PSTATE_GOVERNOR_AC_OFF" ;;
				amd-pstate-epp) GOVERNOR_AC_OFF="$DEFAULT_AMD_PSTATE_EPP_GOVERNOR_AC_OFF" ;;
				*) GOVERNOR_AC_OFF="$DEFAULT_GOVERNOR_AC_OFF" ;;
			esac
		fi
		set_cpufreq -g "$GOVERNOR_AC_OFF"
		;;
	status)
		status
		;;
	*)
		fatal "unknown command: '$cmd'"
		;;
esac
