// SPDX-License-Identifier: GPL-3.0-only // SPDX-FileCopyrightText: Copyright (C) 2026 Catcrafts® // lint-disable-file fixed-width-types /* Fingerprintd:Sensor unit tests. Mostly one thing. gpio8-11 are the fingerprint SPI pads, they are XPU-protected, and touching one from the normal world is not an error return -- it is an immediate SError and the phone reboots where it stands. Mainline's DTS reserves the range but a userspace chardev request never consults that, so the guard is ours and it is worth a test that spells out every pin. */ import std; import Fingerprintd; using namespace fingerprintd::sensor; namespace { int Failures = 0; void Check(bool cond, std::string_view msg) { if (!cond) { std::println(std::cerr, "FAIL: {}", msg); ++Failures; } } } int main() { // ---- The XPU-protected range, pin by pin Check(IsReserved(8) && IsReserved(9) && IsReserved(10) && IsReserved(11), "gpio8-11 are all reserved"); Check(!IsReserved(7), "gpio7 is below the range"); Check(!IsReserved(12), "gpio12 is above it"); Check(ReservedSpiFirst == 8 && ReservedSpiCount == 4, "the range matches the DTS gpio-reserved-ranges = <8 4>"); for (unsigned l = 8; l <= 11; l++) Check(!IsSafeLine(l), std::format("gpio{} must never be opened", l)); // ---- Every line we own is outside it for (unsigned l : OwnedLines) Check(IsSafeLine(l), std::format("owned line gpio{} is safe", l)); Check(OwnedLines.size() == 3, "three lines: power, reset, irq"); // ---- The pins themselves, from the stock device tree Check(PowerLine == 29, "vdd-gpio = <&tlmm 29>"); Check(ResetLine == 74, "reset-gpio = <&tlmm 74>"); Check(IrqLine == 75, "irq-gpio = <&tlmm 75>"); Check(PowerLine != ResetLine && ResetLine != IrqLine && PowerLine != IrqLine, "the three are distinct"); // The vendor calls it FPS_INT_N but the DT says edge-rising: it idles low // and pulses high. Reading it as active-low sees the finger backwards. Check(IrqIsActiveHigh, "the interrupt is active high despite the _N"); // ---- The chip is found by label // // The chardev reports the DT unit address, not the binding's name. "tlmm" // is what every DT reference calls it and matching on that finds nothing. Check(ChipLabel == "f100000.pinctrl", "TLMM advertises its DT unit address"); Check(ChipLabel != "tlmm", "the binding name is not the chardev label"); Check(!ChipLabel.empty(), "never an index: /dev/gpiochipN is not stable"); // The line-count check has to actually exclude the other pinctrl on this // SoC, which has 23 lines, while admitting TLMM's 168. Check(MinChipLines > IrqLine, "a valid chip can contain every line we open"); Check(MinChipLines > 23, "excludes the 23-line 3440000.pinctrl"); Check(MinChipLines <= 168, "admits TLMM"); // ---- Sequencing Check(PowerSettle > ResetSettle, "the rail gets the longer settle"); Check(PowerSettle.count() == 250 && ResetSettle.count() == 50, "the proven delays"); Check(AssertResetBeforePower, "a warm restart starts from the cold state"); // ---- The reason the daemon owns the rail at all Check(RcDeviceNotFound == -205, "a second init in one power cycle answers -205, so recovery is a power cycle"); if (Failures == 0) std::println("Sensor: all tests passed"); return Failures; }