-
Notifications
You must be signed in to change notification settings - Fork 0
Hardware Interface
All sysfs path knowledge lives in one module (src/smc.rs); nothing outside
it contains a path string (grep-gated). Two backends implement the frozen
Smc trait: SysfsSmc (real) and MockSmc (scriptable faults for tests).
Sysfs root: /sys/devices/platform/applesmc.768/ — fan files sit directly
there, not under hwmon.
| File | SMC key | Meaning | Access |
|---|---|---|---|
fan1_label |
— |
Exhaust (single-fan scope) |
RO |
fan1_input |
F0Ac |
Actual rpm (tachometer), read-only | RO |
fan1_output |
F0Tg |
Target (command register), read-write | RW |
fan1_manual |
bit 0 of FS!
|
0 = firmware curve, 1 = our command |
RW |
fan1_min / fan1_max
|
F0Mn / F0Mx
|
Hardware range: 1200 / 7200 rpm | RO |
fan1_safe |
— | Present, reads empty, semantics unknown — ignored (Q3) | RO |
Sensors: coretemp → dynamic hwmon index (hwmon4 on the verified machine):
Package id 0, Core 0, Core 1; temp*_crit (Tjmax) = 100 °C. The
applesmc hwmon dir (hwmon3) exists but is an attribute-less husk —
upstream applesmc is mid-conversion to standard hwmon attrs. applesmc also
exposes 33 raw SMC temp keys (temp1..33, labels like TA0V, TB0T) — out of
scope for control; coretemp is the trusted set.
Measured dynamics (2026-09-14, calibrates the code and the mocks): the SMC
adopts a written target within ≤ 1 s on a ~1 s internal tick; a full swing
takes ~5 s (6688 → 2664 → 1632 → … → 2001 rpm); steady-state jitter ±20 rpm
(worst sampled second-to-second delta 26 rpm). fan1_output mirrors the SMC's
own target while in AUTO, so a write is always preceded by a verified
manual-mode write.
Fan discovery: devices/platform/applesmc.768 → if fan1_input exists there,
use it (classic layout); else walk hwmon/ subdirs (sorted) and use the first
one containing fan1_input (post-conversion layout).
Coretemp discovery: walk /sys/devices/platform/coretemp.0/hwmon/hwmon*/,
scan tempN_input files (N parsed as u32, sorted), read optional
tempN_label (fallback tempN), in discovery order. No hardcoded hwmonN
anywhere (Q5).
Every state-changing write (fan1_output, fan1_manual) is followed by a
read-back of the attribute just written, within tolerance; logical state
(last_written, manual_armed) commits only on verified read-back; failed
verification re-issues within a settle window, then surfaces VerifyFailed
upward (which triggers fail-toward-AUTO).
-
RULING F16:
fan1_outputecho is the verification source (toleranceWRITE_ECHO_TOLERANCE_RPM = 50);fan1_inputis the tachometer and is never a write-verification source — a fan still spinning down is not a failed write. -
RULING F19 settle windows: the echo is verified inside
ECHO_SETTLE_MS = 1500(sampled 10 × 150 ms;MODE_SETTLE_MS = 1000forset_mode, exact 0/1 match) because the SMC adoptsF0Tgasynchronously on a ~1 s tick. One write per window, no microsecond retries; at mostWRITE_RETRY_MAX = 1re-issue after a dead window, thenVerifyFailed. - All rpm writes clamped to [
fan1_min,fan1_max] read from hardware at discovery;hw_min > hw_maxat open isInvalidValue. - Sensor readings
< 0 °Cor> 120 °C(also empty/unparseable) are rejected as failed reads (outlier rejection). -
--sysfs-root <dir>redirects all sysfs access (the entire test suite runs against fixtures this way).
SysfsSmc pre-opens O_WRONLY on fan1_manual at discovery and exposes it
via Smc::panic_fd() -> Option<i32> (None for MockSmc and for read-only
trees, with a debug log). safety::install_death_path(fd) consumes it.
src/notify.rs: sd_ready() (READY=1), sd_watchdog() (WATCHDOG=1),
sd_status(msg) (STATUS=…) via unix datagram to $NOTIFY_SOCKET
(filesystem or @-abstract path, newline-terminated). Unset socket → no-op
false; send failures → false, never a panic.
ReadWritePaths pins today's platform path, and doctor detects a layout
change (fan attrs appearing under the hwmon husk → "conversion in flight")
and tells the user to update the unit. A kernel bump changing layout = a
one-module fix, detected by doctor (Q4).
- Home
- Installation
- CLI Reference
- Configuration
- Control Policy
- Supervisor and Run Modes
- Safety Model
- Hardware Interface
- Diagnostics (doctor)
- Plugin Surface (omafan)
- JSON Schemas
- systemd and Packaging
- Development and Testing
- Architecture and Internals
- Troubleshooting and FAQ
- Background and Verification
- afanctl-vs-mbpfan