From 8559b460b1caf1b619ef25ef9bb251cfa8282db9 Mon Sep 17 00:00:00 2001 From: Krzysztof Nazarewski Date: Thu, 18 Apr 2024 13:33:19 +0200 Subject: [PATCH] edido: init --- pkgs/by-name/ed/edido/edido.sh | 176 ++++++++++++++++++++++++++++++ pkgs/by-name/ed/edido/package.nix | 19 ++++ 2 files changed, 195 insertions(+) create mode 100755 pkgs/by-name/ed/edido/edido.sh create mode 100644 pkgs/by-name/ed/edido/package.nix diff --git a/pkgs/by-name/ed/edido/edido.sh b/pkgs/by-name/ed/edido/edido.sh new file mode 100755 index 000000000000..136205386ee1 --- /dev/null +++ b/pkgs/by-name/ed/edido/edido.sh @@ -0,0 +1,176 @@ +#!/usr/bin/env bash +set -eEuo pipefail +test -z "${DEBUG:-}" || set -x +set -eEuo pipefail + +FIRMWARE_PATH="${EDID_PATH:-"/run/current-system/firmware"}" +mapfile -t edid_paths <<<"${FIRMWARE_PATH//":"/$'\n'}" + +err() { + LOGGER="ERROR" log "$@" + return 1 +} + +log() { + # shellcheck disable=SC2059 + printf "[${LOGGER:-"INFO"}] $1\n" "${@:2}" >&2 +} + +find_path() { + local filePath="$1" + mapfile -t candidates < <( + set -x + find -L "${@:2}" -path "*/${filePath}" + ) + if test "${#candidates[@]}" -eq 0; then + log "'%s' path not found" "${filePath}" + return 1 + fi + log "'%s' path found at %s" "${filePath}" "${candidates[0]}" + echo -n "${candidates[0]}" +} + +wait_for_file() { + local filePath="$1" + until find_path "${filePath}" "${@:2}"; do + backoff "${filePath}" + done +} + +backoff() { + local what="$1" sleepFor + + backoff_start="${backoff_start:-"5"}" + backoff_current="${backoff_current:-"${backoff_start}"}" + backoff_jitter_multiplier="${backoff_jitter_multiplier:-"0.3"}" + backoff_multiplier="${backoff_multiplier:-1.5}" + + sleepFor="$(bc <<<"${backoff_current} + ${RANDOM} % (${backoff_current} * ${backoff_jitter_multiplier})")" + + log "still waiting for '%s', retry in %s sec..." "${what}" "${sleepFor}" + sleep "${sleepFor}" + backoff_current="$(bc <<<"scale=2; ${backoff_current} * ${backoff_multiplier}")" + +} + +force_mode() { + local connPath="$1" newMode="$2" currentMode + currentMode="$(cat "$connPath/force")" + if test "${currentMode}" == "${newMode}"; then + log "video mode is already '%s'" "${currentMode}" + return + fi + log "changing video mode from '%s' to '%s'" "${currentMode}" "${newMode}" + echo "${newMode}" >"$connPath/force" + CHANGED=1 +} + +force_edid() { + local connPath="$1" edidPath="$2" +} + +apply_mode() { + local connPath="$1" mode="$2" + test -n "$mode" || return + log "setting up fb mode..." + + # see https://github.com/torvalds/linux/blob/8cd26fd90c1ad7acdcfb9f69ca99d13aa7b24561/drivers/gpu/drm/drm_sysfs.c#L202-L207 + # see https://docs.kernel.org/fb/modedb.html + case "${mode}" in + *d) force_mode "$connPath" off ;; + *e) force_mode "$connPath" on ;; + *D) force_mode "$connPath" on-digital ;; + esac +} + +apply_edid() { + local connPath="$1" edidFilename="$2" edidPath + test -n "${edidFilename}" || return + log "loading EDID override..." + edidPath="$(find_path "${edidFilename}" "${edid_paths[@]/%/"/"}" -maxdepth 2)" + + force_edid "${connPath}" "$edidPath" + cat "$edidPath" >"${connPath}/edid_override" + + if cmp "${connPath}/edid_override" "${edidPath}" &>/dev/null; then + log "EDID is already up to date with '%s'" "${edidPath}" + else + log "applying EDID override from ${edidPath}" + cat "$edidPath" >"${connPath}/edid_override" + CHANGED=1 + fi +} + +load() { + local conn="$1" edidFilename="$2" mode="$3" + export LOGGER="$conn:${edidFilename}:$mode" + CHANGED="${CHANGED:-0}" + + log "starting configuration" + local connPath + connPath="$(wait_for_file "$conn" /sys/kernel/debug/dri/ -maxdepth 2 -type d)" + apply_edid "${connPath}" "${edidFilename}" + apply_mode "${connPath}" "$mode" + + if test "${CHANGED}" != 0; then + log "changes detected, triggering hotplug" + echo 1 >"${connPath}/trigger_hotplug" + else + log "no changes detected, skipping hotplug trigger" + fi +} + +main() { + if [[ $EUID -ne 0 ]]; then + err "must be run as root" + fi + + if test "$#" == 0; then + log "loading kernel parameters from /proc/cmdline" + # replace script arguments with kernel parameters + mapfile -t args < <(xargs -n1