mirror of
https://github.com/archr-linux/Arch-R.git
synced 2026-03-31 14:41:55 -07:00
387 lines
9.5 KiB
Bash
Executable File
387 lines
9.5 KiB
Bash
Executable File
#!/bin/sh
|
|
# SPDX-License-Identifier: GPL-2.0
|
|
# Copyright (C) 2025-present ROCKNIX (https://github.com/ROCKNIX)
|
|
|
|
. /etc/profile
|
|
|
|
### Enable logging
|
|
case $(get_setting system.loglevel) in
|
|
verbose)
|
|
DEBUG=true
|
|
;;
|
|
*)
|
|
DEBUG=false
|
|
;;
|
|
esac
|
|
|
|
check_hardware_suspend_enabled() {
|
|
local SUSPEND_MODE="$(get_setting system.suspendmode)"
|
|
|
|
if [[ "${SUSPEND_MODE}" != "off" ]]; then
|
|
return 0
|
|
else
|
|
return 1
|
|
fi
|
|
}
|
|
|
|
check_hdmi_connected() {
|
|
local HDMI_STATUS=$(cat /sys/class/drm/card*/card*-HDMI-A-[0-9]/status)
|
|
|
|
if [[ "${HDMI_STATUS}" = "connected" ]]; then
|
|
return 0
|
|
else
|
|
return 1
|
|
fi
|
|
}
|
|
|
|
check_charging() {
|
|
local CHARGE_STATUS=$(cat /sys/class/power_supply/battery/status)
|
|
|
|
if [[ "${CHARGE_STATUS}" = "Charging" ]]; then
|
|
return 0
|
|
else
|
|
return 1
|
|
fi
|
|
}
|
|
|
|
check_es_running_game() {
|
|
local HTTP_STATUS=$(curl -s -o /dev/null -w "%{http_code}" "http://localhost:1234/runningGame")
|
|
${DEBUG} && log $0 "ES runningGame HTTP_STATUS - ${HTTP_STATUS}"
|
|
test $? != 0 && return 1 # call failed, assume no game running
|
|
test "${HTTP_STATUS}" = 201 && return 1 # 201 when no game running
|
|
test "${HTTP_STATUS}" = 200 && return 0 # 200 when game running
|
|
}
|
|
|
|
display_off() {
|
|
if [[ "${HW_DEVICE}" == "S922X" ]]; then
|
|
# S922X - dpms occasionaly causes hard reboots, so just turn off the backlight
|
|
echo 4 > /sys/class/backlight/backlight/bl_power
|
|
else
|
|
if echo "${UI_SERVICE}" | grep "sway"; then
|
|
${DEBUG} && log $0 "Display power off"
|
|
swaymsg "output * power off"
|
|
elif echo "${UI_SERVICE}" | grep "weston"; then
|
|
weston-dpms -m off
|
|
fi
|
|
fi
|
|
}
|
|
|
|
display_on() {
|
|
if [[ "${HW_DEVICE}" == "S922X" ]]; then
|
|
# S922X - dpms occasionaly causes hard reboots, so just turn on the backlight
|
|
echo 0 > /sys/class/backlight/backlight/bl_power
|
|
else
|
|
if echo "${UI_SERVICE}" | grep "sway"; then
|
|
${DEBUG} && log $0 "Display power on"
|
|
swaymsg "output * power on"
|
|
elif echo "${UI_SERVICE}" | grep "weston"; then
|
|
weston-dpms -m on
|
|
fi
|
|
fi
|
|
}
|
|
|
|
mute_audio() {
|
|
${DEBUG} && log $0 "Mute audio"
|
|
pactl set-sink-mute @DEFAULT_SINK@ true
|
|
}
|
|
|
|
unmute_audio() {
|
|
${DEBUG} && log $0 "Unmute audio"
|
|
pactl set-sink-mute @DEFAULT_SINK@ false
|
|
}
|
|
|
|
powersave_governors() {
|
|
${DEBUG} && log $0 "Set CPU/GPU governors to powersave"
|
|
|
|
# Get the current cpu and gpu governor, save for restoration on resume
|
|
local CURR_CPU_GOVERNOR="$(cat ${CPU_FREQ}/scaling_governor)"
|
|
local CURR_GPU_GOVERNOR="$(cat ${GPU_FREQ}/governor)"
|
|
|
|
set_setting sleep.cpugovernor "${CURR_CPU_GOVERNOR}"
|
|
set_setting sleep.gpugovernor "${CURR_GPU_GOVERNOR}"
|
|
|
|
# Set all governors to powersave
|
|
set_cpu_gov powersave
|
|
set_gpu_gov powersave
|
|
}
|
|
|
|
restore_governors() {
|
|
${DEBUG} && log $0 "Restore CPU/GPU governors"
|
|
|
|
# Grab the old governors
|
|
local PRE_SUSPEND_CPU_GOVERNOR=$(get_setting "sleep.cpugovernor")
|
|
[[ -z "${PRE_SUSPEND_CPU_GOVERNOR}" ]] && PRE_SUSPEND_CPU_GOVERNOR="ondemand"
|
|
|
|
local PRE_SUSPEND_GPU_GOVERNOR=$(get_setting "sleep.gpugovernor")
|
|
[[ -z "${PRE_SUSPEND_GPU_GOVERNOR}" ]] && PRE_SUSPEND_GPU_GOVERNOR="simple_ondemand"
|
|
|
|
# Restore old governors
|
|
set_cpu_gov "${PRE_SUSPEND_CPU_GOVERNOR}"
|
|
set_gpu_gov "${PRE_SUSPEND_GPU_GOVERNOR}"
|
|
|
|
# Clean up
|
|
del_setting "sleep.cpugovernor"
|
|
del_setting "sleep.gpugovernor"
|
|
}
|
|
|
|
park_cores() {
|
|
${DEBUG} && log $0 "CPU core parking"
|
|
for x in /sys/devices/system/cpu/cpu*/online; do
|
|
if [[ ! $(echo "${x}" | grep "cpu0") ]]; then
|
|
echo 0 > "${x}"
|
|
fi
|
|
done
|
|
}
|
|
|
|
unpark_cores() {
|
|
${DEBUG} && log $0 "Undo CPU core parking"
|
|
for x in /sys/devices/system/cpu/cpu*/online; do
|
|
echo 1 > "${x}"
|
|
done
|
|
}
|
|
|
|
block_input() {
|
|
for x in /dev/input/event*; do
|
|
local EVENT_INPUT=$(echo ${x} | awk 'BEGIN{FS="/"} {print $NF}')
|
|
local DEVICE_NAME=$(cat /sys/class/input/$EVENT_INPUT/device/name)
|
|
|
|
# If device is not in whitelist, block input
|
|
local FOUND=0
|
|
for WHITELIST_DEVICE in "${INPUT_WHITELIST[@]}"; do
|
|
if [[ "${WHITELIST_DEVICE}" = "${DEVICE_NAME}" ]]; then
|
|
FOUND=1
|
|
break
|
|
fi
|
|
done
|
|
|
|
if (( ! ${FOUND})); then
|
|
${DEBUG} && log $0 "Blocking input for ${x} - ${DEVICE_NAME}"
|
|
/usr/bin/evtest --grab ${x} > /dev/null &
|
|
fi
|
|
done
|
|
}
|
|
|
|
unblock_input() {
|
|
${DEBUG} && log $0 "Unblocking input"
|
|
for x in $(pgrep -f "evtest --grab"); do
|
|
kill -9 ${x}
|
|
done
|
|
}
|
|
|
|
do_suspend_actions() {
|
|
# Turn off display
|
|
display_off
|
|
|
|
# Mute audio
|
|
mute_audio
|
|
|
|
# Set CPU / GPU governors
|
|
powersave_governors
|
|
|
|
# CPU core parking (if enabled)
|
|
[[ "${ENABLE_CORE_PARKING}" == "1" ]] && park_cores
|
|
|
|
# Block input
|
|
block_input
|
|
}
|
|
|
|
do_resume_actions() {
|
|
# Turn on display
|
|
display_on
|
|
|
|
# Unmute audio
|
|
unmute_audio
|
|
|
|
# Restore CPU / GPU governors
|
|
restore_governors
|
|
|
|
# Undo CPU core parking (if enabled)
|
|
[[ "${ENABLE_CORE_PARKING}" == "1" ]] && unpark_cores
|
|
|
|
# Unblock input
|
|
unblock_input
|
|
}
|
|
|
|
do_shutdown() {
|
|
# Check if HDMI has been connected while suspended
|
|
check_hdmi_connected
|
|
local HDMI_CONNECTED=$?
|
|
|
|
if [[ $HDMI_CONNECTED -eq 0 ]]; then
|
|
${DEBUG} && log $0 "HDMI connected, not shutting down"
|
|
return 0
|
|
fi
|
|
|
|
# Check if charger has been connected while suspended
|
|
check_charging
|
|
local CHARGING=$?
|
|
|
|
if [[ $CHARGING -eq 0 ]]; then
|
|
${DEBUG} && log $0 "Charging, not shutting down"
|
|
return 0
|
|
fi
|
|
|
|
# Unmute audio - otherwise wireplumber will keep it muted on next boot
|
|
unmute_audio
|
|
|
|
# Check whether a game is running
|
|
check_es_running_game
|
|
local RUNNING_GAME=$?
|
|
|
|
if [[ $RUNNING_GAME -eq 0 ]]; then
|
|
# ES shutdown API won't work if a game is running
|
|
${DEBUG} && log $0 "Shutting down now"
|
|
shutdown now
|
|
else
|
|
# Use ES shutdown API so metadata is saved
|
|
${DEBUG} && log $0 "Shutting down via ES API"
|
|
curl "http://localhost:1234/shutdown"
|
|
fi
|
|
}
|
|
|
|
suspend() {
|
|
# Create delay flag file
|
|
${DEBUG} && log $0 "Creating ${DELAY_FLAG_FILE}"
|
|
touch "${DELAY_FLAG_FILE}"
|
|
|
|
check_es_running_game
|
|
local RUNNING_GAME=$?
|
|
|
|
check_charging
|
|
local CHARGING=$?
|
|
|
|
# Determine shutdown delay
|
|
local DELAY=${SHUTDOWN_DELAY}
|
|
[[ $RUNNING_GAME -eq 0 ]] && DELAY=${SHUTDOWN_DELAY_RUNNING_GAME}
|
|
${DEBUG} && log $0 "Shutdown delay - ${DELAY} seconds"
|
|
[[ ${CHARGING} -eq 0 ]] && ${DEBUG} && log $0 "Charging ..."
|
|
|
|
if [[ "${DELAY}" -gt 0 || ${CHARGING} -eq 0 ]]; then
|
|
do_suspend_actions
|
|
fi
|
|
|
|
# Delay shutdown
|
|
sleep ${DELAY}
|
|
|
|
# Delay has completed - check whether the flag file is still present
|
|
if [[ -f "${DELAY_FLAG_FILE}" ]]; then
|
|
${DEBUG} && log $0 "Delay expired, flag file found"
|
|
# Flag present - shutdown
|
|
do_shutdown
|
|
else
|
|
${DEBUG} && log $0 "Delay expired, flag file not found"
|
|
fi
|
|
}
|
|
|
|
resume() {
|
|
# Resume event - remove all flag files and kill processes
|
|
${DEBUG} && log $0 "Removing flags"
|
|
rm -f "${DELAY_FLAG_FILE_PATTERN}".*
|
|
rm -f "${POWER_SUSPEND_ACTIVE_FLAG_FILE}"
|
|
rm -f "${LID_CLOSED_FLAG_FILE}"
|
|
|
|
# Do resume actions
|
|
do_resume_actions
|
|
|
|
${DEBUG} && log $0 "Resume - killing ${TO_KILL} processes"
|
|
killall ${TO_KILL}
|
|
}
|
|
|
|
# Main logic
|
|
# Only do something when hardware suspend is disabled
|
|
check_hardware_suspend_enabled
|
|
HW_SUSPEND_ENABLED=$?
|
|
|
|
if [[ $HW_SUSPEND_ENABLED -eq 0 ]]; then
|
|
${DEBUG} && log $0 "Hardware suspend enabled, exiting"
|
|
exit 0
|
|
fi
|
|
|
|
# If a game is not running, by default shutdown immediately
|
|
SHUTDOWN_DELAY="$(get_setting system.shutdown_delay)"
|
|
[[ "${SHUTDOWN_DELAY}" = "" ]] && SHUTDOWN_DELAY=0
|
|
|
|
# If a game is running, by default delay the shutdown for 15 minutes
|
|
SHUTDOWN_DELAY_RUNNING_GAME="$(get_setting system.shutdown_delay_running_game)"
|
|
[[ "${SHUTDOWN_DELAY_RUNNING_GAME}" = "" ]] && SHUTDOWN_DELAY_RUNNING_GAME=900
|
|
|
|
# On suspend, should CPU cores be parked
|
|
ENABLE_CORE_PARKING="$(get_setting system.suspend.park_cores)"
|
|
[[ "${ENABLE_CORE_PARKING}" = "" ]] && ENABLE_CORE_PARKING="1"
|
|
|
|
# flag files
|
|
PID=$$
|
|
DELAY_FLAG_FILE_PATTERN="/var/run/shutdown-delay.flag"
|
|
DELAY_FLAG_FILE="${DELAY_FLAG_FILE_PATTERN}.${PID}"
|
|
POWER_SUSPEND_ACTIVE_FLAG_FILE="/var/run/power-fake-suspend-active.flag"
|
|
LID_CLOSED_FLAG_FILE="/var/run/lid-closed.flag"
|
|
|
|
# Process to kill
|
|
TO_KILL="rocknix-fake-suspend"
|
|
|
|
# Lid / power button - event input device whitelist
|
|
INPUT_WHITELIST=(
|
|
# H700
|
|
"axp20x-pek" \
|
|
"gpio-keys-lid" \
|
|
# S922X
|
|
"rk805 pwrkey" \
|
|
# SM8550
|
|
"pmic_pwrkey"
|
|
)
|
|
|
|
# Source = power / lid
|
|
SOURCE=$1
|
|
|
|
# Action = open / close
|
|
ACTION=$2
|
|
|
|
# Check if HDMI is connected
|
|
check_hdmi_connected
|
|
HDMI_CONNECTED=$?
|
|
|
|
# Handle event
|
|
if [[ "${SOURCE}" = "power" ]]; then
|
|
${DEBUG} && log $0 "Power button pressed ..."
|
|
|
|
if [[ -f "${LID_CLOSED_FLAG_FILE}" ]]; then
|
|
${DEBUG} && log $0 "Lid closed - no action"
|
|
elif [[ -f "${POWER_SUSPEND_ACTIVE_FLAG_FILE}" ]]; then
|
|
# In a 'suspend' state from power button, 'resume'
|
|
${DEBUG} && log $0 "Power suspend active - resuming"
|
|
resume
|
|
else
|
|
if [[ $HDMI_CONNECTED -eq 0 ]]; then
|
|
${DEBUG} && log $0 "HDMI connected, not suspending"
|
|
else
|
|
# Create flag file and suspend
|
|
${DEBUG} && log $0 "Suspending"
|
|
touch ${POWER_SUSPEND_ACTIVE_FLAG_FILE}
|
|
suspend
|
|
fi
|
|
fi
|
|
elif [[ "${SOURCE}" = "lid" && "${ACTION}" = "close" ]]; then
|
|
${DEBUG} && log $0 "Lid closed ..."
|
|
touch ${LID_CLOSED_FLAG_FILE}
|
|
|
|
if [[ -f "${POWER_SUSPEND_ACTIVE_FLAG_FILE}" ]]; then
|
|
# In a 'suspend' state from power button, do nothing
|
|
${DEBUG} && log $0 "Power suspend active - no action"
|
|
else
|
|
if [[ $HDMI_CONNECTED -eq 0 ]]; then
|
|
${DEBUG} && log $0 "HDMI connected, not suspending"
|
|
else
|
|
# Suspend
|
|
${DEBUG} && log $0 "Suspending"
|
|
suspend
|
|
fi
|
|
fi
|
|
elif [[ "${SOURCE}" = "lid" && "${ACTION}" = "open" ]]; then
|
|
rm -f "${LID_CLOSED_FLAG_FILE}"
|
|
|
|
# Always resume on lid open - regardless of suspend source
|
|
${DEBUG} && log $0 "Lid opened - resuming"
|
|
resume
|
|
fi
|
|
|
|
exit 0 |