edido: init
This commit is contained in:
parent
eb6459a233
commit
8559b460b1
176
pkgs/by-name/ed/edido/edido.sh
Executable file
176
pkgs/by-name/ed/edido/edido.sh
Executable file
@ -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 </proc/cmdline)
|
||||||
|
else
|
||||||
|
log "loading kernel parameters compatible arguments from commandline"
|
||||||
|
args=("$@")
|
||||||
|
fi
|
||||||
|
|
||||||
|
local -A edids modes connectors
|
||||||
|
local -a entries
|
||||||
|
local key value
|
||||||
|
|
||||||
|
for arg in "${args[@]}"; do
|
||||||
|
key="${arg%%=*}"
|
||||||
|
value=""
|
||||||
|
test "${key}" == "${arg}" || value="${arg#*=}"
|
||||||
|
|
||||||
|
case "${key}" in
|
||||||
|
video)
|
||||||
|
# one argument per connector:
|
||||||
|
# video=DP-4:e video=DP-1:e
|
||||||
|
connector="${value%:*}"
|
||||||
|
mode="${value#*:}"
|
||||||
|
connectors["${connector}"]=""
|
||||||
|
modes["$connector"]="$mode"
|
||||||
|
;;
|
||||||
|
drm.edid_firmware)
|
||||||
|
# single argument for all connectors:
|
||||||
|
# drm.edid_firmware=DP-4:edid/one.bin,DP-1:edid/two.bin
|
||||||
|
mapfile -t entries <<<"${value//","/$'\n'}"
|
||||||
|
for entry in "${entries[@]}"; do
|
||||||
|
connector="${entry%:*}"
|
||||||
|
edidFilename="${entry#*:}"
|
||||||
|
connectors["${connector}"]=""
|
||||||
|
edids["${connector}"]="${edidFilename}"
|
||||||
|
done
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
|
||||||
|
for connector in "${!connectors[@]}"; do
|
||||||
|
# spawn in a subshell to easily adjust and runtime modify global variables
|
||||||
|
(load "${connector}" "${edids["${connector}"]:-""}" "${modes["${connector}"]:-""}") &
|
||||||
|
done
|
||||||
|
wait
|
||||||
|
}
|
||||||
|
|
||||||
|
main "$@"
|
19
pkgs/by-name/ed/edido/package.nix
Normal file
19
pkgs/by-name/ed/edido/package.nix
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
{ lib
|
||||||
|
, writeShellApplication
|
||||||
|
, bc
|
||||||
|
, diffutils
|
||||||
|
, findutils
|
||||||
|
, coreutils
|
||||||
|
, firmwarePaths ? [
|
||||||
|
"/run/current-system/firmware"
|
||||||
|
]
|
||||||
|
}:
|
||||||
|
writeShellApplication {
|
||||||
|
name = "edido";
|
||||||
|
meta.description = "A tool to apply display configuration from `boot.kernelParams`.";
|
||||||
|
runtimeInputs = [ diffutils findutils coreutils bc ];
|
||||||
|
text = ''
|
||||||
|
FIRMWARE_PATH="''${FIRMWARE_PATH:-"${builtins.concatStringsSep ":" firmwarePaths}"}"
|
||||||
|
${builtins.readFile ./edido.sh}
|
||||||
|
'';
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user