A built-in RGB+IR webcam (common on recent ThinkPads, e.g. the T14s AMD Gen 4) exposes its IR face-unlock sensor as a second, identically-named "Integrated Camera"; apps that pick it show a dark, 8-bit-greyscale image. nomarchy.hardware.camera.hideIrSensor disables that node on the V4L2 PipeWire path (WirePlumber monitor.v4l2.rules) so only the colour camera is offered, matched by card name (overridable irMatch). - libcamera is left untouched: an external camera you plug in is never affected, and surgical internal-only libcamera scoping isn't possible (its distinguishing props bind after the monitor rule runs). - Only the PipeWire node is hidden; the kernel /dev/video* stays open, so Howdy face-unlock still reads the IR sensor directly. - The installer's hardware-db.sh auto-detects a paired RGB+IR webcam from /sys/class/video4linux/*/name and bakes the toggle into system.nix; commented example added to the downstream template. Validated live on a T14s: collapses the four enumerated "Integrated Camera" entries to one colour source; the exact shipped regex disables the IR node (confirmed in the WirePlumber log) and leaves libcamera intact. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
267 lines
12 KiB
Bash
267 lines
12 KiB
Bash
# Nomarchy hardware database — sourced by nomarchy-install.
|
|
#
|
|
# Flat table mapping detected DMI fields to nixos-hardware module names
|
|
# (the strings nomarchy.lib.mkFlake's hardwareProfile accepts). Ported
|
|
# from the previous iteration (installer/hardware-db.sh at 3bdfc35).
|
|
#
|
|
# Format (pipe-separated):
|
|
# sys_vendor_regex | product_regex | nixos_hardware_module
|
|
#
|
|
# - Matching is bash `[[ =~ ]]` regex, case-insensitive.
|
|
# - First match wins — put more specific entries (e.g. exact model years)
|
|
# above broader fallbacks.
|
|
#
|
|
# To add a new device: grab `/sys/class/dmi/id/product_name` on the
|
|
# target machine and add a line. Module names must exist in
|
|
# nixos-hardware.nixosModules (mkFlake fails with suggestions if not).
|
|
|
|
HARDWARE_DB=(
|
|
# Framework ---------------------------------------------------------------
|
|
# Module names follow nixos-hardware's actual attrs — for Framework 13
|
|
# the per-generation modules dropped the "13-" prefix.
|
|
"Framework|Laptop 16.*AMD|framework-16-7040-amd"
|
|
"Framework|Laptop 16.*Ryzen AI 300|framework-16-amd-ai-300-series"
|
|
"Framework|Laptop 13.*Ryzen AI 300|framework-amd-ai-300-series"
|
|
"Framework|Laptop 13.*Ryzen 7040|framework-13-7040-amd"
|
|
"Framework|Laptop 13.*Core Ultra|framework-intel-core-ultra-series1"
|
|
"Framework|Laptop 13.*13th Gen Intel|framework-13th-gen-intel"
|
|
"Framework|Laptop 13.*12th Gen Intel|framework-12th-gen-intel"
|
|
"Framework|Laptop 13.*11th Gen Intel|framework-11th-gen-intel"
|
|
"Framework|Laptop \(13.*|framework"
|
|
|
|
# Dell XPS / Precision / Latitude ----------------------------------------
|
|
"Dell|XPS 15 9500|dell-xps-15-9500"
|
|
"Dell|XPS 15 9510|dell-xps-15-9510"
|
|
"Dell|XPS 15 9520|dell-xps-15-9520"
|
|
"Dell|XPS 13 9310|dell-xps-13-9310"
|
|
"Dell|XPS 13 9370|dell-xps-13-9370"
|
|
"Dell|XPS 13 9380|dell-xps-13-9380"
|
|
"Dell|XPS 13 7390|dell-xps-13-7390"
|
|
"Dell|Precision 5530|dell-precision-5530"
|
|
"Dell|Latitude 7490|dell-latitude-7490"
|
|
"Dell|Latitude 7430|dell-latitude-7430"
|
|
"Dell|Latitude 7420|dell-latitude-7420"
|
|
|
|
# Lenovo ThinkPad --------------------------------------------------------
|
|
# X1 Carbon: the per-gen modules are named "x1-Nth-gen", not
|
|
# "x1-carbon-genN" — the X1 series IS the Carbon line.
|
|
"LENOVO|ThinkPad X1 Carbon Gen 11|lenovo-thinkpad-x1-11th-gen"
|
|
"LENOVO|ThinkPad X1 Carbon Gen 10|lenovo-thinkpad-x1-10th-gen"
|
|
"LENOVO|ThinkPad X1 Carbon Gen 9|lenovo-thinkpad-x1-9th-gen"
|
|
"LENOVO|ThinkPad X1 Carbon Gen 7|lenovo-thinkpad-x1-7th-gen"
|
|
"LENOVO|ThinkPad X1 Carbon Gen 6|lenovo-thinkpad-x1-6th-gen"
|
|
"LENOVO|ThinkPad X1 Extreme|lenovo-thinkpad-x1-extreme"
|
|
"LENOVO|ThinkPad X1 Nano|lenovo-thinkpad-x1-nano-gen1"
|
|
"LENOVO|ThinkPad T14 Gen 3|lenovo-thinkpad-t14-amd-gen3"
|
|
"LENOVO|ThinkPad T14 Gen 2|lenovo-thinkpad-t14-amd-gen2"
|
|
"LENOVO|ThinkPad T14 Gen 1|lenovo-thinkpad-t14-amd-gen1"
|
|
"LENOVO|ThinkPad T480|lenovo-thinkpad-t480"
|
|
"LENOVO|ThinkPad L13|lenovo-thinkpad-l13"
|
|
"LENOVO|ThinkPad P14s.*Gen 5|lenovo-thinkpad-p14s-amd-gen5"
|
|
"LENOVO|ThinkPad P14s.*Gen 4|lenovo-thinkpad-p14s-amd-gen4"
|
|
"LENOVO|ThinkPad P14s.*Gen 3|lenovo-thinkpad-p14s-amd-gen3"
|
|
|
|
# Microsoft Surface ------------------------------------------------------
|
|
# nixos-hardware ships per-chip modules, not per-revision.
|
|
"Microsoft|Surface Pro 10|microsoft-surface-pro-intel"
|
|
"Microsoft|Surface Pro 9|microsoft-surface-pro-9"
|
|
"Microsoft|Surface Pro 8|microsoft-surface-pro-intel"
|
|
"Microsoft|Surface Pro 7|microsoft-surface-pro-intel"
|
|
"Microsoft|Surface Pro 6|microsoft-surface-pro-intel"
|
|
"Microsoft|Surface Pro 3|microsoft-surface-pro-3"
|
|
"Microsoft|Surface Laptop.*Ryzen|microsoft-surface-laptop-amd"
|
|
"Microsoft|Surface Go|microsoft-surface-go"
|
|
|
|
# ASUS ROG Ally / Zephyrus / Strix ---------------------------------------
|
|
"ASUS.*|RC71L|asus-ally-rc71l"
|
|
"ASUS.*|RC72LA|asus-ally-rc71l"
|
|
"ASUS.*|ROG Ally|asus-ally-rc71l"
|
|
"ASUS.*|ROG Zephyrus G14.*GA402X|asus-zephyrus-ga402x"
|
|
"ASUS.*|ROG Zephyrus G14.*GA402|asus-zephyrus-ga402"
|
|
"ASUS.*|ROG Zephyrus G14.*GA401|asus-zephyrus-ga401"
|
|
"ASUS.*|ROG Zephyrus G15|asus-zephyrus-ga503"
|
|
"ASUS.*|ROG Zephyrus.*GU603|asus-zephyrus-gu603h"
|
|
"ASUS.*|ROG Strix G513|asus-rog-strix-g513im"
|
|
"ASUS.*|ROG Strix G533|asus-rog-strix-g533zw"
|
|
|
|
# Apple (T2 Intel; M-series is aarch64 — out of scope) -------------------
|
|
"Apple.*|MacBookPro15|apple-t2"
|
|
"Apple.*|MacBookPro16|apple-t2"
|
|
"Apple.*|MacBookAir8|apple-t2"
|
|
"Apple.*|MacBookAir9|apple-t2"
|
|
"Apple.*|iMac19|apple-t2"
|
|
"Apple.*|iMacPro1|apple-t2"
|
|
|
|
# System76 ---------------------------------------------------------------
|
|
"System76|Oryx Pro.*|system76"
|
|
"System76|Lemur Pro.*|system76"
|
|
"System76|Darter Pro.*|system76"
|
|
"System76|Galago Pro.*|system76"
|
|
"System76|Pangolin.*|system76"
|
|
|
|
# Known-unsupported (so contributors know they're not missing):
|
|
# - Valve Steam Deck: Jovian-NixOS territory, not nixos-hardware.
|
|
# - Snapdragon X laptops / Raspberry Pi: aarch64; installer is x86_64.
|
|
)
|
|
|
|
# ----------------------------------------------------------------------------
|
|
# nomarchy_detect_hw — inspects DMI + lspci + /sys, emits one line per hit:
|
|
# MODULE <nixos-hardware module name>
|
|
# DETAIL <human-readable explanation>
|
|
# Returns 0 if at least one module was detected.
|
|
# ----------------------------------------------------------------------------
|
|
nomarchy_detect_hw() {
|
|
local sys_vendor product_name cpu_vendor
|
|
local nvidia=0 amdgpu=0 intelgpu=0
|
|
sys_vendor=$(cat /sys/class/dmi/id/sys_vendor 2>/dev/null || echo "")
|
|
product_name=$(cat /sys/class/dmi/id/product_name 2>/dev/null || echo "")
|
|
cpu_vendor=$(lscpu 2>/dev/null | awk -F: '/Vendor ID/{gsub(/ /,"",$2); print $2; exit}')
|
|
|
|
local detected=0
|
|
|
|
# CPU
|
|
case "$cpu_vendor" in
|
|
AuthenticAMD) echo "MODULE common-cpu-amd"; echo "DETAIL cpu: AMD"; detected=1 ;;
|
|
GenuineIntel) echo "MODULE common-cpu-intel"; echo "DETAIL cpu: Intel"; detected=1 ;;
|
|
esac
|
|
|
|
# GPU (lspci may list several; report all)
|
|
if command -v lspci >/dev/null 2>&1; then
|
|
local gpu_line
|
|
while IFS= read -r gpu_line; do
|
|
case "$gpu_line" in
|
|
*"[10de:"*|*"NVIDIA"*) nvidia=1 ;;
|
|
*"[1002:"*|*"AMD/ATI"*|*"Advanced Micro Devices"*) amdgpu=1 ;;
|
|
*"[8086:"*|*"Intel Corporation"*) intelgpu=1 ;;
|
|
esac
|
|
done < <(lspci -nn 2>/dev/null | grep -iE 'vga|3d|display')
|
|
|
|
(( nvidia )) && { echo "MODULE common-gpu-nvidia"; echo "DETAIL gpu: NVIDIA"; detected=1; }
|
|
(( amdgpu )) && { echo "MODULE common-gpu-amd"; echo "DETAIL gpu: AMD"; detected=1; }
|
|
(( intelgpu )) && { echo "MODULE common-gpu-intel"; echo "DETAIL gpu: Intel"; detected=1; }
|
|
fi
|
|
|
|
# ── nomarchy.hardware.* enablement — the gap ABOVE the nixos-hardware
|
|
# commons (GuC/HuC, amd-pstate, the AMD VA-API env, GPU-compute runtimes,
|
|
# fprintd, the NPU driver). Emitted as NOMARCHY lines the installer turns
|
|
# into nomarchy.hardware.* in system.nix; safe bits active, heavy opt-ins
|
|
# commented.
|
|
if [[ "$cpu_vendor" == "GenuineIntel" || $intelgpu -eq 1 ]]; then
|
|
echo "NOMARCHY hardware.intel.enable=true"
|
|
echo "DETAIL nomarchy.hardware.intel: GuC/HuC on; GPU-compute runtime opt-in"
|
|
# i915.enable_guc applies to the i915 driver only. The newer `xe` driver
|
|
# (Lunar Lake / Battlemage / Panther Lake, recent Xe GPUs) enables GuC by
|
|
# default and ignores the param — so turn the toggle off when xe is bound.
|
|
if lspci -k 2>/dev/null | grep -qiE 'driver in use: xe\b'; then
|
|
echo "NOMARCHY hardware.intel.guc=false"
|
|
echo "DETAIL Intel GPU on the xe driver → GuC default-on (i915 param skipped)"
|
|
fi
|
|
fi
|
|
if [[ "$cpu_vendor" == "AuthenticAMD" || $amdgpu -eq 1 ]]; then
|
|
echo "NOMARCHY hardware.amd.enable=true"
|
|
echo "DETAIL nomarchy.hardware.amd: amd-pstate + VA-API on; ROCm opt-in"
|
|
fi
|
|
|
|
# Fingerprint reader — libfprint's common USB vendor IDs (Goodix,
|
|
# Synaptics/Validity, Elan, EgisTec, Upek, AuthenTec, FocalTech, NB).
|
|
local have_fp=0
|
|
if command -v lsusb >/dev/null 2>&1; then
|
|
local vid
|
|
for vid in 27c6 06cb 138a 04f3 1c7a 147e 08ff 2808 1fae; do
|
|
lsusb 2>/dev/null | grep -qiE "ID ${vid}:" && { have_fp=1; break; }
|
|
done
|
|
else
|
|
local f
|
|
for f in /sys/bus/usb/devices/*/idVendor; do
|
|
[[ -e "$f" ]] || continue
|
|
case "$(cat "$f" 2>/dev/null)" in
|
|
27c6|06cb|138a|04f3|1c7a|147e|08ff|2808|1fae) have_fp=1; break ;;
|
|
esac
|
|
done
|
|
fi
|
|
if [[ $have_fp -eq 1 ]]; then
|
|
echo "NOMARCHY hardware.fingerprint.enable=true"
|
|
echo "DETAIL fingerprint reader detected → fprintd (PAM login/sudo opt-in)"
|
|
fi
|
|
|
|
# Dual-sensor webcam (RGB + IR face-unlock). Such modules expose the IR
|
|
# sensor as a SECOND, identically-named "Integrated Camera"; an app that
|
|
# picks it shows a dark, 8-bit-greyscale image. When an IR-companion node
|
|
# sits alongside a normal camera node, enable hiding the IR one from
|
|
# PipeWire (the colour camera stays; the kernel /dev/video* is untouched, so
|
|
# Howdy can still read the IR sensor directly). Read from /sys — no
|
|
# v4l2-ctl needed in the installer env.
|
|
local cam_name have_ir_cam=0 have_color_cam=0 vf
|
|
local ir_re='Integrated I|IR Camera|Infrared'
|
|
for vf in /sys/class/video4linux/video*/name; do
|
|
[[ -e "$vf" ]] || continue
|
|
cam_name=$(cat "$vf" 2>/dev/null)
|
|
shopt -s nocasematch
|
|
if [[ "$cam_name" =~ $ir_re ]]; then
|
|
have_ir_cam=1
|
|
elif [[ "$cam_name" =~ (Camera|Webcam) ]]; then
|
|
have_color_cam=1
|
|
fi
|
|
shopt -u nocasematch
|
|
done
|
|
if [[ $have_ir_cam -eq 1 && $have_color_cam -eq 1 ]]; then
|
|
echo "NOMARCHY hardware.camera.hideIrSensor=true"
|
|
echo "DETAIL dual-sensor webcam (RGB+IR) → hide the IR node so apps get the colour camera"
|
|
fi
|
|
|
|
# NPU (detect-only → a commented, experimental opt-in). Match the PCI
|
|
# "Processing accelerators" class [1200] (or accelerator keywords) and
|
|
# attribute by vendor — future-proof vs a per-device-ID list, so new gens
|
|
# (e.g. Panther Lake) are caught without a code change. Known IDs kept for
|
|
# reference: Intel VPU 8086:{7d1d,643e,ad1d,b03e}, AMD XDNA 1022:1502.
|
|
if command -v lspci >/dev/null 2>&1; then
|
|
local npu_line
|
|
npu_line=$(lspci -nn 2>/dev/null \
|
|
| grep -iE '\[1200\]|processing accelerat|neural|\[8086:(7d1d|643e|ad1d|b03e)\]|\[1022:1502\]' \
|
|
| head -1)
|
|
case "$npu_line" in
|
|
*"[8086:"*|*Intel*)
|
|
echo "NOMARCHY-NPU intel"; echo "DETAIL Intel NPU detected (opt-in, experimental)" ;;
|
|
*"[1022:"*|*"Advanced Micro Devices"*|*AMD*)
|
|
echo "NOMARCHY-NPU amd"; echo "DETAIL AMD XDNA NPU detected (opt-in, experimental)" ;;
|
|
esac
|
|
fi
|
|
|
|
# Chassis (glob test, not compgen — nixpkgs' non-interactive bash
|
|
# is built without the completion builtins)
|
|
local bats=(/sys/class/power_supply/BAT*)
|
|
if [[ -e "${bats[0]}" ]]; then
|
|
echo "MODULE common-pc-laptop"
|
|
echo "DETAIL chassis: laptop (battery present)"
|
|
else
|
|
echo "MODULE common-pc"
|
|
echo "DETAIL chassis: desktop"
|
|
fi
|
|
detected=1
|
|
|
|
# SSD
|
|
local rotational
|
|
rotational=$(cat /sys/block/nvme0n1/queue/rotational 2>/dev/null \
|
|
|| cat /sys/block/sda/queue/rotational 2>/dev/null || echo "")
|
|
if [[ "$rotational" == "0" ]]; then
|
|
echo "MODULE common-pc-ssd"
|
|
echo "DETAIL storage: SSD"
|
|
fi
|
|
|
|
# Model-specific match from the DB
|
|
local entry v_re p_re mod
|
|
for entry in "${HARDWARE_DB[@]}"; do
|
|
IFS='|' read -r v_re p_re mod <<< "$entry"
|
|
shopt -s nocasematch
|
|
if [[ "$sys_vendor" =~ $v_re ]] && [[ "$product_name" =~ $p_re ]]; then
|
|
shopt -u nocasematch
|
|
echo "MODULE $mod"
|
|
echo "DETAIL model: $sys_vendor $product_name → $mod"
|
|
break
|
|
fi
|
|
shopt -u nocasematch
|
|
done
|
|
|
|
return $(( 1 - detected ))
|
|
}
|