From d00f3c0bbdeced72e2dad8c71c988ca6cde875cc Mon Sep 17 00:00:00 2001 From: Patrick Mulligan Date: Thu, 6 Aug 2026 18:52:33 +0200 Subject: [PATCH] fix(batm3): make touch calibration immune to USB-boot timing race MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit egalax-calibrate polls 30s for the eGalax X device then gives up; on a slow USB boot usbtouchscreen binds the panel later than that, so the calibration matrix is never applied and touch registers in the wrong place ("dead" panel). Seen on cold boots (2/2 today), fine on others — a nondeterministic race, not a regression. - Add a udev rule that (re)starts egalax-calibrate the instant the eGalax input node appears (SYSTEMD_WANTS) — device-driven, can't lose the race. - Widen the calibrate poll window 30s -> 120s as a fallback. Recovery when it does strand: `systemctl restart egalax-calibrate`, or apply the matrix live via xinput set-prop. --- deploy/nixos/hardware/batm3.nix | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/deploy/nixos/hardware/batm3.nix b/deploy/nixos/hardware/batm3.nix index 40983c9..1d6af0b 100644 --- a/deploy/nixos/hardware/batm3.nix +++ b/deploy/nixos/hardware/batm3.nix @@ -173,6 +173,13 @@ SUBSYSTEM=="tty", ATTRS{serial}=="A9YW78OC", SYMLINK+="ttyMEI", MODE="0666" SUBSYSTEM=="tty", ATTRS{serial}=="A9ZF8ELY", SYMLINK+="ttyNFC", MODE="0666" ACTION=="add", SUBSYSTEM=="usb", ATTRS{idVendor}=="0eef", ATTRS{idProduct}=="0001", RUN+="${pkgs.bash}/bin/bash -c '${pkgs.kmod}/bin/modprobe usbtouchscreen 2>/dev/null; echo ''$kernel:1.0 > /sys/bus/usb/drivers/usbhid/unbind 2>/dev/null; echo 0eef 0001 > /sys/bus/usb/drivers/usbtouchscreen/new_id 2>/dev/null'" + # Belt-and-suspenders for touch calibration: on a slow USB boot the + # usbtouchscreen panel can bind AFTER egalax-calibrate's poll window, which + # leaves the panel uncalibrated and unresponsive ("dead"). (Re)start the + # calibration the instant the eGalax input node actually appears — this is + # device-driven, so it cannot lose a boot-timing race no matter how late the + # driver hands over. Pairs with egalax-calibrate's own (widened) poll loop. + ACTION=="add", SUBSYSTEM=="input", KERNEL=="event*", ATTRS{name}=="eGalax Inc. USB TouchController", TAG+="systemd", ENV{SYSTEMD_WANTS}+="egalax-calibrate.service" ''; # Force the X evdev driver on the eGalax (not libinput). The usbtouchscreen @@ -211,17 +218,21 @@ Environment = [ "DISPLAY=:0" "XAUTHORITY=/home/bitspire/.Xauthority" ]; # Wait for the eGalax X device to appear (usbtouchscreen binds a little # after display-manager on a USB boot) and retry, instead of a fixed - # sleep — more robust to boot timing. Matrix: swap X/Y + invert + scale - # to the active panel area (matches the known-good internal install). + # sleep — more robust to boot timing. 120s window: on a slow USB boot the + # panel has bound as late as ~30-60s after display-manager, so a 30s cap + # gave up before the device appeared and left touch dead (this service is + # ALSO re-triggered by a udev rule when the input node shows up, so this + # loop is the fallback, not the only path). Matrix: swap X/Y + invert + + # scale to the active panel area (matches the known-good internal install). ExecStart = pkgs.writeShellScript "egalax-calibrate" '' - for i in $(${pkgs.coreutils}/bin/seq 1 30); do + for i in $(${pkgs.coreutils}/bin/seq 1 120); do if ${pkgs.xorg.xinput}/bin/xinput list --name-only 2>/dev/null | ${pkgs.gnugrep}/bin/grep -qx 'eGalax Inc. USB TouchController'; then exec ${pkgs.xorg.xinput}/bin/xinput set-prop 'eGalax Inc. USB TouchController' \ 'Coordinate Transformation Matrix' 0 -1.268 1.147 -1.224 0 1.118 0 0 1 fi ${pkgs.coreutils}/bin/sleep 1 done - echo "egalax-calibrate: eGalax device not found after 30s" >&2 + echo "egalax-calibrate: eGalax device not found after 120s" >&2 exit 1 ''; };