bitspire/deploy/nixos/hardware/upboard.nix
Padreug c83b40fe5e feat(deploy): enable pcscd on upboard (sintra/tejo) for NFC gate
The access gate (ADR-003, #86) only wired services.pcscd + the pcsc
polkit rule into batm3.nix, so the tap-to-enter reader was invisible on
upboard machines. Port the same device-agnostic wiring to upboard.nix
(HID Global OMNIKEY 5022, 076b:5022) so the gate works on the sintra dev
unit — and on tejo — when #86 lands on dev and the nightly upgrade pulls
it.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018ivBosaWmv8vwFE7ejrdHW
2026-09-19 10:34:45 +02:00

139 lines
5.2 KiB
Nix

# Tejo (UP Board / UP4000) Hardware Configuration
# Intel Atom/Celeron boards used in Lamassu Tejo ATM machines.
# Supports both UP Board and UP4000 variants — udev rules for both
# are included since they match different kernel paths and don't conflict.
#
# Serial port mapping:
# ttyJ4 = Printer (Nippon NP-2511D-2)
# ttyJ5 = Validator (iVizion, ID003 protocol)
# ttyJ7 = Dispenser (Fujitsu F53/F56)
{ config, lib, pkgs, ... }:
{
# Serial peripherals (validator/dispenser/printer modules + udev symlinks +
# console=tty0) are shared with the live ISO via ./upboard-serial.nix.
imports = [ ./upboard-serial.nix ];
boot = {
loader = {
systemd-boot.enable = true;
efi.canTouchEfiVariables = true;
timeout = 3;
};
initrd.availableKernelModules = [
"xhci_pci"
"ahci"
"usb_storage"
"sd_mod"
"sdhci_pci"
"sdhci-acpi" # UP Board sintra: eMMC controller is ACPI-enumerated, not PCI
"mmc_block" # creates /dev/mmcblk* block-device nodes
"i915"
];
# Force-load the eMMC stack in stage 1 so root-by-label resolves before
# the kernel hands off to switch_root. Without this, initramfs panics
# with "An error occurred in stage 1 of the boot process" because
# /dev/disk/by-label/nixos never materialises in time.
initrd.kernelModules = [
"sdhci-acpi"
"mmc_block"
];
kernelModules = [
"kvm-intel"
"i2c-dev"
"spi-dev"
# Serial modules (usbserial/ftdi_sio/cp210x) → ./upboard-serial.nix.
];
kernelParams = [
"i915.enable_psr=0"
# console=tty0 (keeps ttyS4 free for the F56) → ./upboard-serial.nix.
"quiet"
"splash"
];
};
# Disk layout: GPT with ESP + ext4 root (eMMC on UP Board).
# Labels match what make-disk-image.nix with partitionTableType="efi"
# produces — ESP for the FAT partition, nixos for the ext4 root. We
# previously expected `by-label/boot` here and had to manually
# `fatlabel` the partition post-flash; aligning the label avoids
# that hand-step on future re-flashes. (douro.nix already uses ESP.)
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";
};
# PC/SC daemon for the HID Global OMNIKEY 5022 contactless reader
# (076b:5022, a CCID smart-card reader) used for Bolt Card tap-to-enter
# (ADR-003). pcscd binds the CCID driver; the app talks to pcscd's socket
# (via nfc-pcsc) rather than the USB device directly. Device-agnostic —
# same wiring as batm3's Feitian KP382; harmless if no reader is attached,
# pcscd just idles. Shared by every upboard machine (sintra, tejo).
services.pcscd.enable = true;
# pcscd gates client access via polkit; without a rule the sandboxed
# `bitspire` service user is "Rejected unauthorized PC/SC client". Authorize
# it to talk to the daemon and the card.
security.polkit.extraConfig = ''
polkit.addRule(function(action, subject) {
if ((action.id == "org.debian.pcsc-lite.access_pcsc" ||
action.id == "org.debian.pcsc-lite.access_card") &&
subject.user == "bitspire") {
return polkit.Result.YES;
}
});
'';
# Disable suspend/hibernate for kiosk
systemd.targets = {
sleep.enable = false;
suspend.enable = false;
hibernate.enable = false;
hybrid-sleep.enable = false;
};
# Camera + LED/SPI peripherals. The serial rules (validator/dispenser/printer
# symlinks + permissions) are shared with the live ISO in ./upboard-serial.nix.
services.udev.extraRules = lib.mkAfter ''
# ── Camera devices ─────────────────────────────────────────────────
SUBSYSTEM=="video4linux", ATTR{index}=="0", KERNELS=="1-5", ATTRS{idVendor}=="0ac8", ATTRS{idProduct}=="0345", SYMLINK+="video-scan"
SUBSYSTEM=="video4linux", ATTR{index}=="0", KERNELS=="1-2", ATTRS{idVendor}=="0ac8", ATTRS{idProduct}=="0345", SYMLINK+="video-scan"
SUBSYSTEM=="video4linux", ATTR{index}=="0", KERNELS=="1-6", ATTRS{idVendor}=="0ac8", ATTRS{idProduct}=="0345", SYMLINK+="video-front"
SUBSYSTEM=="video4linux", ATTR{index}=="0", KERNELS=="1-3", ATTRS{idVendor}=="0ac8", ATTRS{idProduct}=="0345", SYMLINK+="video-front"
# ── LED SPI / peripherals ──────────────────────────────────────────
KERNEL=="spidev1.0", SYMLINK+="ledspi"
KERNEL=="spidev2.0", SYMLINK+="ledspi"
SUBSYSTEM=="spidev", GROUP="spi", MODE="0660"
SUBSYSTEM=="i2c-dev", GROUP="i2c", MODE="0660"
SUBSYSTEM=="leds", KERNEL=="upboard:*", ACTION=="add|change", RUN+="${pkgs.findutils}/bin/find /sys$devpath -type f -exec ${pkgs.coreutils}/bin/chmod g+u {} + -exec ${pkgs.coreutils}/bin/chown :leds {} +"
'';
}