first commit
This commit is contained in:
@@ -0,0 +1,632 @@
|
||||
// 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.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace LibreHardwareMonitor.Hardware.Motherboard.Lpc.EC;
|
||||
|
||||
public abstract class EmbeddedController : Hardware
|
||||
{
|
||||
// If you are updating board information, please consider sharing your changes with the corresponding Linux driver.
|
||||
// You can do that at https://github.com/zeule/asus-ec-sensors or contribute directly to Linux HWMON.
|
||||
// If you are adding a new board, please share DSDT table for the board at https://github.com/zeule/asus-ec-sensors.
|
||||
// https://dortania.github.io/Getting-Started-With-ACPI/Manual/dump.html
|
||||
private static readonly BoardInfo[] _boards =
|
||||
{
|
||||
new(Model.PRIME_X470_PRO,
|
||||
BoardFamily.Amd400,
|
||||
ECSensor.TempChipset,
|
||||
ECSensor.TempCPU,
|
||||
ECSensor.TempMB,
|
||||
ECSensor.TempVrm,
|
||||
ECSensor.TempVrm,
|
||||
ECSensor.FanCPUOpt,
|
||||
ECSensor.CurrCPU,
|
||||
ECSensor.VoltageCPU),
|
||||
new(Model.PRIME_X570_PRO,
|
||||
BoardFamily.Amd500,
|
||||
ECSensor.TempChipset,
|
||||
ECSensor.TempCPU,
|
||||
ECSensor.TempMB,
|
||||
ECSensor.TempVrm,
|
||||
ECSensor.TempTSensor,
|
||||
ECSensor.FanChipset),
|
||||
new(Model.PROART_X570_CREATOR_WIFI,
|
||||
BoardFamily.Amd500,
|
||||
ECSensor.TempChipset,
|
||||
ECSensor.TempCPU,
|
||||
ECSensor.TempMB,
|
||||
ECSensor.TempVrm,
|
||||
ECSensor.TempTSensor,
|
||||
ECSensor.FanCPUOpt,
|
||||
ECSensor.CurrCPU,
|
||||
ECSensor.VoltageCPU),
|
||||
new(Model.PRO_WS_X570_ACE,
|
||||
BoardFamily.Amd500,
|
||||
ECSensor.TempChipset,
|
||||
ECSensor.TempCPU,
|
||||
ECSensor.TempMB,
|
||||
ECSensor.TempVrm,
|
||||
ECSensor.FanChipset,
|
||||
ECSensor.CurrCPU,
|
||||
ECSensor.VoltageCPU),
|
||||
new(new[] { Model.ROG_CROSSHAIR_VIII_HERO, Model.ROG_CROSSHAIR_VIII_HERO_WIFI, Model.ROG_CROSSHAIR_VIII_FORMULA },
|
||||
BoardFamily.Amd500,
|
||||
ECSensor.TempChipset,
|
||||
ECSensor.TempCPU,
|
||||
ECSensor.TempMB,
|
||||
ECSensor.TempTSensor,
|
||||
ECSensor.TempVrm,
|
||||
ECSensor.TempWaterIn,
|
||||
ECSensor.TempWaterOut,
|
||||
ECSensor.FanCPUOpt,
|
||||
ECSensor.FanChipset,
|
||||
ECSensor.FanWaterFlow,
|
||||
ECSensor.CurrCPU,
|
||||
ECSensor.VoltageCPU),
|
||||
new(Model.ROG_CROSSHAIR_X670E_EXTREME,
|
||||
BoardFamily.Amd600,
|
||||
ECSensor.TempWaterIn,
|
||||
ECSensor.TempWaterOut,
|
||||
ECSensor.FanCPUOpt),
|
||||
new(Model.ROG_CROSSHAIR_X670E_HERO,
|
||||
BoardFamily.Amd600,
|
||||
ECSensor.TempWaterIn,
|
||||
ECSensor.TempWaterOut,
|
||||
ECSensor.FanCPUOpt),
|
||||
new(Model.ROG_CROSSHAIR_X670E_GENE,
|
||||
BoardFamily.Amd600,
|
||||
ECSensor.TempWaterIn,
|
||||
ECSensor.TempWaterOut,
|
||||
ECSensor.FanCPUOpt),
|
||||
new(Model.ROG_STRIX_X670E_E_GAMING_WIFI,
|
||||
BoardFamily.Amd600,
|
||||
ECSensor.TempWaterIn,
|
||||
ECSensor.TempWaterOut,
|
||||
ECSensor.FanCPUOpt),
|
||||
new(Model.ROG_STRIX_X670E_F_GAMING_WIFI,
|
||||
BoardFamily.Amd600,
|
||||
ECSensor.TempWaterIn,
|
||||
ECSensor.TempWaterOut,
|
||||
ECSensor.FanCPUOpt),
|
||||
new(Model.ROG_CROSSHAIR_VIII_DARK_HERO,
|
||||
BoardFamily.Amd500,
|
||||
ECSensor.TempChipset,
|
||||
ECSensor.TempCPU,
|
||||
ECSensor.TempMB,
|
||||
ECSensor.TempTSensor,
|
||||
ECSensor.TempVrm,
|
||||
ECSensor.TempWaterIn,
|
||||
ECSensor.TempWaterOut,
|
||||
ECSensor.FanCPUOpt,
|
||||
ECSensor.FanWaterFlow,
|
||||
ECSensor.CurrCPU,
|
||||
ECSensor.VoltageCPU),
|
||||
new(Model.ROG_CROSSHAIR_VIII_IMPACT,
|
||||
BoardFamily.Amd500,
|
||||
ECSensor.TempChipset,
|
||||
ECSensor.TempCPU,
|
||||
ECSensor.TempMB,
|
||||
ECSensor.TempTSensor,
|
||||
ECSensor.TempVrm,
|
||||
ECSensor.FanChipset,
|
||||
ECSensor.CurrCPU,
|
||||
ECSensor.VoltageCPU),
|
||||
new(Model.ROG_STRIX_B550_E_GAMING,
|
||||
BoardFamily.Amd500,
|
||||
ECSensor.TempChipset,
|
||||
ECSensor.TempCPU,
|
||||
ECSensor.TempMB,
|
||||
ECSensor.TempTSensor,
|
||||
ECSensor.TempVrm,
|
||||
ECSensor.FanCPUOpt),
|
||||
new(Model.ROG_STRIX_B550_I_GAMING,
|
||||
BoardFamily.Amd500,
|
||||
ECSensor.TempChipset,
|
||||
ECSensor.TempCPU,
|
||||
ECSensor.TempMB,
|
||||
ECSensor.TempTSensor,
|
||||
ECSensor.TempVrm,
|
||||
ECSensor.FanVrmHS,
|
||||
ECSensor.CurrCPU,
|
||||
ECSensor.VoltageCPU),
|
||||
new(Model.ROG_STRIX_X570_E_GAMING,
|
||||
BoardFamily.Amd500,
|
||||
ECSensor.TempChipset,
|
||||
ECSensor.TempCPU,
|
||||
ECSensor.TempMB,
|
||||
ECSensor.TempTSensor,
|
||||
ECSensor.TempVrm,
|
||||
ECSensor.FanChipset,
|
||||
ECSensor.CurrCPU,
|
||||
ECSensor.VoltageCPU),
|
||||
new(Model.ROG_STRIX_X570_E_GAMING_WIFI_II,
|
||||
BoardFamily.Amd500,
|
||||
ECSensor.TempChipset,
|
||||
ECSensor.TempCPU,
|
||||
ECSensor.TempMB,
|
||||
ECSensor.TempTSensor,
|
||||
ECSensor.TempVrm),
|
||||
new(Model.ROG_STRIX_X570_F_GAMING,
|
||||
BoardFamily.Amd500,
|
||||
ECSensor.TempChipset,
|
||||
ECSensor.TempCPU,
|
||||
ECSensor.TempMB,
|
||||
ECSensor.TempTSensor,
|
||||
ECSensor.FanChipset),
|
||||
new(Model.ROG_STRIX_X570_I_GAMING,
|
||||
BoardFamily.Amd500,
|
||||
ECSensor.TempTSensor,
|
||||
ECSensor.FanVrmHS,
|
||||
ECSensor.FanChipset,
|
||||
ECSensor.CurrCPU,
|
||||
ECSensor.VoltageCPU,
|
||||
ECSensor.TempChipset,
|
||||
ECSensor.TempVrm),
|
||||
new(Model.ROG_STRIX_Z390_E_GAMING,
|
||||
BoardFamily.Intel300,
|
||||
ECSensor.TempVrm,
|
||||
ECSensor.TempChipset,
|
||||
ECSensor.TempTSensor,
|
||||
ECSensor.FanCPUOpt),
|
||||
new(Model.ROG_STRIX_Z390_F_GAMING,
|
||||
BoardFamily.Intel300,
|
||||
ECSensor.TempVrm,
|
||||
ECSensor.TempChipset,
|
||||
ECSensor.TempTSensor,
|
||||
ECSensor.FanCPUOpt),
|
||||
new(Model.ROG_STRIX_Z390_I_GAMING,
|
||||
BoardFamily.Intel300,
|
||||
ECSensor.TempVrm,
|
||||
ECSensor.TempChipset,
|
||||
ECSensor.TempTSensor),
|
||||
new(Model.ROG_MAXIMUS_XI_FORMULA,
|
||||
BoardFamily.Intel300,
|
||||
ECSensor.TempVrm,
|
||||
ECSensor.TempChipset,
|
||||
ECSensor.TempWaterIn,
|
||||
ECSensor.TempWaterOut,
|
||||
ECSensor.TempTSensor,
|
||||
ECSensor.FanCPUOpt),
|
||||
new(Model.ROG_MAXIMUS_XII_Z490_FORMULA,
|
||||
BoardFamily.Intel400,
|
||||
ECSensor.TempTSensor,
|
||||
ECSensor.TempVrm,
|
||||
ECSensor.TempWaterIn,
|
||||
ECSensor.TempWaterOut,
|
||||
ECSensor.FanWaterFlow),
|
||||
new(Model.ROG_STRIX_Z690_A_GAMING_WIFI_D4,
|
||||
BoardFamily.Intel600,
|
||||
ECSensor.TempTSensor,
|
||||
ECSensor.TempVrm),
|
||||
new(Model.ROG_MAXIMUS_Z690_HERO,
|
||||
BoardFamily.Intel600,
|
||||
ECSensor.TempTSensor,
|
||||
ECSensor.TempWaterIn,
|
||||
ECSensor.TempWaterOut,
|
||||
ECSensor.FanWaterFlow),
|
||||
new(Model.ROG_MAXIMUS_Z690_FORMULA,
|
||||
BoardFamily.Intel600,
|
||||
ECSensor.TempTSensor,
|
||||
ECSensor.TempVrm,
|
||||
ECSensor.TempWaterIn,
|
||||
ECSensor.TempWaterOut,
|
||||
ECSensor.TempWaterBlockIn,
|
||||
ECSensor.FanWaterFlow),
|
||||
new(Model.ROG_MAXIMUS_Z690_EXTREME_GLACIAL,
|
||||
BoardFamily.Intel600,
|
||||
ECSensor.TempVrm,
|
||||
ECSensor.TempWaterIn,
|
||||
ECSensor.TempWaterOut,
|
||||
ECSensor.TempWaterBlockIn,
|
||||
ECSensor.FanWaterFlow),
|
||||
new(Model.ROG_MAXIMUS_Z790_HERO,
|
||||
BoardFamily.Intel700,
|
||||
ECSensor.TempVrm,
|
||||
ECSensor.TempTSensor,
|
||||
ECSensor.TempWaterIn,
|
||||
ECSensor.TempWaterOut,
|
||||
ECSensor.FanWaterFlow,
|
||||
ECSensor.FanCPUOpt),
|
||||
new(Model.ROG_MAXIMUS_Z790_DARK_HERO,
|
||||
BoardFamily.Intel700,
|
||||
ECSensor.TempVrm,
|
||||
ECSensor.FanCPUOpt,
|
||||
ECSensor.TempTSensor,
|
||||
ECSensor.TempWaterIn,
|
||||
ECSensor.TempWaterOut,
|
||||
ECSensor.FanWaterFlow),
|
||||
new(Model.Z170_A,
|
||||
BoardFamily.Intel100,
|
||||
ECSensor.TempTSensor,
|
||||
ECSensor.TempChipset,
|
||||
ECSensor.FanWaterPump,
|
||||
ECSensor.CurrCPU,
|
||||
ECSensor.VoltageCPU),
|
||||
new(Model.PRIME_Z690_A,
|
||||
BoardFamily.Intel600,
|
||||
ECSensor.TempTSensor,
|
||||
ECSensor.TempVrm),
|
||||
new(Model.ROG_STRIX_Z790_I_GAMING_WIFI,
|
||||
BoardFamily.Intel700,
|
||||
ECSensor.TempTSensor,
|
||||
ECSensor.TempTSensor2),
|
||||
new(Model.ROG_STRIX_Z790_E_GAMING_WIFI,
|
||||
BoardFamily.Intel700,
|
||||
ECSensor.TempWaterIn),
|
||||
new(Model.ROG_MAXIMUS_Z790_FORMULA,
|
||||
BoardFamily.Intel700,
|
||||
ECSensor.TempWaterIn,
|
||||
ECSensor.TempWaterOut),
|
||||
new(Model.ROG_MAXIMUS_XII_HERO_WIFI,
|
||||
BoardFamily.Intel400,
|
||||
ECSensor.TempTSensor,
|
||||
ECSensor.TempChipset,
|
||||
ECSensor.TempVrm,
|
||||
ECSensor.TempWaterIn,
|
||||
ECSensor.TempWaterOut,
|
||||
ECSensor.CurrCPU,
|
||||
ECSensor.FanCPUOpt,
|
||||
ECSensor.FanWaterFlow),
|
||||
};
|
||||
|
||||
private static readonly Dictionary<BoardFamily, Dictionary<ECSensor, EmbeddedControllerSource>> _knownSensors = new()
|
||||
{
|
||||
{
|
||||
BoardFamily.Amd400, new Dictionary<ECSensor, EmbeddedControllerSource>() // no chipset fans in this generation
|
||||
{
|
||||
{ ECSensor.TempChipset, new EmbeddedControllerSource("Chipset", SensorType.Temperature, 0x003a) },
|
||||
{ ECSensor.TempCPU, new EmbeddedControllerSource("CPU", SensorType.Temperature, 0x003b) },
|
||||
{ ECSensor.TempMB, new EmbeddedControllerSource("Motherboard", SensorType.Temperature, 0x003c) },
|
||||
{ ECSensor.TempTSensor, new EmbeddedControllerSource("T Sensor", SensorType.Temperature, 0x003d, blank: -40) },
|
||||
{ ECSensor.TempVrm, new EmbeddedControllerSource("VRM", SensorType.Temperature, 0x003e) },
|
||||
{ ECSensor.VoltageCPU, new EmbeddedControllerSource("CPU Core", SensorType.Voltage, 0x00a2, 2, factor: 1e-3f) },
|
||||
{ ECSensor.FanCPUOpt, new EmbeddedControllerSource("CPU Optional Fan", SensorType.Fan, 0x00bc, 2) },
|
||||
{ ECSensor.FanVrmHS, new EmbeddedControllerSource("VRM Heat Sink Fan", SensorType.Fan, 0x00b2, 2) },
|
||||
{ ECSensor.FanWaterFlow, new EmbeddedControllerSource("Water flow", SensorType.Flow, 0x00b4, 2, factor: 1.0f / 42f * 60f) },
|
||||
{ ECSensor.CurrCPU, new EmbeddedControllerSource("CPU", SensorType.Current, 0x00f4) },
|
||||
{ ECSensor.TempWaterIn, new EmbeddedControllerSource("Water In", SensorType.Temperature, 0x010d, blank: -40) },
|
||||
{ ECSensor.TempWaterOut, new EmbeddedControllerSource("Water Out", SensorType.Temperature, 0x010b, blank: -40) }
|
||||
}
|
||||
},
|
||||
{
|
||||
BoardFamily.Amd500, new Dictionary<ECSensor, EmbeddedControllerSource>
|
||||
{
|
||||
{ ECSensor.TempChipset, new EmbeddedControllerSource("Chipset", SensorType.Temperature, 0x003a) },
|
||||
{ ECSensor.TempCPU, new EmbeddedControllerSource("CPU", SensorType.Temperature, 0x003b) },
|
||||
{ ECSensor.TempMB, new EmbeddedControllerSource("Motherboard", SensorType.Temperature, 0x003c) },
|
||||
{ ECSensor.TempTSensor, new EmbeddedControllerSource("T Sensor", SensorType.Temperature, 0x003d, blank: -40) },
|
||||
{ ECSensor.TempVrm, new EmbeddedControllerSource("VRM", SensorType.Temperature, 0x003e) },
|
||||
{ ECSensor.VoltageCPU, new EmbeddedControllerSource("CPU Core", SensorType.Voltage, 0x00a2, 2, factor: 1e-3f) },
|
||||
{ ECSensor.FanCPUOpt, new EmbeddedControllerSource("CPU Optional Fan", SensorType.Fan, 0x00b0, 2) },
|
||||
{ ECSensor.FanVrmHS, new EmbeddedControllerSource("VRM Heat Sink Fan", SensorType.Fan, 0x00b2, 2) },
|
||||
{ ECSensor.FanChipset, new EmbeddedControllerSource("Chipset Fan", SensorType.Fan, 0x00b4, 2) },
|
||||
// TODO: "why 42?" is a silly question, I know, but still, why? On the serious side, it might be 41.6(6)
|
||||
{ ECSensor.FanWaterFlow, new EmbeddedControllerSource("Water flow", SensorType.Flow, 0x00bc, 2, factor: 1.0f / 42f * 60f) },
|
||||
{ ECSensor.CurrCPU, new EmbeddedControllerSource("CPU", SensorType.Current, 0x00f4) },
|
||||
{ ECSensor.TempWaterIn, new EmbeddedControllerSource("Water In", SensorType.Temperature, 0x0100, blank: -40) },
|
||||
{ ECSensor.TempWaterOut, new EmbeddedControllerSource("Water Out", SensorType.Temperature, 0x0101, blank: -40) }
|
||||
}
|
||||
},
|
||||
{
|
||||
BoardFamily.Amd600, new Dictionary<ECSensor, EmbeddedControllerSource>
|
||||
{
|
||||
{ ECSensor.FanCPUOpt, new EmbeddedControllerSource("CPU Optional Fan", SensorType.Fan, 0x00b0, 2) },
|
||||
{ ECSensor.TempWaterIn, new EmbeddedControllerSource("Water In", SensorType.Temperature, 0x0100, blank: -40) },
|
||||
{ ECSensor.TempWaterOut, new EmbeddedControllerSource("Water Out", SensorType.Temperature, 0x0101, blank: -40) }
|
||||
}
|
||||
},
|
||||
{
|
||||
BoardFamily.Intel100, new Dictionary<ECSensor, EmbeddedControllerSource>
|
||||
{
|
||||
{ ECSensor.TempChipset, new EmbeddedControllerSource("Chipset", SensorType.Temperature, 0x003a) },
|
||||
{ ECSensor.TempTSensor, new EmbeddedControllerSource("T Sensor", SensorType.Temperature, 0x003d, blank: -40) },
|
||||
{ ECSensor.FanWaterPump, new EmbeddedControllerSource("Water Pump", SensorType.Fan, 0x00bc, 2) },
|
||||
{ ECSensor.CurrCPU, new EmbeddedControllerSource("CPU", SensorType.Current, 0x00f4) },
|
||||
{ ECSensor.VoltageCPU, new EmbeddedControllerSource("CPU Core", SensorType.Voltage, 0x00a2, 2, factor: 1e-3f) }
|
||||
}
|
||||
},
|
||||
{
|
||||
BoardFamily.Intel300, new Dictionary<ECSensor, EmbeddedControllerSource>
|
||||
{
|
||||
{ ECSensor.TempVrm, new EmbeddedControllerSource("VRM", SensorType.Temperature, 0x003e) },
|
||||
{ ECSensor.TempChipset, new EmbeddedControllerSource("Chipset", SensorType.Temperature, 0x003a) },
|
||||
{ ECSensor.TempTSensor, new EmbeddedControllerSource("T Sensor", SensorType.Temperature, 0x003d, blank: -40) },
|
||||
{ ECSensor.TempWaterIn, new EmbeddedControllerSource("Water In", SensorType.Temperature, 0x0100, blank: -40) },
|
||||
{ ECSensor.TempWaterOut, new EmbeddedControllerSource("Water Out", SensorType.Temperature, 0x0101, blank: -40) },
|
||||
{ ECSensor.FanCPUOpt, new EmbeddedControllerSource("CPU Optional Fan", SensorType.Fan, 0x00b0, 2) }
|
||||
}
|
||||
},
|
||||
{
|
||||
BoardFamily.Intel400, new Dictionary<ECSensor, EmbeddedControllerSource>
|
||||
{
|
||||
{ ECSensor.TempChipset, new EmbeddedControllerSource("Chipset", SensorType.Temperature, 0x003a) },
|
||||
{ ECSensor.TempTSensor, new EmbeddedControllerSource("T Sensor", SensorType.Temperature, 0x003d, blank: -40) },
|
||||
{ ECSensor.TempVrm, new EmbeddedControllerSource("VRM", SensorType.Temperature, 0x003e) },
|
||||
{ ECSensor.FanCPUOpt, new EmbeddedControllerSource("CPU Optional Fan", SensorType.Fan, 0x00b0, 2) },
|
||||
{ ECSensor.FanWaterFlow, new EmbeddedControllerSource("Water Flow", SensorType.Flow, 0x00be, 2, factor: 1.0f / 42f * 60f) }, // todo: need validation for this calculation
|
||||
{ ECSensor.CurrCPU, new EmbeddedControllerSource("CPU", SensorType.Current, 0x00f4) },
|
||||
{ ECSensor.TempWaterIn, new EmbeddedControllerSource("Water In", SensorType.Temperature, 0x0100, blank: -40) },
|
||||
{ ECSensor.TempWaterOut, new EmbeddedControllerSource("Water Out", SensorType.Temperature, 0x0101, blank: -40) },
|
||||
}
|
||||
},
|
||||
{
|
||||
BoardFamily.Intel600, new Dictionary<ECSensor, EmbeddedControllerSource>
|
||||
{
|
||||
{ ECSensor.TempTSensor, new EmbeddedControllerSource("T Sensor", SensorType.Temperature, 0x003d, blank: -40) },
|
||||
{ ECSensor.TempVrm, new EmbeddedControllerSource("VRM", SensorType.Temperature, 0x003e) },
|
||||
{ ECSensor.TempWaterIn, new EmbeddedControllerSource("Water In", SensorType.Temperature, 0x0100, blank: -40) },
|
||||
{ ECSensor.TempWaterOut, new EmbeddedControllerSource("Water Out", SensorType.Temperature, 0x0101, blank: -40) },
|
||||
{ ECSensor.TempWaterBlockIn, new EmbeddedControllerSource("Water Block In", SensorType.Temperature, 0x0102, blank: -40) },
|
||||
{ ECSensor.FanWaterFlow, new EmbeddedControllerSource("Water Flow", SensorType.Flow, 0x00be, 2, factor: 1.0f / 42f * 60f) } // todo: need validation for this calculation
|
||||
}
|
||||
},
|
||||
{
|
||||
BoardFamily.Intel700, new Dictionary<ECSensor, EmbeddedControllerSource>
|
||||
{
|
||||
{ ECSensor.TempVrm, new EmbeddedControllerSource("VRM", SensorType.Temperature, 0x0033) },
|
||||
{ ECSensor.FanCPUOpt, new EmbeddedControllerSource("CPU Optional Fan", SensorType.Fan, 0x00b0, 2) },
|
||||
{ ECSensor.TempTSensor, new EmbeddedControllerSource("T Sensor", SensorType.Temperature, 0x0109, blank: -40) },
|
||||
{ ECSensor.TempTSensor2, new EmbeddedControllerSource("T Sensor 2", SensorType.Temperature, 0x105, blank: -40) },
|
||||
{ ECSensor.TempWaterIn, new EmbeddedControllerSource("Water In", SensorType.Temperature, 0x0100, blank: -40) },
|
||||
{ ECSensor.TempWaterOut, new EmbeddedControllerSource("Water Out", SensorType.Temperature, 0x0101, blank: -40) },
|
||||
{ ECSensor.FanWaterFlow, new EmbeddedControllerSource("Water Flow", SensorType.Flow, 0x00be, 2, factor: 1.0f / 42f * 60f) } // todo: need validation for this calculation
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
private readonly byte[] _data;
|
||||
private readonly ushort[] _registers;
|
||||
private readonly List<Sensor> _sensors;
|
||||
|
||||
private readonly IReadOnlyList<EmbeddedControllerSource> _sources;
|
||||
|
||||
protected EmbeddedController(IEnumerable<EmbeddedControllerSource> sources, ISettings settings) : base("Embedded Controller", new Identifier("lpc", "ec"), settings)
|
||||
{
|
||||
// sorting by address, which implies sorting by bank, for optimized EC access
|
||||
var sourcesList = sources.ToList();
|
||||
sourcesList.Sort((left, right) => left.Register.CompareTo(right.Register));
|
||||
_sources = sourcesList;
|
||||
var indices = new Dictionary<SensorType, int>();
|
||||
foreach (SensorType t in Enum.GetValues(typeof(SensorType)))
|
||||
{
|
||||
indices.Add(t, 0);
|
||||
}
|
||||
|
||||
_sensors = new List<Sensor>();
|
||||
List<ushort> registers = new();
|
||||
foreach (EmbeddedControllerSource s in _sources)
|
||||
{
|
||||
int index = indices[s.Type];
|
||||
indices[s.Type] = index + 1;
|
||||
_sensors.Add(new Sensor(s.Name, index, s.Type, this, settings));
|
||||
for (int i = 0; i < s.Size; ++i)
|
||||
{
|
||||
registers.Add((ushort)(s.Register + i));
|
||||
}
|
||||
|
||||
ActivateSensor(_sensors[_sensors.Count - 1]);
|
||||
}
|
||||
|
||||
_registers = registers.ToArray();
|
||||
_data = new byte[_registers.Length];
|
||||
}
|
||||
|
||||
public override HardwareType HardwareType => HardwareType.EmbeddedController;
|
||||
|
||||
internal static EmbeddedController Create(Model model, ISettings settings)
|
||||
{
|
||||
var boards = _boards.Where(b => b.Models.Contains(model)).ToList();
|
||||
switch (boards.Count)
|
||||
{
|
||||
case 0:
|
||||
return null;
|
||||
case > 1:
|
||||
throw new MultipleBoardRecordsFoundException(model.ToString());
|
||||
}
|
||||
|
||||
BoardInfo board = boards[0];
|
||||
IEnumerable<EmbeddedControllerSource> sources = board.Sensors.Select(ecs => _knownSensors[board.Family][ecs]);
|
||||
|
||||
return Environment.OSVersion.Platform switch
|
||||
{
|
||||
PlatformID.Win32NT => new WindowsEmbeddedController(sources, settings),
|
||||
_ => null
|
||||
};
|
||||
}
|
||||
|
||||
public override void Update()
|
||||
{
|
||||
if (!TryUpdateData())
|
||||
{
|
||||
// just skip this update cycle?
|
||||
return;
|
||||
}
|
||||
|
||||
int readRegister = 0;
|
||||
for (int si = 0; si < _sensors.Count; ++si)
|
||||
{
|
||||
int val = _sources[si].Size switch
|
||||
{
|
||||
1 => _sources[si].Type switch { SensorType.Temperature => unchecked((sbyte)_data[readRegister]), _ => _data[readRegister] },
|
||||
2 => unchecked((short)((_data[readRegister] << 8) + _data[readRegister + 1])),
|
||||
_ => 0
|
||||
};
|
||||
|
||||
readRegister += _sources[si].Size;
|
||||
|
||||
_sensors[si].Value = val != _sources[si].Blank ? val * _sources[si].Factor : null;
|
||||
}
|
||||
}
|
||||
|
||||
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();
|
||||
ushort[] src = new ushort[0x100];
|
||||
byte[] data = new byte[0x100];
|
||||
for (ushort i = 0; i < src.Length; ++i)
|
||||
{
|
||||
src[i] = i;
|
||||
}
|
||||
|
||||
embeddedControllerIO.Read(src, data);
|
||||
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(data[address].ToString("X2", CultureInfo.InvariantCulture));
|
||||
}
|
||||
|
||||
r.AppendLine();
|
||||
}
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
r.AppendLine(e.Message);
|
||||
}
|
||||
|
||||
return r.ToString();
|
||||
}
|
||||
|
||||
protected abstract IEmbeddedControllerIO AcquireIOInterface();
|
||||
|
||||
private bool TryUpdateData()
|
||||
{
|
||||
try
|
||||
{
|
||||
using IEmbeddedControllerIO embeddedControllerIO = AcquireIOInterface();
|
||||
embeddedControllerIO.Read(_registers, _data);
|
||||
return true;
|
||||
}
|
||||
catch (IOException)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private enum ECSensor
|
||||
{
|
||||
/// <summary>Chipset temperature [℃]</summary>
|
||||
TempChipset,
|
||||
|
||||
/// <summary>CPU temperature [℃]</summary>
|
||||
TempCPU,
|
||||
|
||||
/// <summary>motherboard temperature [℃]</summary>
|
||||
TempMB,
|
||||
|
||||
/// <summary>"T_Sensor" temperature sensor reading [℃]</summary>
|
||||
TempTSensor,
|
||||
|
||||
/// <summary>"T_Sensor 2" temperature sensor reading [℃]</summary>
|
||||
TempTSensor2,
|
||||
|
||||
/// <summary>VRM temperature [℃]</summary>
|
||||
TempVrm,
|
||||
|
||||
/// <summary>CPU Core voltage [mV]</summary>
|
||||
VoltageCPU,
|
||||
|
||||
/// <summary>CPU_Opt fan [RPM]</summary>
|
||||
FanCPUOpt,
|
||||
|
||||
/// <summary>VRM heat sink fan [RPM]</summary>
|
||||
FanVrmHS,
|
||||
|
||||
/// <summary>Chipset fan [RPM]</summary>
|
||||
FanChipset,
|
||||
|
||||
/// <summary>Water Pump [RPM]</summary>
|
||||
FanWaterPump,
|
||||
|
||||
/// <summary>Water flow sensor reading [RPM]</summary>
|
||||
FanWaterFlow,
|
||||
|
||||
/// <summary>CPU current [A]</summary>
|
||||
CurrCPU,
|
||||
|
||||
/// <summary>"Water_In" temperature sensor reading [℃]</summary>
|
||||
TempWaterIn,
|
||||
|
||||
/// <summary>"Water_Out" temperature sensor reading [℃]</summary>
|
||||
TempWaterOut,
|
||||
|
||||
/// <summary>Water block temperature sensor reading [℃]</summary>
|
||||
TempWaterBlockIn,
|
||||
Max
|
||||
}
|
||||
|
||||
private enum BoardFamily
|
||||
{
|
||||
Amd400,
|
||||
Amd500,
|
||||
Amd600,
|
||||
Intel100,
|
||||
Intel300,
|
||||
Intel400,
|
||||
Intel600,
|
||||
Intel700
|
||||
}
|
||||
|
||||
private struct BoardInfo
|
||||
{
|
||||
public BoardInfo(Model[] models, BoardFamily family, params ECSensor[] sensors)
|
||||
{
|
||||
Models = models;
|
||||
Family = family;
|
||||
Sensors = sensors;
|
||||
}
|
||||
|
||||
public BoardInfo(Model model, BoardFamily family, params ECSensor[] sensors)
|
||||
{
|
||||
Models = new[] { model };
|
||||
Family = family;
|
||||
Sensors = sensors;
|
||||
}
|
||||
|
||||
public Model[] Models { get; }
|
||||
|
||||
public BoardFamily Family { get; }
|
||||
|
||||
public ECSensor[] Sensors { get; }
|
||||
}
|
||||
|
||||
public class IOException : System.IO.IOException
|
||||
{
|
||||
public IOException(string message) : base($"ACPI embedded controller I/O error: {message}")
|
||||
{ }
|
||||
}
|
||||
|
||||
public class BadConfigurationException : Exception
|
||||
{
|
||||
public BadConfigurationException(string message) : base(message)
|
||||
{ }
|
||||
}
|
||||
|
||||
public class MultipleBoardRecordsFoundException : BadConfigurationException
|
||||
{
|
||||
public MultipleBoardRecordsFoundException(string model) : base($"Multiple board records refer to the same model '{model}'")
|
||||
{ }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
// 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, ushort register);
|
||||
@@ -0,0 +1,31 @@
|
||||
// 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, SensorType type, ushort register, byte size = 1, float factor = 1.0f, int blank = int.MaxValue)
|
||||
{
|
||||
Name = name;
|
||||
|
||||
Register = register;
|
||||
Size = size;
|
||||
Type = type;
|
||||
Factor = factor;
|
||||
Blank = blank;
|
||||
}
|
||||
|
||||
public string Name { get; }
|
||||
public ushort Register { get; }
|
||||
public byte Size { get; }
|
||||
public float Factor { get; }
|
||||
|
||||
public int Blank { get; }
|
||||
|
||||
public EmbeddedControllerReader Reader { get; }
|
||||
|
||||
public SensorType Type { get; }
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
// 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 Read(ushort[] registers, byte[] data);
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
// 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(IEnumerable<EmbeddedControllerSource> sources, ISettings settings) : base(sources, settings)
|
||||
{ }
|
||||
|
||||
protected override IEmbeddedControllerIO AcquireIOInterface()
|
||||
{
|
||||
return new WindowsEmbeddedControllerIO();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,248 @@
|
||||
// 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.Diagnostics;
|
||||
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 _disposed;
|
||||
|
||||
private int _waitReadFailures;
|
||||
|
||||
public WindowsEmbeddedControllerIO()
|
||||
{
|
||||
if (!Mutexes.WaitEc(10))
|
||||
{
|
||||
throw new BusMutexLockingFailedException();
|
||||
}
|
||||
}
|
||||
|
||||
public void Read(ushort[] registers, byte[] data)
|
||||
{
|
||||
Trace.Assert(registers.Length <= data.Length,
|
||||
"data buffer length has to be greater or equal to the registers array length");
|
||||
|
||||
byte bank = 0;
|
||||
byte prevBank = SwitchBank(bank);
|
||||
|
||||
// oops... somebody else is working with the EC too
|
||||
Trace.WriteLineIf(prevBank != 0, "Concurrent access to the ACPI EC detected.\nRace condition possible.");
|
||||
|
||||
// read registers minimizing bank switches.
|
||||
for (int i = 0; i < registers.Length; i++)
|
||||
{
|
||||
byte regBank = (byte)(registers[i] >> 8);
|
||||
byte regIndex = (byte)(registers[i] & 0xFF);
|
||||
// registers are sorted by bank
|
||||
if (regBank > bank)
|
||||
{
|
||||
bank = SwitchBank(regBank);
|
||||
}
|
||||
data[i] = ReadByte(regIndex);
|
||||
}
|
||||
|
||||
SwitchBank(prevBank);
|
||||
}
|
||||
|
||||
private byte ReadByte(byte register)
|
||||
{
|
||||
return ReadLoop<byte>(register, ReadByteOp);
|
||||
}
|
||||
|
||||
private void WriteByte(byte register, byte value)
|
||||
{
|
||||
WriteLoop(register, value, WriteByteOp);
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
if (!_disposed)
|
||||
{
|
||||
_disposed = true;
|
||||
Mutexes.ReleaseEc();
|
||||
}
|
||||
}
|
||||
|
||||
private byte SwitchBank(byte bank)
|
||||
{
|
||||
byte previous = ReadByte(0xFF);
|
||||
WriteByte(0xFF, bank);
|
||||
return previous;
|
||||
}
|
||||
|
||||
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 : EmbeddedController.IOException
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
Reference in New Issue
Block a user