mirror of
https://github.com/kuhyx/testsAndMisc.git
synced 2026-11-11 12:27:50 +01:00
Some checks failed
dependency freshness / dependencies on newest stable (push) Has been cancelled
md-naming / markdown naming convention (push) Has been cancelled
Pre-commit checks / pre-commit (push) Has been cancelled
Python tests / test (push) Has been cancelled
Shell tests / shell-tests (push) Has been cancelled
Shell tests / arch-tests (push) Has been cancelled
The dkms pacman hook already rebuilds every preset on install and remove, so the unconditional mkinitcpio -P cost 20 s twice per run on the host. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01SS8M5wk88nJTXxDWz61KKk
214 lines
6.8 KiB
Bash
Executable File
214 lines
6.8 KiB
Bash
Executable File
#!/bin/bash
|
|
|
|
# ============================================================================
|
|
# Logitech G29: replace the in-tree hid-logitech FFB driver with new-lg4ff
|
|
#
|
|
# new-lg4ff (github.com/berarma/new-lg4ff) adds spring/damper/friction and
|
|
# periodic effects the in-tree lg4ff lacks (it only has constant force). Its
|
|
# dkms.conf installs the module AS hid-logitech under updates/dkms/, so it
|
|
# shadows the in-tree copy by name: no blacklist, no modules-load drop-in.
|
|
# Why this matters for BeamNG and the SDL env vars: ../docs/DOCS-g29-ffb.md.
|
|
#
|
|
# install_new_lg4ff.sh install from AUR, reload, regen initramfs
|
|
# install_new_lg4ff.sh --status which module owns the wheel + FFB caps
|
|
# install_new_lg4ff.sh --revert remove the package, back to in-tree
|
|
#
|
|
# Run as the desktop user (yay refuses root); sudo is used where needed.
|
|
# The initramfs regen is required: mkinitcpio's autodetect hook bundles
|
|
# hid-logitech because the wheel is plugged in at build time, and a stale
|
|
# in-tree copy in the initramfs would win at boot over the DKMS one.
|
|
# ============================================================================
|
|
|
|
set -euo pipefail
|
|
|
|
SCRIPT_NAME="$(basename "$0")"
|
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
readonly SCRIPT_NAME SCRIPT_DIR
|
|
readonly AUR_PKG="new-lg4ff-dkms-git"
|
|
readonly DKMS_NAME="new-lg4ff"
|
|
readonly MODULE="hid_logitech"
|
|
readonly VID_PID="046D:C24F"
|
|
readonly SHIFTER_FIX="$SCRIPT_DIR/fix_g29_shifter.sh"
|
|
readonly PACKAGES=(dkms joyutils)
|
|
|
|
MODE="install"
|
|
|
|
usage() {
|
|
sed -n '4,16p' "$0" | sed 's/^# \{0,3\}//'
|
|
exit 0
|
|
}
|
|
|
|
log() { echo "[$SCRIPT_NAME] $*"; }
|
|
die() {
|
|
echo "[$SCRIPT_NAME] ERROR: $*" >&2
|
|
exit 1
|
|
}
|
|
|
|
install_packages() {
|
|
local -a missing=()
|
|
local pkg
|
|
for pkg in "${PACKAGES[@]}"; do
|
|
pacman -Q "$pkg" &>/dev/null || missing+=("$pkg")
|
|
done
|
|
if ((${#missing[@]})); then
|
|
log "installing: ${missing[*]}"
|
|
sudo pacman -S --needed --noconfirm "${missing[@]}"
|
|
fi
|
|
# Headers for the RUNNING kernel, or dkms builds for a kernel nobody boots.
|
|
[[ -d "/usr/lib/modules/$(uname -r)/build" ]] ||
|
|
die "no headers for $(uname -r): install the matching linux*-headers"
|
|
}
|
|
|
|
# Path of the module modprobe would load: updates/dkms/... means new-lg4ff.
|
|
module_path() { modinfo -F filename "$MODULE" 2>/dev/null || echo "-"; }
|
|
|
|
is_new_lg4ff_active() {
|
|
# The DKMS module registers itself as hid-logitech-new even though the
|
|
# file is named hid-logitech; /proc/modules shows the registered name.
|
|
grep -q '^hid_logitech_new ' /proc/modules
|
|
}
|
|
|
|
wheel_event_dev() {
|
|
readlink -f /dev/input/by-id/usb-Logitech_G29_Driving_Force_Racing_Wheel-event-joystick 2>/dev/null || true
|
|
}
|
|
|
|
# Unbind and rebind the wheel so the freshly installed module takes over
|
|
# without a reboot. hid core rebinds the device on modprobe by itself.
|
|
reload_module() {
|
|
log "reloading $MODULE"
|
|
sudo modprobe -r "$MODULE"
|
|
sudo modprobe "$MODULE"
|
|
sleep 1
|
|
}
|
|
|
|
regen_initramfs() {
|
|
# Rebuild only when an image carries hid-logitech from the OTHER location
|
|
# than modprobe now resolves. The dkms pacman hook already regenerates on
|
|
# install and remove, so this is a safety net, not the normal path.
|
|
local want="kernel/drivers/hid/hid-logitech"
|
|
[[ "$(module_path)" == */updates/dkms/* ]] && want="updates/dkms/hid-logitech"
|
|
local img stale=0 listing
|
|
for img in /boot/initramfs-*.img; do
|
|
[[ -f $img ]] || continue
|
|
listing="$(lsinitcpio -l "$img" 2>/dev/null | grep 'hid-logitech' || true)"
|
|
[[ -z $listing ]] && continue
|
|
grep -q "$want" <<<"$listing" || stale=1
|
|
done
|
|
if ((stale)); then
|
|
log "initramfs bundles the other hid-logitech: regenerating all presets"
|
|
sudo mkinitcpio -P
|
|
else
|
|
log "initramfs already matches $(module_path)"
|
|
fi
|
|
}
|
|
|
|
show_status() {
|
|
local dev caps
|
|
log "package: $(pacman -Q "$AUR_PKG" 2>/dev/null || echo 'not installed')"
|
|
# `dkms status <name>` is a prefix filter that prints everything on a miss.
|
|
log "dkms: $(dkms status 2>/dev/null | grep "^$DKMS_NAME/" || echo 'none')"
|
|
log "module file: $(module_path)"
|
|
if is_new_lg4ff_active; then
|
|
log "loaded now: hid-logitech-new (new-lg4ff)"
|
|
elif grep -q '^hid_logitech ' /proc/modules; then
|
|
log "loaded now: hid_logitech (in-tree)"
|
|
else
|
|
log "loaded now: none"
|
|
fi
|
|
local d
|
|
for d in /sys/bus/hid/devices/*"$VID_PID"*; do
|
|
[[ -e $d ]] || continue
|
|
# USB interface 1 is unbound by design (hid-lg rejects it); only
|
|
# interface 0 carries the wheel, so "none" there is normal.
|
|
if [[ -e $d/driver ]]; then
|
|
log "$(basename "$d") driver: $(basename "$(readlink -f "$d/driver")")"
|
|
else
|
|
log "$(basename "$d") driver: none"
|
|
fi
|
|
done
|
|
dev="$(wheel_event_dev)"
|
|
if [[ -n $dev ]]; then
|
|
caps="$(cat "/sys/class/input/$(basename "$dev")/device/capabilities/ff")"
|
|
# In-tree lg4ff: "300040000 0" (constant, gain, autocenter only).
|
|
log "evdev $dev ff caps: $caps"
|
|
local sysdev
|
|
sysdev="$(readlink -f "/sys/class/input/$(basename "$dev")/device/device")"
|
|
local knob
|
|
for knob in range gain autocenter spring_level damper_level friction_level; do
|
|
[[ -f $sysdev/$knob ]] && log " $knob=$(cat "$sysdev/$knob")"
|
|
done
|
|
else
|
|
log "wheel: not plugged in"
|
|
fi
|
|
# An `&&` list as the last statement would make the function return 1
|
|
# when the shifter fix is absent, and set -e would abort on it.
|
|
if [[ -x $SHIFTER_FIX ]]; then
|
|
"$SHIFTER_FIX" --status | sed 's/^/ shifter: /'
|
|
fi
|
|
}
|
|
|
|
do_install() {
|
|
install_packages
|
|
if pacman -Q "$AUR_PKG" &>/dev/null; then
|
|
log "$AUR_PKG already installed"
|
|
else
|
|
command -v yay >/dev/null || die "yay not found; install it first"
|
|
log "installing $AUR_PKG from AUR (builds against $(uname -r))"
|
|
yay -S --needed --noconfirm "$AUR_PKG"
|
|
fi
|
|
dkms status | grep "^$DKMS_NAME/" | grep -q "$(uname -r).*installed" ||
|
|
die "dkms did not install $DKMS_NAME for $(uname -r): $(dkms status | grep "^$DKMS_NAME/")"
|
|
[[ "$(module_path)" == */updates/dkms/* ]] ||
|
|
die "modprobe still resolves $MODULE to $(module_path)"
|
|
regen_initramfs
|
|
if [[ -n "$(wheel_event_dev)" ]]; then
|
|
reload_module
|
|
is_new_lg4ff_active || die "reload done but hid_logitech_new is not loaded"
|
|
else
|
|
log "wheel not plugged in: module swap takes effect on next plug/boot"
|
|
fi
|
|
show_status
|
|
log "done. Feel check: fftest $(wheel_event_dev)"
|
|
}
|
|
|
|
do_revert() {
|
|
if pacman -Q "$AUR_PKG" &>/dev/null; then
|
|
# The dkms pacman hook removes the module from updates/dkms/.
|
|
sudo pacman -Rns --noconfirm "$AUR_PKG"
|
|
else
|
|
log "$AUR_PKG not installed"
|
|
fi
|
|
sudo depmod -a
|
|
[[ "$(module_path)" != */updates/dkms/* ]] ||
|
|
die "in-tree module not restored: $(module_path)"
|
|
regen_initramfs
|
|
if [[ -n "$(wheel_event_dev)" ]]; then
|
|
reload_module
|
|
! is_new_lg4ff_active || die "reload done but hid_logitech_new still loaded"
|
|
fi
|
|
show_status
|
|
}
|
|
|
|
main() {
|
|
case "$MODE" in
|
|
install) do_install ;;
|
|
revert) do_revert ;;
|
|
status) show_status ;;
|
|
esac
|
|
}
|
|
|
|
while [[ $# -gt 0 ]]; do
|
|
case $1 in
|
|
--status) MODE="status" ;;
|
|
--revert) MODE="revert" ;;
|
|
-h | --help) usage ;;
|
|
*)
|
|
echo "Unknown option: $1" >&2
|
|
exit 1
|
|
;;
|
|
esac
|
|
shift
|
|
done
|
|
|
|
main
|