`networking.wireguard.interfaces.wg0.ips` was set in hardware/douro.nix and hardware/batm3.nix, but hardware/upboard.nix is shared by tejo and sintra — an address there would be claimed by both machines on the same /24, so neither got one. tejo therefore evaluated to `wg0.ips = [ ]`: the interface comes up with no IP and the tunnel is silently dead. On a machine with no other route in, that is how you lose a box. Replace the two per-hardware definitions with one `wireguardIpForModel` table in flake.nix, keyed on model like fiatCodeForModel / upgradeWindowForModel / nfcReaderForModel, and give tejo 10.0.0.3/24 — the address it answers on today under its factory Debian. douro (10.0.0.4/24) and batm3 (10.0.0.5/24) evaluate unchanged; sintra stays deliberately unlisted, since it is reachable on the LAN and has never had a tunnel address. The address is only half of it: the VPS maps peer pubkey to tunnel IP, so the machine still needs /var/lib/wireguard/wg0.key carried over from its previous install (or a fresh key added to the VPS peer list). Both wireguard units are ConditionPathExists-guarded on that key, so a keyless first boot is clean and the tunnel starts once it is dropped in. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
227 lines
9.2 KiB
Nix
227 lines
9.2 KiB
Nix
# BATM3 Hardware Configuration
|
|
# Dell OptiPlex 9030 AIO, Intel i7-4790S, Intel HD 4600
|
|
# Board replacement for GeneralBytes BATM3 (ARM Android → x86 NixOS)
|
|
|
|
{ config, lib, pkgs, ... }:
|
|
|
|
{
|
|
boot = {
|
|
loader = {
|
|
systemd-boot.enable = true;
|
|
efi.canTouchEfiVariables = true;
|
|
timeout = 3;
|
|
};
|
|
|
|
# Pin the 6.6 LTS kernel. The Dell 9030 AIO's eGalax SAW touch panel
|
|
# (0eef:0001) works with the usbtouchscreen driver on 6.6 (the known-good
|
|
# internal-SATA install runs 6.6.68). On 25.11's default 6.12 kernel this
|
|
# old controller regressed: hid-multitouch grabs it and mis-parses the HID
|
|
# report ("failed to fetch feature 7", axes read stuck), usbtouchscreen
|
|
# refuses it, and touch is unusable regardless of udev/X config. Matching
|
|
# douro.nix's per-hardware kernel pin. Re-test touch before bumping this.
|
|
kernelPackages = pkgs.linuxPackages_6_6;
|
|
|
|
initrd.availableKernelModules = [
|
|
"xhci_pci"
|
|
"ahci"
|
|
"usbhid"
|
|
"sd_mod"
|
|
# USB mass-storage: required to boot the dd'd image from a USB stick
|
|
# (stage-1 must bind the flash drive as a SCSI disk so
|
|
# /dev/disk/by-label/nixos appears). Harmless on the internal-SATA
|
|
# install, where ahci+sd_mod already cover the root device.
|
|
#
|
|
# NOTE: deliberately NO "uas" here. Many USB sticks/bridges advertise
|
|
# UAS but drop off the bus ("device offline error, dev sdb") under the
|
|
# sustained write load of first-boot growPartition/journal/swapfile.
|
|
# Blacklisting uas below forces the slower-but-reliable usb-storage
|
|
# (Bulk-Only Transport) path. SATA/eMMC installs don't use uas anyway.
|
|
"usb_storage"
|
|
];
|
|
|
|
# Keep the USB flash drive off the flaky UAS driver (see note above).
|
|
blacklistedKernelModules = [ "uas" ];
|
|
|
|
kernelModules = [
|
|
"kvm-intel"
|
|
"usbtouchscreen"
|
|
];
|
|
|
|
kernelParams = [
|
|
"quiet"
|
|
"splash"
|
|
# Disable USB autosuspend so the boot medium (and kiosk peripherals)
|
|
# aren't power-suspended mid-I/O — another cause of "device offline".
|
|
"usbcore.autosuspend=-1"
|
|
];
|
|
};
|
|
|
|
# Disk layout: GPT with ESP (sda1) + ext4 root (sda2)
|
|
fileSystems."/" = {
|
|
device = "/dev/disk/by-label/nixos";
|
|
fsType = "ext4";
|
|
};
|
|
|
|
fileSystems."/boot" = {
|
|
device = "/dev/disk/by-label/ESP";
|
|
fsType = "vfat";
|
|
};
|
|
|
|
hardware = {
|
|
graphics = {
|
|
enable = true;
|
|
extraPackages = with pkgs; [
|
|
intel-media-driver
|
|
libva-vdpau-driver
|
|
libvdpau-va-gl
|
|
];
|
|
};
|
|
enableRedistributableFirmware = true;
|
|
cpu.intel.updateMicrocode = true;
|
|
};
|
|
|
|
powerManagement = {
|
|
enable = true;
|
|
cpuFreqGovernor = "performance";
|
|
};
|
|
|
|
# The Feitian KP382 contactless reader (096e:0608) is declared as a machine
|
|
# capability, not here: `nfcReaderForModel` in flake.nix drives
|
|
# services.bitspire.nfc.enable, which owns pcscd, the polkit rules and the
|
|
# wedge-recovery unit (deploy/nixos/bitspire-atm.nix).
|
|
|
|
# Disable suspend/hibernate for kiosk
|
|
systemd.targets = {
|
|
sleep.enable = false;
|
|
suspend.enable = false;
|
|
hibernate.enable = false;
|
|
hybrid-sleep.enable = false;
|
|
};
|
|
|
|
# WiFi: read credentials from /var/lib/bitspire/wifi.conf (not in repo)
|
|
# Format: SSID=MyNetwork\nPSK=MyPassword
|
|
system.activationScripts.wifi-setup = ''
|
|
WIFI_CONF="/var/lib/bitspire/wifi.conf"
|
|
if [ -f "$WIFI_CONF" ]; then
|
|
SSID=$(grep '^SSID=' "$WIFI_CONF" | cut -d= -f2-)
|
|
PSK=$(grep '^PSK=' "$WIFI_CONF" | cut -d= -f2-)
|
|
if [ -n "$SSID" ] && [ -n "$PSK" ]; then
|
|
CONN_FILE="/etc/NetworkManager/system-connections/$SSID.nmconnection"
|
|
if [ ! -f "$CONN_FILE" ]; then
|
|
cat > "$CONN_FILE" << EOF
|
|
[connection]
|
|
id=$SSID
|
|
type=wifi
|
|
autoconnect=true
|
|
|
|
[wifi]
|
|
mode=infrastructure
|
|
ssid=$SSID
|
|
|
|
[wifi-security]
|
|
key-mgmt=wpa-psk
|
|
psk=$PSK
|
|
|
|
[ipv4]
|
|
method=auto
|
|
|
|
[ipv6]
|
|
method=auto
|
|
EOF
|
|
chmod 600 "$CONN_FILE"
|
|
echo "[WiFi] Created connection for $SSID"
|
|
fi
|
|
fi
|
|
fi
|
|
'';
|
|
|
|
# eGalax touchscreen (Dell 9030 AIO built-in panel)
|
|
# By default usbhid/hid-multitouch claim the eGalax and mis-parse its
|
|
# HID report descriptor (X axis reads as stuck), so touch is unusable.
|
|
# Fix: hand the device to the usbtouchscreen kernel driver, which parses
|
|
# the raw eGalax protocol into a clean single-touch ABS device that the
|
|
# X evdev driver + calibration matrix (below) map correctly. This mirrors
|
|
# the known-good internal-SATA install.
|
|
#
|
|
# The RUN command modprobes usbtouchscreen ITSELF before unbinding usbhid
|
|
# and handing over via new_id. usbtouchscreen is also in boot.kernelModules
|
|
# (systemd-modules-load), but on a USB boot systemd-udev-trigger fires this
|
|
# rule (~2s) BEFORE modules-load gets usbtouchscreen in (~12s) — so the
|
|
# new_id write hit a not-yet-loaded driver and the panel was left bound to
|
|
# nothing. Loading it inline here makes the handoff independent of that
|
|
# boot-ordering race (on internal-SATA boot the order happened to work).
|
|
services.udev.extraRules = lib.mkAfter ''
|
|
KERNEL=="ttyS[0-9]*", MODE="0666"
|
|
KERNEL=="ttyUSB[0-9]*", MODE="0666"
|
|
KERNEL=="ttyACM[0-9]*", MODE="0666"
|
|
SUBSYSTEM=="tty", ATTRS{serial}=="DDDLb103Y23", SYMLINK+="ttyF56", MODE="0666"
|
|
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
|
|
# node is a plain single-touch absolute device; evdev + the transformation
|
|
# matrix in egalax-calibrate below give correct orientation. Mirrors the
|
|
# working internal-SATA install's /etc/X11/xorg.conf.d/99-egalax.conf.
|
|
environment.etc."X11/xorg.conf.d/99-egalax.conf".text = ''
|
|
Section "InputClass"
|
|
Identifier "eGalax Touchscreen"
|
|
MatchVendor "0eef"
|
|
MatchProduct "0001"
|
|
MatchDevicePath "/dev/input/event*"
|
|
Driver "evdev"
|
|
Option "InvertY" "false"
|
|
Option "InvertX" "false"
|
|
Option "SwapAxes" "false"
|
|
Option "Calibration" ""
|
|
EndSection
|
|
'';
|
|
|
|
# Apply touchscreen calibration after X11 starts
|
|
# Matrix: swap X/Y axes, invert both, scale to active panel area (238-1853 x 197-1869)
|
|
systemd.services.egalax-calibrate = {
|
|
description = "Calibrate eGalax touchscreen";
|
|
after = [ "display-manager.service" ];
|
|
requires = [ "display-manager.service" ];
|
|
wantedBy = [ "graphical.target" ];
|
|
serviceConfig = {
|
|
Type = "oneshot";
|
|
RemainAfterExit = true;
|
|
User = "bitspire";
|
|
# DISPLAY *and* XAUTHORITY — without the auth cookie xinput dies with
|
|
# "Invalid MIT-MAGIC-COOKIE-1 key / Unable to connect to X server" and
|
|
# the matrix is never applied, so touches register but land in the wrong
|
|
# place (the panel then feels dead). This was the actual boot-time bug.
|
|
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. 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 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 120s" >&2
|
|
exit 1
|
|
'';
|
|
};
|
|
};
|
|
|
|
# WireGuard VPN address → wireguardIpForModel in flake.nix.
|
|
}
|