Add sensors for ASUS Crosshair VIII Hero (#453)

Thanks to @zeule!
This commit is contained in:
Eugene Shalygin
2021-06-01 11:06:42 +02:00
committed by GitHub
parent 993dadd4dd
commit 37e917a4f8
20 changed files with 741 additions and 127 deletions
@@ -18,7 +18,8 @@ namespace LibreHardwareMonitor.Hardware
GpuAmd,
Storage,
Network,
Cooler
Cooler,
EmbeddedController
}
public interface IHardware : IElement
@@ -12,6 +12,7 @@ namespace LibreHardwareMonitor.Hardware
public enum SensorType
{
Voltage, // V
Current, // A
Clock, // MHz
Temperature, // °C
Load, // %
@@ -141,6 +141,8 @@ namespace LibreHardwareMonitor.Hardware.Motherboard
return Model.P55_Deluxe;
case var _ when name.Equals("Crosshair III Formula", StringComparison.OrdinalIgnoreCase):
return Model.CROSSHAIR_III_FORMULA;
case var _ when name.Equals("ROG CROSSHAIR VIII HERO", StringComparison.OrdinalIgnoreCase):
return Model.ROG_CROSSHAIR_VIII_HERO;
case var _ when name.Equals("M2N-SLI DELUXE", StringComparison.OrdinalIgnoreCase):
return Model.M2N_SLI_Deluxe;
case var _ when name.Equals("M4A79XTD EVO", StringComparison.OrdinalIgnoreCase):
@@ -0,0 +1,136 @@
// This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
// If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
// Copyright (C) LibreHardwareMonitor and Contributors.
// All Rights Reserved.
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Text;
namespace LibreHardwareMonitor.Hardware.Motherboard.Lpc.EC
{
public abstract class EmbeddedController : Hardware
{
private readonly List<EmbeddedControllerSensor> _sensors;
protected EmbeddedController(List<EmbeddedControllerSource> sources, ISettings settings) : base("Embedded Controller", new Identifier("lpc", "ec"), settings)
{
var indices = new Dictionary<SensorType, int>();
foreach (SensorType t in Enum.GetValues(typeof(SensorType)))
{
indices.Add(t, 0);
}
_sensors = new List<EmbeddedControllerSensor>();
foreach (EmbeddedControllerSource s in sources)
{
int index = indices[s.Type];
indices[s.Type] = index + 1;
_sensors.Add(new EmbeddedControllerSensor(s, index, this, settings));
ActivateSensor(_sensors[_sensors.Count - 1]);
}
}
public override HardwareType HardwareType => HardwareType.EmbeddedController;
public static EmbeddedController Create(List<EmbeddedControllerSource> sources, ISettings settings)
{
return Environment.OSVersion.Platform switch
{
PlatformID.Win32NT => new WindowsEmbeddedController(sources, settings),
_ => null
};
}
public override void Update()
{
try
{
using IEmbeddedControllerIO embeddedControllerIO = AcquireIOInterface();
foreach (EmbeddedControllerSensor sensor in _sensors)
{
sensor.Update(embeddedControllerIO);
}
}
catch (WindowsEmbeddedControllerIO.BusMutexLockingFailedException)
{
// just skip this update cycle?
}
}
public override string GetReport()
{
StringBuilder r = new();
r.AppendLine("EC " + GetType().Name);
r.AppendLine("Embedded Controller Registers");
r.AppendLine();
r.AppendLine(" 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F");
r.AppendLine();
try
{
using IEmbeddedControllerIO embeddedControllerIO = AcquireIOInterface();
for (int i = 0; i <= 0xF; ++i)
{
r.Append(" ");
r.Append((i << 4).ToString("X2", CultureInfo.InvariantCulture));
r.Append(" ");
for (int j = 0; j <= 0xF; ++j)
{
byte address = (byte)(i << 4 | j);
r.Append(" ");
r.Append(embeddedControllerIO.ReadByte(address).ToString("X2", CultureInfo.InvariantCulture));
}
r.AppendLine();
}
}
catch (WindowsEmbeddedControllerIO.BusMutexLockingFailedException e)
{
r.AppendLine(e.Message);
}
return r.ToString();
}
public static float ReadByte(IEmbeddedControllerIO ecIO, byte port)
{
return ecIO.ReadByte(port);
}
public static float ReadWordLE(IEmbeddedControllerIO ecIO, byte port)
{
return ecIO.ReadWordLE(port);
}
public static float ReadWordBE(IEmbeddedControllerIO ecIO, byte port)
{
return ecIO.ReadWordBE(port);
}
protected abstract IEmbeddedControllerIO AcquireIOInterface();
private class EmbeddedControllerSensor : Sensor
{
readonly byte _port;
readonly EmbeddedControllerReader _reader;
public EmbeddedControllerSensor(EmbeddedControllerSource embeddedControllerSource, int index, EmbeddedController hardware, ISettings settings)
: base(embeddedControllerSource.Name, index, embeddedControllerSource.Type, hardware, settings)
{
_port = embeddedControllerSource.Port;
_reader = embeddedControllerSource.Reader;
}
public void Update(IEmbeddedControllerIO ecIO)
{
Value = _reader(ecIO, _port);
}
}
}
}
@@ -0,0 +1,9 @@
// This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
// If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
// Copyright (C) LibreHardwareMonitor and Contributors.
// All Rights Reserved.
namespace LibreHardwareMonitor.Hardware.Motherboard.Lpc.EC
{
public delegate float EmbeddedControllerReader(IEmbeddedControllerIO ecIO, byte port);
}
@@ -0,0 +1,26 @@
// This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
// If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
// Copyright (C) LibreHardwareMonitor and Contributors.
// All Rights Reserved.
namespace LibreHardwareMonitor.Hardware.Motherboard.Lpc.EC
{
public class EmbeddedControllerSource
{
public EmbeddedControllerSource(string name, byte port, SensorType type, EmbeddedControllerReader reader)
{
Name = name;
Port = port;
Type = type;
Reader = reader;
}
public string Name { get; }
public byte Port { get; }
public EmbeddedControllerReader Reader { get; }
public SensorType Type { get; }
}
}
@@ -0,0 +1,22 @@
// This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
// If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
// Copyright (C) LibreHardwareMonitor and Contributors.
// All Rights Reserved.
using System;
namespace LibreHardwareMonitor.Hardware.Motherboard.Lpc.EC
{
public interface IEmbeddedControllerIO : IDisposable
{
void WriteByte(byte register, byte value);
void WriteWord(byte register, ushort value);
byte ReadByte(byte register);
ushort ReadWordBE(byte register);
ushort ReadWordLE(byte register);
}
}
@@ -0,0 +1,20 @@
// This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
// If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
// Copyright (C) LibreHardwareMonitor and Contributors.
// All Rights Reserved.
using System.Collections.Generic;
namespace LibreHardwareMonitor.Hardware.Motherboard.Lpc.EC
{
public class WindowsEmbeddedController : EmbeddedController
{
public WindowsEmbeddedController(List<EmbeddedControllerSource> sources, ISettings settings) : base(sources, settings)
{ }
protected override IEmbeddedControllerIO AcquireIOInterface()
{
return new WindowsEmbeddedControllerIO();
}
}
}
@@ -0,0 +1,284 @@
// This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
// If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
// Copyright (C) LibreHardwareMonitor and Contributors.
// All Rights Reserved.
using System;
using System.Threading;
namespace LibreHardwareMonitor.Hardware.Motherboard.Lpc.EC
{
/// <summary>
/// An unsafe but universal implementation for the ACPI Embedded Controller IO interface for Windows
/// </summary>
/// <remarks>
/// It is unsafe because of possible race condition between this application and the PC firmware when
/// writing to the EC registers. For a safe approach ACPI/WMI methods have to be used, but those are
/// different for each motherboard model.
/// </remarks>
public class WindowsEmbeddedControllerIO : IEmbeddedControllerIO
{
private const int FailuresBeforeSkip = 20;
private const int MaxRetries = 5;
// implementation
private const int WaitSpins = 50;
private bool _disposedValue;
private int _waitReadFailures;
public WindowsEmbeddedControllerIO()
{
if (!Ring0.WaitIsaBusMutex(10))
{
throw new BusMutexLockingFailedException();
}
_disposedValue = false;
}
~WindowsEmbeddedControllerIO()
{
Dispose(false);
}
public byte ReadByte(byte register)
{
return ReadLoop<byte>(register, ReadByteOp);
}
public ushort ReadWordLE(byte register)
{
return ReadLoop<ushort>(register, ReadWordLEOp);
}
public ushort ReadWordBE(byte register)
{
return ReadLoop<ushort>(register, ReadWordBEOp);
}
public void WriteByte(byte register, byte value)
{
WriteLoop(register, value, WriteByteOp);
}
public void WriteWord(byte register, ushort value)
{
WriteLoop(register, value, WriteWordOp);
}
protected virtual void Dispose(bool disposing)
{
if (!_disposedValue)
{
Ring0.ReleaseIsaBusMutex();
_disposedValue = true;
}
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
private TResult ReadLoop<TResult>(byte register, ReadOp<TResult> op) where TResult : new()
{
TResult result = new();
for (int i = 0; i < MaxRetries; i++)
{
if (op(register, out result))
{
return result;
}
}
return result;
}
private void WriteLoop<TValue>(byte register, TValue value, WriteOp<TValue> op)
{
for (int i = 0; i < MaxRetries; i++)
{
if (op(register, value))
{
return;
}
}
}
private bool WaitForStatus(Status status, bool isSet)
{
for (int i = 0; i < WaitSpins; i++)
{
byte value = ReadIOPort(Port.Command);
if (((byte)status & (!isSet ? value : (byte)~value)) == 0)
{
return true;
}
Thread.Sleep(1);
}
return false;
}
private bool WaitRead()
{
if (_waitReadFailures > FailuresBeforeSkip)
{
return true;
}
if (WaitForStatus(Status.OutputBufferFull, true))
{
_waitReadFailures = 0;
return true;
}
_waitReadFailures++;
return false;
}
private bool WaitWrite()
{
return WaitForStatus(Status.InputBufferFull, false);
}
private byte ReadIOPort(Port port)
{
return Ring0.ReadIoPort((uint)port);
}
private void WriteIOPort(Port port, byte datum)
{
Ring0.WriteIoPort((uint)port, datum);
}
public class BusMutexLockingFailedException : ApplicationException
{
public BusMutexLockingFailedException()
: base("Could not lock ISA bus mutex")
{ }
}
private delegate bool ReadOp<TParam>(byte register, out TParam p);
private delegate bool WriteOp<in TParam>(byte register, TParam p);
// see the ACPI specification chapter 12
private enum Port : byte
{
Command = 0x66,
Data = 0x62
}
private enum Command : byte
{
Read = 0x80, // RD_EC
Write = 0x81, // WR_EC
BurstEnable = 0x82, // BE_EC
BurstDisable = 0x83, // BD_EC
Query = 0x84 // QR_EC
}
private enum Status : byte
{
OutputBufferFull = 0x01, // EC_OBF
InputBufferFull = 0x02, // EC_IBF
Command = 0x08, // CMD
BurstMode = 0x10, // BURST
SciEventPending = 0x20, // SCI_EVT
SmiEventPending = 0x40 // SMI_EVT
}
#region Read/Write ops
protected bool ReadByteOp(byte register, out byte value)
{
if (WaitWrite())
{
WriteIOPort(Port.Command, (byte)Command.Read);
if (WaitWrite())
{
WriteIOPort(Port.Data, register);
if (WaitWrite() && WaitRead())
{
value = ReadIOPort(Port.Data);
return true;
}
}
}
value = 0;
return false;
}
protected bool WriteByteOp(byte register, byte value)
{
if (WaitWrite())
{
WriteIOPort(Port.Command, (byte)Command.Write);
if (WaitWrite())
{
WriteIOPort(Port.Data, register);
if (WaitWrite())
{
WriteIOPort(Port.Data, value);
return true;
}
}
}
return false;
}
protected bool ReadWordLEOp(byte register, out ushort value)
{
return ReadWordOp(register, (byte)(register + 1), out value);
}
protected bool ReadWordBEOp(byte register, out ushort value)
{
return ReadWordOp((byte)(register + 1), register, out value);
}
protected bool ReadWordOp(byte registerLsb, byte registerMsb, out ushort value)
{
value = 0;
if (!ReadByteOp(registerLsb, out byte result))
{
return false;
}
value = result;
if (!ReadByteOp(registerMsb, out result))
{
return false;
}
value |= (ushort)(result << 8);
return true;
}
protected bool WriteWordOp(byte register, ushort value)
{
//Byte order: little endia
byte msb = (byte)(value >> 8);
byte lsb = (byte)value;
return WriteByteOp(register, lsb) && WriteByteOp((byte)(register + 1), msb);
}
#endregion
}
}
@@ -5,6 +5,7 @@
// All Rights Reserved.
using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Globalization;
using System.Text;
@@ -14,7 +15,25 @@ namespace LibreHardwareMonitor.Hardware.Motherboard.Lpc
{
internal class Nct677X : ISuperIO
{
private readonly ushort?[] _alternateTemperatureRegister;
private readonly struct TemperatureSourceData
{
public TemperatureSourceData(Enum? source, ushort register, ushort halfRegister = 0, int halfBit = -1, ushort sourceRegister = 0, ushort? alternateRegister = null)
{
Source = source;
Register = register;
HalfRegister = halfRegister;
HalfBit = halfBit;
SourceRegister = sourceRegister;
AlternateRegister = alternateRegister;
}
public readonly Enum? Source;
public readonly ushort Register;
public readonly ushort HalfRegister;
public readonly int HalfBit;
public readonly ushort SourceRegister;
public readonly ushort? AlternateRegister;
};
private readonly ushort[] _fanCountRegister;
private readonly ushort[] _fanRpmRegister;
private readonly byte[] _initialFanControlMode = new byte[7];
@@ -27,11 +46,7 @@ namespace LibreHardwareMonitor.Hardware.Motherboard.Lpc
private readonly ushort _port;
private readonly bool[] _restoreDefaultFanControlRequired = new bool[7];
private readonly byte _revision;
private readonly int[] _temperatureHalfBit;
private readonly ushort[] _temperatureHalfRegister;
private readonly ushort[] _temperatureRegister;
private readonly ushort[] _temperatureSourceRegister;
private readonly Enum[] _temperaturesSource;
private readonly TemperatureSourceData[] _temperaturesSource;
private readonly ushort _vBatMonitorControlRegister;
private readonly ushort[] _voltageRegisters;
private readonly ushort _voltageVBatRegister;
@@ -94,8 +109,6 @@ namespace LibreHardwareMonitor.Hardware.Motherboard.Lpc
// min value RPM value with 16-bit fan counter
_minFanRpm = (int)(1.35e6 / 0xFFFF);
_temperaturesSource = new Enum[] { SourceNct6771F.PECI_0, SourceNct6771F.CPUTIN, SourceNct6771F.AUXTIN, SourceNct6771F.SYSTIN };
}
else
{
@@ -103,8 +116,6 @@ namespace LibreHardwareMonitor.Hardware.Motherboard.Lpc
// min value RPM value with 13-bit fan counter
_minFanRpm = (int)(1.35e6 / 0x1FFF);
_temperaturesSource = new Enum[] { SourceNct6776F.PECI_0, SourceNct6776F.CPUTIN, SourceNct6776F.AUXTIN, SourceNct6776F.SYSTIN };
}
_fanRpmRegister = new ushort[5];
@@ -116,14 +127,20 @@ namespace LibreHardwareMonitor.Hardware.Motherboard.Lpc
Voltages = new float?[9];
_voltageRegisters = new ushort[] { 0x020, 0x021, 0x022, 0x023, 0x024, 0x025, 0x026, 0x550, 0x551 };
_voltageVBatRegister = 0x551;
_temperaturesSource = new TemperatureSourceData[]
{
new TemperatureSourceData(chip == Chip.NCT6771F ? SourceNct6771F.PECI_0 : SourceNct6776F.PECI_0, 0x027, 0, -1, 0x621),
new TemperatureSourceData(chip == Chip.NCT6771F ? SourceNct6771F.CPUTIN : SourceNct6776F.CPUTIN, 0x073, 0x074, 7, 0x100),
new TemperatureSourceData(chip == Chip.NCT6771F ? SourceNct6771F.AUXTIN : SourceNct6776F.AUXTIN, 0x075, 0x076, 7, 0x200),
new TemperatureSourceData(chip == Chip.NCT6771F ? SourceNct6771F.SYSTIN : SourceNct6776F.SYSTIN, 0x077, 0x078, 7, 0x300),
new TemperatureSourceData(null, 0x150, 0x151, 7, 0x622),
new TemperatureSourceData(null, 0x250, 0x251, 7, 0x623),
new TemperatureSourceData(null, 0x62B, 0x62E, 0, 0x624),
new TemperatureSourceData(null, 0x62C, 0x62E, 1, 0x625),
new TemperatureSourceData(null, 0x62D, 0x62E, 2, 0x626)
};
Temperatures = new float?[4];
_temperatureRegister = new ushort[] { 0x027, 0x073, 0x075, 0x077, 0x150, 0x250, 0x62B, 0x62C, 0x62D };
_temperatureHalfRegister = new ushort[] { 0, 0x074, 0x076, 0x078, 0x151, 0x251, 0x62E, 0x62E, 0x62E };
_temperatureHalfBit = new[] { -1, 7, 7, 7, 7, 7, 0, 1, 2 };
_temperatureSourceRegister = new ushort[] { 0x621, 0x100, 0x200, 0x300, 0x622, 0x623, 0x624, 0x625, 0x626 };
_alternateTemperatureRegister = new ushort?[] { null, null, null, null };
break;
}
case Chip.NCT6779D:
@@ -172,6 +189,7 @@ namespace LibreHardwareMonitor.Hardware.Motherboard.Lpc
Voltages = new float?[15];
_voltageRegisters = new ushort[] { 0x480, 0x481, 0x482, 0x483, 0x484, 0x485, 0x486, 0x487, 0x488, 0x489, 0x48A, 0x48B, 0x48C, 0x48D, 0x48E };
_voltageVBatRegister = 0x488;
var temperaturesSources = new List<TemperatureSourceData>();
switch (chip)
{
case Chip.NCT6796D:
@@ -179,79 +197,61 @@ namespace LibreHardwareMonitor.Hardware.Motherboard.Lpc
case Chip.NCT6797D:
case Chip.NCT6798D:
{
Temperatures = new float?[24];
_temperaturesSource = new Enum[]
temperaturesSources.AddRange(new TemperatureSourceData[]
{
SourceNct67Xxd.PECI_0,
SourceNct67Xxd.CPUTIN,
SourceNct67Xxd.SYSTIN,
SourceNct67Xxd.AUXTIN0,
SourceNct67Xxd.AUXTIN1,
SourceNct67Xxd.AUXTIN2,
SourceNct67Xxd.AUXTIN3,
SourceNct67Xxd.AUXTIN4,
SourceNct67Xxd.SMBUSMASTER0,
SourceNct67Xxd.SMBUSMASTER1,
SourceNct67Xxd.PECI_1,
SourceNct67Xxd.PCH_CHIP_CPU_MAX_TEMP,
SourceNct67Xxd.PCH_CHIP_TEMP,
SourceNct67Xxd.PCH_CPU_TEMP,
SourceNct67Xxd.PCH_MCH_TEMP,
SourceNct67Xxd.AGENT0_DIMM0,
SourceNct67Xxd.AGENT0_DIMM1,
SourceNct67Xxd.AGENT1_DIMM0,
SourceNct67Xxd.AGENT1_DIMM1,
SourceNct67Xxd.BYTE_TEMP0,
SourceNct67Xxd.BYTE_TEMP1,
SourceNct67Xxd.PECI_0_CAL,
SourceNct67Xxd.PECI_1_CAL,
SourceNct67Xxd.VIRTUAL_TEMP
};
new TemperatureSourceData(SourceNct67Xxd.PECI_0, 0x073, 0x074, 7, 0x100),
new TemperatureSourceData(SourceNct67Xxd.CPUTIN, 0x075, 0x076, 7, 0x200, 0x491),
new TemperatureSourceData(SourceNct67Xxd.SYSTIN, 0x077, 0x078, 7, 0x300, 0x490),
new TemperatureSourceData(SourceNct67Xxd.AUXTIN0, 0x079, 0x07A, 7, 0x800, 0x492),
new TemperatureSourceData(SourceNct67Xxd.AUXTIN1, 0x07B, 0x07C, 7, 0x900, 0x493),
new TemperatureSourceData(SourceNct67Xxd.AUXTIN2, 0x07D, 0x07E, 7, 0xA00, 0x494),
new TemperatureSourceData(SourceNct67Xxd.AUXTIN3, 0x4A0, 0x49E, 6, 0xB00, 0x495),
new TemperatureSourceData(SourceNct67Xxd.AUXTIN4, 0x027,0, 7, 0x621),
new TemperatureSourceData(SourceNct67Xxd.SMBUSMASTER0, 0x150, 0x151, -1, 0x622),
new TemperatureSourceData(SourceNct67Xxd.SMBUSMASTER1, 0x670, 0, -1, 0xC26),
new TemperatureSourceData(SourceNct67Xxd.PECI_1, 0x672, 0, -1, 0xC27),
new TemperatureSourceData(SourceNct67Xxd.PCH_CHIP_CPU_MAX_TEMP, 0x674, 0, -1, 0xC28, 0x400),
new TemperatureSourceData(SourceNct67Xxd.PCH_CHIP_TEMP, 0x676, 0, -1, 0xC29, 0x401),
new TemperatureSourceData(SourceNct67Xxd.PCH_CPU_TEMP, 0x678, 0, -1, 0xC2A, 0x402),
new TemperatureSourceData(SourceNct67Xxd.PCH_MCH_TEMP, 0x67A, 0, -1, 0xC2B, 0x404),
new TemperatureSourceData(SourceNct67Xxd.AGENT0_DIMM0, 0),
new TemperatureSourceData(SourceNct67Xxd.AGENT0_DIMM1, 0),
new TemperatureSourceData(SourceNct67Xxd.AGENT1_DIMM0, 0),
new TemperatureSourceData(SourceNct67Xxd.AGENT1_DIMM1, 0),
new TemperatureSourceData(SourceNct67Xxd.BYTE_TEMP0, 0),
new TemperatureSourceData(SourceNct67Xxd.BYTE_TEMP1, 0),
new TemperatureSourceData(SourceNct67Xxd.PECI_0_CAL, 0),
new TemperatureSourceData(SourceNct67Xxd.PECI_1_CAL, 0),
new TemperatureSourceData(SourceNct67Xxd.VIRTUAL_TEMP, 0)
});
_temperatureRegister = new ushort[]
if (chip == Chip.NCT6798D)
{
0x073, 0x075, 0x077, 0x079, 0x07B, 0x07D, 0x4A0, 0x027, 0x150, 0x670, 0x672, 0x674, 0x676, 0x678, 0x67A
};
_temperatureHalfRegister = new ushort[]
{
0x074, 0x076, 0x078, 0x07A, 0x07C, 0x07E, 0x49E, 0, 0x151, 0, 0, 0, 0, 0, 0
};
_temperatureHalfBit = new[]
{
7, 7, 7, 7, 7, 7, 6, -1, 7, -1, -1, -1, -1, -1, -1
};
_temperatureSourceRegister = new ushort[]
{
0x100, 0x200, 0x300, 0x800, 0x900, 0xA00, 0xB00, 0x621, 0x622, 0xC26, 0xC27, 0xC28, 0xC29, 0xC2A, 0xC2B
};
_alternateTemperatureRegister = new ushort?[]
{
null, 0x491, 0x490, 0x492, 0x493, 0x494, 0x495, null, null, null, null, 0x400, 0x401, 0x402, 0x404, null, null, null, null, null, null, null, null, null
};
temperaturesSources.AddRange(new TemperatureSourceData[]
{
new TemperatureSourceData(SourceNct67Xxd.WATER_IN, 0xC33),
new TemperatureSourceData(SourceNct67Xxd.WATER_OUT, 0xC39)
});
}
break;
}
default:
{
Temperatures = new float?[7];
_temperaturesSource = new Enum[]
temperaturesSources.AddRange(new TemperatureSourceData[]
{
SourceNct67Xxd.PECI_0,
SourceNct67Xxd.CPUTIN,
SourceNct67Xxd.SYSTIN,
SourceNct67Xxd.AUXTIN0,
SourceNct67Xxd.AUXTIN1,
SourceNct67Xxd.AUXTIN2,
SourceNct67Xxd.AUXTIN3
};
_temperatureRegister = new ushort[] { 0x027, 0x073, 0x075, 0x077, 0x079, 0x07B, 0x150 };
_temperatureHalfRegister = new ushort[] { 0, 0x074, 0x076, 0x078, 0x07A, 0x07C, 0x151 };
_temperatureHalfBit = new[] { -1, 7, 7, 7, 7, 7, 7 };
_temperatureSourceRegister = new ushort[] { 0x621, 0x100, 0x200, 0x300, 0x800, 0x900, 0x622 };
_alternateTemperatureRegister = new ushort?[] { null, 0x491, 0x490, 0x492, 0x493, 0x494, 0x495 };
new TemperatureSourceData(SourceNct67Xxd.PECI_0, 0x027, 0, -1, 0x621),
new TemperatureSourceData(SourceNct67Xxd.CPUTIN, 0x073, 0x074, 7, 0x100, 0x491),
new TemperatureSourceData(SourceNct67Xxd.SYSTIN, 0x075, 0x076, 7, 0x200, 0x490),
new TemperatureSourceData(SourceNct67Xxd.AUXTIN0, 0x077, 0x078, 7, 0x300, 0x492),
new TemperatureSourceData(SourceNct67Xxd.AUXTIN1, 0x079, 0x07A, 7, 0x800, 0x493),
new TemperatureSourceData(SourceNct67Xxd.AUXTIN2, 0x07B, 0x07C, 7, 0x900, 0x494),
new TemperatureSourceData(SourceNct67Xxd.AUXTIN3, 0x150, 0x151, 7, 0x622, 0x495)
});
break;
}
}
_temperaturesSource = temperaturesSources.ToArray();
Temperatures = new float?[_temperaturesSource.Length];
break;
}
case Chip.NCT610XD:
@@ -270,14 +270,12 @@ namespace LibreHardwareMonitor.Hardware.Motherboard.Lpc
_voltageRegisters = new ushort[] { 0x300, 0x301, 0x302, 0x303, 0x304, 0x305, 0x307, 0x308, 0x309 };
_voltageVBatRegister = 0x308;
Temperatures = new float?[4];
_temperaturesSource = new Enum[] { SourceNct610X.PECI_0, SourceNct610X.SYSTIN, SourceNct610X.CPUTIN, SourceNct610X.AUXTIN };
_temperatureRegister = new ushort[] { 0x027, 0x018, 0x019, 0x01A };
_temperatureHalfRegister = new ushort[] { 0, 0x01B, 0x11B, 0x21B };
_temperatureHalfBit = new[] { -1, 7, 7, 7 };
_temperatureSourceRegister = new ushort[] { 0x621, 0x100, 0x200, 0x300 };
_alternateTemperatureRegister = new ushort?[] { null, 0x018, 0x019, 0x01A };
_temperaturesSource = new TemperatureSourceData[] {
new TemperatureSourceData(SourceNct610X.PECI_0, 0x027, 0, -1, 0x621),
new TemperatureSourceData(SourceNct610X.SYSTIN, 0x018, 0x01B, 7, 0x100, 0x018),
new TemperatureSourceData(SourceNct610X.CPUTIN, 0x019, 0x11B, 7, 0x200, 0x019),
new TemperatureSourceData(SourceNct610X.AUXTIN, 0x01A, 0x21B, 7, 0x300, 0x01A)
};
break;
}
case Chip.NCT6683D:
@@ -295,7 +293,15 @@ namespace LibreHardwareMonitor.Hardware.Motherboard.Lpc
// CPU Socket
// PCIE_1
// M2_1
_temperatureRegister = new ushort[] { 0x100, 0x102, 0x104, 0x106, 0x108, 0x10A, 0x10C };
_temperaturesSource = new TemperatureSourceData[] {
new TemperatureSourceData(null, 0x100),
new TemperatureSourceData(null, 0x102),
new TemperatureSourceData(null, 0x104),
new TemperatureSourceData(null, 0x106),
new TemperatureSourceData(null, 0x108),
new TemperatureSourceData(null, 0x10A),
new TemperatureSourceData(null, 0x10C),
};
// VIN0 +12V
// VIN1 +5V
@@ -342,8 +348,6 @@ namespace LibreHardwareMonitor.Hardware.Motherboard.Lpc
WriteByte(0x1BE, 0x64);
WriteByte(0x1BF, 0x65);
_alternateTemperatureRegister = new ushort?[] { };
break;
}
}
@@ -469,15 +473,16 @@ namespace LibreHardwareMonitor.Hardware.Motherboard.Lpc
System.Diagnostics.Debug.WriteLine("Updating temperatures.");
long temperatureSourceMask = 0;
for (int i = 0; i < _temperatureRegister.Length ; i++)
for (int i = 0; i < _temperaturesSource.Length ; i++)
{
TemperatureSourceData ts = _temperaturesSource[i];
switch (Chip)
{
case Chip.NCT6687D:
case Chip.NCT6683D:
{
int value = (sbyte)ReadByte(_temperatureRegister[i]);
int half = (ReadByte((ushort)(_temperatureRegister[i] + 1)) >> 7) & 0x1;
int value = (sbyte)ReadByte(ts.Register);
int half = (ReadByte((ushort)(ts.Register + 1)) >> 7) & 0x1;
float temperature = value + (0.5f * half);
Temperatures[i] = temperature;
break;
@@ -487,29 +492,29 @@ namespace LibreHardwareMonitor.Hardware.Motherboard.Lpc
case Chip.NCT6797D:
case Chip.NCT6798D:
{
if (_temperatureRegister[i] == 0)
if (_temperaturesSource[i].Register == 0)
{
System.Diagnostics.Debug.WriteLine("Temperature register {0} skipped, address 0.", i);
continue;
}
int value = (sbyte)ReadByte(_temperatureRegister[i]) << 1;
System.Diagnostics.Debug.WriteLine("Temperature register {0} at 0x{1:X3} value (integer): {2}/2", i, _temperatureRegister[i], value);
if (_temperatureHalfBit[i] > 0)
int value = (sbyte)ReadByte(_temperaturesSource[i].Register) << 1;
System.Diagnostics.Debug.WriteLine("Temperature register {0} at 0x{1:X3} value (integer): {2}/2", i, ts.Register, value);
if (_temperaturesSource[i].HalfBit > 0)
{
value |= (ReadByte(_temperatureHalfRegister[i]) >> _temperatureHalfBit[i]) & 0x1;
System.Diagnostics.Debug.WriteLine("Temperature register {0} value updated from 0x{1:X3} (fractional): {2}/2", i, _temperatureHalfRegister[i], value);
value |= (ReadByte(_temperaturesSource[i].HalfRegister) >> ts.HalfBit) & 0x1;
System.Diagnostics.Debug.WriteLine("Temperature register {0} value updated from 0x{1:X3} (fractional): {2}/2", i, ts.HalfRegister, value);
}
SourceNct67Xxd source;
if (_temperatureSourceRegister[i] > 0)
if (ts.SourceRegister > 0)
{
source = (SourceNct67Xxd)(ReadByte(_temperatureSourceRegister[i]) & 0x1F);
System.Diagnostics.Debug.WriteLine("Temperature register {0} source at 0x{1:X3}: {2:G} ({2:D})", i, _temperatureSourceRegister[i], source);
source = (SourceNct67Xxd)(ReadByte(ts.SourceRegister) & 0x1F);
System.Diagnostics.Debug.WriteLine("Temperature register {0} source at 0x{1:X3}: {2:G} ({2:D})", i, ts.SourceRegister, source);
}
else
{
source = (SourceNct67Xxd)_temperaturesSource[i];
source = (SourceNct67Xxd)ts.Source;
System.Diagnostics.Debug.WriteLine("Temperature register {0} source register is 0, source set to: {1:G} ({1:D})", i, source);
}
@@ -534,23 +539,23 @@ namespace LibreHardwareMonitor.Hardware.Motherboard.Lpc
for (int j = 0; j < Temperatures.Length; j++)
{
if ((SourceNct67Xxd)_temperaturesSource[j] == source)
if ((SourceNct67Xxd)_temperaturesSource[j].Source == source)
{
Temperatures[j] = temperature;
System.Diagnostics.Debug.WriteLine("Temperature register {0}, value from source {1:G} ({1:D}), written at position {2}.", i, _temperaturesSource[j], j);
System.Diagnostics.Debug.WriteLine("Temperature register {0}, value from source {1:G} ({1:D}), written at position {2}.", i, _temperaturesSource[j].Source, j);
}
}
break;
}
default:
{
int value = (sbyte)ReadByte(_temperatureRegister[i]) << 1;
if (_temperatureHalfBit[i] > 0)
int value = (sbyte)ReadByte(ts.Register) << 1;
if (ts.HalfBit > 0)
{
value |= (ReadByte(_temperatureHalfRegister[i]) >> _temperatureHalfBit[i]) & 0x1;
value |= (ReadByte(ts.HalfRegister) >> ts.HalfBit) & 0x1;
}
SourceNct67Xxd source = (SourceNct67Xxd)ReadByte(_temperatureSourceRegister[i]);
SourceNct67Xxd source = (SourceNct67Xxd)ReadByte(ts.SourceRegister);
temperatureSourceMask |= 1L << (byte)source;
float? temperature = 0.5f * value;
@@ -559,7 +564,7 @@ namespace LibreHardwareMonitor.Hardware.Motherboard.Lpc
for (int j = 0; j < Temperatures.Length; j++)
{
if ((SourceNct67Xxd)_temperaturesSource[j] == source)
if ((SourceNct67Xxd)_temperaturesSource[j].Source == source)
Temperatures[j] = temperature;
}
break;
@@ -567,28 +572,29 @@ namespace LibreHardwareMonitor.Hardware.Motherboard.Lpc
}
}
for (int i = 0; i < _alternateTemperatureRegister.Length; i++)
for (int i = 0; i < _temperaturesSource.Length; i++)
{
if (!_alternateTemperatureRegister[i].HasValue)
TemperatureSourceData ts = _temperaturesSource[i];
if (!ts.AlternateRegister.HasValue)
{
System.Diagnostics.Debug.WriteLine("Alternate temperature register for temperature {0}, {1:G} ({1:D}), skipped, because address is null.", i, _temperaturesSource[i]);
System.Diagnostics.Debug.WriteLine("Alternate temperature register for temperature {0}, {1:G} ({1:D}), skipped, because address is null.", i, ts.Source);
continue;
}
if ((temperatureSourceMask & (1L << (byte)(SourceNct67Xxd)_temperaturesSource[i])) > 0)
if ((temperatureSourceMask & (1L << (byte)(SourceNct67Xxd)ts.Source)) > 0)
{
System.Diagnostics.Debug.WriteLine("Alternate temperature register for temperature {0}, {1:G} ({1:D}), at 0x{2:X3} skipped, because value already set.", i, _temperaturesSource[i], _alternateTemperatureRegister[i].Value);
System.Diagnostics.Debug.WriteLine("Alternate temperature register for temperature {0}, {1:G} ({1:D}), at 0x{2:X3} skipped, because value already set.", i, ts.Source, ts.AlternateRegister.Value);
continue;
}
float? temperature = (sbyte)ReadByte(_alternateTemperatureRegister[i].Value);
System.Diagnostics.Debug.WriteLine("Alternate temperature register for temperature {0}, {1:G} ({1:D}), at 0x{2:X3} final temperature: {3}.", i, _temperaturesSource[i], _alternateTemperatureRegister[i].Value, temperature);
float? temperature = (sbyte)ReadByte(ts.AlternateRegister.Value);
System.Diagnostics.Debug.WriteLine("Alternate temperature register for temperature {0}, {1:G} ({1:D}), at 0x{2:X3} final temperature: {3}.", i, ts.Source, ts.AlternateRegister.Value, temperature);
if (temperature > 125 || temperature <= 0)
{
temperature = null;
System.Diagnostics.Debug.WriteLine("Alternate Temperature register for temperature {0}, {1:G} ({1:D}), discarded: Out of range.", i, _temperaturesSource[i]);
System.Diagnostics.Debug.WriteLine("Alternate Temperature register for temperature {0}, {1:G} ({1:D}), discarded: Out of range.", i, ts.Source);
}
Temperatures[i] = temperature;
@@ -984,7 +990,9 @@ namespace LibreHardwareMonitor.Hardware.Motherboard.Lpc
BYTE_TEMP1 = 27,
PECI_0_CAL = 28,
PECI_1_CAL = 29,
VIRTUAL_TEMP = 31
VIRTUAL_TEMP = 31,
WATER_IN = 32,
WATER_OUT = 33
}
[SuppressMessage("ReSharper", "InconsistentNaming")]
@@ -37,6 +37,7 @@ namespace LibreHardwareMonitor.Hardware.Motherboard
// ASUS
CROSSHAIR_III_FORMULA,
ROG_CROSSHAIR_VIII_HERO,
ROG_STRIX_X470_I,
M2N_SLI_Deluxe,
M4A79XTD_EVO,
@@ -8,6 +8,8 @@ using System;
using System.Collections.Generic;
using System.Text;
using LibreHardwareMonitor.Hardware.Motherboard.Lpc;
using LibreHardwareMonitor.Hardware.Motherboard.Lpc.EC;
using OperatingSystem = LibreHardwareMonitor.Software.OperatingSystem;
namespace LibreHardwareMonitor.Hardware.Motherboard
{
@@ -49,7 +51,7 @@ namespace LibreHardwareMonitor.Hardware.Motherboard
_customName = settings.GetValue(new Identifier(Identifier, "name").ToString(), _name);
if (Software.OperatingSystem.IsUnix)
if (OperatingSystem.IsUnix)
{
_lmSensors = new LMSensors();
superIO = _lmSensors.SuperIO;
@@ -60,11 +62,22 @@ namespace LibreHardwareMonitor.Hardware.Motherboard
superIO = _lpcIO.SuperIO;
}
SubHardware = new IHardware[superIO.Count];
EmbeddedController embeddedController = CreateEmbeddedController(model, settings);
SubHardware = new IHardware[superIO.Count + (embeddedController != null ? 1 : 0)];
for (int i = 0; i < superIO.Count; i++)
SubHardware[i] = new SuperIOHardware(this, superIO[i], manufacturer, model, settings);
if (embeddedController != null)
{
SubHardware[superIO.Count] = embeddedController;
}
}
public event SensorEventHandler SensorAdded;
public event SensorEventHandler SensorRemoved;
public HardwareType HardwareType
{
get { return HardwareType.Motherboard; }
@@ -72,7 +85,7 @@ namespace LibreHardwareMonitor.Hardware.Motherboard
public Identifier Identifier
{
get { return new Identifier("motherboard"); }
get { return new("motherboard"); }
}
public string Name
@@ -105,7 +118,7 @@ namespace LibreHardwareMonitor.Hardware.Motherboard
public string GetReport()
{
StringBuilder r = new StringBuilder();
StringBuilder r = new();
r.AppendLine("Motherboard");
r.AppendLine();
@@ -135,10 +148,6 @@ namespace LibreHardwareMonitor.Hardware.Motherboard
hardware.Accept(visitor);
}
public event SensorEventHandler SensorAdded;
public event SensorEventHandler SensorRemoved;
public void Close()
{
_lmSensors?.Close();
@@ -148,5 +157,34 @@ namespace LibreHardwareMonitor.Hardware.Motherboard
hardware.Close();
}
}
private static EmbeddedController CreateEmbeddedController(Model model, ISettings settings)
{
var sources = new List<EmbeddedControllerSource>();
switch (model)
{
case Model.ROG_CROSSHAIR_VIII_HERO:
{
sources.AddRange(new EmbeddedControllerSource[]
{
new("Chipset", 0x3A, SensorType.Temperature, EmbeddedController.ReadByte),
new("CPU", 0x3B, SensorType.Temperature, EmbeddedController.ReadByte),
new("Motherboard", 0x3C, SensorType.Temperature, EmbeddedController.ReadByte),
new("T Sensor", 0x3D, SensorType.Temperature, EmbeddedController.ReadByte),
new("VRM", 0x3E, SensorType.Temperature, EmbeddedController.ReadByte),
new("CPU Opt", 0xB0, SensorType.Fan, EmbeddedController.ReadWordBE),
new("Chipset", 0xB4, SensorType.Fan, EmbeddedController.ReadWordBE),
// TODO: "why 42?" is a silly question, I know, but still, why? On the serious side, it might be 41.6(6)
new("Flow Rate", 0xBC, SensorType.Flow, (ecIO, port) => ecIO.ReadWordBE(port) / 42f * 60f),
new("CPU", 0xF4, SensorType.Current, EmbeddedController.ReadByte)
});
break;
}
}
return sources.Count > 0 ? EmbeddedController.Create(sources, settings) : null;
}
}
}
@@ -2313,6 +2313,58 @@ namespace LibreHardwareMonitor.Hardware.Motherboard
break;
}
case Model.ROG_CROSSHAIR_VIII_HERO: // NCT6798D
{
v.Add(new Voltage("Vcore", 0));
v.Add(new Voltage("Voltage #2", 1, true));
v.Add(new Voltage("AVCC", 2, 34, 34));
v.Add(new Voltage("+3.3V", 3, 34, 34));
v.Add(new Voltage("Voltage #5", 4, true));
v.Add(new Voltage("Voltage #6", 5, true));
v.Add(new Voltage("Voltage #7", 6, true));
v.Add(new Voltage("3VSB", 7, 34, 34));
v.Add(new Voltage("VBat", 8, 34, 34));
v.Add(new Voltage("VTT", 9));
v.Add(new Voltage("Voltage #11", 10, true));
v.Add(new Voltage("Voltage #12", 11, true));
v.Add(new Voltage("Voltage #13", 12, true));
v.Add(new Voltage("Voltage #14", 13, true));
v.Add(new Voltage("Voltage #15", 14, true));
t.Add(new Temperature("PECI 0", 0));
t.Add(new Temperature("CPU", 1));
t.Add(new Temperature("Motherboard", 2));
t.Add(new Temperature("AUX 0", 3));
t.Add(new Temperature("AUX 1", 4));
t.Add(new Temperature("AUX 2", 5));
t.Add(new Temperature("AUX 3", 6));
t.Add(new Temperature("AUX 4", 7));
t.Add(new Temperature("SMBus 0", 8));
t.Add(new Temperature("SMBus 1", 9));
t.Add(new Temperature("PECI 1", 10));
t.Add(new Temperature("PCH Chip CPU Max", 11));
t.Add(new Temperature("PCH Chip", 12));
t.Add(new Temperature("PCH CPU", 13));
t.Add(new Temperature("PCH MCH", 14));
t.Add(new Temperature("Agent 0 DIMM 0", 15));
t.Add(new Temperature("Agent 0 DIMM 1", 16));
t.Add(new Temperature("Agent 1 DIMM 0", 17));
t.Add(new Temperature("Agent 1 DIMM 1", 18));
t.Add(new Temperature("Device 0", 19));
t.Add(new Temperature("Device 1", 20));
t.Add(new Temperature("PECI 0 Calibrated", 21));
t.Add(new Temperature("PECI 1 Calibrated", 22));
t.Add(new Temperature("Virtual", 23));
t.Add(new Temperature("Water In", 24));
t.Add(new Temperature("Water Out", 25));
for (int i = 0; i < superIO.Fans.Length; i++)
f.Add(new Fan("Fan #" + (i + 1), i));
for (int i = 0; i < superIO.Controls.Length; i++)
c.Add(new Ctrl("Fan Control #" + (i + 1), i));
break;
}
default:
{
v.Add(new Voltage("Vcore", 0));