Created
June 19, 2026 06:55
-
-
Save Anexgohan/9dc8ad67da8e7570db95d9da218b0def to your computer and use it in GitHub Desktop.
PWM write test for Pankha fan-control
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #!/usr/bin/env bash | |
| # | |
| set -u | |
| HW="${1:-}" | |
| N="${2:-}" | |
| TARGET_PWM="${TARGET_PWM:-200}" | |
| WATCH_SECS="${WATCH_SECS:-30}" | |
| # --- Fan selection ------------------------------------------------------- | |
| # Both args supplied -> use directly. Otherwise list PWM-capable fans and let | |
| # the user pick one (requires an interactive terminal). | |
| if [ -z "$HW" ] || [ -z "$N" ]; then | |
| if [ ! -t 0 ]; then | |
| echo "No fan specified and not running interactively." >&2 | |
| echo "Usage: sudo $0 <hwmon_path> <fan_number>" >&2 | |
| exit 1 | |
| fi | |
| echo "=== Available PWM-capable fans ===" | |
| echo "Pick a CHASSIS fan (rpm>0, writable=yes). Avoid the CPU cooler or an AIO pump header." | |
| echo | |
| declare -a SEL_HW SEL_N | |
| idx=0 | |
| for h in /sys/class/hwmon/hwmon*; do | |
| [ -e "$h" ] || continue | |
| name=$(cat "$h/name" 2>/dev/null) | |
| for f in "$h"/fan[0-9]*_input; do | |
| [ -e "$f" ] || continue | |
| n=$(basename "$f" | sed 's/fan//; s/_input//') | |
| pp="$h/pwm${n}" | |
| [ -e "$pp" ] || continue | |
| idx=$((idx + 1)) | |
| SEL_HW[$idx]="$h" | |
| SEL_N[$idx]="$n" | |
| printf ' [%2d] %-10s %s fan%s rpm=%-6s pwm=%-4s enable=%-3s writable=%s\n' \ | |
| "$idx" "$name" "$h" "$n" \ | |
| "$(cat "$f" 2>/dev/null)" \ | |
| "$(cat "$pp" 2>/dev/null)" \ | |
| "$(cat "$h/pwm${n}_enable" 2>/dev/null || echo -)" \ | |
| "$( [ -w "$pp" ] && echo yes || echo no )" | |
| done | |
| done | |
| if [ "$idx" -eq 0 ]; then | |
| echo "No PWM-capable fans found under /sys/class/hwmon." >&2 | |
| echo "Is the it87 (or relevant Super I/O) driver loaded? See pankha-fan-diag.sh." >&2 | |
| exit 1 | |
| fi | |
| echo | |
| read -rp "Select fan number [1-$idx] (or q to quit): " choice | |
| case "$choice" in | |
| q|Q) echo "Aborted."; exit 0 ;; | |
| ''|*[!0-9]*) echo "Invalid selection." >&2; exit 1 ;; | |
| esac | |
| if [ "$choice" -lt 1 ] || [ "$choice" -gt "$idx" ]; then | |
| echo "Selection out of range." >&2 | |
| exit 1 | |
| fi | |
| HW="${SEL_HW[$choice]}" | |
| N="${SEL_N[$choice]}" | |
| echo | |
| fi | |
| PWM="$HW/pwm$N" | |
| EN="$HW/pwm${N}_enable" | |
| RPM="$HW/fan${N}_input" | |
| if [ ! -w "$PWM" ]; then | |
| echo "ERROR: cannot write $PWM (run as root? wrong path/fan number?)" >&2 | |
| exit 1 | |
| fi | |
| # Final confirmation when interactive. | |
| if [ -t 0 ]; then | |
| echo "Selected : $(cat "$HW/name" 2>/dev/null) fan$N ($PWM)" | |
| echo "This will raise it to pwm=$TARGET_PWM for ${WATCH_SECS}s, then restore the original value." | |
| read -rp "Proceed? [y/N]: " ok | |
| case "$ok" in | |
| y|Y|yes|YES) ;; | |
| *) echo "Aborted."; exit 0 ;; | |
| esac | |
| echo | |
| fi | |
| orig_pwm="$(cat "$PWM")" | |
| orig_en="$(cat "$EN" 2>/dev/null || echo n/a)" | |
| echo "Chip : $(cat "$HW/name" 2>/dev/null) ($HW)" | |
| echo "BASELINE : pwm=$orig_pwm enable=$orig_en rpm=$(cat "$RPM" 2>/dev/null)" | |
| restore() { | |
| [ "$orig_en" != "n/a" ] && echo "$orig_en" > "$EN" 2>/dev/null | |
| echo "$orig_pwm" > "$PWM" 2>/dev/null | |
| echo "RESTORED : pwm=$(cat "$PWM" 2>/dev/null) enable=$(cat "$EN" 2>/dev/null) rpm=$(cat "$RPM" 2>/dev/null)" | |
| } | |
| trap restore EXIT | |
| # Enable manual PWM mode. | |
| echo 1 > "$EN" 2>/dev/null | |
| echo "After enable=1, reads back: $(cat "$EN" 2>/dev/null) (if this is not 1, the chip refused manual mode)" | |
| echo "Writing pwm=$TARGET_PWM and watching ${WATCH_SECS}s:" | |
| echo "$TARGET_PWM" > "$PWM" | |
| for i in $(seq 0 "$WATCH_SECS"); do | |
| printf ' t=%2ss pwm=%-3s enable=%-2s rpm=%s\n' \ | |
| "$i" "$(cat "$PWM" 2>/dev/null)" "$(cat "$EN" 2>/dev/null)" "$(cat "$RPM" 2>/dev/null)" | |
| sleep 1 | |
| done | |
| echo "Watch complete. Interpretation:" | |
| echo " - pwm stayed $TARGET_PWM and rpm rose/held -> writes HOLD (control works)" | |
| echo " - pwm/rpm dropped back on their own -> BIOS/SMM re-assert (timed override)" | |
| echo " - enable would not stay 1, or rpm flat -> driver won't enter manual mode" | |
| echo "Trap now restores original values." |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment