* Add NCT6687DR fan control support with bit mapping and configuration phase handling
* NCT6687DR: emulate CC_Engine SetManualFAN protocol
- System fans (index > 8): skip manual mode bit (0xA00), use flat SmartFAN curve instead
- Change commit value from 0x40 to 0xC0 (REQ|DONE) matching CC_Engine
- Write 7-point temp curve (all 0x20/32C) alongside duty curve for system fans
- Add Sleep(10ms) after request (0x80) and commit (0xC0) per CC_Engine timing
- Restore: only clear manual mode bit for CPU/Pump/Chipset/EZ-Connect fans
* NCT6687DR: add INVALID bit check with retry after EC commit
- FinishFanCfgUpdate now returns bool: false if EC sets INVALID (0xCF8 & 0x10)
- SetControl and RestoreDefaultFanControl retry up to 3 times on INVALID
- Matches CC_Engine's post-commit validation behavior
* fix(NCT6687DR): bypass SmartFAN engine for system fans — use direct PWM
System fans (SYSFAN1-7) now use the same direct PWM mechanism as
CPU/Pump/Chipset fans, completely bypassing the SmartFAN curve engine
and its inherent ~2%/sec PWM smoothing.
Key changes:
- FAN_PWM_COMMAND_REG: system fans now point to direct PWM registers
(SYSFAN7: 08:E9, SYSFAN1-6: 02:65..02:60) instead of SmartFAN
curve base addresses (0xBE0..0xC70)
- FAN_CONTROL_MODE_REG: system fans use 08:0F (not 0xA00) for their
manual-mode enable bits
- FAN_CONTROL_MODE_BIT: corrected per-channel bit positions derived
from BIOS unk_104C0 table (sub_2F50 / sub_2BDC analysis)
- Set6687DRControl: simplified to single WriteByte for all fans
(no more 7-point flat curve + step/rate writes)
- SetControl: unified path — all fans set manual-mode bit + direct PWM
- RestoreDefaultFanControl: clear manual-mode bit to return to SmartFAN
Register mapping discovered via IDA analysis of BIOS firmware:
- Extended unk_101E0 table at 0x103AC contains channels 10-15
- sub_2BDC configures 5 register operations per channel before curve write
- Entry[1] in unk_104C0 = manual-mode enable register + bit position
* review: Stopwatch, engineSts rename, CompleteFanConfigUpdate
* refactor: PreciseWait via SpinWait, DateTime to Stopwatch in ReadByte/WriteByte
* review: remove regions, revert PreciseWait to Thread.Sleep