From 9a9d670ca795d94fe620014cce7bd9a436b64124 Mon Sep 17 00:00:00 2001 From: Phyxion <7643972+Phyxion@users.noreply.github.com> Date: Wed, 26 Feb 2020 10:58:56 +0100 Subject: [PATCH] Update from upstream --- LibreHardwareMonitor/UI/MainForm.cs | 4 + LibreHardwareMonitor/UI/SensorNode.cs | 23 ++- LibreHardwareMonitorLib/Hardware/Cpu/CpuId.cs | 9 ++ .../Hardware/Gpu/NvidiaGpu.cs | 119 ++++++++++++++-- .../Hardware/Motherboard/Identification.cs | 66 +++++++-- .../Hardware/Motherboard/Lpc/Chip.cs | 5 + .../Hardware/Motherboard/Lpc/IT87XX.cs | 117 ++++++++------- .../Hardware/Motherboard/Lpc/LPcPort.cs | 8 +- .../Hardware/Motherboard/Lpc/LpcIO.cs | 115 +++++++++++++++ .../Hardware/Motherboard/Lpc/Nct677X.cs | 3 +- .../Hardware/Motherboard/Manufacturer.cs | 18 +++ .../Hardware/Motherboard/SuperIOHardware.cs | 1 + .../Hardware/Storage/SmartNames.cs | 12 ++ .../Hardware/Storage/SsdIndilinx.cs | 3 +- .../Hardware/Storage/SsdIntel.cs | 18 ++- .../Hardware/Storage/SsdMicron.cs | 82 ++++++++++- .../Hardware/Storage/SsdPlextor.cs | 3 +- .../Hardware/Storage/SsdSamsung.cs | 21 ++- .../Hardware/Storage/SsdSandforce.cs | 10 +- LibreHardwareMonitorLib/Interop/NvApi.cs | 134 ++++++++++++------ LibreHardwareMonitorLib/Interop/NvidiaML.cs | 41 +++++- 21 files changed, 657 insertions(+), 155 deletions(-) diff --git a/LibreHardwareMonitor/UI/MainForm.cs b/LibreHardwareMonitor/UI/MainForm.cs index 98d1022..9a2d935 100644 --- a/LibreHardwareMonitor/UI/MainForm.cs +++ b/LibreHardwareMonitor/UI/MainForm.cs @@ -635,6 +635,10 @@ namespace LibreHardwareMonitor.UI private void SaveConfiguration() { + if (_plotPanel == null || _settings == null) + return; + + _plotPanel.SetCurrentSettings(); foreach (TreeColumn column in treeView.Columns) diff --git a/LibreHardwareMonitor/UI/SensorNode.cs b/LibreHardwareMonitor/UI/SensorNode.cs index c5c073e..8533b1e 100644 --- a/LibreHardwareMonitor/UI/SensorNode.cs +++ b/LibreHardwareMonitor/UI/SensorNode.cs @@ -25,7 +25,9 @@ namespace LibreHardwareMonitor.UI switch (Sensor.SensorType) { case SensorType.Temperature when _unitManager.TemperatureUnit == TemperatureUnit.Fahrenheit: + { return $"{value * 1.8 + 32:F1} °F"; + } case SensorType.Throughput: { string result; @@ -36,11 +38,15 @@ namespace LibreHardwareMonitor.UI switch (value) { case 100000000: + { result = "100Mbps"; break; + } case 1000000000: + { result = "1Gbps"; break; + } default: { if (value < 1024) @@ -54,21 +60,24 @@ namespace LibreHardwareMonitor.UI } break; } - } + break; + } default: { - if (value < 1048576) - result = $"{value / 1024:F1} KB/s"; - else - result = $"{value / 1048576:F1} MB/s"; - } + const int _1MB = 1048576; + + result = value < _1MB ? $"{value / 1024:F1} KB/s" : $"{value / _1MB:F1} MB/s"; + break; + } } return result; } default: + { return string.Format(Format, value); + } } } @@ -84,7 +93,7 @@ namespace LibreHardwareMonitor.UI switch (sensor.SensorType) { case SensorType.Voltage: Format = "{0:F3} V"; break; - case SensorType.Clock: Format = "{0:F0} MHz"; break; + case SensorType.Clock: Format = "{0:F1} MHz"; break; case SensorType.Load: Format = "{0:F1} %"; break; case SensorType.Temperature: Format = "{0:F1} °C"; break; case SensorType.Fan: Format = "{0:F0} RPM"; break; diff --git a/LibreHardwareMonitorLib/Hardware/Cpu/CpuId.cs b/LibreHardwareMonitorLib/Hardware/Cpu/CpuId.cs index b39d135..939c877 100644 --- a/LibreHardwareMonitorLib/Hardware/Cpu/CpuId.cs +++ b/LibreHardwareMonitorLib/Hardware/Cpu/CpuId.cs @@ -111,9 +111,18 @@ namespace LibreHardwareMonitor.Hardware.CPU nameBuilder.Replace("(TM)", string.Empty); nameBuilder.Replace("(tm)", string.Empty); nameBuilder.Replace("CPU", string.Empty); + nameBuilder.Replace("Dual-Core Processor", string.Empty); + nameBuilder.Replace("Triple-Core Processor", string.Empty); nameBuilder.Replace("Quad-Core Processor", string.Empty); nameBuilder.Replace("Six-Core Processor", string.Empty); nameBuilder.Replace("Eight-Core Processor", string.Empty); + nameBuilder.Replace("6-Core Processor", string.Empty); + nameBuilder.Replace("8-Core Processor", string.Empty); + nameBuilder.Replace("12-Core Processor", string.Empty); + nameBuilder.Replace("16-Core Processor", string.Empty); + nameBuilder.Replace("24-Core Processor", string.Empty); + nameBuilder.Replace("32-Core Processor", string.Empty); + nameBuilder.Replace("64-Core Processor", string.Empty); for (int i = 0; i < 10; i++) nameBuilder.Replace(" ", " "); diff --git a/LibreHardwareMonitorLib/Hardware/Gpu/NvidiaGpu.cs b/LibreHardwareMonitorLib/Hardware/Gpu/NvidiaGpu.cs index 9143532..fd7e7b2 100644 --- a/LibreHardwareMonitorLib/Hardware/Gpu/NvidiaGpu.cs +++ b/LibreHardwareMonitorLib/Hardware/Gpu/NvidiaGpu.cs @@ -25,6 +25,8 @@ namespace LibreHardwareMonitor.Hardware.Gpu private readonly Sensor _memoryLoad; private readonly Sensor _memoryUsed; private readonly NvidiaML.NvmlDevice? _nvmlDevice; + private readonly Sensor _pcieThroughputRx; + private readonly Sensor _pcieThroughputTx; private readonly Sensor _powerUsage; private readonly Sensor[] _temperatures; @@ -69,14 +71,10 @@ namespace LibreHardwareMonitor.Hardware.Gpu ActivateSensor(_temperatures[i]); } - if (NvApi.NvAPI_GPU_GetTachReading != null && NvApi.NvAPI_GPU_GetTachReading(handle, out int value) == NvApi.NvStatus.OK) - { - if (value >= 0) - { - _fan = new Sensor("GPU", 0, SensorType.Fan, this, settings); - ActivateSensor(_fan); - } - } + if (NvApi.NvAPI_GPU_GetTachReading != null && NvApi.NvAPI_GPU_GetTachReading(handle, out _) == NvApi.NvStatus.OK) + _fan = new Sensor("GPU", 0, SensorType.Fan, this, settings); + else if (NvApi.NvAPI_GPU_ClientFanCoolersGetStatus != null && GetCoolerSettings().Count > 0) + _fan = new Sensor("GPU", 0, SensorType.Fan, this, settings); _clocks = new Sensor[3]; _clocks[0] = new Sensor("GPU Core", 0, SensorType.Clock, this, settings); @@ -85,14 +83,17 @@ namespace LibreHardwareMonitor.Hardware.Gpu for (int i = 0; i < _clocks.Length; i++) ActivateSensor(_clocks[i]); - _loads = new Sensor[3]; + _loads = new Sensor[4]; _loads[0] = new Sensor("GPU Core", 0, SensorType.Load, this, settings); _loads[1] = new Sensor("GPU Memory Controller", 1, SensorType.Load, this, settings); _loads[2] = new Sensor("GPU Video Engine", 2, SensorType.Load, this, settings); + _loads[3] = new Sensor("GPU Bus", 4, SensorType.Load, this, settings); + _memoryLoad = new Sensor("GPU Memory", 3, SensorType.Load, this, settings); _memoryFree = new Sensor("GPU Memory Free", 1, SensorType.SmallData, this, settings); _memoryUsed = new Sensor("GPU Memory Used", 2, SensorType.SmallData, this, settings); _memoryAvail = new Sensor("GPU Memory Total", 3, SensorType.SmallData, this, settings); + _control = new Sensor("GPU Fan", 0, SensorType.Control, this, settings); NvApi.NvGPUCoolerSettings coolerSettings = GetCoolerSettings(); @@ -115,6 +116,9 @@ namespace LibreHardwareMonitor.Hardware.Gpu if (_nvmlDevice.HasValue) { _powerUsage = new Sensor("GPU Package", 0, SensorType.Power, this, settings); + + _pcieThroughputRx = new Sensor("GPU PCIe Rx", 0, SensorType.Throughput, this, settings); + _pcieThroughputTx = new Sensor("GPU PCIe Tx", 1, SensorType.Throughput, this, settings); } } @@ -151,6 +155,18 @@ namespace LibreHardwareMonitor.Hardware.Gpu return settings; } + private NvApi.NvFanCoolersStatus GetFanCoolersStatus() + { + var coolers = new NvApi.NvFanCoolersStatus { Version = NvApi.GPU_FAN_COOLERS_STATUS_VER, Items = new NvApi.NvFanCoolersStatusItem[NvApi.MAX_FAN_COOLERS_STATUS_ITEMS] }; + + if (!(NvApi.NvAPI_GPU_ClientFanCoolersGetStatus != null && NvApi.NvAPI_GPU_ClientFanCoolersGetStatus(_handle, ref coolers) == NvApi.NvStatus.OK)) + { + coolers.Count = 0; + } + + return coolers; + } + private NvApi.NvGPUCoolerSettings GetCoolerSettings() { NvApi.NvGPUCoolerSettings settings = new NvApi.NvGPUCoolerSettings { Version = NvApi.GPU_COOLER_SETTINGS_VER, Cooler = new NvApi.NvCooler[NvApi.MAX_COOLER_PER_GPU] }; @@ -179,10 +195,16 @@ namespace LibreHardwareMonitor.Hardware.Gpu foreach (Sensor sensor in _temperatures) sensor.Value = settings.Sensor[sensor.Index].CurrentTemp; + bool readTach = false; if (_fan != null) { - NvApi.NvAPI_GPU_GetTachReading(_handle, out int value); - _fan.Value = value; + if (NvApi.NvAPI_GPU_GetTachReading(_handle, out int value) == NvApi.NvStatus.OK) + { + _fan.Value = value; + ActivateSensor(_fan); + + readTach = true; + } } uint[] values = GetClocks(); @@ -204,7 +226,7 @@ namespace LibreHardwareMonitor.Hardware.Gpu NvApi.NvPStates states = new NvApi.NvPStates { Version = NvApi.GPU_PSTATES_VER, PStates = new NvApi.NvPState[NvApi.MAX_PSTATES_PER_GPU] }; if (NvApi.NvAPI_GPU_GetPStates != null && NvApi.NvAPI_GPU_GetPStates(_handle, ref states) == NvApi.NvStatus.OK) { - for (int i = 0; i < 3; i++) + for (int i = 0; i < _loads.Length; i++) { if (states.PStates[i].Present) { @@ -226,11 +248,33 @@ namespace LibreHardwareMonitor.Hardware.Gpu } } + bool readCoolerSettings = false; NvApi.NvGPUCoolerSettings coolerSettings = GetCoolerSettings(); if (coolerSettings.Count > 0) { _control.Value = coolerSettings.Cooler[0].CurrentLevel; ActivateSensor(_control); + + readCoolerSettings = true; + } + + if (!readTach || !readCoolerSettings) + { + NvApi.NvFanCoolersStatus coolersStatus = GetFanCoolersStatus(); + if (coolersStatus.Count > 0) + { + if (!readCoolerSettings) + { + _control.Value = coolersStatus.Items[0].CurrentLevel; + ActivateSensor(_control); + } + + if (!readTach && _fan != null) + { + _fan.Value = coolersStatus.Items[0].CurrentRpm; + ActivateSensor(_fan); + } + } } NvApi.NvMemoryInfo memoryInfo = new NvApi.NvMemoryInfo { Version = NvApi.GPU_MEMORY_INFO_VER, Values = new uint[NvApi.MAX_MEMORY_VALUES_PER_GPU] }; @@ -257,6 +301,21 @@ namespace LibreHardwareMonitor.Hardware.Gpu _powerUsage.Value = (float)result.Value / 1000; ActivateSensor(_powerUsage); } + + // In MB/s, throughput sensors are passed as in KB/s. + uint? rx = NvidiaML.NvmlDeviceGetPcieThroughput(_nvmlDevice.Value, NvidiaML.NvmlPcieUtilCounter.RxBytes); + if (rx.HasValue) + { + _pcieThroughputRx.Value = rx * 1024; + ActivateSensor(_pcieThroughputRx); + } + + uint? tx = NvidiaML.NvmlDeviceGetPcieThroughput(_nvmlDevice.Value, NvidiaML.NvmlPcieUtilCounter.TxBytes); + if (tx.HasValue) + { + _pcieThroughputTx.Value = tx * 1024; + ActivateSensor(_pcieThroughputTx); + } } } @@ -457,6 +516,42 @@ namespace LibreHardwareMonitor.Hardware.Gpu r.AppendLine(); } + if (NvApi.NvAPI_GPU_ClientFanCoolersGetStatus != null) + { + var coolers = new NvApi.NvFanCoolersStatus + { + Version = NvApi.GPU_FAN_COOLERS_STATUS_VER, + Items = new NvApi.NvFanCoolersStatusItem[NvApi.MAX_FAN_COOLERS_STATUS_ITEMS] + }; + + NvApi.NvStatus status = NvApi.NvAPI_GPU_ClientFanCoolersGetStatus(_handle, ref coolers); + + r.AppendLine("Fan Coolers Status"); + r.AppendLine(); + if (status == NvApi.NvStatus.OK) + { + for (int i = 0; i < coolers.Count; i++) + { + r.AppendFormat(" Items[{0}].Type: {1}{2}", i, + coolers.Items[i].Type, Environment.NewLine); + r.AppendFormat(" Items[{0}].CurrentRpm: {1}{2}", i, + coolers.Items[i].CurrentRpm, Environment.NewLine); + r.AppendFormat(" Items[{0}].CurrentMinLevel: {1}{2}", i, + coolers.Items[i].CurrentMinLevel, Environment.NewLine); + r.AppendFormat(" Items[{0}].CurrentMaxLevel: {1}{2}", i, + coolers.Items[i].CurrentMaxLevel, Environment.NewLine); + r.AppendFormat(" Items[{0}].CurrentLevel: {1}{2}", i, + coolers.Items[i].CurrentLevel, Environment.NewLine); + } + } + else + { + r.Append(" Status: "); + r.AppendLine(status.ToString()); + } + r.AppendLine(); + } + if (NvApi.NvAPI_GPU_GetMemoryInfo != null && _displayHandle.HasValue) { NvApi.NvMemoryInfo memoryInfo = new NvApi.NvMemoryInfo { Version = NvApi.GPU_MEMORY_INFO_VER, Values = new uint[NvApi.MAX_MEMORY_VALUES_PER_GPU] }; diff --git a/LibreHardwareMonitorLib/Hardware/Motherboard/Identification.cs b/LibreHardwareMonitorLib/Hardware/Motherboard/Identification.cs index 95a61b1..048a78d 100644 --- a/LibreHardwareMonitorLib/Hardware/Motherboard/Identification.cs +++ b/LibreHardwareMonitorLib/Hardware/Motherboard/Identification.cs @@ -13,52 +13,90 @@ namespace LibreHardwareMonitor.Hardware.Motherboard { switch (name) { + case var _ when name.IndexOf("abit.com.tw", StringComparison.OrdinalIgnoreCase) > -1: + return Manufacturer.Acer; + case var _ when name.StartsWith("Acer", StringComparison.OrdinalIgnoreCase): + return Manufacturer.Acer; + case var _ when name.StartsWith("AMD", StringComparison.OrdinalIgnoreCase): + return Manufacturer.AMD; case var _ when name.Equals("Alienware", StringComparison.OrdinalIgnoreCase): return Manufacturer.Alienware; - case var _ when name.Equals("Apple Inc.", StringComparison.OrdinalIgnoreCase): + case var _ when name.StartsWith("AOpen", StringComparison.OrdinalIgnoreCase): + return Manufacturer.AOpen; + case var _ when name.StartsWith("Apple", StringComparison.OrdinalIgnoreCase): return Manufacturer.Apple; case var _ when name.Equals("ASRock", StringComparison.OrdinalIgnoreCase): return Manufacturer.ASRock; - case var _ when name.Equals("ASUSTeK Computer INC.", StringComparison.OrdinalIgnoreCase): + case var _ when name.StartsWith("ASUSTeK", StringComparison.OrdinalIgnoreCase): + case var _ when name.StartsWith("ASUS ", StringComparison.OrdinalIgnoreCase): return Manufacturer.ASUS; - case var _ when name.Equals("Dell Inc.", StringComparison.OrdinalIgnoreCase): + case var _ when name.StartsWith("Biostar", StringComparison.OrdinalIgnoreCase): + return Manufacturer.Biostar; + case var _ when name.StartsWith("Clevo", StringComparison.OrdinalIgnoreCase): + return Manufacturer.Clevo; + case var _ when name.StartsWith("Dell", StringComparison.OrdinalIgnoreCase): return Manufacturer.Dell; case var _ when name.Equals("DFI", StringComparison.OrdinalIgnoreCase): - case var _ when name.Equals("DFI Inc.", StringComparison.OrdinalIgnoreCase): + case var _ when name.StartsWith("DFI Inc", StringComparison.OrdinalIgnoreCase): return Manufacturer.DFI; case var _ when name.Equals("ECS", StringComparison.OrdinalIgnoreCase): + case var _ when name.StartsWith("ELITEGROUP", StringComparison.OrdinalIgnoreCase): return Manufacturer.ECS; case var _ when name.Equals("EPoX COMPUTER CO., LTD", StringComparison.OrdinalIgnoreCase): return Manufacturer.EPoX; - case var _ when name.Equals("EVGA", StringComparison.OrdinalIgnoreCase): + case var _ when name.StartsWith("EVGA", StringComparison.OrdinalIgnoreCase): return Manufacturer.EVGA; - case var _ when name.Equals("First International Computer, Inc.", StringComparison.OrdinalIgnoreCase): + case var _ when name.Equals("FIC", StringComparison.OrdinalIgnoreCase): + case var _ when name.StartsWith("First International Computer", StringComparison.OrdinalIgnoreCase): return Manufacturer.FIC; - case var _ when name.Equals("Fujitsu", StringComparison.OrdinalIgnoreCase): - case var _ when name.Equals("Fujitsu Siemens", StringComparison.OrdinalIgnoreCase): + case var _ when name.Equals("Foxconn", StringComparison.OrdinalIgnoreCase): + return Manufacturer.Foxconn; + case var _ when name.StartsWith("Fujitsu", StringComparison.OrdinalIgnoreCase): return Manufacturer.Fujitsu; - case var _ when name.Equals("Gigabyte Technology Co., Ltd.", StringComparison.OrdinalIgnoreCase): + case var _ when name.StartsWith("Gigabyte", StringComparison.OrdinalIgnoreCase): return Manufacturer.Gigabyte; - case var _ when name.Equals("Hewlett-Packard", StringComparison.OrdinalIgnoreCase): + case var _ when name.StartsWith("Hewlett-Packard", StringComparison.OrdinalIgnoreCase): + case var _ when name.Equals("HP", StringComparison.OrdinalIgnoreCase): return Manufacturer.HP; case var _ when name.Equals("IBM", StringComparison.OrdinalIgnoreCase): return Manufacturer.IBM; case var _ when name.Equals("Intel", StringComparison.OrdinalIgnoreCase): case var _ when name.StartsWith("Intel Corp", StringComparison.OrdinalIgnoreCase): return Manufacturer.Intel; - case var _ when name.Equals("Lenovo", StringComparison.OrdinalIgnoreCase): + case var _ when name.StartsWith("Jetway", StringComparison.OrdinalIgnoreCase): + return Manufacturer.Jetway; + case var _ when name.StartsWith("Lenovo", StringComparison.OrdinalIgnoreCase): return Manufacturer.Lenovo; + case var _ when name.Equals("LattePanda", StringComparison.OrdinalIgnoreCase): + return Manufacturer.LattePanda; + case var _ when name.StartsWith("Medion", StringComparison.OrdinalIgnoreCase): + return Manufacturer.Medion; + case var _ when name.StartsWith("Microsoft", StringComparison.OrdinalIgnoreCase): + return Manufacturer.Microsoft; case var _ when name.StartsWith("Micro-Star International", StringComparison.OrdinalIgnoreCase): case var _ when name.Equals("MSI", StringComparison.OrdinalIgnoreCase): return Manufacturer.MSI; - case var _ when name.Equals("Shuttle", StringComparison.OrdinalIgnoreCase): + case var _ when name.StartsWith("NEC ", StringComparison.OrdinalIgnoreCase): + case var _ when name.Equals("NEC", StringComparison.OrdinalIgnoreCase): + return Manufacturer.NEC; + case var _ when name.StartsWith("Pegatron", StringComparison.OrdinalIgnoreCase): + return Manufacturer.Pegatron; + case var _ when name.StartsWith("Samsung", StringComparison.OrdinalIgnoreCase): + return Manufacturer.Samsung; + case var _ when name.StartsWith("Sapphire", StringComparison.OrdinalIgnoreCase): + return Manufacturer.Sapphire; + case var _ when name.StartsWith("Shuttle", StringComparison.OrdinalIgnoreCase): return Manufacturer.Shuttle; - case var _ when name.Equals("Supermicro", StringComparison.OrdinalIgnoreCase): + case var _ when name.StartsWith("Sony", StringComparison.OrdinalIgnoreCase): + return Manufacturer.Sony; + case var _ when name.StartsWith("Supermicro", StringComparison.OrdinalIgnoreCase): return Manufacturer.Supermicro; - case var _ when name.Equals("Toshiba", StringComparison.OrdinalIgnoreCase): + case var _ when name.StartsWith("Toshiba", StringComparison.OrdinalIgnoreCase): return Manufacturer.Toshiba; case var _ when name.Equals("XFX", StringComparison.OrdinalIgnoreCase): return Manufacturer.XFX; + case var _ when name.StartsWith("Zotac", StringComparison.OrdinalIgnoreCase): + return Manufacturer.Zotac; case var _ when name.Equals("To be filled by O.E.M.", StringComparison.OrdinalIgnoreCase): return Manufacturer.Unknown; default: diff --git a/LibreHardwareMonitorLib/Hardware/Motherboard/Lpc/Chip.cs b/LibreHardwareMonitorLib/Hardware/Motherboard/Lpc/Chip.cs index 8530764..e0e3f45 100644 --- a/LibreHardwareMonitorLib/Hardware/Motherboard/Lpc/Chip.cs +++ b/LibreHardwareMonitorLib/Hardware/Motherboard/Lpc/Chip.cs @@ -27,6 +27,7 @@ namespace LibreHardwareMonitor.Hardware.Motherboard.Lpc IT8620E = 0x8620, IT8628E = 0x8628, + IT8655E = 0x8655, IT8665E = 0x8665, IT8686E = 0x8686, IT8688E = 0x8688, @@ -48,6 +49,7 @@ namespace LibreHardwareMonitor.Hardware.Motherboard.Lpc NCT6779D = 0xC560, NCT6791D = 0xC803, NCT6792D = 0xC911, + NCT6792DA = 0xC913, NCT6793D = 0xD121, NCT6795D = 0xD352, NCT6796D = 0xD423, @@ -86,6 +88,7 @@ namespace LibreHardwareMonitor.Hardware.Motherboard.Lpc case Chip.IT8620E: return "ITE IT8620E"; case Chip.IT8628E: return "ITE IT8628E"; + case Chip.IT8655E: return "ITE IT8655E"; case Chip.IT8665E: return "ITE IT8665E"; case Chip.IT8686E: return "ITE IT8686E"; case Chip.IT8688E: return "ITE IT8688E"; @@ -107,6 +110,7 @@ namespace LibreHardwareMonitor.Hardware.Motherboard.Lpc case Chip.NCT6779D: return "Nuvoton NCT6779D"; case Chip.NCT6791D: return "Nuvoton NCT6791D"; case Chip.NCT6792D: return "Nuvoton NCT6792D"; + case Chip.NCT6792DA: return "Nuvoton NCT6792D-A"; case Chip.NCT6793D: return "Nuvoton NCT6793D"; case Chip.NCT6795D: return "Nuvoton NCT6795D"; case Chip.NCT6796D: return "Nuvoton NCT6796D"; @@ -124,6 +128,7 @@ namespace LibreHardwareMonitor.Hardware.Motherboard.Lpc case Chip.W83687THF: return "Winbond W83687THF"; case Chip.Unknown: return "Unkown"; + break; default: return "Unknown"; } } diff --git a/LibreHardwareMonitorLib/Hardware/Motherboard/Lpc/IT87XX.cs b/LibreHardwareMonitorLib/Hardware/Motherboard/Lpc/IT87XX.cs index c6e80a4..b3b6784 100644 --- a/LibreHardwareMonitorLib/Hardware/Motherboard/Lpc/IT87XX.cs +++ b/LibreHardwareMonitorLib/Hardware/Motherboard/Lpc/IT87XX.cs @@ -55,57 +55,73 @@ namespace LibreHardwareMonitor.Hardware.Motherboard.Lpc return; - // IT8686E has more sensors - if (chip == Chip.IT8686E) + switch (chip) { - Voltages = new float?[10]; - Temperatures = new float?[5]; - Fans = new float?[5]; - Controls = new float?[3]; - - _fansDisabled = new bool[5]; + // IT8686E has more sensors + case Chip.IT8686E: + { + Voltages = new float?[10]; + Temperatures = new float?[5]; + Fans = new float?[5]; + Controls = new float?[3]; + break; + } + case Chip.IT8665E: + { + Voltages = new float?[10]; + Temperatures = new float?[6]; + Fans = new float?[6]; + Controls = new float?[3]; + break; + } + case Chip.IT8655E: + { + Voltages = new float?[6]; + Temperatures = new float?[6]; + Fans = new float?[3]; + Controls = new float?[3]; + break; + } + case Chip.IT8688E: + { + Voltages = new float?[11]; + Temperatures = new float?[6]; + Fans = new float?[5]; + Controls = new float?[3]; + break; + } + case Chip.IT879XE: + { + Voltages = new float?[9]; + Temperatures = new float?[3]; + Fans = new float?[3]; + Controls = new float?[3]; + break; + } + case Chip.IT8705F: + { + Voltages = new float?[9]; + Temperatures = new float?[3]; + Fans = new float?[3]; + Controls = new float?[3]; + break; + } + default: + { + Voltages = new float?[9]; + Temperatures = new float?[3]; + Fans = new float?[5]; + Controls = new float?[3]; + break; + } } - else if (chip == Chip.IT8665E) - { - Voltages = new float?[10]; - Temperatures = new float?[6]; - Fans = new float?[6]; - Controls = new float?[3]; - _fansDisabled = new bool[6]; - } - else if (chip == Chip.IT8688E) - { - Voltages = new float?[11]; - Temperatures = new float?[6]; - Fans = new float?[5]; - Controls = new float?[3]; - - _fansDisabled = new bool[5]; - } - else if (chip == Chip.IT879XE) - { - Voltages = new float?[9]; - Temperatures = new float?[3]; - Fans = new float?[3]; - Controls = new float?[3]; - - _fansDisabled = new bool[3]; - } - else - { - Voltages = new float?[9]; - Temperatures = new float?[3]; - Fans = new float?[chip == Chip.IT8705F ? 3 : 5]; - Controls = new float?[3]; - - _fansDisabled = new bool[chip == Chip.IT8705F ? 3 : 5]; - } + _fansDisabled = new bool[Fans.Length]; switch (chip) { - // IT8620E, IT8628E, IT8721F, IT8728F, IT8772E and IT8686E use a 12mV resolution - // ADC, all others 16mV + // IT8620E, IT8628E, IT8721F, IT8728F, IT8772E and IT8686E use a 12mV resolution. + // All others 16mV. case Chip.IT8620E: case Chip.IT8628E: case Chip.IT8721F: @@ -117,7 +133,8 @@ namespace LibreHardwareMonitor.Hardware.Motherboard.Lpc { _voltageGain = 0.012f; break; - } + } + case Chip.IT8655E: case Chip.IT8665E: case Chip.IT879XE: { @@ -185,13 +202,7 @@ namespace LibreHardwareMonitor.Hardware.Motherboard.Lpc _gpioCount = 8; break; } - case Chip.IT8620E: - case Chip.IT8628E: - case Chip.IT8688E: - case Chip.IT8705F: - case Chip.IT8728F: - case Chip.IT8771E: - case Chip.IT8772E: + default: { _gpioCount = 0; break; diff --git a/LibreHardwareMonitorLib/Hardware/Motherboard/Lpc/LPcPort.cs b/LibreHardwareMonitorLib/Hardware/Motherboard/Lpc/LPcPort.cs index 8b69d80..d1990ba 100644 --- a/LibreHardwareMonitorLib/Hardware/Motherboard/Lpc/LPcPort.cs +++ b/LibreHardwareMonitorLib/Hardware/Motherboard/Lpc/LPcPort.cs @@ -73,8 +73,12 @@ namespace LibreHardwareMonitor.Hardware.Motherboard.Lpc public void IT87Exit() { - Ring0.WriteIoPort(RegisterPort, CONFIGURATION_CONTROL_REGISTER); - Ring0.WriteIoPort(ValuePort, 0x02); + // Do not exit config mode for secondary super IO. + if (RegisterPort != 0x4E) + { + Ring0.WriteIoPort(RegisterPort, CONFIGURATION_CONTROL_REGISTER); + Ring0.WriteIoPort(ValuePort, 0x02); + } } public void SmscEnter() diff --git a/LibreHardwareMonitorLib/Hardware/Motherboard/Lpc/LpcIO.cs b/LibreHardwareMonitorLib/Hardware/Motherboard/Lpc/LpcIO.cs index b4c4bb6..dbd63e6 100644 --- a/LibreHardwareMonitorLib/Hardware/Motherboard/Lpc/LpcIO.cs +++ b/LibreHardwareMonitorLib/Hardware/Motherboard/Lpc/LpcIO.cs @@ -113,272 +113,386 @@ namespace LibreHardwareMonitor.Hardware.Motherboard.Lpc switch (id) { case 0x05: + { switch (revision) { case 0x07: + { chip = Chip.F71858; logicalDeviceNumber = F71858_HARDWARE_MONITOR_LDN; break; + } case 0x41: + { chip = Chip.F71882; logicalDeviceNumber = FINTEK_HARDWARE_MONITOR_LDN; break; + } } break; + } case 0x06: + { switch (revision) { case 0x01: + { chip = Chip.F71862; logicalDeviceNumber = FINTEK_HARDWARE_MONITOR_LDN; break; + } } break; + } case 0x07: + { switch (revision) { case 0x23: + { chip = Chip.F71889F; logicalDeviceNumber = FINTEK_HARDWARE_MONITOR_LDN; break; + } } break; + } case 0x08: + { switch (revision) { case 0x14: + { chip = Chip.F71869; logicalDeviceNumber = FINTEK_HARDWARE_MONITOR_LDN; break; + } } break; + } case 0x09: + { switch (revision) { case 0x01: + { chip = Chip.F71808E; logicalDeviceNumber = FINTEK_HARDWARE_MONITOR_LDN; break; + } case 0x09: + { chip = Chip.F71889ED; logicalDeviceNumber = FINTEK_HARDWARE_MONITOR_LDN; break; + } } break; + } case 0x10: + { switch (revision) { case 0x05: + { chip = Chip.F71889AD; logicalDeviceNumber = FINTEK_HARDWARE_MONITOR_LDN; break; + } case 0x07: + { chip = Chip.F71869A; logicalDeviceNumber = FINTEK_HARDWARE_MONITOR_LDN; break; + } } break; + } case 0x11: + { switch (revision) { case 0x06: + { chip = Chip.F71878AD; logicalDeviceNumber = FINTEK_HARDWARE_MONITOR_LDN; break; + } } break; + } case 0x52: + { switch (revision) { case 0x17: case 0x3A: case 0x41: + { chip = Chip.W83627HF; logicalDeviceNumber = WINBOND_NUVOTON_HARDWARE_MONITOR_LDN; break; + } } break; + } case 0x82: + { switch (revision & 0xF0) { case 0x80: + { chip = Chip.W83627THF; logicalDeviceNumber = WINBOND_NUVOTON_HARDWARE_MONITOR_LDN; break; + } } break; + } case 0x85: + { switch (revision) { case 0x41: + { chip = Chip.W83687THF; logicalDeviceNumber = WINBOND_NUVOTON_HARDWARE_MONITOR_LDN; break; + } } break; + } case 0x88: + { switch (revision & 0xF0) { case 0x50: case 0x60: + { chip = Chip.W83627EHF; logicalDeviceNumber = WINBOND_NUVOTON_HARDWARE_MONITOR_LDN; break; + } } break; + } case 0xA0: + { switch (revision & 0xF0) { case 0x20: + { chip = Chip.W83627DHG; logicalDeviceNumber = WINBOND_NUVOTON_HARDWARE_MONITOR_LDN; break; + } } break; + } case 0xA5: + { switch (revision & 0xF0) { case 0x10: + { chip = Chip.W83667HG; logicalDeviceNumber = WINBOND_NUVOTON_HARDWARE_MONITOR_LDN; break; + } } break; + } case 0xB0: + { switch (revision & 0xF0) { case 0x70: + { chip = Chip.W83627DHGP; logicalDeviceNumber = WINBOND_NUVOTON_HARDWARE_MONITOR_LDN; break; + } } break; + } case 0xB3: + { switch (revision & 0xF0) { case 0x50: + { chip = Chip.W83667HGB; logicalDeviceNumber = WINBOND_NUVOTON_HARDWARE_MONITOR_LDN; break; + } } break; + } case 0xB4: + { switch (revision & 0xF0) { case 0x70: + { chip = Chip.NCT6771F; logicalDeviceNumber = WINBOND_NUVOTON_HARDWARE_MONITOR_LDN; break; + } } break; + } case 0xC3: + { switch (revision & 0xF0) { case 0x30: + { chip = Chip.NCT6776F; logicalDeviceNumber = WINBOND_NUVOTON_HARDWARE_MONITOR_LDN; break; + } } break; + } case 0xC4: + { switch (revision & 0xF0) { case 0x50: + { chip = Chip.NCT610XD; logicalDeviceNumber = WINBOND_NUVOTON_HARDWARE_MONITOR_LDN; break; + } } break; + } case 0xC5: + { switch (revision & 0xF0) { case 0x60: + { chip = Chip.NCT6779D; logicalDeviceNumber = WINBOND_NUVOTON_HARDWARE_MONITOR_LDN; break; + } } break; + } case 0xC8: + { switch (revision) { case 0x03: + { chip = Chip.NCT6791D; logicalDeviceNumber = WINBOND_NUVOTON_HARDWARE_MONITOR_LDN; break; + } } break; + } case 0xC9: + { switch (revision) { case 0x11: + { chip = Chip.NCT6792D; logicalDeviceNumber = WINBOND_NUVOTON_HARDWARE_MONITOR_LDN; break; + } + case 0x13: + { + chip = Chip.NCT6792DA; + logicalDeviceNumber = WINBOND_NUVOTON_HARDWARE_MONITOR_LDN; + break; + } } break; + } case 0xD1: + { switch (revision) { case 0x21: + { chip = Chip.NCT6793D; logicalDeviceNumber = WINBOND_NUVOTON_HARDWARE_MONITOR_LDN; break; + } } break; + } case 0xD3: + { switch (revision) { case 0x52: + { chip = Chip.NCT6795D; logicalDeviceNumber = WINBOND_NUVOTON_HARDWARE_MONITOR_LDN; break; + } } break; + } case 0xD4: + { switch (revision) { case 0x23: + { chip = Chip.NCT6796D; logicalDeviceNumber = WINBOND_NUVOTON_HARDWARE_MONITOR_LDN; break; + } case 0x2A: + { chip = Chip.NCT6796DR; logicalDeviceNumber = WINBOND_NUVOTON_HARDWARE_MONITOR_LDN; break; + } case 0x51: + { chip = Chip.NCT6797D; logicalDeviceNumber = WINBOND_NUVOTON_HARDWARE_MONITOR_LDN; break; + } case 0x2B: + { chip = Chip.NCT6798D; logicalDeviceNumber = WINBOND_NUVOTON_HARDWARE_MONITOR_LDN; break; + } } break; + } } if (chip == Chip.Unknown) @@ -453,6 +567,7 @@ namespace LibreHardwareMonitor.Hardware.Motherboard.Lpc case Chip.NCT6779D: case Chip.NCT6791D: case Chip.NCT6792D: + case Chip.NCT6792DA: case Chip.NCT6793D: case Chip.NCT6795D: case Chip.NCT6796D: diff --git a/LibreHardwareMonitorLib/Hardware/Motherboard/Lpc/Nct677X.cs b/LibreHardwareMonitorLib/Hardware/Motherboard/Lpc/Nct677X.cs index 7867d1b..5de65cc 100644 --- a/LibreHardwareMonitorLib/Hardware/Motherboard/Lpc/Nct677X.cs +++ b/LibreHardwareMonitorLib/Hardware/Motherboard/Lpc/Nct677X.cs @@ -125,6 +125,7 @@ namespace LibreHardwareMonitor.Hardware.Motherboard.Lpc case Chip.NCT6779D: case Chip.NCT6791D: case Chip.NCT6792D: + case Chip.NCT6792DA: case Chip.NCT6793D: case Chip.NCT6795D: case Chip.NCT6796D: @@ -535,7 +536,7 @@ namespace LibreHardwareMonitor.Hardware.Motherboard.Lpc private void DisableIOSpaceLock() { - if (Chip != Chip.NCT6791D && Chip != Chip.NCT6796D && Chip != Chip.NCT6796DR && Chip != Chip.NCT6793D && Chip != Chip.NCT6795D && Chip != Chip.NCT6798D && Chip != Chip.NCT6797D) + if (Chip != Chip.NCT6791D && Chip != Chip.NCT6796D && Chip != Chip.NCT6792DA && Chip != Chip.NCT6796DR && Chip != Chip.NCT6793D && Chip != Chip.NCT6795D && Chip != Chip.NCT6798D && Chip != Chip.NCT6797D) return; diff --git a/LibreHardwareMonitorLib/Hardware/Motherboard/Manufacturer.cs b/LibreHardwareMonitorLib/Hardware/Motherboard/Manufacturer.cs index 1393dd4..a3ce4b8 100644 --- a/LibreHardwareMonitorLib/Hardware/Motherboard/Manufacturer.cs +++ b/LibreHardwareMonitorLib/Hardware/Motherboard/Manufacturer.cs @@ -12,27 +12,45 @@ namespace LibreHardwareMonitor.Hardware.Motherboard [SuppressMessage("ReSharper", "InconsistentNaming")] internal enum Manufacturer { + Abit, + Acer, Alienware, + AMD, + AOpen, Apple, ASRock, ASUS, + Biostar, + Clevo, Dell, DFI, ECS, EPoX, EVGA, FIC, + Foxconn, Fujitsu, + Gateway, Gigabyte, HP, IBM, Intel, + Jetway, + LattePanda, Lenovo, + Medion, + Microsoft, MSI, + NEC, + Pegatron, + Samsung, + Sapphire, Shuttle, + Sony, Supermicro, Toshiba, XFX, + Zotac, Unknown } } diff --git a/LibreHardwareMonitorLib/Hardware/Motherboard/SuperIOHardware.cs b/LibreHardwareMonitorLib/Hardware/Motherboard/SuperIOHardware.cs index e1f1835..cdc2458 100644 --- a/LibreHardwareMonitorLib/Hardware/Motherboard/SuperIOHardware.cs +++ b/LibreHardwareMonitorLib/Hardware/Motherboard/SuperIOHardware.cs @@ -223,6 +223,7 @@ namespace LibreHardwareMonitor.Hardware.Motherboard case Chip.IT8720F: case Chip.IT8726F: case Chip.IT8665E: + case Chip.IT8655E: case Chip.IT8686E: case Chip.IT879XE: { diff --git a/LibreHardwareMonitorLib/Hardware/Storage/SmartNames.cs b/LibreHardwareMonitorLib/Hardware/Storage/SmartNames.cs index c463de2..3030113 100644 --- a/LibreHardwareMonitorLib/Hardware/Storage/SmartNames.cs +++ b/LibreHardwareMonitorLib/Hardware/Storage/SmartNames.cs @@ -60,6 +60,8 @@ namespace LibreHardwareMonitor.Hardware.Storage public static string EraseFailure => "Erase Failure"; + public static string ErrorCorrectionCount => "Error Correction Count"; + public static string ExceptionModeStatus => "Exception Mode Status"; public static string FactoryBadBlockCount => "Factory Bad Block Count"; @@ -68,6 +70,8 @@ namespace LibreHardwareMonitor.Hardware.Storage public static string FreeFallProtection => "Free Fall Protection"; + public static string FTLProgramNANDPagesCount => "FTL Program NAND Pages Count"; + public static string GmrHeadAmplitude => "GMR Head Amplitude"; public static string GSenseErrorRate => "G-sense Error Rate"; @@ -80,6 +84,8 @@ namespace LibreHardwareMonitor.Hardware.Storage public static string HighFlyWrites => "High Fly Writes"; + public static string HostProgramNANDPagesCount => "Host Program NAND Pages Count"; + public static string HostReads => "Host Reads"; public static string HostWrites => "Host Writes"; @@ -150,6 +156,8 @@ namespace LibreHardwareMonitor.Hardware.Storage public static string ReadFailure => "Read Failure"; + public static string ReallocatedNANDBlockCount => "Reallocated NAND Block Count"; + public static string ReallocatedSectorsCount => "Reallocated Sectors Count"; public static string ReallocationEventCount => "Reallocation Event Count"; @@ -196,6 +204,8 @@ namespace LibreHardwareMonitor.Hardware.Storage public static string StartStopCount => "Start/Stop Count"; + public static string SuccessfulRAINRecoveryCount => "Successful RAIN Recovery Count"; + public static string SupercapStatus => "Supercap Status"; public static string TaCounterDetected => "TA Counter Detected"; @@ -234,6 +244,8 @@ namespace LibreHardwareMonitor.Hardware.Storage public static string UnsafeShutdownCount => "Unsafe Shutdown Count"; + public static string UnusedReserveNANDBlocks => "Unused Reserve NAND Blocks"; + public static string UsedReservedBlockCountChip => "Used Reserved Block Count (Chip)"; public static string UsedReservedBlockCountTotal => "Used Reserved Block Count (Total)"; diff --git a/LibreHardwareMonitorLib/Hardware/Storage/SsdIndilinx.cs b/LibreHardwareMonitorLib/Hardware/Storage/SsdIndilinx.cs index 584616e..06e3c2e 100644 --- a/LibreHardwareMonitorLib/Hardware/Storage/SsdIndilinx.cs +++ b/LibreHardwareMonitorLib/Hardware/Storage/SsdIndilinx.cs @@ -37,6 +37,7 @@ namespace LibreHardwareMonitor.Hardware.Storage }; public SsdIndilinx(StorageInfo storageInfo, ISmart smart, string name, string firmwareRevision, int index, ISettings settings) - : base(storageInfo, smart, name, firmwareRevision, "ssd", index, _smartAttributes, settings) { } + : base(storageInfo, smart, name, firmwareRevision, "ssd", index, _smartAttributes, settings) + { } } } diff --git a/LibreHardwareMonitorLib/Hardware/Storage/SsdIntel.cs b/LibreHardwareMonitorLib/Hardware/Storage/SsdIntel.cs index 6858a5a..4da6103 100644 --- a/LibreHardwareMonitorLib/Hardware/Storage/SsdIntel.cs +++ b/LibreHardwareMonitorLib/Hardware/Storage/SsdIntel.cs @@ -21,11 +21,20 @@ namespace LibreHardwareMonitor.Hardware.Storage new SmartAttribute(0xAA, SmartNames.AvailableReservedSpace), new SmartAttribute(0xAB, SmartNames.ProgramFailCount), new SmartAttribute(0xAC, SmartNames.EraseFailCount), + new SmartAttribute(0xAE, SmartNames.UnexpectedPowerLossCount, RawToInt), + new SmartAttribute(0xB7, SmartNames.SataDownshiftErrorCount, RawToInt), new SmartAttribute(0xB8, SmartNames.EndToEndError), - new SmartAttribute(0xBE, SmartNames.Temperature, (r, v, p) => r[0] + (p?[0].Value ?? 0), - SensorType.Temperature, 0, SmartNames.AirflowTemperature, false, - new[] { new ParameterDescription("Offset [°C]", "Temperature offset of the thermal sensor.\nTemperature = Value + Offset.", 0) }), + new SmartAttribute(0xBB, SmartNames.UncorrectableErrorCount, RawToInt), + new SmartAttribute(0xBE, + SmartNames.Temperature, + (r, v, p) => r[0] + (p?[0].Value ?? 0), + SensorType.Temperature, + 0, + SmartNames.AirflowTemperature, + false, + new[] { new ParameterDescription("Offset [°C]", "Temperature offset of the thermal sensor.\nTemperature = Value + Offset.", 0) }), new SmartAttribute(0xC0, SmartNames.UnsafeShutdownCount), + new SmartAttribute(0xC7, SmartNames.CrcErrorCount, RawToInt), new SmartAttribute(0xE1, SmartNames.HostWrites, (r, v, p) => RawToInt(r, v, p) / 0x20, SensorType.Data, 0, SmartNames.HostWrites), new SmartAttribute(0xE8, SmartNames.RemainingLife, null, SensorType.Level, 0, SmartNames.RemainingLife), new SmartAttribute(0xE9, SmartNames.MediaWearOutIndicator), @@ -34,6 +43,7 @@ namespace LibreHardwareMonitor.Hardware.Storage }; public SsdIntel(StorageInfo storageInfo, ISmart smart, string name, string firmwareRevision, int index, ISettings settings) - : base(storageInfo, smart, name, firmwareRevision, "ssd", index, _smartAttributes, settings) { } + : base(storageInfo, smart, name, firmwareRevision, "ssd", index, _smartAttributes, settings) + { } } } diff --git a/LibreHardwareMonitorLib/Hardware/Storage/SsdMicron.cs b/LibreHardwareMonitorLib/Hardware/Storage/SsdMicron.cs index 8dd4394..84a1e30 100644 --- a/LibreHardwareMonitorLib/Hardware/Storage/SsdMicron.cs +++ b/LibreHardwareMonitorLib/Hardware/Storage/SsdMicron.cs @@ -4,16 +4,17 @@ // All Rights Reserved using System.Collections.Generic; +using LibreHardwareMonitor.Interop; namespace LibreHardwareMonitor.Hardware.Storage { - [NamePrefix(""), RequireSmart(0xAA), RequireSmart(0xAB), RequireSmart(0xAC), RequireSmart(0xAD), RequireSmart(0xAE), RequireSmart(0xCA)] + [NamePrefix(""), RequireSmart(0xAB), RequireSmart(0xAC), RequireSmart(0xAD), RequireSmart(0xAE), RequireSmart(0xC4), RequireSmart(0xCA), RequireSmart(0xCE)] internal class SsdMicron : AtaStorage { private static readonly IReadOnlyList _smartAttributes = new List { new SmartAttribute(0x01, SmartNames.ReadErrorRate, RawToInt), - new SmartAttribute(0x05, SmartNames.ReallocatedSectorsCount, RawToInt), + new SmartAttribute(0x05, SmartNames.ReallocatedNANDBlockCount, RawToInt), new SmartAttribute(0x09, SmartNames.PowerOnHours, RawToInt), new SmartAttribute(0x0C, SmartNames.PowerCycleCount, RawToInt), new SmartAttribute(0xAA, SmartNames.NewFailingBlockCount, RawToInt), @@ -21,20 +22,93 @@ namespace LibreHardwareMonitor.Hardware.Storage new SmartAttribute(0xAC, SmartNames.EraseFailCount, RawToInt), new SmartAttribute(0xAD, SmartNames.WearLevelingCount, RawToInt), new SmartAttribute(0xAE, SmartNames.UnexpectedPowerLossCount, RawToInt), + new SmartAttribute(0xB4, SmartNames.UnusedReserveNANDBlocks, RawToInt), new SmartAttribute(0xB5, SmartNames.Non4KAlignedAccess, (raw, value, p) => 6e4f * ((raw[5] << 8) | raw[4])), new SmartAttribute(0xB7, SmartNames.SataDownshiftErrorCount, RawToInt), + new SmartAttribute(0xB8, SmartNames.ErrorCorrectionCount, RawToInt), new SmartAttribute(0xBB, SmartNames.ReportedUncorrectableErrors, RawToInt), new SmartAttribute(0xBC, SmartNames.CommandTimeout, RawToInt), new SmartAttribute(0xBD, SmartNames.FactoryBadBlockCount, RawToInt), + new SmartAttribute(0xC2, SmartNames.Temperature, RawToInt), new SmartAttribute(0xC4, SmartNames.ReallocationEventCount, RawToInt), new SmartAttribute(0xC5, SmartNames.CurrentPendingSectorCount), new SmartAttribute(0xC6, SmartNames.OffLineUncorrectableErrorCount, RawToInt), new SmartAttribute(0xC7, SmartNames.UltraDmaCrcErrorCount, RawToInt), new SmartAttribute(0xCA, SmartNames.RemainingLife, (raw, value, p) => 100 - RawToInt(raw, value, p), SensorType.Level, 0, SmartNames.RemainingLife), - new SmartAttribute(0xCE, SmartNames.WriteErrorRate, (raw, value, p) => 6e4f * ((raw[1] << 8) | raw[0])) + new SmartAttribute(0xCE, SmartNames.WriteErrorRate, (raw, value, p) => 6e4f * ((raw[1] << 8) | raw[0])), + new SmartAttribute(0xD2, SmartNames.SuccessfulRAINRecoveryCount, RawToInt), + new SmartAttribute(0xF6, + SmartNames.TotalLbasWritten, + (r, v, p) => (((long)r[5] << 40) | + ((long)r[4] << 32) | + ((long)r[3] << 24) | + ((long)r[2] << 16) | + ((long)r[1] << 8) | + r[0]) * + (512.0f / 1024 / 1024 / 1024), + SensorType.Data, + 0, + "Total Bytes Written"), + new SmartAttribute(0xF7, SmartNames.HostProgramNANDPagesCount, RawToInt), + new SmartAttribute(0xF8, SmartNames.FTLProgramNANDPagesCount, RawToInt) }; + private readonly Sensor _temperature; + private readonly Sensor _writeAmplification; + public SsdMicron(StorageInfo storageInfo, ISmart smart, string name, string firmwareRevision, int index, ISettings settings) - : base(storageInfo, smart, name, firmwareRevision, "ssd", index, _smartAttributes, settings) { } + : base(storageInfo, smart, name, firmwareRevision, "ssd", index, _smartAttributes, settings) + { + _temperature = new Sensor("Temperature", + 0, + false, + SensorType.Temperature, + this, + new[] + { + new ParameterDescription("Offset [°C]", + "Temperature offset of the thermal sensor.\n" + + "Temperature = Value + Offset.", + 0) + }, + settings); + + _writeAmplification = new Sensor("Write Amplification", + 0, + SensorType.Factor, + this, + settings); + } + + /// + protected override void UpdateAdditionalSensors(Kernel32.SMART_ATTRIBUTE[] values) + { + float? hostProgramPagesCount = null; + float? ftlProgramPagesCount = null; + + foreach (Kernel32.SMART_ATTRIBUTE value in values) + { + if (value.Id == 0xF7) + hostProgramPagesCount = RawToInt(value.RawValue, value.CurrentValue, null); + + if (value.Id == 0xF8) + ftlProgramPagesCount = RawToInt(value.RawValue, value.CurrentValue, null); + + if (value.Id == 0xC2) + { + _temperature.Value = value.RawValue[0] + _temperature.Parameters[0].Value; + + if (value.RawValue[0] != 0) + ActivateSensor(_temperature); + } + } + + if (hostProgramPagesCount.HasValue && ftlProgramPagesCount.HasValue) + { + _writeAmplification.Value = hostProgramPagesCount.Value > 0 ? (hostProgramPagesCount.Value + ftlProgramPagesCount) / hostProgramPagesCount.Value : 0; + + ActivateSensor(_writeAmplification); + } + } } } diff --git a/LibreHardwareMonitorLib/Hardware/Storage/SsdPlextor.cs b/LibreHardwareMonitorLib/Hardware/Storage/SsdPlextor.cs index 97e5ca9..a67ea70 100644 --- a/LibreHardwareMonitorLib/Hardware/Storage/SsdPlextor.cs +++ b/LibreHardwareMonitorLib/Hardware/Storage/SsdPlextor.cs @@ -19,7 +19,8 @@ namespace LibreHardwareMonitor.Hardware.Storage }; public SsdPlextor(StorageInfo storageInfo, ISmart smart, string name, string firmwareRevision, int index, ISettings settings) - : base(storageInfo, smart, name, firmwareRevision, "ssd", index, _smartAttributes, settings) { } + : base(storageInfo, smart, name, firmwareRevision, "ssd", index, _smartAttributes, settings) + { } private static float RawToGb(byte[] rawValue, byte value, IReadOnlyList parameters) { diff --git a/LibreHardwareMonitorLib/Hardware/Storage/SsdSamsung.cs b/LibreHardwareMonitorLib/Hardware/Storage/SsdSamsung.cs index 2655bc0..7e16d0f 100644 --- a/LibreHardwareMonitorLib/Hardware/Storage/SsdSamsung.cs +++ b/LibreHardwareMonitorLib/Hardware/Storage/SsdSamsung.cs @@ -27,8 +27,14 @@ namespace LibreHardwareMonitor.Hardware.Storage new SmartAttribute(0xB6, SmartNames.EraseFailCountTotal, RawToInt), new SmartAttribute(0xB7, SmartNames.RuntimeBadBlockTotal, RawToInt), new SmartAttribute(0xBB, SmartNames.UncorrectableErrorCount, RawToInt), - new SmartAttribute(0xBE, SmartNames.Temperature, (r, v, p) => r[0] + (p?[0].Value ?? 0), SensorType.Temperature, 0, SmartNames.Temperature, false, - new[] { new ParameterDescription("Offset [°C]", "Temperature offset of the thermal sensor.\nTemperature = Value + Offset.", 0) }), + new SmartAttribute(0xBE, + SmartNames.Temperature, + (r, v, p) => r[0] + (p?[0].Value ?? 0), + SensorType.Temperature, + 0, + SmartNames.Temperature, + false, + new[] { new ParameterDescription("Offset [°C]", "Temperature offset of the thermal sensor.\nTemperature = Value + Offset.", 0) }), new SmartAttribute(0xC2, SmartNames.AirflowTemperature), new SmartAttribute(0xC3, SmartNames.EccRate), new SmartAttribute(0xC6, SmartNames.OffLineUncorrectableErrorCount, RawToInt), @@ -36,11 +42,16 @@ namespace LibreHardwareMonitor.Hardware.Storage new SmartAttribute(0xC9, SmartNames.SupercapStatus), new SmartAttribute(0xCA, SmartNames.ExceptionModeStatus), new SmartAttribute(0xEB, SmartNames.PowerRecoveryCount), - new SmartAttribute(0xF1, SmartNames.TotalLbasWritten, (r, v, p) => (((long) r[5] << 40) | ((long) r[4] << 32) | ((long) r[3] << 24) | ((long) r[2] << 16) | ((long) r[1] << 8) | r[0]) * (512.0f / 1024 / 1024 / 1024), - SensorType.Data, 0, "Total Bytes Written") + new SmartAttribute(0xF1, + SmartNames.TotalLbasWritten, + (r, v, p) => (((long)r[5] << 40) | ((long)r[4] << 32) | ((long)r[3] << 24) | ((long)r[2] << 16) | ((long)r[1] << 8) | r[0]) * (512.0f / 1024 / 1024 / 1024), + SensorType.Data, + 0, + "Total Bytes Written") }; public SsdSamsung(StorageInfo storageInfo, ISmart smart, string name, string firmwareRevision, int index, ISettings settings) - : base(storageInfo, smart, name, firmwareRevision, "ssd", index, _smartAttributes, settings) { } + : base(storageInfo, smart, name, firmwareRevision, "ssd", index, _smartAttributes, settings) + { } } } diff --git a/LibreHardwareMonitorLib/Hardware/Storage/SsdSandforce.cs b/LibreHardwareMonitorLib/Hardware/Storage/SsdSandforce.cs index b8359fe..78f0a62 100644 --- a/LibreHardwareMonitorLib/Hardware/Storage/SsdSandforce.cs +++ b/LibreHardwareMonitorLib/Hardware/Storage/SsdSandforce.cs @@ -24,8 +24,14 @@ namespace LibreHardwareMonitor.Hardware.Storage new SmartAttribute(0xB5, SmartNames.AlternativeProgramFailCount, RawToInt), new SmartAttribute(0xB6, SmartNames.AlternativeEraseFailCount, RawToInt), new SmartAttribute(0xBB, SmartNames.UncorrectableErrorCount, RawToInt), - new SmartAttribute(0xC2, SmartNames.Temperature, (raw, value, p) => value + (p?[0].Value ?? 0), SensorType.Temperature, 0, SmartNames.Temperature, true, - new[] { new ParameterDescription("Offset [°C]", "Temperature offset of the thermal sensor.\nTemperature = Value + Offset.", 0) }), + new SmartAttribute(0xC2, + SmartNames.Temperature, + (raw, value, p) => value + (p?[0].Value ?? 0), + SensorType.Temperature, + 0, + SmartNames.Temperature, + true, + new[] { new ParameterDescription("Offset [°C]", "Temperature offset of the thermal sensor.\nTemperature = Value + Offset.", 0) }), new SmartAttribute(0xC3, SmartNames.UnrecoverableEcc), new SmartAttribute(0xC4, SmartNames.ReallocationEventCount, RawToInt), new SmartAttribute(0xE7, SmartNames.RemainingLife, null, SensorType.Level, 0, SmartNames.RemainingLife), diff --git a/LibreHardwareMonitorLib/Interop/NvApi.cs b/LibreHardwareMonitorLib/Interop/NvApi.cs index d0062e1..c7a2768 100644 --- a/LibreHardwareMonitorLib/Interop/NvApi.cs +++ b/LibreHardwareMonitorLib/Interop/NvApi.cs @@ -15,6 +15,7 @@ namespace LibreHardwareMonitor.Interop { public const int MAX_CLOCKS_PER_GPU = 0x120; public const int MAX_COOLER_PER_GPU = 20; + public const int MAX_FAN_COOLERS_STATUS_ITEMS = 32; public const int MAX_MEMORY_VALUES_PER_GPU = 5; public const int MAX_PHYSICAL_GPUS = 64; public const int MAX_PSTATES_PER_GPU = 8; @@ -30,71 +31,27 @@ namespace LibreHardwareMonitor.Interop public static readonly uint GPU_PSTATES_VER = (uint)Marshal.SizeOf(typeof(NvPStates)) | 0x10000; public static readonly uint GPU_THERMAL_SETTINGS_VER = (uint)Marshal.SizeOf(typeof(NvGPUThermalSettings)) | 0x10000; public static readonly uint GPU_USAGES_VER = (uint)Marshal.SizeOf(typeof(NvUsages)) | 0x10000; + public static readonly uint GPU_FAN_COOLERS_STATUS_VER = (uint)Marshal.SizeOf(typeof(NvFanCoolersStatus)) | 0x10000; public static readonly NvAPI_EnumNvidiaDisplayHandleDelegate NvAPI_EnumNvidiaDisplayHandle; public static readonly NvAPI_EnumPhysicalGPUsDelegate NvAPI_EnumPhysicalGPUs; public static readonly NvAPI_GetDisplayDriverVersionDelegate NvAPI_GetDisplayDriverVersion; public static readonly NvAPI_GetPhysicalGPUsFromDisplayDelegate NvAPI_GetPhysicalGPUsFromDisplay; public static readonly NvAPI_GPU_GetAllClocksDelegate NvAPI_GPU_GetAllClocks; + public static readonly NvAPI_GPU_GetBusIdDelegate NvAPI_GPU_GetBusId; public static readonly NvAPI_GPU_GetCoolerSettingsDelegate NvAPI_GPU_GetCoolerSettings; public static readonly NvAPI_GPU_GetMemoryInfoDelegate NvAPI_GPU_GetMemoryInfo; public static readonly NvAPI_GPU_GetPCIIdentifiersDelegate NvAPI_GPU_GetPCIIdentifiers; public static readonly NvAPI_GPU_GetPStatesDelegate NvAPI_GPU_GetPStates; public static readonly NvAPI_GPU_GetTachReadingDelegate NvAPI_GPU_GetTachReading; - public static readonly NvAPI_GPU_GetBusIdDelegate NvAPI_GPU_GetBusId; - public static readonly NvAPI_GPU_GetThermalSettingsDelegate NvAPI_GPU_GetThermalSettings; public static readonly NvAPI_GPU_GetUsagesDelegate NvAPI_GPU_GetUsages; public static readonly NvAPI_GPU_SetCoolerLevelsDelegate NvAPI_GPU_SetCoolerLevels; + public static readonly NvAPI_GPU_ClientFanCoolersGetStatusDelegate NvAPI_GPU_ClientFanCoolersGetStatus; private static readonly NvAPI_GetInterfaceVersionStringDelegate _nvAPI_GetInterfaceVersionString; private static readonly NvAPI_GPU_GetFullNameDelegate _nvAPI_GPU_GetFullName; - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - public delegate NvStatus NvAPI_EnumNvidiaDisplayHandleDelegate(int thisEnum, ref NvDisplayHandle displayHandle); - - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - public delegate NvStatus NvAPI_EnumPhysicalGPUsDelegate([Out] NvPhysicalGpuHandle[] gpuHandles, out int gpuCount); - - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - public delegate NvStatus NvAPI_GetDisplayDriverVersionDelegate(NvDisplayHandle displayHandle, [In, Out] ref NvDisplayDriverVersion nvDisplayDriverVersion); - - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - public delegate NvStatus NvAPI_GetInterfaceVersionStringDelegate(StringBuilder version); - - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - public delegate NvStatus NvAPI_GetPhysicalGPUsFromDisplayDelegate(NvDisplayHandle displayHandle, [Out] NvPhysicalGpuHandle[] gpuHandles, out uint gpuCount); - - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - public delegate NvStatus NvAPI_GPU_GetAllClocksDelegate(NvPhysicalGpuHandle gpuHandle, ref NvClocks nvClocks); - - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - public delegate NvStatus NvAPI_GPU_GetCoolerSettingsDelegate(NvPhysicalGpuHandle gpuHandle, int coolerIndex, ref NvGPUCoolerSettings nvGPUCoolerSettings); - - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - public delegate NvStatus NvAPI_GPU_GetMemoryInfoDelegate(NvDisplayHandle displayHandle, ref NvMemoryInfo nvMemoryInfo); - - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - public delegate NvStatus NvAPI_GPU_GetPCIIdentifiersDelegate(NvPhysicalGpuHandle gpuHandle, out uint deviceId, out uint subSystemId, out uint revisionId, out uint extDeviceId); - - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - public delegate NvStatus NvAPI_GPU_GetPStatesDelegate(NvPhysicalGpuHandle gpuHandle, ref NvPStates nvPStates); - - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - public delegate NvStatus NvAPI_GPU_GetTachReadingDelegate(NvPhysicalGpuHandle gpuHandle, out int value); - - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - public delegate NvStatus NvAPI_GPU_GetThermalSettingsDelegate(NvPhysicalGpuHandle gpuHandle, int sensorIndex, ref NvGPUThermalSettings nvGPUThermalSettings); - - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - public delegate NvStatus NvAPI_GPU_GetUsagesDelegate(NvPhysicalGpuHandle gpuHandle, ref NvUsages nvUsages); - - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - public delegate NvStatus NvAPI_GPU_SetCoolerLevelsDelegate(NvPhysicalGpuHandle gpuHandle, int coolerIndex, ref NvGPUCoolerLevels NvGPUCoolerLevels); - - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - public delegate NvStatus NvAPI_GPU_GetBusIdDelegate(NvPhysicalGpuHandle gpuHandle, out uint busId); - static NvApi() { NvAPI_InitializeDelegate nvApiInitialize; @@ -134,11 +91,60 @@ namespace LibreHardwareMonitor.Interop GetDelegate(0x01053FA5, out _nvAPI_GetInterfaceVersionString); GetDelegate(0x2DDFB66E, out NvAPI_GPU_GetPCIIdentifiers); GetDelegate(0x1BE0B8E5, out NvAPI_GPU_GetBusId); + GetDelegate(0x35AED5E8, out NvAPI_GPU_ClientFanCoolersGetStatus); IsAvailable = true; } } + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] + public delegate NvStatus NvAPI_EnumNvidiaDisplayHandleDelegate(int thisEnum, ref NvDisplayHandle displayHandle); + + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] + public delegate NvStatus NvAPI_EnumPhysicalGPUsDelegate([Out] NvPhysicalGpuHandle[] gpuHandles, out int gpuCount); + + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] + public delegate NvStatus NvAPI_GetDisplayDriverVersionDelegate(NvDisplayHandle displayHandle, [In, Out] ref NvDisplayDriverVersion nvDisplayDriverVersion); + + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] + public delegate NvStatus NvAPI_GetInterfaceVersionStringDelegate(StringBuilder version); + + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] + public delegate NvStatus NvAPI_GetPhysicalGPUsFromDisplayDelegate(NvDisplayHandle displayHandle, [Out] NvPhysicalGpuHandle[] gpuHandles, out uint gpuCount); + + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] + public delegate NvStatus NvAPI_GPU_GetAllClocksDelegate(NvPhysicalGpuHandle gpuHandle, ref NvClocks nvClocks); + + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] + public delegate NvStatus NvAPI_GPU_GetBusIdDelegate(NvPhysicalGpuHandle gpuHandle, out uint busId); + + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] + public delegate NvStatus NvAPI_GPU_GetCoolerSettingsDelegate(NvPhysicalGpuHandle gpuHandle, int coolerIndex, ref NvGPUCoolerSettings nvGPUCoolerSettings); + + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] + public delegate NvStatus NvAPI_GPU_GetMemoryInfoDelegate(NvDisplayHandle displayHandle, ref NvMemoryInfo nvMemoryInfo); + + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] + public delegate NvStatus NvAPI_GPU_GetPCIIdentifiersDelegate(NvPhysicalGpuHandle gpuHandle, out uint deviceId, out uint subSystemId, out uint revisionId, out uint extDeviceId); + + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] + public delegate NvStatus NvAPI_GPU_GetPStatesDelegate(NvPhysicalGpuHandle gpuHandle, ref NvPStates nvPStates); + + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] + public delegate NvStatus NvAPI_GPU_GetTachReadingDelegate(NvPhysicalGpuHandle gpuHandle, out int value); + + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] + public delegate NvStatus NvAPI_GPU_GetThermalSettingsDelegate(NvPhysicalGpuHandle gpuHandle, int sensorIndex, ref NvGPUThermalSettings nvGPUThermalSettings); + + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] + public delegate NvStatus NvAPI_GPU_GetUsagesDelegate(NvPhysicalGpuHandle gpuHandle, ref NvUsages nvUsages); + + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] + public delegate NvStatus NvAPI_GPU_SetCoolerLevelsDelegate(NvPhysicalGpuHandle gpuHandle, int coolerIndex, ref NvGPUCoolerLevels NvGPUCoolerLevels); + + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] + public delegate NvStatus NvAPI_GPU_ClientFanCoolersGetStatusDelegate(NvPhysicalGpuHandle gpuHandle, ref NvFanCoolersStatus fanCoolersStatus); + public static bool IsAvailable { get; } [DllImport(@"nvapi.dll", EntryPoint = @"nvapi_QueryInterface", CallingConvention = CallingConvention.Cdecl, PreserveSig = true)] @@ -342,6 +348,40 @@ namespace LibreHardwareMonitor.Interop public int Active; } + [StructLayout(LayoutKind.Sequential, Pack = 8)] + internal struct NvFanCoolersStatus + { + public uint Version; + public uint Count; + + public ulong Reserved1; + public ulong Reserved2; + public ulong Reserved3; + public ulong Reserved4; + + [MarshalAs(UnmanagedType.ByValArray, SizeConst = MAX_FAN_COOLERS_STATUS_ITEMS)] + internal NvFanCoolersStatusItem[] Items; + } + + [StructLayout(LayoutKind.Sequential, Pack = 8)] + internal struct NvFanCoolersStatusItem + { + public uint Type; + public uint CurrentRpm; + public uint CurrentMinLevel; + public uint CurrentMaxLevel; + public uint CurrentLevel; + + public uint Reserved1; + public uint Reserved2; + public uint Reserved3; + public uint Reserved4; + public uint Reserved5; + public uint Reserved6; + public uint Reserved7; + public uint Reserved8; + } + [StructLayout(LayoutKind.Sequential, Pack = 8)] internal struct NvGPUCoolerSettings { diff --git a/LibreHardwareMonitorLib/Interop/NvidiaML.cs b/LibreHardwareMonitorLib/Interop/NvidiaML.cs index 5bd4c53..d87c627 100644 --- a/LibreHardwareMonitorLib/Interop/NvidiaML.cs +++ b/LibreHardwareMonitorLib/Interop/NvidiaML.cs @@ -16,6 +16,7 @@ namespace LibreHardwareMonitor.Interop private static WindowsNvmlGetHandleDelegate _windowsNvmlDeviceGetHandleByIndex; private static WindowsNvmlGetPowerUsageDelegate _windowsNvmlDeviceGetPowerUsage; + private static WindowsNvmlDeviceGetPcieThroughputDelegate _windowsNvmlDeviceGetPcieThroughputDelegate; private static WindowsNvmlGetHandleByPciBusIdDelegate _windowsNvmlDeviceGetHandleByPciBusId; private static WindowsNvmlDelegate _windowsNvmlInit; private static WindowsNvmlDelegate _windowsNvmlShutdown; @@ -119,6 +120,12 @@ namespace LibreHardwareMonitor.Interop else return false; + IntPtr nvmlGetPcieThroughput = Kernel32.GetProcAddress(WindowsDll, "nvmlDeviceGetPcieThroughput"); + if (nvmlGetPcieThroughput != IntPtr.Zero) + _windowsNvmlDeviceGetPcieThroughputDelegate = (WindowsNvmlDeviceGetPcieThroughputDelegate)Marshal.GetDelegateForFunctionPointer(nvmlGetPcieThroughput, typeof(WindowsNvmlDeviceGetPcieThroughputDelegate)); + else + return false; + IntPtr nvmlGetHandlePciBus = Kernel32.GetProcAddress(WindowsDll, "nvmlDeviceGetHandleByPciBusId_v2"); if (nvmlGetHandlePciBus != IntPtr.Zero) _windowsNvmlDeviceGetHandleByPciBusId = (WindowsNvmlGetHandleByPciBusIdDelegate)Marshal.GetDelegateForFunctionPointer(nvmlGetHandlePciBus, typeof(WindowsNvmlGetHandleByPciBusIdDelegate)); @@ -210,7 +217,26 @@ namespace LibreHardwareMonitor.Interop return null; } - + internal static uint? NvmlDeviceGetPcieThroughput(NvmlDevice nvmlDevice, NvmlPcieUtilCounter counter) + { + if (IsAvailable) + { + uint pcieThroughput; + if (Software.OperatingSystem.IsLinux) + { + if (nvmlDeviceGetPcieThroughput(nvmlDevice, counter, out pcieThroughput) == NvmlReturn.Success) + return pcieThroughput; + } + else if (_windowsNvmlDeviceGetPcieThroughputDelegate(nvmlDevice, counter, out pcieThroughput) == NvmlReturn.Success) + { + return pcieThroughput; + } + } + + return null; + } + + [DllImport(LinuxDllName, EntryPoint = "nvmlInit_v2", ExactSpelling = true)] private static extern NvmlReturn nvmlInit(); @@ -232,6 +258,9 @@ namespace LibreHardwareMonitor.Interop [DllImport(LinuxDllName, EntryPoint = "nvmlDeviceGetPowerUsage", ExactSpelling = true)] private static extern NvmlReturn nvmlDeviceGetPowerUsage(NvmlDevice device, out int power); + [DllImport(LinuxDllName, EntryPoint = "nvmlDeviceGetPcieThroughput", ExactSpelling = true)] + private static extern NvmlReturn nvmlDeviceGetPcieThroughput(NvmlDevice device, NvmlPcieUtilCounter counter, out uint value); + private delegate NvmlReturn WindowsNvmlDelegate(); private delegate NvmlReturn WindowsNvmlGetHandleDelegate(int index, out NvmlDevice device); @@ -239,7 +268,15 @@ namespace LibreHardwareMonitor.Interop private delegate NvmlReturn WindowsNvmlGetHandleByPciBusIdDelegate([MarshalAs(UnmanagedType.LPStr)] string pciBusId, out NvmlDevice device); private delegate NvmlReturn WindowsNvmlGetPowerUsageDelegate(NvmlDevice device, out int power); - + + private delegate NvmlReturn WindowsNvmlDeviceGetPcieThroughputDelegate(NvmlDevice device, NvmlPcieUtilCounter counter, out uint value); + + internal enum NvmlPcieUtilCounter + { + TxBytes = 0, + RxBytes = 1 + } + [StructLayout(LayoutKind.Sequential)] internal struct NvmlDevice {