first commit

This commit is contained in:
2025-04-07 07:44:27 -07:00
commit d6cde0c05e
512 changed files with 142392 additions and 0 deletions

View File

@@ -0,0 +1,13 @@
namespace LibreHardwareMonitor.Hardware.Motherboard;
internal class Control
{
public readonly int Index;
public readonly string Name;
public Control(string name, int index)
{
Name = name;
Index = index;
}
}

View File

@@ -0,0 +1,13 @@
namespace LibreHardwareMonitor.Hardware.Motherboard;
internal class Fan
{
public readonly int Index;
public readonly string Name;
public Fan(string name, int index)
{
Name = name;
Index = index;
}
}

View File

@@ -0,0 +1,617 @@
// 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.
// Partial Copyright (C) Michael Möller <mmoeller@openhardwaremonitor.org> and Contributors.
// All Rights Reserved.
using System;
namespace LibreHardwareMonitor.Hardware.Motherboard;
internal class Identification
{
public static Manufacturer GetManufacturer(string name)
{
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.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.StartsWith("ASUSTeK", StringComparison.OrdinalIgnoreCase):
case var _ when name.StartsWith("ASUS ", StringComparison.OrdinalIgnoreCase):
return Manufacturer.ASUS;
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.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.StartsWith("EVGA", StringComparison.OrdinalIgnoreCase):
return Manufacturer.EVGA;
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("Foxconn", StringComparison.OrdinalIgnoreCase):
return Manufacturer.Foxconn;
case var _ when name.StartsWith("Fujitsu", StringComparison.OrdinalIgnoreCase):
return Manufacturer.Fujitsu;
case var _ when name.StartsWith("Gigabyte", StringComparison.OrdinalIgnoreCase):
return Manufacturer.Gigabyte;
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.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.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.StartsWith("Sony", StringComparison.OrdinalIgnoreCase):
return Manufacturer.Sony;
case var _ when name.StartsWith("Supermicro", StringComparison.OrdinalIgnoreCase):
return Manufacturer.Supermicro;
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:
return Manufacturer.Unknown;
}
}
public static Model GetModel(string name)
{
switch (name)
{
case var _ when name.Equals("880GMH/USB3", StringComparison.OrdinalIgnoreCase):
return Model._880GMH_USB3;
case var _ when name.Equals("B85M-DGS", StringComparison.OrdinalIgnoreCase):
return Model.B85M_DGS;
case var _ when name.Equals("ASRock AOD790GX/128M", StringComparison.OrdinalIgnoreCase):
return Model.AOD790GX_128M;
case var _ when name.Equals("AB350 Pro4", StringComparison.OrdinalIgnoreCase):
return Model.AB350_Pro4;
case var _ when name.Equals("AB350M Pro4", StringComparison.OrdinalIgnoreCase):
return Model.AB350M_Pro4;
case var _ when name.Equals("AB350M", StringComparison.OrdinalIgnoreCase):
return Model.AB350M;
case var _ when name.Equals("B450 Steel Legend", StringComparison.OrdinalIgnoreCase):
return Model.B450_Steel_Legend;
case var _ when name.Equals("B450M Steel Legend", StringComparison.OrdinalIgnoreCase):
return Model.B450M_Steel_Legend;
case var _ when name.Equals("B450 Pro4", StringComparison.OrdinalIgnoreCase):
return Model.B450_Pro4;
case var _ when name.Equals("B450M Pro4", StringComparison.OrdinalIgnoreCase):
return Model.B450M_Pro4;
case var _ when name.Equals("Fatal1ty AB350 Gaming K4", StringComparison.OrdinalIgnoreCase):
return Model.Fatal1ty_AB350_Gaming_K4;
case var _ when name.Equals("AB350M-HDV", StringComparison.OrdinalIgnoreCase):
return Model.AB350M_HDV;
case var _ when name.Equals("X399 Phantom Gaming 6", StringComparison.OrdinalIgnoreCase):
return Model.X399_Phantom_Gaming_6;
case var _ when name.Equals("A320M-HDV", StringComparison.OrdinalIgnoreCase):
return Model.A320M_HDV;
case var _ when name.Equals("P55 Deluxe", StringComparison.OrdinalIgnoreCase):
return Model.P55_Deluxe;
case var _ when name.Equals("Crosshair III Formula", StringComparison.OrdinalIgnoreCase):
return Model.CROSSHAIR_III_FORMULA;
case var _ when name.Equals("ROG CROSSHAIR VIII HERO", StringComparison.OrdinalIgnoreCase):
return Model.ROG_CROSSHAIR_VIII_HERO;
case var _ when name.Equals("ROG CROSSHAIR VIII HERO (WI-FI)", StringComparison.OrdinalIgnoreCase):
return Model.ROG_CROSSHAIR_VIII_HERO_WIFI;
case var _ when name.Equals("ROG CROSSHAIR VIII DARK HERO", StringComparison.OrdinalIgnoreCase):
return Model.ROG_CROSSHAIR_VIII_DARK_HERO;
case var _ when name.Equals("ROG CROSSHAIR VIII FORMULA", StringComparison.OrdinalIgnoreCase):
return Model.ROG_CROSSHAIR_VIII_FORMULA;
case var _ when name.Equals("ROG CROSSHAIR VIII IMPACT", StringComparison.OrdinalIgnoreCase):
return Model.ROG_CROSSHAIR_VIII_IMPACT;
case var _ when name.Equals("PRIME B650-PLUS", StringComparison.OrdinalIgnoreCase):
return Model.PRIME_B650_PLUS;
case var _ when name.Equals("ROG CROSSHAIR X670E EXTREME", StringComparison.OrdinalIgnoreCase):
return Model.ROG_CROSSHAIR_X670E_EXTREME;
case var _ when name.Equals("ROG CROSSHAIR X670E HERO", StringComparison.OrdinalIgnoreCase):
return Model.ROG_CROSSHAIR_X670E_HERO;
case var _ when name.Equals("ROG CROSSHAIR X670E GENE", StringComparison.OrdinalIgnoreCase):
return Model.ROG_CROSSHAIR_X670E_GENE;
case var _ when name.Equals("PROART X670E-CREATOR WIFI", StringComparison.OrdinalIgnoreCase):
return Model.PROART_X670E_CREATOR_WIFI;
case var _ when name.Equals("M2N-SLI DELUXE", StringComparison.OrdinalIgnoreCase):
return Model.M2N_SLI_Deluxe;
case var _ when name.Equals("M4A79XTD EVO", StringComparison.OrdinalIgnoreCase):
return Model.M4A79XTD_EVO;
case var _ when name.Equals("P5W DH Deluxe", StringComparison.OrdinalIgnoreCase):
return Model.P5W_DH_Deluxe;
case var _ when name.Equals("P6T", StringComparison.OrdinalIgnoreCase):
return Model.P6T;
case var _ when name.Equals("P6X58D-E", StringComparison.OrdinalIgnoreCase):
return Model.P6X58D_E;
case var _ when name.Equals("P8P67", StringComparison.OrdinalIgnoreCase):
case var _ when name.Equals("P8P67 REV 3.1", StringComparison.OrdinalIgnoreCase):
return Model.P8P67;
case var _ when name.Equals("P8P67 EVO", StringComparison.OrdinalIgnoreCase):
return Model.P8P67_EVO;
case var _ when name.Equals("P8P67 PRO", StringComparison.OrdinalIgnoreCase):
return Model.P8P67_PRO;
case var _ when name.Equals("P8P67-M PRO", StringComparison.OrdinalIgnoreCase):
return Model.P8P67_M_PRO;
case var _ when name.Equals("P8Z77-V", StringComparison.OrdinalIgnoreCase):
return Model.P8Z77_V;
case var _ when name.Equals("P9X79", StringComparison.OrdinalIgnoreCase):
return Model.P9X79;
case var _ when name.Equals("Rampage Extreme", StringComparison.OrdinalIgnoreCase):
return Model.RAMPAGE_EXTREME;
case var _ when name.Equals("Rampage II GENE", StringComparison.OrdinalIgnoreCase):
return Model.RAMPAGE_II_GENE;
case var _ when name.Equals("LP BI P45-T2RS Elite", StringComparison.OrdinalIgnoreCase):
return Model.LP_BI_P45_T2RS_Elite;
case var _ when name.Equals("ROG STRIX B550-F GAMING (WI-FI)", StringComparison.OrdinalIgnoreCase):
return Model.ROG_STRIX_B550_F_GAMING_WIFI;
case var _ when name.Equals("ROG STRIX X470-I GAMING", StringComparison.OrdinalIgnoreCase):
return Model.ROG_STRIX_X470_I;
case var _ when name.Equals("ROG STRIX B550-E GAMING", StringComparison.OrdinalIgnoreCase):
return Model.ROG_STRIX_B550_E_GAMING;
case var _ when name.Equals("ROG STRIX B550-I GAMING", StringComparison.OrdinalIgnoreCase):
return Model.ROG_STRIX_B550_I_GAMING;
case var _ when name.Equals("ROG STRIX X570-E GAMING", StringComparison.OrdinalIgnoreCase):
return Model.ROG_STRIX_X570_E_GAMING;
case var _ when name.Equals("ROG STRIX X570-E GAMING WIFI II", StringComparison.OrdinalIgnoreCase):
return Model.ROG_STRIX_X570_E_GAMING_WIFI_II;
case var _ when name.Equals("ROG STRIX X570-I GAMING", StringComparison.OrdinalIgnoreCase):
return Model.ROG_STRIX_X570_I_GAMING;
case var _ when name.Equals("ROG STRIX X570-F GAMING", StringComparison.OrdinalIgnoreCase):
return Model.ROG_STRIX_X570_F_GAMING;
case var _ when name.Equals("LP DK P55-T3eH9", StringComparison.OrdinalIgnoreCase):
return Model.LP_DK_P55_T3EH9;
case var _ when name.Equals("A890GXM-A", StringComparison.OrdinalIgnoreCase):
return Model.A890GXM_A;
case var _ when name.Equals("X58 SLI Classified", StringComparison.OrdinalIgnoreCase):
return Model.X58_SLI_Classified;
case var _ when name.Equals("132-BL-E758", StringComparison.OrdinalIgnoreCase):
return Model.X58_3X_SLI;
case var _ when name.Equals("965P-S3", StringComparison.OrdinalIgnoreCase):
return Model._965P_S3;
case var _ when name.Equals("EP45-DS3R", StringComparison.OrdinalIgnoreCase):
return Model.EP45_DS3R;
case var _ when name.Equals("EP45-UD3R", StringComparison.OrdinalIgnoreCase):
return Model.EP45_UD3R;
case var _ when name.Equals("EX58-EXTREME", StringComparison.OrdinalIgnoreCase):
return Model.EX58_EXTREME;
case var _ when name.Equals("EX58-UD3R", StringComparison.OrdinalIgnoreCase):
return Model.EX58_UD3R;
case var _ when name.Equals("G41M-Combo", StringComparison.OrdinalIgnoreCase):
return Model.G41M_COMBO;
case var _ when name.Equals("G41MT-S2", StringComparison.OrdinalIgnoreCase):
return Model.G41MT_S2;
case var _ when name.Equals("G41MT-S2P", StringComparison.OrdinalIgnoreCase):
return Model.G41MT_S2P;
case var _ when name.Equals("970A-DS3P", StringComparison.OrdinalIgnoreCase):
case var _ when name.Equals("970A-DS3P FX", StringComparison.OrdinalIgnoreCase):
return Model._970A_DS3P;
case var _ when name.Equals("GA-970A-UD3", StringComparison.OrdinalIgnoreCase):
return Model._970A_UD3;
case var _ when name.Equals("GA-MA770T-UD3", StringComparison.OrdinalIgnoreCase):
return Model.MA770T_UD3;
case var _ when name.Equals("GA-MA770T-UD3P", StringComparison.OrdinalIgnoreCase):
return Model.MA770T_UD3P;
case var _ when name.Equals("GA-MA785GM-US2H", StringComparison.OrdinalIgnoreCase):
return Model.MA785GM_US2H;
case var _ when name.Equals("GA-MA785GMT-UD2H", StringComparison.OrdinalIgnoreCase):
return Model.MA785GMT_UD2H;
case var _ when name.Equals("GA-MA78LM-S2H", StringComparison.OrdinalIgnoreCase):
return Model.MA78LM_S2H;
case var _ when name.Equals("GA-MA790X-UD3P", StringComparison.OrdinalIgnoreCase):
return Model.MA790X_UD3P;
case var _ when name.Equals("H55-USB3", StringComparison.OrdinalIgnoreCase):
return Model.H55_USB3;
case var _ when name.Equals("H55N-USB3", StringComparison.OrdinalIgnoreCase):
return Model.H55N_USB3;
case var _ when name.Equals("H61M-DGS", StringComparison.OrdinalIgnoreCase):
return Model.H61M_DGS;
case var _ when name.Equals("H61M-DS2 REV 1.2", StringComparison.OrdinalIgnoreCase):
return Model.H61M_DS2_REV_1_2;
case var _ when name.Equals("H61M-USB3-B3 REV 2.0", StringComparison.OrdinalIgnoreCase):
return Model.H61M_USB3_B3_REV_2_0;
case var _ when name.Equals("H67A-UD3H-B3", StringComparison.OrdinalIgnoreCase):
return Model.H67A_UD3H_B3;
case var _ when name.Equals("H67A-USB3-B3", StringComparison.OrdinalIgnoreCase):
return Model.H67A_USB3_B3;
case var _ when name.Equals("H97-D3H-CF", StringComparison.OrdinalIgnoreCase):
return Model.H97_D3H;
case var _ when name.Equals("H81M-HD3", StringComparison.OrdinalIgnoreCase):
return Model.H81M_HD3;
case var _ when name.Equals("B75M-D3H", StringComparison.OrdinalIgnoreCase):
return Model.B75M_D3H;
case var _ when name.Equals("P35-DS3", StringComparison.OrdinalIgnoreCase):
return Model.P35_DS3;
case var _ when name.Equals("P35-DS3L", StringComparison.OrdinalIgnoreCase):
return Model.P35_DS3L;
case var _ when name.Equals("P55-UD4", StringComparison.OrdinalIgnoreCase):
return Model.P55_UD4;
case var _ when name.Equals("P55A-UD3", StringComparison.OrdinalIgnoreCase):
return Model.P55A_UD3;
case var _ when name.Equals("P55M-UD4", StringComparison.OrdinalIgnoreCase):
return Model.P55M_UD4;
case var _ when name.Equals("P67A-UD3-B3", StringComparison.OrdinalIgnoreCase):
return Model.P67A_UD3_B3;
case var _ when name.Equals("P67A-UD3R-B3", StringComparison.OrdinalIgnoreCase):
return Model.P67A_UD3R_B3;
case var _ when name.Equals("P67A-UD4-B3", StringComparison.OrdinalIgnoreCase):
return Model.P67A_UD4_B3;
case var _ when name.Equals("P8Z68-V PRO", StringComparison.OrdinalIgnoreCase):
return Model.P8Z68_V_PRO;
case var _ when name.Equals("X38-DS5", StringComparison.OrdinalIgnoreCase):
return Model.X38_DS5;
case var _ when name.Equals("X58A-UD3R", StringComparison.OrdinalIgnoreCase):
return Model.X58A_UD3R;
case var _ when name.Equals("Z270 PC MATE", StringComparison.OrdinalIgnoreCase):
case var _ when name.Equals("Z270 PC MATE (MS-7A72)", StringComparison.OrdinalIgnoreCase):
return Model.Z270_PC_MATE;
case var _ when name.Equals("Z77 MPower", StringComparison.OrdinalIgnoreCase): // MS-7751 Rev 4.x
case var _ when name.Equals("Z77 MPower (MS-7751)", StringComparison.OrdinalIgnoreCase):
case var _ when name.Equals("Z77A-GD65", StringComparison.OrdinalIgnoreCase): // MS-7751 Rev >1.x
case var _ when name.Equals("Z77A-GD65 (MS-7751)", StringComparison.OrdinalIgnoreCase):
case var _ when name.Equals("Z77A-GD65 GAMING", StringComparison.OrdinalIgnoreCase): // MS-7751 Rev 2.x
case var _ when name.Equals("Z77A-GD65 GAMING (MS-7751)", StringComparison.OrdinalIgnoreCase):
case var _ when name.Equals("Z77A-GD55", StringComparison.OrdinalIgnoreCase): // MS-7751 Rev 1.x
case var _ when name.Equals("Z77A-GD55 (MS-7751)", StringComparison.OrdinalIgnoreCase):
case var _ when name.Equals("Z77A-GD80", StringComparison.OrdinalIgnoreCase):
case var _ when name.Equals("Z77A-GD80 (MS-7757)", StringComparison.OrdinalIgnoreCase):
return Model.Z77_MS7751;
case var _ when name.Equals("Z68A-GD80", StringComparison.OrdinalIgnoreCase):
case var _ when name.Equals("Z68A-GD80 (MS-7672)", StringComparison.OrdinalIgnoreCase):
case var _ when name.Equals("P67A-GD80", StringComparison.OrdinalIgnoreCase):
case var _ when name.Equals("P67A-GD80 (MS-7672)", StringComparison.OrdinalIgnoreCase):
return Model.Z68_MS7672;
case var _ when name.Equals("X79-UD3", StringComparison.OrdinalIgnoreCase):
return Model.X79_UD3;
case var _ when name.Equals("Z68A-D3H-B3", StringComparison.OrdinalIgnoreCase):
return Model.Z68A_D3H_B3;
case var _ when name.Equals("Z68AP-D3", StringComparison.OrdinalIgnoreCase):
return Model.Z68AP_D3;
case var _ when name.Equals("Z68X-UD3H-B3", StringComparison.OrdinalIgnoreCase):
return Model.Z68X_UD3H_B3;
case var _ when name.Equals("Z68X-UD7-B3", StringComparison.OrdinalIgnoreCase):
return Model.Z68X_UD7_B3;
case var _ when name.Equals("Z68XP-UD3R", StringComparison.OrdinalIgnoreCase):
return Model.Z68XP_UD3R;
case var _ when name.Equals("Z170N-WIFI-CF", StringComparison.OrdinalIgnoreCase):
return Model.Z170N_WIFI;
case var _ when name.Equals("Z390 M GAMING-CF", StringComparison.OrdinalIgnoreCase):
return Model.Z390_M_GAMING;
case var _ when name.Equals("Z390 AORUS ULTRA", StringComparison.OrdinalIgnoreCase):
return Model.Z390_AORUS_ULTRA;
case var _ when name.Equals("Z390 AORUS PRO-CF", StringComparison.OrdinalIgnoreCase):
return Model.Z390_AORUS_PRO;
case var _ when name.Equals("Z390 UD", StringComparison.OrdinalIgnoreCase):
return Model.Z390_UD;
case var _ when name.Equals("Z690 AORUS PRO", StringComparison.OrdinalIgnoreCase):
return Model.Z690_AORUS_PRO;
case var _ when name.Equals("Z690 AORUS ULTRA", StringComparison.OrdinalIgnoreCase):
return Model.Z690_AORUS_ULTRA;
case var _ when name.Equals("Z690 AORUS MASTER", StringComparison.OrdinalIgnoreCase):
return Model.Z690_AORUS_MASTER;
case var _ when name.Equals("Z690 GAMING X DDR4", StringComparison.OrdinalIgnoreCase):
return Model.Z690_GAMING_X_DDR4;
case var _ when name.Equals("Z790 AORUS PRO X", StringComparison.OrdinalIgnoreCase):
case var _ when name.Equals("Z790 AORUS PRO X WIFI7", StringComparison.OrdinalIgnoreCase):
return Model.Z790_AORUS_PRO_X;
case var _ when name.Equals("Z790 UD", StringComparison.OrdinalIgnoreCase):
return Model.Z790_UD;
case var _ when name.Equals("Z790 UD AC", StringComparison.OrdinalIgnoreCase):
return Model.Z790_UD_AC;
case var _ when name.Equals("Z790 GAMING X", StringComparison.OrdinalIgnoreCase):
return Model.Z790_GAMING_X;
case var _ when name.Equals("Z790 GAMING X AX", StringComparison.OrdinalIgnoreCase):
return Model.Z790_GAMING_X_AX;
case var _ when name.Equals("FH67", StringComparison.OrdinalIgnoreCase):
return Model.FH67;
case var _ when name.Equals("AX370-Gaming K7", StringComparison.OrdinalIgnoreCase):
return Model.AX370_Gaming_K7;
case var _ when name.Equals("PRIME X370-PRO", StringComparison.OrdinalIgnoreCase):
return Model.PRIME_X370_PRO;
case var _ when name.Equals("PRIME X470-PRO", StringComparison.OrdinalIgnoreCase):
return Model.PRIME_X470_PRO;
case var _ when name.Equals("PRIME X570-PRO", StringComparison.OrdinalIgnoreCase):
return Model.PRIME_X570_PRO;
case var _ when name.Equals("ProArt X570-CREATOR WIFI", StringComparison.OrdinalIgnoreCase):
return Model.PROART_X570_CREATOR_WIFI;
case var _ when name.Equals("Pro WS X570-ACE", StringComparison.OrdinalIgnoreCase):
return Model.PRO_WS_X570_ACE;
case var _ when name.Equals("ROG MAXIMUS X APEX", StringComparison.OrdinalIgnoreCase):
return Model.ROG_MAXIMUS_X_APEX;
case var _ when name.Equals("AB350-Gaming 3-CF", StringComparison.OrdinalIgnoreCase):
return Model.AB350_Gaming_3;
case var _ when name.Equals("X399 AORUS Gaming 7", StringComparison.OrdinalIgnoreCase):
return Model.X399_AORUS_Gaming_7;
case var _ when name.Equals("ROG ZENITH EXTREME", StringComparison.OrdinalIgnoreCase):
return Model.ROG_ZENITH_EXTREME;
case var _ when name.Equals("ROG ZENITH II EXTREME", StringComparison.OrdinalIgnoreCase):
return Model.ROG_ZENITH_II_EXTREME;
case var _ when name.Equals("Z170-A", StringComparison.OrdinalIgnoreCase):
return Model.Z170_A;
case var _ when name.Equals("B150M-C", StringComparison.OrdinalIgnoreCase):
return Model.B150M_C;
case var _ when name.Equals("B150M-C D3", StringComparison.OrdinalIgnoreCase):
return Model.B150M_C_D3;
case var _ when name.Equals("Z77 Pro4-M", StringComparison.OrdinalIgnoreCase):
return Model.Z77Pro4M;
case var _ when name.Equals("X570 Pro4", StringComparison.OrdinalIgnoreCase):
return Model.X570_Pro4;
case var _ when name.Equals("X570 Taichi", StringComparison.OrdinalIgnoreCase):
return Model.X570_Taichi;
case var _ when name.Equals("X570 Phantom Gaming-ITX/TB3", StringComparison.OrdinalIgnoreCase):
return Model.X570_Phantom_Gaming_ITX;
case var _ when name.Equals("X570 Phantom Gaming 4", StringComparison.OrdinalIgnoreCase):
return Model.X570_Phantom_Gaming_4;
case var _ when name.Equals("AX370-Gaming 5", StringComparison.OrdinalIgnoreCase):
return Model.AX370_Gaming_5;
case var _ when name.Equals("TUF X470-PLUS GAMING", StringComparison.OrdinalIgnoreCase):
return Model.TUF_X470_PLUS_GAMING;
case var _ when name.Equals("B360M PRO-VDH (MS-7B24)", StringComparison.OrdinalIgnoreCase):
return Model.B360M_PRO_VDH;
case var _ when name.Equals("B550-A PRO (MS-7C56)", StringComparison.OrdinalIgnoreCase):
case var _ when name.Equals("PRO B550-VC (MS-7C56)", StringComparison.OrdinalIgnoreCase):
return Model.B550A_PRO;
case var _ when name.Equals("B450-A PRO (MS-7B86)", StringComparison.OrdinalIgnoreCase):
return Model.B450A_PRO;
case var _ when name.Equals("B350 GAMING PLUS (MS-7A34)", StringComparison.OrdinalIgnoreCase):
return Model.B350_Gaming_Plus;
case var _ when name.Equals("B450 AORUS PRO", StringComparison.OrdinalIgnoreCase):
case var _ when name.Equals("B450 AORUS PRO WIFI", StringComparison.OrdinalIgnoreCase):
return Model.B450_AORUS_PRO;
case var _ when name.Equals("B450 GAMING X", StringComparison.OrdinalIgnoreCase):
return Model.B450_GAMING_X;
case var _ when name.Equals("B450 AORUS ELITE", StringComparison.OrdinalIgnoreCase):
case var _ when name.Equals("B450 AORUS ELITE V2", StringComparison.OrdinalIgnoreCase):
return Model.B450_AORUS_ELITE;
case var _ when name.Equals("B450M AORUS ELITE", StringComparison.OrdinalIgnoreCase):
case var _ when name.Equals("B450M AORUS ELITE-CF", StringComparison.OrdinalIgnoreCase):
return Model.B450M_AORUS_ELITE;
case var _ when name.Equals("B450M GAMING", StringComparison.OrdinalIgnoreCase):
case var _ when name.Equals("B450M GAMING-CF", StringComparison.OrdinalIgnoreCase):
return Model.B450M_GAMING;
case var _ when name.Equals("B450M AORUS M", StringComparison.OrdinalIgnoreCase):
case var _ when name.Equals("B450M AORUS M-CF", StringComparison.OrdinalIgnoreCase):
return Model.B450_AORUS_M;
case var _ when name.Equals("B450M DS3H", StringComparison.OrdinalIgnoreCase):
case var _ when name.Equals("B450M DS3H WIFI", StringComparison.OrdinalIgnoreCase):
case var _ when name.Equals("B450M DS3H-CF", StringComparison.OrdinalIgnoreCase):
case var _ when name.Equals("B450M DS3H WIFI-CF", StringComparison.OrdinalIgnoreCase):
case var _ when name.Equals("B450M DS3H V2", StringComparison.OrdinalIgnoreCase):
case var _ when name.Equals("B450M DS3H V2-CF", StringComparison.OrdinalIgnoreCase):
return Model.B450M_DS3H;
case var _ when name.Equals("B450M S2H", StringComparison.OrdinalIgnoreCase):
case var _ when name.Equals("B450M S2H V2", StringComparison.OrdinalIgnoreCase):
case var _ when name.Equals("B450M S2H-CF", StringComparison.OrdinalIgnoreCase):
case var _ when name.Equals("B450M S2H V2-CF", StringComparison.OrdinalIgnoreCase):
return Model.B450M_S2H;
case var _ when name.Equals("B450M H", StringComparison.OrdinalIgnoreCase):
case var _ when name.Equals("B450M H-CF", StringComparison.OrdinalIgnoreCase):
return Model.B450M_H;
case var _ when name.Equals("B450M K", StringComparison.OrdinalIgnoreCase):
case var _ when name.Equals("B450M K-CF", StringComparison.OrdinalIgnoreCase):
return Model.B450M_K;
case var _ when name.Equals("B450M I AORUS PRO WIFI", StringComparison.OrdinalIgnoreCase):
case var _ when name.Equals("B450M I AORUS PRO WIFI-CF", StringComparison.OrdinalIgnoreCase):
return Model.B450_I_AORUS_PRO_WIFI;
case var _ when name.Equals("X470 AORUS GAMING 7 WIFI-CF", StringComparison.OrdinalIgnoreCase):
return Model.X470_AORUS_GAMING_7_WIFI;
case var _ when name.Equals("X570 AORUS MASTER", StringComparison.OrdinalIgnoreCase):
return Model.X570_AORUS_MASTER;
case var _ when name.Equals("X570 AORUS PRO", StringComparison.OrdinalIgnoreCase):
return Model.X570_AORUS_PRO;
case var _ when name.Equals("X570 AORUS ULTRA", StringComparison.OrdinalIgnoreCase):
return Model.X570_AORUS_ULTRA;
case var _ when name.Equals("X570 GAMING X", StringComparison.OrdinalIgnoreCase):
return Model.X570_GAMING_X;
case var _ when name.Equals("TUF GAMING X570-PLUS (WI-FI)", StringComparison.OrdinalIgnoreCase):
return Model.TUF_GAMING_X570_PLUS_WIFI;
case var _ when name.Equals("TUF GAMING B550M-PLUS (WI-FI)", StringComparison.OrdinalIgnoreCase):
return Model.TUF_GAMING_B550M_PLUS_WIFI;
case var _ when name.Equals("B360 AORUS GAMING 3 WIFI-CF", StringComparison.OrdinalIgnoreCase):
return Model.B360_AORUS_GAMING_3_WIFI_CF;
case var _ when name.Equals("B550I AORUS PRO AX", StringComparison.OrdinalIgnoreCase):
return Model.B550I_AORUS_PRO_AX;
case var _ when name.Equals("B550M AORUS PRO", StringComparison.OrdinalIgnoreCase):
case var _ when name.Equals("B550M AORUS PRO-P", StringComparison.OrdinalIgnoreCase):
return Model.B550M_AORUS_PRO;
case var _ when name.Equals("B550M AORUS PRO AX", StringComparison.OrdinalIgnoreCase):
return Model.B550M_AORUS_PRO_AX;
case var _ when name.Equals("B550M AORUS ELITE", StringComparison.OrdinalIgnoreCase):
return Model.B550M_AORUS_ELITE;
case var _ when name.Equals("B550M GAMING", StringComparison.OrdinalIgnoreCase):
return Model.B550M_GAMING;
case var _ when name.Equals("B550M DS3H", StringComparison.OrdinalIgnoreCase):
return Model.B550M_DS3H;
case var _ when name.Equals("B550M DS3H AC", StringComparison.OrdinalIgnoreCase):
return Model.B550M_DS3H_AC;
case var _ when name.Equals("B550M S2H", StringComparison.OrdinalIgnoreCase):
return Model.B550M_S2H;
case var _ when name.Equals("B550M H", StringComparison.OrdinalIgnoreCase):
return Model.B550M_H;
case var _ when name.Equals("B550 AORUS MASTER", StringComparison.OrdinalIgnoreCase):
return Model.B550_AORUS_MASTER;
case var _ when name.Equals("B550 AORUS PRO", StringComparison.OrdinalIgnoreCase):
case var _ when name.Equals("B550 AORUS PRO V2", StringComparison.OrdinalIgnoreCase):
return Model.B550_AORUS_PRO;
case var _ when name.Equals("B550 AORUS PRO AC", StringComparison.OrdinalIgnoreCase):
return Model.B550_AORUS_PRO_AC;
case var _ when name.Equals("B550 AORUS PRO AX", StringComparison.OrdinalIgnoreCase):
return Model.B550_AORUS_PRO_AX;
case var _ when name.Equals("B550 VISION D", StringComparison.OrdinalIgnoreCase):
case var _ when name.Equals("B550 VISION D-P", StringComparison.OrdinalIgnoreCase):
return Model.B550_VISION_D;
case var _ when name.Equals("B550 AORUS ELITE", StringComparison.OrdinalIgnoreCase):
case var _ when name.Equals("B550 AORUS ELITE V2", StringComparison.OrdinalIgnoreCase):
return Model.B550_AORUS_ELITE;
case var _ when name.Equals("B550 AORUS ELITE AX", StringComparison.OrdinalIgnoreCase):
case var _ when name.Equals("B550 AORUS ELITE AX V2", StringComparison.OrdinalIgnoreCase):
case var _ when name.Equals("B550 AORUS ELITE AX V3", StringComparison.OrdinalIgnoreCase):
return Model.B550_AORUS_ELITE_AX;
case var _ when name.Equals("B550 GAMING X", StringComparison.OrdinalIgnoreCase):
case var _ when name.Equals("B550 GAMING X V2", StringComparison.OrdinalIgnoreCase):
return Model.B550_GAMING_X;
case var _ when name.Equals("B550 UD AC", StringComparison.OrdinalIgnoreCase):
case var _ when name.Equals("B550 UD AC-Y1", StringComparison.OrdinalIgnoreCase):
return Model.B550_UD_AC;
case var _ when name.Equals("B560M AORUS ELITE", StringComparison.OrdinalIgnoreCase):
return Model.B560M_AORUS_ELITE;
case var _ when name.Equals("B560M AORUS PRO", StringComparison.OrdinalIgnoreCase):
return Model.B560M_AORUS_PRO;
case var _ when name.Equals("B560M AORUS PRO AX", StringComparison.OrdinalIgnoreCase):
return Model.B560M_AORUS_PRO_AX;
case var _ when name.Equals("B560I AORUS PRO AX", StringComparison.OrdinalIgnoreCase):
return Model.B560I_AORUS_PRO_AX;
case var _ when name.Equals("B650 AORUS ELITE", StringComparison.OrdinalIgnoreCase):
return Model.B650_AORUS_ELITE;
case var _ when name.Equals("B650 AORUS ELITE AX", StringComparison.OrdinalIgnoreCase):
return Model.B650_AORUS_ELITE_AX;
case var _ when name.Equals("B650 AORUS ELITE V2", StringComparison.OrdinalIgnoreCase):
return Model.B650_AORUS_ELITE_V2;
case var _ when name.Equals("B650 AORUS ELITE AX V2", StringComparison.OrdinalIgnoreCase):
return Model.B650_AORUS_ELITE_AX_V2;
case var _ when name.Equals("B650 AORUS ELITE AX ICE", StringComparison.OrdinalIgnoreCase):
return Model.B650_AORUS_ELITE_AX_ICE;
case var _ when name.Equals("B650E AORUS ELITE AX ICE", StringComparison.OrdinalIgnoreCase):
return Model.B650E_AORUS_ELITE_AX_ICE;
case var _ when name.Equals("B650M AORUS PRO", StringComparison.OrdinalIgnoreCase):
return Model.B650M_AORUS_PRO;
case var _ when name.Equals("B650M AORUS PRO AX", StringComparison.OrdinalIgnoreCase):
return Model.B650M_AORUS_PRO_AX;
case var _ when name.Equals("B650M AORUS ELITE", StringComparison.OrdinalIgnoreCase):
return Model.B650M_AORUS_ELITE;
case var _ when name.Equals("B650M AORUS ELITE AX", StringComparison.OrdinalIgnoreCase):
return Model.B650M_AORUS_ELITE_AX;
case var _ when name.Equals("ROG STRIX Z390-E GAMING", StringComparison.OrdinalIgnoreCase):
return Model.ROG_STRIX_Z390_E_GAMING;
case var _ when name.Equals("ROG STRIX Z390-F GAMING", StringComparison.OrdinalIgnoreCase):
return Model.ROG_STRIX_Z390_F_GAMING;
case var _ when name.Equals("ROG STRIX Z390-I GAMING", StringComparison.OrdinalIgnoreCase):
return Model.ROG_STRIX_Z390_I_GAMING;
case var _ when name.Equals("ROG STRIX Z690-A GAMING WIFI D4", StringComparison.OrdinalIgnoreCase):
return Model.ROG_STRIX_Z690_A_GAMING_WIFI_D4;
case var _ when name.Equals("ROG MAXIMUS XI FORMULA", StringComparison.OrdinalIgnoreCase):
return Model.ROG_MAXIMUS_XI_FORMULA;
case var _ when name.Equals("ROG MAXIMUS XII FORMULA", StringComparison.OrdinalIgnoreCase):
return Model.ROG_MAXIMUS_XII_Z490_FORMULA;
case var _ when name.Equals("ROG MAXIMUS X HERO (WI-FI AC)", StringComparison.OrdinalIgnoreCase):
return Model.ROG_MAXIMUS_X_HERO_WIFI_AC;
case var _ when name.Equals("ROG MAXIMUS Z690 FORMULA", StringComparison.OrdinalIgnoreCase):
return Model.ROG_MAXIMUS_Z690_FORMULA;
case var _ when name.Equals("ROG MAXIMUS Z690 HERO", StringComparison.OrdinalIgnoreCase):
return Model.ROG_MAXIMUS_Z690_HERO;
case var _ when name.Equals("ROG MAXIMUS Z690 EXTREME GLACIAL", StringComparison.OrdinalIgnoreCase):
return Model.ROG_MAXIMUS_Z690_EXTREME_GLACIAL;
case var _ when name.Equals("ROG STRIX X670E-A GAMING WIFI", StringComparison.OrdinalIgnoreCase):
return Model.ROG_STRIX_X670E_A_GAMING_WIFI;
case var _ when name.Equals("ROG STRIX X670E-E GAMING WIFI", StringComparison.OrdinalIgnoreCase):
return Model.ROG_STRIX_X670E_E_GAMING_WIFI;
case var _ when name.Equals("ROG STRIX X670E-F GAMING WIFI", StringComparison.OrdinalIgnoreCase):
return Model.ROG_STRIX_X670E_F_GAMING_WIFI;
case var _ when name.Equals("B660GTN", StringComparison.OrdinalIgnoreCase):
return Model.B660GTN;
case var _ when name.Equals("X670E VALKYRIE", StringComparison.OrdinalIgnoreCase):
return Model.X670E_Valkyrie;
case var _ when name.Equals("ROG MAXIMUS Z790 HERO", StringComparison.OrdinalIgnoreCase):
return Model.ROG_MAXIMUS_Z790_HERO;
case var _ when name.Equals("ROG MAXIMUS Z790 DARK HERO", StringComparison.OrdinalIgnoreCase):
return Model.ROG_MAXIMUS_Z790_DARK_HERO;
case var _ when name.Equals("PRIME Z690-A", StringComparison.OrdinalIgnoreCase):
return Model.PRIME_Z690_A;
case var _ when name.Equals("Z690 Steel Legend WiFi 6E", StringComparison.OrdinalIgnoreCase):
case var _ when name.Equals("Z690 Steel Legend", StringComparison.OrdinalIgnoreCase):
return Model.Z690_Steel_Legend;
case var _ when name.Equals("Z690 Extreme WiFi 6E", StringComparison.OrdinalIgnoreCase):
case var _ when name.Equals("Z690 Extreme", StringComparison.OrdinalIgnoreCase):
return Model.Z690_Extreme;
case var _ when name.Equals("Z790 Pro RS", StringComparison.OrdinalIgnoreCase):
case var _ when name.Equals("Z790 Pro RS WiFi", StringComparison.OrdinalIgnoreCase):
return Model.Z790_Pro_RS;
case var _ when name.Equals("Z790 Taichi", StringComparison.OrdinalIgnoreCase):
case var _ when name.Equals("Z790 Taichi Carrara", StringComparison.OrdinalIgnoreCase):
return Model.Z790_Taichi;
case var _ when name.Equals("B650M-C", StringComparison.OrdinalIgnoreCase):
case var _ when name.Equals("B650M-CW", StringComparison.OrdinalIgnoreCase):
case var _ when name.Equals("B650M-CX", StringComparison.OrdinalIgnoreCase):
case var _ when name.Equals("B650M-CWX", StringComparison.OrdinalIgnoreCase):
return Model.B650M_C;
case var _ when name.Equals("B650M GAMING PLUS WIFI (MS-7E24)", StringComparison.OrdinalIgnoreCase):
return Model.B650M_Gaming_Plus_Wifi;
case var _ when name.Equals("B660 DS3H DDR4-Y1",StringComparison.OrdinalIgnoreCase):
case var _ when name.Equals("B660 DS3H DDR4",StringComparison.OrdinalIgnoreCase):
return Model.B660_DS3H_DDR4;
case var _ when name.Equals("B660 DS3H AC DDR4-Y1",StringComparison.OrdinalIgnoreCase):
case var _ when name.Equals("B660 DS3H AC DDR4",StringComparison.OrdinalIgnoreCase):
return Model.B660_DS3H_AC_DDR4;
case var _ when name.Equals("B660M DS3H AX DDR4",StringComparison.OrdinalIgnoreCase):
return Model.B660M_DS3H_AX_DDR4;
case var _ when name.Equals("ROG STRIX Z790-I GAMING WIFI", StringComparison.OrdinalIgnoreCase):
return Model.ROG_STRIX_Z790_I_GAMING_WIFI;
case var _ when name.Equals("ROG STRIX Z790-E GAMING WIFI", StringComparison.OrdinalIgnoreCase):
return Model.ROG_STRIX_Z790_E_GAMING_WIFI;
case var _ when name.Equals("MPG X570 GAMING PLUS (MS-7C37)",StringComparison.OrdinalIgnoreCase):
return Model.X570_Gaming_Plus;
case var _ when name.Equals("ROG MAXIMUS Z790 FORMULA", StringComparison.OrdinalIgnoreCase):
return Model.ROG_MAXIMUS_Z790_FORMULA;
case var _ when name.Equals("Z790 Nova WiFi", StringComparison.OrdinalIgnoreCase):
return Model.Z790_Nova_WiFi;
case var _ when name.Equals("ROG MAXIMUS XII HERO (WI-FI)", StringComparison.OrdinalIgnoreCase):
return Model.ROG_MAXIMUS_XII_HERO_WIFI;
case var _ when name.Equals("X870E AORUS PRO", StringComparison.OrdinalIgnoreCase):
return Model.X870E_AORUS_PRO;
case var _ when name.Equals("X870E AORUS PRO ICE", StringComparison.OrdinalIgnoreCase):
return Model.X870E_AORUS_PRO_ICE;
case var _ when name.Equals("Base Board Product Name", StringComparison.OrdinalIgnoreCase):
case var _ when name.Equals("To be filled by O.E.M.", StringComparison.OrdinalIgnoreCase):
return Model.Unknown;
default:
return Model.Unknown;
}
}
}

View File

@@ -0,0 +1,160 @@
// 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.
// Partial Copyright (C) Michael Möller <mmoeller@openhardwaremonitor.org> and Contributors.
// All Rights Reserved.
using System.Diagnostics.CodeAnalysis;
namespace LibreHardwareMonitor.Hardware.Motherboard.Lpc;
[SuppressMessage("ReSharper", "InconsistentNaming")]
internal enum Chip : ushort
{
Unknown = 0,
ATK0110 = 0x0110,
F71808E = 0x0901,
F71811 = 0x1007,
F71858 = 0x0507,
F71862 = 0x0601,
F71869 = 0x0814,
F71869A = 0x1007,
F71878AD = 0x1106,
F71882 = 0x0541,
F71889AD = 0x1005,
F71889ED = 0x0909,
F71889F = 0x0723,
IT8613E = 0x8613,
IT8620E = 0x8620,
IT8625E = 0x8625,
IT8628E = 0x8628,
IT8631E = 0x8631,
IT8655E = 0x8655,
IT8665E = 0x8665,
IT8686E = 0x8686,
IT8688E = 0x8688,
IT8689E = 0x8689,
IT8696E = 0x8696,
IT8705F = 0x8705,
IT8712F = 0x8712,
IT8716F = 0x8716,
IT8718F = 0x8718,
IT8720F = 0x8720,
IT8721F = 0x8721,
IT8726F = 0x8726,
IT8728F = 0x8728,
IT8771E = 0x8771,
IT8772E = 0x8772,
IT8790E = 0x8790,
IT8792E = 0x8733, // Could also be IT8791E, IT8795E
IT87952E = 0x8695,
NCT610XD = 0xC452,
NCT6771F = 0xB470,
NCT6776F = 0xC330,
NCT6779D = 0xC560,
NCT6791D = 0xC803,
NCT6792D = 0xC911,
NCT6792DA = 0xC913,
NCT6793D = 0xD121,
NCT6795D = 0xD352,
NCT6796D = 0xD423,
NCT6796DR = 0xD42A,
NCT6797D = 0xD451,
NCT6798D = 0xD42B,
NCT6686D = 0xD440,
NCT6687D = 0xD592,
NCT6683D = 0xC732,
NCT6799D = 0xD802,
W83627DHG = 0xA020,
W83627DHGP = 0xB070,
W83627EHF = 0x8800,
W83627HF = 0x5200,
W83627THF = 0x8280,
W83667HG = 0xA510,
W83667HGB = 0xB350,
W83687THF = 0x8541,
IPMI = 0x4764,
}
internal class ChipName
{
public static string GetName(Chip chip)
{
switch (chip)
{
case Chip.ATK0110: return "Asus ATK0110";
case Chip.F71858: return "Fintek F71858";
case Chip.F71862: return "Fintek F71862";
case Chip.F71869: return "Fintek F71869";
case Chip.F71878AD: return "Fintek F71878AD";
case Chip.F71869A: return "Fintek F71869A/F71811";
case Chip.F71882: return "Fintek F71882";
case Chip.F71889AD: return "Fintek F71889AD";
case Chip.F71889ED: return "Fintek F71889ED";
case Chip.F71889F: return "Fintek F71889F";
case Chip.F71808E: return "Fintek F71808E";
case Chip.IT8613E: return "ITE IT8613E";
case Chip.IT8620E: return "ITE IT8620E";
case Chip.IT8625E: return "ITE IT8625E";
case Chip.IT8628E: return "ITE IT8628E";
case Chip.IT8631E: return "ITE IT8631E";
case Chip.IT8655E: return "ITE IT8655E";
case Chip.IT8665E: return "ITE IT8665E";
case Chip.IT8686E: return "ITE IT8686E";
case Chip.IT8688E: return "ITE IT8688E";
case Chip.IT8689E: return "ITE IT8689E";
case Chip.IT8696E: return "ITE IT8696E";
case Chip.IT8705F: return "ITE IT8705F";
case Chip.IT8712F: return "ITE IT8712F";
case Chip.IT8716F: return "ITE IT8716F";
case Chip.IT8718F: return "ITE IT8718F";
case Chip.IT8720F: return "ITE IT8720F";
case Chip.IT8721F: return "ITE IT8721F";
case Chip.IT8726F: return "ITE IT8726F";
case Chip.IT8728F: return "ITE IT8728F";
case Chip.IT8771E: return "ITE IT8771E";
case Chip.IT8772E: return "ITE IT8772E";
case Chip.IT8790E: return "ITE IT8790E";
case Chip.IT8792E: return "ITE IT8791E/IT8792E/IT8795E";
case Chip.IT87952E: return "ITE IT87952E";
case Chip.NCT610XD: return "Nuvoton NCT6102D/NCT6104D/NCT6106D";
case Chip.NCT6771F: return "Nuvoton NCT6771F";
case Chip.NCT6776F: return "Nuvoton NCT6776F";
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";
case Chip.NCT6796DR: return "Nuvoton NCT6796D-R";
case Chip.NCT6797D: return "Nuvoton NCT6797D";
case Chip.NCT6798D: return "Nuvoton NCT6798D";
case Chip.NCT6799D: return "Nuvoton NCT6799D";
case Chip.NCT6686D: return "Nuvoton NCT6686D";
case Chip.NCT6687D: return "Nuvoton NCT6687D";
case Chip.NCT6683D: return "Nuvoton NCT6683D";
case Chip.W83627DHG: return "Winbond W83627DHG";
case Chip.W83627DHGP: return "Winbond W83627DHG-P";
case Chip.W83627EHF: return "Winbond W83627EHF";
case Chip.W83627HF: return "Winbond W83627HF";
case Chip.W83627THF: return "Winbond W83627THF";
case Chip.W83667HG: return "Winbond W83667HG";
case Chip.W83667HGB: return "Winbond W83667HG-B";
case Chip.W83687THF: return "Winbond W83687THF";
case Chip.IPMI: return "IPMI";
default: return "Unknown";
}
}
}

View File

@@ -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}'")
{ }
}
}

View File

@@ -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);

View File

@@ -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; }
}

View File

@@ -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);
}

View File

@@ -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();
}
}

View File

@@ -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
}

View File

@@ -0,0 +1,77 @@
// 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.
// Partial Copyright (C) Michael Möller <mmoeller@openhardwaremonitor.org> and Contributors.
// All Rights Reserved.
using System;
using System.Threading;
namespace LibreHardwareMonitor.Hardware.Motherboard.Lpc;
internal class EcioPortGigabyteController : IGigabyteController
{
private const ushort ControllerVersionOffset = 0x00;
private const ushort ControllerEnableRegister = 0x47;
private const ushort ControllerFanControlArea = 0x900;
private const ushort EcioRegisterPort = 0x3F4;
private const ushort EcioValuePort = 0x3F0;
private readonly IT879xEcioPort _port;
private bool? _initialState;
private EcioPortGigabyteController(IT879xEcioPort port)
{
_port = port;
}
public static EcioPortGigabyteController TryCreate()
{
IT879xEcioPort port = new(EcioRegisterPort, EcioValuePort);
// Check compatibility by querying its version.
if (!port.Read(ControllerFanControlArea + ControllerVersionOffset, out byte majorVersion) || majorVersion != 1)
{
return null;
}
return new EcioPortGigabyteController(port);
}
public bool Enable(bool enabled)
{
ushort offset = ControllerFanControlArea + ControllerEnableRegister;
if (!_port.Read(offset, out byte bCurrent))
{
return false;
}
bool current = Convert.ToBoolean(bCurrent);
_initialState ??= current;
if (current != enabled)
{
if (!_port.Write(offset, Convert.ToByte(enabled)))
{
return false;
}
// Allow the system to catch up.
Thread.Sleep(500);
}
return true;
}
public void Restore()
{
if (_initialState.HasValue)
{
Enable(_initialState.Value);
}
}
}

View File

@@ -0,0 +1,252 @@
// 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.
// Partial Copyright (C) Michael Möller <mmoeller@openhardwaremonitor.org> and Contributors.
// All Rights Reserved.
using System;
using System.Globalization;
using System.Text;
// ReSharper disable once InconsistentNaming
namespace LibreHardwareMonitor.Hardware.Motherboard.Lpc;
internal class F718XX : ISuperIO
{
private readonly ushort _address;
private readonly byte[] _initialFanPwmControl = new byte[4];
private readonly bool[] _restoreDefaultFanPwmControlRequired = new bool[4];
public F718XX(Chip chip, ushort address)
{
_address = address;
Chip = chip;
Voltages = new float?[chip == Chip.F71858 ? 3 : 9];
Temperatures = new float?[chip == Chip.F71808E ? 2 : 3];
Fans = new float?[chip is Chip.F71882 or Chip.F71858 ? 4 : 3];
Controls = new float?[chip == Chip.F71878AD || chip == Chip.F71889AD ? 3 : (chip == Chip.F71882 ? 4 : 0)];
}
public Chip Chip { get; }
public float?[] Controls { get; }
public float?[] Fans { get; }
public float?[] Temperatures { get; }
public float?[] Voltages { get; }
public byte? ReadGpio(int index)
{
return null;
}
public void WriteGpio(int index, byte value)
{ }
public void SetControl(int index, byte? value)
{
if (index < 0 || index >= Controls.Length)
throw new ArgumentOutOfRangeException(nameof(index));
if (!Mutexes.WaitIsaBus(10))
return;
if (value.HasValue)
{
SaveDefaultFanPwmControl(index);
WriteByte(FAN_PWM_REG[index], value.Value);
}
else
{
RestoreDefaultFanPwmControl(index);
}
Mutexes.ReleaseIsaBus();
}
public string GetReport()
{
StringBuilder r = new();
r.AppendLine("LPC " + GetType().Name);
r.AppendLine();
r.Append("Base Address: 0x");
r.AppendLine(_address.ToString("X4", CultureInfo.InvariantCulture));
r.AppendLine();
if (!Mutexes.WaitIsaBus(100))
return r.ToString();
r.AppendLine("Hardware Monitor Registers");
r.AppendLine();
r.AppendLine(" 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F");
r.AppendLine();
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++)
{
r.Append(" ");
r.Append(ReadByte((byte)((i << 4) | j)).ToString("X2",
CultureInfo.InvariantCulture));
}
r.AppendLine();
}
r.AppendLine();
Mutexes.ReleaseIsaBus();
return r.ToString();
}
public void Update()
{
if (!Mutexes.WaitIsaBus(10))
return;
for (int i = 0; i < Voltages.Length; i++)
{
if (Chip == Chip.F71808E && i == 6)
{
// 0x26 is reserved on F71808E
Voltages[i] = 0;
}
else
{
int value = ReadByte((byte)(VOLTAGE_BASE_REG + i));
Voltages[i] = 0.008f * value;
}
}
for (int i = 0; i < Temperatures.Length; i++)
{
switch (Chip)
{
case Chip.F71858:
{
int tableMode = 0x3 & ReadByte(TEMPERATURE_CONFIG_REG);
int high = ReadByte((byte)(TEMPERATURE_BASE_REG + (2 * i)));
int low = ReadByte((byte)(TEMPERATURE_BASE_REG + (2 * i) + 1));
if (high is not 0xbb and not 0xcc)
{
int bits = 0;
switch (tableMode)
{
case 0:
break;
case 1:
bits = 0;
break;
case 2:
bits = (high & 0x80) << 8;
break;
case 3:
bits = (low & 0x01) << 15;
break;
}
bits |= high << 7;
bits |= (low & 0xe0) >> 1;
short value = (short)(bits & 0xfff0);
Temperatures[i] = value / 128.0f;
}
else
{
Temperatures[i] = null;
}
}
break;
default:
{
sbyte value = (sbyte)ReadByte((byte)(TEMPERATURE_BASE_REG + (2 * (i + 1))));
if (value is < sbyte.MaxValue and > 0)
Temperatures[i] = value;
else
Temperatures[i] = null;
}
break;
}
}
for (int i = 0; i < Fans.Length; i++)
{
int value = ReadByte(FAN_TACHOMETER_REG[i]) << 8;
value |= ReadByte((byte)(FAN_TACHOMETER_REG[i] + 1));
if (value > 0)
Fans[i] = value < 0x0fff ? 1.5e6f / value : 0;
else
Fans[i] = null;
}
for (int i = 0; i < Controls.Length; i++)
{
if (Chip == Chip.F71882 || Chip == Chip.F71889AD)
{
Controls[i] = ReadByte((byte)(FAN_PWM_REG[i])) * 100.0f / 0xFF;
}
else
{
Controls[i] = ReadByte((byte)(PWM_VALUES_OFFSET + i)) * 100.0f / 0xFF;
}
}
Mutexes.ReleaseIsaBus();
}
private void SaveDefaultFanPwmControl(int index)
{
if (!_restoreDefaultFanPwmControlRequired[index])
{
_initialFanPwmControl[index] = ReadByte(FAN_PWM_REG[index]);
_restoreDefaultFanPwmControlRequired[index] = true;
}
}
private void RestoreDefaultFanPwmControl(int index)
{
if (_restoreDefaultFanPwmControlRequired[index])
{
WriteByte(FAN_PWM_REG[index], _initialFanPwmControl[index]);
_restoreDefaultFanPwmControlRequired[index] = false;
}
}
private byte ReadByte(byte register)
{
Ring0.WriteIoPort((ushort)(_address + ADDRESS_REGISTER_OFFSET), register);
return Ring0.ReadIoPort((ushort)(_address + DATA_REGISTER_OFFSET));
}
private void WriteByte(byte register, byte value)
{
Ring0.WriteIoPort((ushort)(_address + ADDRESS_REGISTER_OFFSET), register);
Ring0.WriteIoPort((ushort)(_address + DATA_REGISTER_OFFSET), value);
}
// ReSharper disable InconsistentNaming
#pragma warning disable IDE1006 // Naming Styles
private const byte ADDRESS_REGISTER_OFFSET = 0x05;
private const byte DATA_REGISTER_OFFSET = 0x06;
private const byte PWM_VALUES_OFFSET = 0x2D;
private const byte TEMPERATURE_BASE_REG = 0x70;
private const byte TEMPERATURE_CONFIG_REG = 0x69;
private const byte VOLTAGE_BASE_REG = 0x20;
private readonly byte[] FAN_PWM_REG = { 0xA3, 0xB3, 0xC3, 0xD3 };
private readonly byte[] FAN_TACHOMETER_REG = { 0xA0, 0xB0, 0xC0, 0xD0 };
// ReSharper restore InconsistentNaming
#pragma warning restore IDE1006 // Naming Styles
}

View File

@@ -0,0 +1,14 @@
// 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.
// Partial Copyright (C) Michael Möller <mmoeller@openhardwaremonitor.org> and Contributors.
// All Rights Reserved.
namespace LibreHardwareMonitor.Hardware.Motherboard.Lpc;
internal interface IGigabyteController
{
bool Enable(bool enabled);
void Restore();
}

View File

@@ -0,0 +1,33 @@
// 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.
// Partial Copyright (C) Michael Möller <mmoeller@openhardwaremonitor.org> and Contributors.
// All Rights Reserved.
namespace LibreHardwareMonitor.Hardware.Motherboard.Lpc;
internal interface ISuperIO
{
Chip Chip { get; }
float?[] Controls { get; }
float?[] Fans { get; }
float?[] Temperatures { get; }
// get voltage, temperature, fan and control channel values
float?[] Voltages { get; }
// set control value, null = auto
void SetControl(int index, byte? value);
// read and write GPIO
byte? ReadGpio(int index);
void WriteGpio(int index, byte value);
string GetReport();
void Update();
}

View File

@@ -0,0 +1,139 @@
// 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.
// Partial Copyright (C) Michael Möller <mmoeller@openhardwaremonitor.org> and Contributors.
// All Rights Reserved.
using System.Diagnostics;
namespace LibreHardwareMonitor.Hardware.Motherboard.Lpc;
internal class IT879xEcioPort
{
public IT879xEcioPort(ushort registerPort, ushort valuePort)
{
RegisterPort = registerPort;
ValuePort = valuePort;
}
public ushort RegisterPort { get; }
public ushort ValuePort { get; }
public bool Read(ushort offset, out byte value)
{
if (!Init(0xB0, offset))
{
value = 0;
return false;
}
return ReadFromValue(out value);
}
public bool Write(ushort offset, byte value)
{
if (!Init(0xB1, offset))
{
return false;
}
return WriteToValue(value);
}
private bool Init(byte command, ushort offset)
{
if (!WriteToRegister(command))
{
return false;
}
if (!WriteToValue((byte)((offset >> 8) & 0xFF)))
{
return false;
}
if (!WriteToValue((byte)(offset & 0xFF)))
{
return false;
}
return true;
}
private bool WriteToRegister(byte value)
{
if (!WaitIBE())
{
return false;
}
Ring0.WriteIoPort(RegisterPort, value);
return true;
}
private bool WriteToValue(byte value)
{
if (!WaitIBE())
{
return false;
}
Ring0.WriteIoPort(ValuePort, value);
return true;
}
private bool ReadFromValue(out byte value)
{
if (!WaitOBF())
{
value = 0;
return false;
}
value = Ring0.ReadIoPort(ValuePort);
return true;
}
private bool WaitIBE()
{
Stopwatch stopwatch = Stopwatch.StartNew();
try
{
while ((Ring0.ReadIoPort(RegisterPort) & 2) != 0)
{
if (stopwatch.ElapsedMilliseconds > WAIT_TIMEOUT)
{
return false;
}
}
return true;
}
finally
{
stopwatch.Stop();
}
}
private bool WaitOBF()
{
Stopwatch stopwatch = Stopwatch.StartNew();
try
{
while ((Ring0.ReadIoPort(RegisterPort) & 1) == 0)
{
if (stopwatch.ElapsedMilliseconds > WAIT_TIMEOUT)
{
return false;
}
}
return true;
}
finally
{
stopwatch.Stop();
}
}
private const long WAIT_TIMEOUT = 1000L;
}

View File

@@ -0,0 +1,619 @@
// 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.
// Partial Copyright (C) Michael Möller <mmoeller@openhardwaremonitor.org> and Contributors.
// All Rights Reserved.
using System;
using System.Globalization;
using System.Linq;
using System.Text;
using System.Threading;
// ReSharper disable once InconsistentNaming
namespace LibreHardwareMonitor.Hardware.Motherboard.Lpc;
internal class IT87XX : ISuperIO
{
private const int MaxFanHeaders = 6;
private readonly ushort _address;
private readonly ushort _addressReg;
private readonly int _bankCount;
private readonly ushort _dataReg;
private readonly bool[] _fansDisabled = Array.Empty<bool>();
private readonly ushort _gpioAddress;
private readonly int _gpioCount;
private readonly bool _has16BitFanCounter;
private readonly bool _hasExtReg;
private readonly bool[] _initialFanOutputModeEnabled = new bool[3]; // Initial Fan Controller Main Control Register value.
private readonly byte[] _initialFanPwmControl = new byte[MaxFanHeaders]; // This will also store the 2nd control register value.
private readonly byte[] _initialFanPwmControlExt = new byte[MaxFanHeaders];
private readonly bool[] _restoreDefaultFanPwmControlRequired = new bool[MaxFanHeaders];
private readonly byte _version;
private readonly float _voltageGain;
private IGigabyteController _gigabyteController;
private readonly bool _requiresBankSelect; // Fix #780 Set to true for those chips that need a SelectBank(0) to fix dodgy temps and fan speeds
private bool SupportsMultipleBanks => _bankCount > 1;
public IT87XX(Chip chip, ushort address, ushort gpioAddress, byte version, Motherboard motherboard, IGigabyteController gigabyteController)
{
_address = address;
_version = version;
_addressReg = (ushort)(address + ADDRESS_REGISTER_OFFSET);
_dataReg = (ushort)(address + DATA_REGISTER_OFFSET);
_gpioAddress = gpioAddress;
_gigabyteController = gigabyteController;
_requiresBankSelect = false;
Chip = chip;
// Check vendor id
byte vendorId = ReadByte(VENDOR_ID_REGISTER, out bool valid);
if (!valid)
return;
bool hasMatchingVendorId = false;
foreach (byte iteVendorId in ITE_VENDOR_IDS)
{
if (iteVendorId == vendorId)
{
hasMatchingVendorId = true;
break;
}
}
if (!hasMatchingVendorId)
return;
// Bit 0x10 of the configuration register should always be 1
byte configuration = ReadByte(CONFIGURATION_REGISTER, out valid);
if (!valid || ((configuration & 0x10) == 0 && chip != Chip.IT8655E && chip != Chip.IT8665E))
return;
FAN_PWM_CTRL_REG = chip switch
{
Chip.IT8665E or Chip.IT8625E => new byte[] { 0x15, 0x16, 0x17, 0x1e, 0x1f, 0x92 },
Chip.IT8792E => new byte[] { 0x15, 0x16, 0x17 },
_ => new byte[] { 0x15, 0x16, 0x17, 0x7f, 0xa7, 0xaf }
};
_bankCount = chip switch
{
Chip.IT8689E => 4,
_ => 1
};
_hasExtReg = chip is Chip.IT8721F or
Chip.IT8728F or
Chip.IT8665E or
Chip.IT8686E or
Chip.IT8688E or
Chip.IT8689E or
Chip.IT87952E or
Chip.IT8628E or
Chip.IT8625E or
Chip.IT8620E or
Chip.IT8613E or
Chip.IT8792E or
Chip.IT8655E or
Chip.IT8631E or
Chip.IT8696E;
switch (chip)
{
case Chip.IT8613E:
Voltages = new float?[10];
Temperatures = new float?[4];
Fans = new float?[5];
Controls = new float?[4];
break;
case Chip.IT8625E:
Voltages = new float?[7];
Temperatures = new float?[3];
Fans = new float?[6];
Controls = new float?[6];
break;
case Chip.IT8628E:
Voltages = new float?[10];
Temperatures = new float?[6];
Fans = new float?[6];
Controls = new float?[6];
break;
case Chip.IT8631E:
Voltages = new float?[9];
Temperatures = new float?[2];
Fans = new float?[2];
Controls = new float?[2];
break;
case Chip.IT8665E:
Voltages = new float?[9];
Temperatures = new float?[6];
Fans = new float?[6];
Controls = new float?[6];
_requiresBankSelect = true;
break;
case Chip.IT8686E:
Voltages = new float?[10];
Temperatures = new float?[6];
Fans = new float?[6];
Controls = new float?[5];
break;
case Chip.IT8688E:
Voltages = new float?[11];
Temperatures = new float?[6];
Fans = new float?[6];
Controls = new float?[5];
break;
case Chip.IT8689E:
Voltages = new float?[10];
Temperatures = new float?[6];
Fans = new float?[6];
Controls = new float?[6];
break;
case Chip.IT8696E:
Voltages = new float?[10];
Temperatures = new float?[6];
Fans = new float?[6];
Controls = new float?[6];
break;
case Chip.IT87952E:
Voltages = new float?[10];
Temperatures = new float?[3];
Fans = new float?[3];
Controls = new float?[3];
break;
case Chip.IT8655E:
Voltages = new float?[9];
Temperatures = new float?[6];
Fans = new float?[3];
Controls = new float?[3];
_requiresBankSelect = true;
break;
case Chip.IT8792E:
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;
case Chip.IT8620E:
Voltages = new float?[9];
Temperatures = new float?[3];
Fans = new float?[5];
Controls = new float?[5];
break;
default:
Voltages = new float?[9];
Temperatures = new float?[3];
Fans = new float?[5];
Controls = new float?[3];
break;
}
_fansDisabled = new bool[Fans.Length];
// Voltage gain varies by model.
// Conflicting reports on IT8792E: either 0.0109 in linux drivers or 0.011 comparing with Gigabyte board & SIV SW.
_voltageGain = chip switch
{
Chip.IT8613E or Chip.IT8620E or Chip.IT8628E or Chip.IT8631E or Chip.IT8721F or Chip.IT8728F or Chip.IT8771E or Chip.IT8772E or Chip.IT8686E or Chip.IT8688E or Chip.IT8689E or Chip.IT8696E => 0.012f,
Chip.IT8625E or Chip.IT8792E or Chip.IT87952E => 0.011f,
Chip.IT8655E or Chip.IT8665E => 0.0109f,
_ => 0.016f
};
// Older IT8705F and IT8721F revisions do not have 16-bit fan counters.
_has16BitFanCounter = (chip != Chip.IT8705F || version >= 3) && (chip != Chip.IT8712F || version >= 8);
// Disable any fans that aren't set with 16-bit fan counters
if (_has16BitFanCounter)
{
int modes = ReadByte(FAN_TACHOMETER_16BIT_REGISTER, out valid);
if (!valid)
return;
if (Fans.Length >= 5)
{
_fansDisabled[3] = (modes & (1 << 4)) == 0;
_fansDisabled[4] = (modes & (1 << 5)) == 0;
}
if (Fans.Length >= 6)
_fansDisabled[5] = (modes & (1 << 2)) == 0;
}
// Set the number of GPIO sets
_gpioCount = chip switch
{
Chip.IT8712F or Chip.IT8716F or Chip.IT8718F or Chip.IT8726F => 5,
Chip.IT8720F or Chip.IT8721F => 8,
_ => 0
};
}
public Chip Chip { get; }
public float?[] Controls { get; } = Array.Empty<float?>();
public float?[] Fans { get; } = Array.Empty<float?>();
public float?[] Temperatures { get; } = Array.Empty<float?>();
public float?[] Voltages { get; } = Array.Empty<float?>();
public byte? ReadGpio(int index)
{
if (index >= _gpioCount)
return null;
return Ring0.ReadIoPort((ushort)(_gpioAddress + index));
}
public void WriteGpio(int index, byte value)
{
if (index >= _gpioCount)
return;
Ring0.WriteIoPort((ushort)(_gpioAddress + index), value);
}
public void SetControl(int index, byte? value)
{
if (index < 0 || index >= Controls.Length)
throw new ArgumentOutOfRangeException(nameof(index));
if (!Mutexes.WaitIsaBus(10))
return;
if (value.HasValue)
{
SaveDefaultFanPwmControl(index);
// Disable the controller when setting values to prevent it from overriding them
if (_gigabyteController != null)
_gigabyteController.Enable(false);
if (index < 3 && !_initialFanOutputModeEnabled[index])
WriteByte(FAN_MAIN_CTRL_REG, (byte)(ReadByte(FAN_MAIN_CTRL_REG, out _) | (1 << index)));
if (_hasExtReg)
{
if (Chip == Chip.IT8689E)
{
WriteByte(FAN_PWM_CTRL_REG[index], 0x7F);
}
else
{
WriteByte(FAN_PWM_CTRL_REG[index], (byte)(_initialFanPwmControl[index] & 0x7F));
}
WriteByte(FAN_PWM_CTRL_EXT_REG[index], value.Value);
}
else
{
WriteByte(FAN_PWM_CTRL_REG[index], (byte)(value.Value >> 1));
}
}
else
{
RestoreDefaultFanPwmControl(index);
}
Mutexes.ReleaseIsaBus();
}
public string GetReport()
{
StringBuilder r = new();
r.AppendLine("LPC " + GetType().Name);
r.AppendLine();
r.Append("Chip ID: 0x");
r.AppendLine(Chip.ToString("X"));
r.Append("Chip Version: 0x");
r.AppendLine(_version.ToString("X", CultureInfo.InvariantCulture));
r.Append("Base Address: 0x");
r.AppendLine(_address.ToString("X4", CultureInfo.InvariantCulture));
r.Append("GPIO Address: 0x");
r.AppendLine(_gpioAddress.ToString("X4", CultureInfo.InvariantCulture));
r.AppendLine();
if (!Mutexes.WaitIsaBus(100))
return r.ToString();
if (_requiresBankSelect)
SelectBank(0);
// dump memory of all banks if supported by chip
for (byte b = 0; b < _bankCount; b++)
{
if (SupportsMultipleBanks && b > 0)
{
SelectBank(b);
}
r.AppendLine($"Environment Controller Registers Bank {b}");
r.AppendLine();
r.AppendLine(" 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F");
r.AppendLine();
for (int i = 0; i <= 0xA; i++)
{
r.Append(" ");
r.Append((i << 4).ToString("X2", CultureInfo.InvariantCulture));
r.Append(" ");
for (int j = 0; j <= 0xF; j++)
{
r.Append(" ");
byte value = ReadByte((byte)((i << 4) | j), out bool valid);
r.Append(valid ? value.ToString("X2", CultureInfo.InvariantCulture) : "??");
}
r.AppendLine();
}
r.AppendLine();
}
if (SupportsMultipleBanks)
{
SelectBank(0);
}
r.AppendLine();
r.AppendLine("GPIO Registers");
r.AppendLine();
for (int i = 0; i < _gpioCount; i++)
{
r.Append(" ");
r.Append(ReadGpio(i)?.ToString("X2", CultureInfo.InvariantCulture));
}
r.AppendLine();
r.AppendLine();
Mutexes.ReleaseIsaBus();
return r.ToString();
}
/// <summary>
/// Selects another bank. Memory from 0x10-0xAF swaps to data from new bank.
/// Beware to select the default bank 0 after changing.
/// Bank selection is reset after power cycle.
/// </summary>
/// <param name="bankIndex">New bank index. Can be a value of 0-3.</param>
private void SelectBank(byte bankIndex)
{
if (bankIndex >= _bankCount)
return; // current chip does not support that many banks
// hard cap SelectBank to 2 bit values. If we ever have chips with more bank bits rewrite this method.
bankIndex &= 0x3;
byte value = ReadByte(BANK_REGISTER, out bool valid);
if (valid)
{
value &= 0x9F;
value |= (byte)(bankIndex << 5);
WriteByte(BANK_REGISTER, value);
}
}
public void Update()
{
if (!Mutexes.WaitIsaBus(10))
return;
// Is this needed on every update? Yes, until a way to detect resume from sleep/hibernation is added, as that invalidates the bank select.
if (_requiresBankSelect)
SelectBank(0);
for (int i = 0; i < Voltages.Length; i++)
{
float value = _voltageGain * ReadByte((byte)(VOLTAGE_BASE_REG + i), out bool valid);
if (!valid)
continue;
if (value > 0)
Voltages[i] = value;
else
Voltages[i] = null;
}
for (int i = 0; i < Temperatures.Length; i++)
{
sbyte value = (sbyte)ReadByte((byte)(TEMPERATURE_BASE_REG + i), out bool valid);
if (!valid)
continue;
if (value is < sbyte.MaxValue and > 0)
Temperatures[i] = value;
else
Temperatures[i] = null;
}
if (_has16BitFanCounter)
{
for (int i = 0; i < Fans.Length; i++)
{
if (_fansDisabled[i])
continue;
int value = ReadByte(FAN_TACHOMETER_REG[i], out bool valid);
if (!valid)
continue;
value |= ReadByte(FAN_TACHOMETER_EXT_REG[i], out valid) << 8;
if (!valid)
continue;
if (value > 0x3f)
Fans[i] = value < 0xffff ? 1.35e6f / (value * 2) : 0;
else
Fans[i] = null;
}
}
else
{
for (int i = 0; i < Fans.Length; i++)
{
int value = ReadByte(FAN_TACHOMETER_REG[i], out bool valid);
if (!valid)
continue;
int divisor = 2;
if (i < 2)
{
int divisors = ReadByte(FAN_TACHOMETER_DIVISOR_REGISTER, out valid);
if (!valid)
continue;
divisor = 1 << ((divisors >> (3 * i)) & 0x7);
}
if (value > 0)
Fans[i] = value < 0xff ? 1.35e6f / (value * divisor) : 0;
else
Fans[i] = null;
}
}
for (int i = 0; i < Controls.Length; i++)
{
byte value = ReadByte(FAN_PWM_CTRL_REG[i], out bool valid);
if (!valid)
continue;
if ((value & 0x80) > 0)
{
// Automatic operation (value can't be read).
Controls[i] = null;
}
else
{
// Software operation.
if (_hasExtReg)
{
value = ReadByte(FAN_PWM_CTRL_EXT_REG[i], out valid);
if (valid)
Controls[i] = (float)Math.Round(value * 100.0f / 0xFF);
}
else
{
Controls[i] = (float)Math.Round((value & 0x7F) * 100.0f / 0x7F);
}
}
}
Mutexes.ReleaseIsaBus();
}
private byte ReadByte(byte register, out bool valid)
{
Ring0.WriteIoPort(_addressReg, register);
byte value = Ring0.ReadIoPort(_dataReg);
valid = register == Ring0.ReadIoPort(_addressReg) || Chip == Chip.IT8688E;
// IT8688E doesn't return the value we wrote to
// addressReg when we read it back.
return value;
}
private void WriteByte(byte register, byte value)
{
Ring0.WriteIoPort(_addressReg, register);
Ring0.WriteIoPort(_dataReg, value);
Ring0.ReadIoPort(_addressReg);
}
private void SaveDefaultFanPwmControl(int index)
{
if (!_restoreDefaultFanPwmControlRequired[index])
{
_initialFanPwmControl[index] = ReadByte(FAN_PWM_CTRL_REG[index], out bool _);
if (index < 3)
_initialFanOutputModeEnabled[index] = ReadByte(FAN_MAIN_CTRL_REG, out bool _) != 0; // Save default control reg value.
if (_hasExtReg)
_initialFanPwmControlExt[index] = ReadByte(FAN_PWM_CTRL_EXT_REG[index], out _);
}
_restoreDefaultFanPwmControlRequired[index] = true;
}
private void RestoreDefaultFanPwmControl(int index)
{
if (_restoreDefaultFanPwmControlRequired[index])
{
WriteByte(FAN_PWM_CTRL_REG[index], _initialFanPwmControl[index]);
if (index < 3)
{
byte value = ReadByte(FAN_MAIN_CTRL_REG, out _);
bool isEnabled = (value & (1 << index)) != 0;
if (isEnabled != _initialFanOutputModeEnabled[index])
WriteByte(FAN_MAIN_CTRL_REG, (byte)(value ^ (1 << index)));
}
if (_hasExtReg)
WriteByte(FAN_PWM_CTRL_EXT_REG[index], _initialFanPwmControlExt[index]);
_restoreDefaultFanPwmControlRequired[index] = false;
// restore the GB controller when all fans become restored
if (_gigabyteController != null && _restoreDefaultFanPwmControlRequired.All(e => e == false))
_gigabyteController.Restore();
}
}
// ReSharper disable InconsistentNaming
#pragma warning disable IDE1006 // Naming Styles
private const byte ADDRESS_REGISTER_OFFSET = 0x05;
private const byte CONFIGURATION_REGISTER = 0x00;
private const byte DATA_REGISTER_OFFSET = 0x06;
private const byte BANK_REGISTER = 0x06; // bit 5-6 define selected bank
private const byte FAN_TACHOMETER_16BIT_REGISTER = 0x0C;
private const byte FAN_TACHOMETER_DIVISOR_REGISTER = 0x0B;
private readonly byte[] ITE_VENDOR_IDS = { 0x90, 0x7F };
private const byte TEMPERATURE_BASE_REG = 0x29;
private const byte VENDOR_ID_REGISTER = 0x58;
private const byte VOLTAGE_BASE_REG = 0x20;
private readonly byte[] FAN_PWM_CTRL_REG;
private readonly byte[] FAN_PWM_CTRL_EXT_REG = { 0x63, 0x6b, 0x73, 0x7b, 0xa3, 0xab };
private readonly byte[] FAN_TACHOMETER_EXT_REG = { 0x18, 0x19, 0x1a, 0x81, 0x83, 0x4d };
private readonly byte[] FAN_TACHOMETER_REG = { 0x0d, 0x0e, 0x0f, 0x80, 0x82, 0x4c };
// Address of the Fan Controller Main Control Register.
// No need for the 2nd control register (bit 7 of 0x15 0x16 0x17),
// as PWM value will set it to manual mode when new value is set.
private const byte FAN_MAIN_CTRL_REG = 0x13;
#pragma warning restore IDE1006 // Naming Styles
// ReSharper restore InconsistentNaming
}

View File

@@ -0,0 +1,335 @@
// 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.Management;
using System.Runtime.InteropServices;
using System.Text;
namespace LibreHardwareMonitor.Hardware.Motherboard.Lpc;
internal class Ipmi : ISuperIO
{
// ReSharper disable InconsistentNaming
private const byte COMMAND_FAN_LEVEL = 0x70;
private const byte COMMAND_FAN_MODE = 0x45;
private const byte COMMAND_GET_SDR = 0x23;
private const byte COMMAND_GET_SDR_REPOSITORY_INFO = 0x20;
private const byte COMMAND_GET_SENSOR_READING = 0x2d;
private const byte FAN_MODE_FULL = 0x01;
private const byte FAN_MODE_OPTIMAL = 0x02;
private const byte NETWORK_FUNCTION_SENSOR_EVENT = 0x04;
private const byte NETWORK_FUNCTION_STORAGE = 0x0a;
private const byte NETWORK_FUNCTION_SUPERMICRO = 0x30;
// ReSharper restore InconsistentNaming
private readonly List<string> _controlNames = new();
private readonly List<float> _controls = new();
private readonly List<string> _fanNames = new();
private readonly List<float> _fans = new();
private readonly ManagementObject _ipmi;
private readonly Manufacturer _manufacturer;
private readonly List<Interop.Ipmi.Sdr> _sdrs = new();
private readonly List<string> _temperatureNames = new();
private readonly List<float> _temperatures = new();
private readonly List<string> _voltageNames = new();
private readonly List<float> _voltages = new();
private bool _touchedFans;
public Ipmi(Manufacturer manufacturer)
{
Chip = Chip.IPMI;
_manufacturer = manufacturer;
using ManagementClass ipmiClass = new("root\\WMI", "Microsoft_IPMI", null);
foreach (ManagementBaseObject ipmi in ipmiClass.GetInstances())
{
if (ipmi is ManagementObject managementObject)
_ipmi = managementObject;
}
// Fan control is exposed for Supermicro only as it differs between IPMI implementations
if (_manufacturer == Manufacturer.Supermicro)
{
_controlNames.Add("CPU Fan");
_controlNames.Add("System Fan");
}
// Perform an early update to count the number of sensors and get their names
Update();
Controls = new float?[_controls.Count];
Fans = new float?[_fans.Count];
Temperatures = new float?[_temperatures.Count];
Voltages = new float?[_voltages.Count];
}
public Chip Chip { get; }
public float?[] Controls { get; }
public float?[] Fans { get; }
public float?[] Temperatures { get; }
public float?[] Voltages { get; }
public string GetReport()
{
StringBuilder sb = new();
Update(sb);
return sb.ToString();
}
public void SetControl(int index, byte? value)
{
if (_manufacturer == Manufacturer.Supermicro)
{
if (value != null || _touchedFans)
{
_touchedFans = true;
if (value == null)
{
RunIPMICommand(COMMAND_FAN_MODE, NETWORK_FUNCTION_SUPERMICRO, new byte[] { 0x01 /* Set */, FAN_MODE_OPTIMAL });
}
else
{
byte[] fanMode = RunIPMICommand(COMMAND_FAN_MODE, NETWORK_FUNCTION_SUPERMICRO, new byte[] { 0x00 });
if (fanMode == null || fanMode.Length < 2 || fanMode[0] != 0 || fanMode[1] != FAN_MODE_FULL)
RunIPMICommand(COMMAND_FAN_MODE, NETWORK_FUNCTION_SUPERMICRO, new byte[] { 0x01 /* Set */, FAN_MODE_FULL });
float speed = (float)value / 255.0f * 100.0f;
RunIPMICommand(COMMAND_FAN_LEVEL, NETWORK_FUNCTION_SUPERMICRO, new byte[] { 0x66, 0x01 /* Set */, (byte)index, (byte)speed });
}
}
}
else
{
throw new NotImplementedException();
}
}
public void Update()
{
Update(null);
}
private unsafe void Update(StringBuilder stringBuilder)
{
_fans.Clear();
_temperatures.Clear();
_voltages.Clear();
_controls.Clear();
if (_sdrs.Count == 0 || stringBuilder != null)
{
byte[] sdrInfo = RunIPMICommand(COMMAND_GET_SDR_REPOSITORY_INFO, NETWORK_FUNCTION_STORAGE, new byte[] { });
if (sdrInfo?[0] == 0)
{
int recordCount = (sdrInfo[3] * 256) + sdrInfo[2];
byte recordLower = 0;
byte recordUpper = 0;
for (int i = 0; i < recordCount; ++i)
{
byte[] sdrRaw = RunIPMICommand(COMMAND_GET_SDR, NETWORK_FUNCTION_STORAGE, new byte[] { 0, 0, recordLower, recordUpper, 0, 0xff });
if (sdrRaw?.Length >= 3 && sdrRaw[0] == 0)
{
recordLower = sdrRaw[1];
recordUpper = sdrRaw[2];
fixed (byte* pSdr = sdrRaw)
{
Interop.Ipmi.Sdr sdr = (Interop.Ipmi.Sdr)Marshal.PtrToStructure((IntPtr)pSdr + 3, typeof(Interop.Ipmi.Sdr));
_sdrs.Add(sdr);
stringBuilder?.AppendLine("IPMI sensor " + i + " num: " + sdr.sens_num + " info: " + BitConverter.ToString(sdrRaw).Replace("-", ""));
}
}
else
{
break;
}
}
}
}
foreach (Interop.Ipmi.Sdr sdr in _sdrs)
{
if (sdr.rectype == 1)
{
byte[] reading = RunIPMICommand(COMMAND_GET_SENSOR_READING, NETWORK_FUNCTION_SENSOR_EVENT, new[] { sdr.sens_num });
if (reading?.Length > 1 && reading[0] == 0)
{
switch (sdr.sens_type)
{
case 1:
_temperatures.Add(RawToFloat(reading[1], sdr));
if (Temperatures == null || Temperatures.Length == 0)
_temperatureNames.Add(sdr.id_string.Replace(" Temp", ""));
break;
case 2:
_voltages.Add(RawToFloat(reading[1], sdr));
if (Voltages == null || Voltages.Length == 0)
_voltageNames.Add(sdr.id_string);
break;
case 4:
_fans.Add(RawToFloat(reading[1], sdr));
if (Fans == null || Fans.Length == 0)
_fanNames.Add(sdr.id_string);
break;
}
stringBuilder?.AppendLine("IPMI sensor num: " + sdr.sens_num + " reading: " + BitConverter.ToString(reading).Replace("-", ""));
}
}
}
if (_manufacturer == Manufacturer.Supermicro)
{
for (int i = 0; i < _controlNames.Count; ++i)
{
byte[] fanLevel = RunIPMICommand(COMMAND_FAN_LEVEL, NETWORK_FUNCTION_SUPERMICRO, new byte[] { 0x66, 0x00 /* Get */, (byte)i });
if (fanLevel?.Length >= 2 && fanLevel[0] == 0)
{
_controls.Add(fanLevel[1]);
stringBuilder?.AppendLine("IPMI fan " + i + ": " + BitConverter.ToString(fanLevel).Replace("-", ""));
}
}
}
if (Temperatures != null)
{
for (int i = 0; i < Math.Min(_temperatures.Count, Temperatures.Length); ++i)
Temperatures[i] = _temperatures[i];
}
if (Voltages != null)
{
for (int i = 0; i < Math.Min(_voltages.Count, Voltages.Length); ++i)
Voltages[i] = _voltages[i];
}
if (Fans != null)
{
for (int i = 0; i < Math.Min(_fans.Count, Fans.Length); ++i)
Fans[i] = _fans[i];
}
if (Controls != null)
{
for (int i = 0; i < Math.Min(_controls.Count, Controls.Length); ++i)
Controls[i] = _controls[i];
}
}
public IEnumerable<Temperature> GetTemperatures()
{
for (int i = 0; i < _temperatureNames.Count; i++)
yield return new Temperature(_temperatureNames[i], i);
}
public IEnumerable<Fan> GetFans()
{
for (int i = 0; i < _fanNames.Count; i++)
yield return new Fan(_fanNames[i], i);
}
public IEnumerable<Voltage> GetVoltages()
{
for (int i = 0; i < _voltageNames.Count; i++)
yield return new Voltage(_voltageNames[i], i);
}
public IEnumerable<Control> GetControls()
{
for (int i = 0; i < _controlNames.Count; i++)
yield return new Control(_controlNames[i], i);
}
public static bool IsBmcPresent()
{
try
{
using ManagementObjectSearcher searcher = new("root\\WMI", "SELECT * FROM Microsoft_IPMI WHERE Active='True'");
return searcher.Get().Count > 0;
}
catch
{
return false;
}
}
public byte? ReadGpio(int index)
{
return null;
}
public void WriteGpio(int index, byte value)
{ }
private byte[] RunIPMICommand(byte command, byte networkFunction, byte[] requestData)
{
using ManagementBaseObject inParams = _ipmi.GetMethodParameters("RequestResponse");
inParams["NetworkFunction"] = networkFunction;
inParams["Lun"] = 0;
inParams["ResponderAddress"] = 0x20;
inParams["Command"] = command;
inParams["RequestDataSize"] = requestData.Length;
inParams["RequestData"] = requestData;
using ManagementBaseObject outParams = _ipmi.InvokeMethod("RequestResponse", inParams, null);
return (byte[])outParams["ResponseData"];
}
// Ported from ipmiutil
// Bare minimum to read Supermicro X13 IPMI sensors, may need expanding for other boards
private static float RawToFloat(byte sensorReading, Interop.Ipmi.Sdr sdr)
{
double reading = sensorReading;
int m = sdr.m + ((sdr.m_t & 0xc0) << 2);
if (Convert.ToBoolean(m & 0x0200))
m -= 0x0400;
int b = sdr.b + ((sdr.b_a & 0xc0) << 2);
if (Convert.ToBoolean(b & 0x0200))
b -= 0x0400;
int rx = (sdr.rx_bx & 0xf0) >> 4;
if (Convert.ToBoolean(rx & 0x08))
rx -= 0x10;
int bExp = sdr.rx_bx & 0x0f;
if (Convert.ToBoolean(bExp & 0x08))
bExp -= 0x10;
if ((sdr.sens_units & 0xc0) != 0)
reading = Convert.ToBoolean(sensorReading & 0x80) ? sensorReading - 0x100 : sensorReading;
reading *= m;
reading += b * Math.Pow(10, bExp);
reading *= Math.Pow(10, rx);
if (sdr.linear != 0)
throw new NotImplementedException();
return (float)reading;
}
}

View File

@@ -0,0 +1,199 @@
// 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.
// Partial Copyright (C) Michael Möller <mmoeller@openhardwaremonitor.org> and Contributors.
// All Rights Reserved.
using System;
using System.Runtime.InteropServices;
using System.Threading;
using LibreHardwareMonitor.Hardware.Cpu;
namespace LibreHardwareMonitor.Hardware.Motherboard.Lpc;
/// <summary>
/// This is a controller present on some Gigabyte motherboards for both Intel and AMD, that is in custom firmware
/// loaded onto the 2nd ITE EC.
/// It can be accessed by using memory mapped IO, mapping its internal RAM onto main RAM via the ISA Bridge.
/// This class can disable it so that the regular IT87XX code can drive the fans.
/// </summary>
internal class IsaBridgeGigabyteController : IGigabyteController
{
private const uint ControllerAddressRange = 0xFF;
private const int ControllerEnableRegister = 0x47;
private const uint ControllerFanControlArea = 0x900;
/// <summary>
/// Base address in PCI RAM that maps to the EC's RAM
/// </summary>
private readonly uint _controllerBaseAddress;
private readonly Vendor _vendor;
private bool? _initialState;
public IsaBridgeGigabyteController(uint address, Vendor vendor)
{
_controllerBaseAddress = address;
_vendor = vendor;
}
/// <summary>
/// Enable/Disable Fan Control
/// </summary>
/// <param name="enabled"></param>
/// <returns>true on success</returns>
public bool Enable(bool enabled)
{
return _vendor switch
{
Vendor.Intel => IntelEnable(enabled),
Vendor.AMD => AmdEnable(enabled),
_ => false
};
}
private bool IntelEnable(bool enabled)
{
if (!Mutexes.WaitPciBus(10))
return false;
bool result = false;
uint intelIsaBridgeAddress = Ring0.GetPciAddress(0x0, 0x1F, 0x0);
const uint ioOrMemoryPortDecodeEnableRegister = 0xD8;
const uint romAddressRange2Register = 0x98;
uint controllerFanControlAddress = _controllerBaseAddress + ControllerFanControlArea;
Ring0.ReadPciConfig(intelIsaBridgeAddress, ioOrMemoryPortDecodeEnableRegister, out uint originalDecodeEnableRegister);
Ring0.ReadPciConfig(intelIsaBridgeAddress, romAddressRange2Register, out uint originalRomAddressRegister);
bool originalMmIoEnabled = false;
if (!enabled)
{
originalMmIoEnabled = ((int)originalDecodeEnableRegister & 1) == 0 || ((int)originalRomAddressRegister & 1) == 1;
}
else
{
originalMmIoEnabled = ((int)originalDecodeEnableRegister & 1) == 0 && ((int)originalRomAddressRegister & 1) == 1;
}
if (enabled == originalMmIoEnabled)
{
result = Enable(enabled, new IntPtr(controllerFanControlAddress));
Mutexes.ReleasePciBus();
return result;
}
uint lpcBiosDecodeEnable;
uint lpcMemoryRange;
if (enabled)
{
lpcBiosDecodeEnable = ioOrMemoryPortDecodeEnableRegister & ~(uint)(1 << 0);
lpcMemoryRange = romAddressRange2Register | (uint)(1 << 0);
}
else
{
lpcBiosDecodeEnable = Convert.ToUInt32(ioOrMemoryPortDecodeEnableRegister | (uint)(1 << 0));
lpcMemoryRange = Convert.ToUInt32(romAddressRange2Register & ~(uint)(1 << 0));
}
Ring0.WritePciConfig(intelIsaBridgeAddress, ioOrMemoryPortDecodeEnableRegister, lpcBiosDecodeEnable);
Ring0.WritePciConfig(intelIsaBridgeAddress, romAddressRange2Register, lpcMemoryRange);
result = Enable(enabled, new IntPtr(controllerFanControlAddress));
Mutexes.ReleasePciBus();
return result;
}
private bool AmdEnable(bool enabled)
{
if (!Mutexes.WaitPciBus(10))
return false;
// see D14F3x https://www.amd.com/system/files/TechDocs/55072_AMD_Family_15h_Models_70h-7Fh_BKDG.pdf
uint amdIsaBridgeAddress = Ring0.GetPciAddress(0x0, 0x14, 0x3);
const uint ioOrMemoryPortDecodeEnableRegister = 0x48;
const uint memoryRangePortEnableMask = 0x1 << 5;
const uint pciMemoryAddressForLpcTargetCyclesRegister = 0x60;
const uint romAddressRange2Register = 0x6C;
uint controllerFanControlAddress = _controllerBaseAddress + ControllerFanControlArea;
uint pciAddressStart = _controllerBaseAddress >> 0x10;
uint pciAddressEnd = pciAddressStart + 1;
uint enabledPciMemoryAddressRegister = pciAddressEnd << 0x10 | pciAddressStart;
uint enabledRomAddressRegister = 0xFFFFU << 0x10 | pciAddressEnd;
Ring0.ReadPciConfig(amdIsaBridgeAddress, ioOrMemoryPortDecodeEnableRegister, out uint originalDecodeEnableRegister);
Ring0.ReadPciConfig(amdIsaBridgeAddress, pciMemoryAddressForLpcTargetCyclesRegister, out uint originalPciMemoryAddressRegister);
Ring0.ReadPciConfig(amdIsaBridgeAddress, romAddressRange2Register, out uint originalRomAddressRegister);
bool originalMmIoEnabled = (originalDecodeEnableRegister & memoryRangePortEnableMask) != 0 &&
originalPciMemoryAddressRegister == enabledPciMemoryAddressRegister &&
originalRomAddressRegister == enabledRomAddressRegister;
if (!originalMmIoEnabled)
{
Ring0.WritePciConfig(amdIsaBridgeAddress, ioOrMemoryPortDecodeEnableRegister, originalDecodeEnableRegister | memoryRangePortEnableMask);
Ring0.WritePciConfig(amdIsaBridgeAddress, pciMemoryAddressForLpcTargetCyclesRegister, enabledPciMemoryAddressRegister);
Ring0.WritePciConfig(amdIsaBridgeAddress, romAddressRange2Register, enabledRomAddressRegister);
}
bool result = Enable(enabled, new IntPtr(controllerFanControlAddress));
// Restore previous values
if (!originalMmIoEnabled)
{
Ring0.WritePciConfig(amdIsaBridgeAddress, ioOrMemoryPortDecodeEnableRegister, originalDecodeEnableRegister);
Ring0.WritePciConfig(amdIsaBridgeAddress, pciMemoryAddressForLpcTargetCyclesRegister, originalPciMemoryAddressRegister);
Ring0.WritePciConfig(amdIsaBridgeAddress, romAddressRange2Register, originalRomAddressRegister);
}
Mutexes.ReleasePciBus();
return result;
}
private bool Enable(bool enabled, IntPtr pciMmIoBaseAddress)
{
// Map PCI memory to this process memory
if (!InpOut.Open())
return false;
IntPtr mapped = InpOut.MapMemory(pciMmIoBaseAddress, ControllerAddressRange, out IntPtr handle);
if (mapped == IntPtr.Zero)
return false;
bool current = Convert.ToBoolean(Marshal.ReadByte(mapped, ControllerEnableRegister));
_initialState ??= current;
// Update Controller State
if (current != enabled)
{
Marshal.WriteByte(mapped, ControllerEnableRegister, Convert.ToByte(enabled));
// Give it some time to see the change
Thread.Sleep(500);
}
InpOut.UnmapMemory(handle, mapped);
return true;
}
/// <summary>
/// Restore settings back to initial values
/// </summary>
public void Restore()
{
if (_initialState.HasValue)
Enable(_initialState.Value);
}
}

View File

@@ -0,0 +1,301 @@
// 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.
// Partial Copyright (C) Michael Möller <mmoeller@openhardwaremonitor.org> and Contributors.
// All Rights Reserved.
using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Text;
// ReSharper disable once InconsistentNaming
namespace LibreHardwareMonitor.Hardware.Motherboard.Lpc;
internal class LMSensors
{
private const string HwMonPath = "/sys/class/hwmon/";
private readonly List<ISuperIO> _superIOs = [];
public LMSensors()
{
if (!Directory.Exists(HwMonPath))
return;
foreach (string basePath in Directory.GetDirectories(HwMonPath))
{
foreach (string devicePath in new[] { "/device", string.Empty })
{
string path = basePath + devicePath;
string name = null;
try
{
using StreamReader reader = new(path + "/name");
name = reader.ReadLine();
}
catch (IOException)
{ }
switch (name)
{
case "atk0110":
_superIOs.Add(new LMChip(Chip.ATK0110, path));
break;
case "f71858fg":
_superIOs.Add(new LMChip(Chip.F71858, path));
break;
case "f71862fg":
_superIOs.Add(new LMChip(Chip.F71862, path));
break;
case "f71869":
_superIOs.Add(new LMChip(Chip.F71869, path));
break;
case "f71869a":
_superIOs.Add(new LMChip(Chip.F71869A, path));
break;
case "f71882fg":
_superIOs.Add(new LMChip(Chip.F71882, path));
break;
case "f71889a":
_superIOs.Add(new LMChip(Chip.F71889AD, path));
break;
case "f71878ad":
_superIOs.Add(new LMChip(Chip.F71878AD, path));
break;
case "f71889ed":
_superIOs.Add(new LMChip(Chip.F71889ED, path));
break;
case "f71889fg":
_superIOs.Add(new LMChip(Chip.F71889F, path));
break;
case "f71808e":
_superIOs.Add(new LMChip(Chip.F71808E, path));
break;
case "it8705":
_superIOs.Add(new LMChip(Chip.IT8705F, path));
break;
case "it8712":
_superIOs.Add(new LMChip(Chip.IT8712F, path));
break;
case "it8716":
_superIOs.Add(new LMChip(Chip.IT8716F, path));
break;
case "it8718":
_superIOs.Add(new LMChip(Chip.IT8718F, path));
break;
case "it8720":
_superIOs.Add(new LMChip(Chip.IT8720F, path));
break;
case "nct6775":
_superIOs.Add(new LMChip(Chip.NCT6771F, path));
break;
case "nct6776":
_superIOs.Add(new LMChip(Chip.NCT6776F, path));
break;
case "nct6779":
_superIOs.Add(new LMChip(Chip.NCT6779D, path));
break;
case "nct6791":
_superIOs.Add(new LMChip(Chip.NCT6791D, path));
break;
case "nct6792":
_superIOs.Add(new LMChip(Chip.NCT6792D, path));
break;
case "nct6793":
_superIOs.Add(new LMChip(Chip.NCT6793D, path));
break;
case "nct6795":
_superIOs.Add(new LMChip(Chip.NCT6795D, path));
break;
case "nct6796":
_superIOs.Add(new LMChip(Chip.NCT6796D, path));
break;
case "nct6797":
_superIOs.Add(new LMChip(Chip.NCT6797D, path));
break;
case "nct6798":
_superIOs.Add(new LMChip(Chip.NCT6798D, path));
break;
case "nct6799":
_superIOs.Add(new LMChip(Chip.NCT6799D, path));
break;
case "w83627ehf":
_superIOs.Add(new LMChip(Chip.W83627EHF, path));
break;
case "w83627dhg":
_superIOs.Add(new LMChip(Chip.W83627DHG, path));
break;
case "w83667hg":
_superIOs.Add(new LMChip(Chip.W83667HG, path));
break;
case "w83627hf":
_superIOs.Add(new LMChip(Chip.W83627HF, path));
break;
case "w83627thf":
_superIOs.Add(new LMChip(Chip.W83627THF, path));
break;
case "w83687thf":
_superIOs.Add(new LMChip(Chip.W83687THF, path));
break;
}
}
}
}
public IReadOnlyList<ISuperIO> SuperIO
{
get { return _superIOs; }
}
public void Close()
{
foreach (ISuperIO superIO in _superIOs)
{
if (superIO is LMChip lmChip)
lmChip.Close();
}
}
private class LMChip : ISuperIO
{
private readonly FileStream[] _fanStreams;
private readonly FileStream[] _temperatureStreams;
private readonly FileStream[] _voltageStreams;
private string _path;
public LMChip(Chip chip, string path)
{
_path = path;
Chip = chip;
string[] voltagePaths = Directory.GetFiles(path, "in*_input");
Voltages = new float?[voltagePaths.Length];
_voltageStreams = new FileStream[voltagePaths.Length];
for (int i = 0; i < voltagePaths.Length; i++)
_voltageStreams[i] = new FileStream(voltagePaths[i], FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
string[] temperaturePaths = Directory.GetFiles(path, "temp*_input");
Temperatures = new float?[temperaturePaths.Length];
_temperatureStreams = new FileStream[temperaturePaths.Length];
for (int i = 0; i < temperaturePaths.Length; i++)
_temperatureStreams[i] = new FileStream(temperaturePaths[i], FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
string[] fanPaths = Directory.GetFiles(path, "fan*_input");
Fans = new float?[fanPaths.Length];
_fanStreams = new FileStream[fanPaths.Length];
for (int i = 0; i < fanPaths.Length; i++)
_fanStreams[i] = new FileStream(fanPaths[i], FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
Controls = Array.Empty<float?>();
}
public Chip Chip { get; }
public float?[] Controls { get; }
public float?[] Fans { get; }
public float?[] Temperatures { get; }
public float?[] Voltages { get; }
public byte? ReadGpio(int index)
{
return null;
}
public void WriteGpio(int index, byte value)
{ }
public string GetReport()
{
return null;
}
public void SetControl(int index, byte? value)
{ }
public void Update()
{
for (int i = 0; i < Voltages.Length; i++)
{
string s = ReadFirstLine(_voltageStreams[i]);
try
{
Voltages[i] = 0.001f *
long.Parse(s, CultureInfo.InvariantCulture);
}
catch
{
Voltages[i] = null;
}
}
for (int i = 0; i < Temperatures.Length; i++)
{
string s = ReadFirstLine(_temperatureStreams[i]);
try
{
Temperatures[i] = 0.001f *
long.Parse(s, CultureInfo.InvariantCulture);
}
catch
{
Temperatures[i] = null;
}
}
for (int i = 0; i < Fans.Length; i++)
{
string s = ReadFirstLine(_fanStreams[i]);
try
{
Fans[i] = long.Parse(s, CultureInfo.InvariantCulture);
}
catch
{
Fans[i] = null;
}
}
}
private static string ReadFirstLine(Stream stream)
{
StringBuilder sb = new();
try
{
stream.Seek(0, SeekOrigin.Begin);
int b = stream.ReadByte();
while (b is not -1 and not 10)
{
sb.Append((char)b);
b = stream.ReadByte();
}
}
catch
{ }
return sb.ToString();
}
public void Close()
{
foreach (FileStream stream in _voltageStreams)
stream.Close();
foreach (FileStream stream in _temperatureStreams)
stream.Close();
foreach (FileStream stream in _fanStreams)
stream.Close();
}
}
}

View File

@@ -0,0 +1,751 @@
// 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.
// Partial Copyright (C) Michael Möller <mmoeller@openhardwaremonitor.org> and Contributors.
// All Rights Reserved.
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Text;
using System.Threading;
using LibreHardwareMonitor.Hardware.Cpu;
namespace LibreHardwareMonitor.Hardware.Motherboard.Lpc;
internal class LpcIO
{
private readonly StringBuilder _report = new();
private readonly List<ISuperIO> _superIOs = new();
public LpcIO(Motherboard motherboard)
{
if (!Ring0.IsOpen || !Mutexes.WaitIsaBus(100))
return;
Detect(motherboard);
Mutexes.ReleaseIsaBus();
if (Ipmi.IsBmcPresent())
_superIOs.Add(new Ipmi(motherboard.Manufacturer));
}
public ISuperIO[] SuperIO => _superIOs.ToArray();
private void ReportUnknownChip(LpcPort port, string type, int chip)
{
_report.Append("Chip ID: Unknown ");
_report.Append(type);
_report.Append(" with ID 0x");
_report.Append(chip.ToString("X", CultureInfo.InvariantCulture));
_report.Append(" at 0x");
_report.Append(port.RegisterPort.ToString("X", CultureInfo.InvariantCulture));
_report.Append("/0x");
_report.AppendLine(port.ValuePort.ToString("X", CultureInfo.InvariantCulture));
_report.AppendLine();
}
private bool DetectSmsc(LpcPort port)
{
port.SmscEnter();
ushort chipId = port.ReadWord(CHIP_ID_REGISTER);
if (chipId is not 0 and not 0xffff)
{
port.SmscExit();
ReportUnknownChip(port, "SMSC", chipId);
}
return false;
}
private void Detect(Motherboard motherboard)
{
for (int i = 0; i < REGISTER_PORTS.Length; i++)
{
var port = new LpcPort(REGISTER_PORTS[i], VALUE_PORTS[i]);
if (DetectWinbondFintek(port)) continue;
if (DetectIT87(port, motherboard)) continue;
if (DetectSmsc(port)) continue;
}
}
public string GetReport()
{
if (_report.Length > 0)
{
return "LpcIO" + Environment.NewLine + Environment.NewLine + _report;
}
return null;
}
private bool DetectWinbondFintek(LpcPort port)
{
port.WinbondNuvotonFintekEnter();
byte logicalDeviceNumber = 0;
byte id = port.ReadByte(CHIP_ID_REGISTER);
byte revision = port.ReadByte(CHIP_REVISION_REGISTER);
Chip chip = Chip.Unknown;
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;
case 0x18:
chip = Chip.F71811;
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 0xC7:
switch (revision)
{
case 0x32:
chip = Chip.NCT6683D;
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;
case 0x40:
case 0x41:
chip = Chip.NCT6686D;
logicalDeviceNumber = WINBOND_NUVOTON_HARDWARE_MONITOR_LDN;
break;
}
break;
case 0xD5:
switch (revision)
{
case 0x92:
chip = Chip.NCT6687D;
logicalDeviceNumber = WINBOND_NUVOTON_HARDWARE_MONITOR_LDN;
break;
}
break;
case 0xD8:
switch (revision)
{
case 0x02:
chip = Chip.NCT6799D;
logicalDeviceNumber = WINBOND_NUVOTON_HARDWARE_MONITOR_LDN;
break;
}
break;
}
if (chip == Chip.Unknown)
{
if (id is not 0 and not 0xff)
{
port.WinbondNuvotonFintekExit();
ReportUnknownChip(port, "Winbond / Nuvoton / Fintek", (id << 8) | revision);
}
}
else
{
port.Select(logicalDeviceNumber);
ushort address = port.ReadWord(BASE_ADDRESS_REGISTER);
Thread.Sleep(1);
ushort verify = port.ReadWord(BASE_ADDRESS_REGISTER);
ushort vendorId = port.ReadWord(FINTEK_VENDOR_ID_REGISTER);
// disable the hardware monitor i/o space lock on NCT679XD chips
if (address == verify &&
chip is Chip.NCT6791D or Chip.NCT6792D or Chip.NCT6792DA or Chip.NCT6793D or Chip.NCT6795D or Chip.NCT6796D or Chip.NCT6796DR or Chip.NCT6798D or Chip.NCT6797D or Chip.NCT6799D)
{
port.NuvotonDisableIOSpaceLock();
}
port.WinbondNuvotonFintekExit();
if (address != verify)
{
_report.Append("Chip ID: 0x");
_report.AppendLine(chip.ToString("X"));
_report.Append("Chip revision: 0x");
_report.AppendLine(revision.ToString("X", CultureInfo.InvariantCulture));
_report.AppendLine("Error: Address verification failed");
_report.AppendLine();
return false;
}
// some Fintek chips have address register offset 0x05 added already
if ((address & 0x07) == 0x05)
address &= 0xFFF8;
if (address < 0x100 || (address & 0xF007) != 0)
{
_report.Append("Chip ID: 0x");
_report.AppendLine(chip.ToString("X"));
_report.Append("Chip revision: 0x");
_report.AppendLine(revision.ToString("X", CultureInfo.InvariantCulture));
_report.Append("Error: Invalid address 0x");
_report.AppendLine(address.ToString("X", CultureInfo.InvariantCulture));
_report.AppendLine();
return false;
}
switch (chip)
{
case Chip.W83627DHG:
case Chip.W83627DHGP:
case Chip.W83627EHF:
case Chip.W83627HF:
case Chip.W83627THF:
case Chip.W83667HG:
case Chip.W83667HGB:
case Chip.W83687THF:
_superIOs.Add(new W836XX(chip, revision, address));
break;
case Chip.NCT610XD:
case Chip.NCT6771F:
case Chip.NCT6776F:
case Chip.NCT6779D:
case Chip.NCT6791D:
case Chip.NCT6792D:
case Chip.NCT6792DA:
case Chip.NCT6793D:
case Chip.NCT6795D:
case Chip.NCT6796D:
case Chip.NCT6796DR:
case Chip.NCT6797D:
case Chip.NCT6798D:
case Chip.NCT6799D:
case Chip.NCT6686D:
case Chip.NCT6687D:
case Chip.NCT6683D:
_superIOs.Add(new Nct677X(chip, revision, address, port));
break;
case Chip.F71858:
case Chip.F71862:
case Chip.F71869:
case Chip.F71878AD:
case Chip.F71869A:
case Chip.F71882:
case Chip.F71889AD:
case Chip.F71889ED:
case Chip.F71889F:
case Chip.F71808E:
if (vendorId != FINTEK_VENDOR_ID)
{
_report.Append("Chip ID: 0x");
_report.AppendLine(chip.ToString("X"));
_report.Append("Chip revision: 0x");
_report.AppendLine(revision.ToString("X", CultureInfo.InvariantCulture));
_report.Append("Error: Invalid vendor ID 0x");
_report.AppendLine(vendorId.ToString("X", CultureInfo.InvariantCulture));
_report.AppendLine();
return false;
}
_superIOs.Add(new F718XX(chip, address));
break;
}
return true;
}
return false;
}
private bool DetectIT87(LpcPort port, Motherboard motherboard)
{
// IT87XX can enter only on port 0x2E
// IT8792 using 0x4E
if (port.RegisterPort is not 0x2E and not 0x4E)
return false;
// Read the chip ID before entering.
// If already entered (not 0xFFFF) and the register port is 0x4E, it is most likely bugged and should be left alone.
// Entering IT8792 in this state will result in IT8792 reporting with chip ID of 0x8883.
if (port.RegisterPort != 0x4E || !port.TryReadWord(CHIP_ID_REGISTER, out ushort chipId))
{
port.IT87Enter();
chipId = port.ReadWord(CHIP_ID_REGISTER);
}
Chip chip = chipId switch
{
0x8613 => Chip.IT8613E,
0x8620 => Chip.IT8620E,
0x8625 => Chip.IT8625E,
0x8628 => Chip.IT8628E,
0x8631 => Chip.IT8631E,
0x8665 => Chip.IT8665E,
0x8655 => Chip.IT8655E,
0x8686 => Chip.IT8686E,
0x8688 => Chip.IT8688E,
0x8689 => Chip.IT8689E,
0x8696 => Chip.IT8696E,
0x8705 => Chip.IT8705F,
0x8712 => Chip.IT8712F,
0x8716 => Chip.IT8716F,
0x8718 => Chip.IT8718F,
0x8720 => Chip.IT8720F,
0x8721 => Chip.IT8721F,
0x8726 => Chip.IT8726F,
0x8728 => Chip.IT8728F,
0x8771 => Chip.IT8771E,
0x8772 => Chip.IT8772E,
0x8790 => Chip.IT8790E,
0x8733 => Chip.IT8792E,
0x8695 => Chip.IT87952E,
_ => Chip.Unknown
};
if (chip == Chip.Unknown)
{
if (chipId is not 0 and not 0xffff)
{
port.IT87Exit();
ReportUnknownChip(port, "ITE", chipId);
}
}
else
{
port.Select(IT87_ENVIRONMENT_CONTROLLER_LDN);
ushort address = port.ReadWord(BASE_ADDRESS_REGISTER);
Thread.Sleep(1);
ushort verify = port.ReadWord(BASE_ADDRESS_REGISTER);
byte version = (byte)(port.ReadByte(IT87_CHIP_VERSION_REGISTER) & 0x0F);
ushort gpioAddress;
ushort gpioVerify;
if (chip == Chip.IT8705F)
{
port.Select(IT8705_GPIO_LDN);
gpioAddress = port.ReadWord(BASE_ADDRESS_REGISTER);
Thread.Sleep(1);
gpioVerify = port.ReadWord(BASE_ADDRESS_REGISTER);
}
else
{
port.Select(IT87XX_GPIO_LDN);
gpioAddress = port.ReadWord(BASE_ADDRESS_REGISTER + 2);
Thread.Sleep(1);
gpioVerify = port.ReadWord(BASE_ADDRESS_REGISTER + 2);
}
IGigabyteController gigabyteController = FindGigabyteEC(port, chip, motherboard);
port.IT87Exit();
if (address != verify || address < 0x100 || (address & 0xF007) != 0)
{
_report.Append("Chip ID: 0x");
_report.AppendLine(chip.ToString("X"));
_report.Append("Error: Invalid address 0x");
_report.AppendLine(address.ToString("X", CultureInfo.InvariantCulture));
_report.AppendLine();
return false;
}
if (gpioAddress != gpioVerify || gpioAddress < 0x100 || (gpioAddress & 0xF007) != 0)
{
_report.Append("Chip ID: 0x");
_report.AppendLine(chip.ToString("X"));
_report.Append("Error: Invalid GPIO address 0x");
_report.AppendLine(gpioAddress.ToString("X", CultureInfo.InvariantCulture));
_report.AppendLine();
return false;
}
_superIOs.Add(new IT87XX(chip, address, gpioAddress, version, motherboard, gigabyteController));
return true;
}
return false;
}
private IGigabyteController FindGigabyteEC(LpcPort port, Chip chip, Motherboard motherboard)
{
// The controller only affects the 2nd ITE chip if present, and only a few
// models are known to use this controller.
// IT8795E likely to need this too, but may use different registers.
if (motherboard.Manufacturer != Manufacturer.Gigabyte || port.RegisterPort != 0x4E || chip is not (Chip.IT8790E or Chip.IT8792E or Chip.IT87952E))
return null;
Vendor vendor = DetectVendor();
IGigabyteController gigabyteController = FindGigabyteECUsingSmfi(port, chip, vendor);
if (gigabyteController != null)
return gigabyteController;
// ECIO is only available on AMD motherboards with IT8791E/IT8792E/IT8795E.
if (chip == Chip.IT8792E && vendor == Vendor.AMD)
{
gigabyteController = EcioPortGigabyteController.TryCreate();
if (gigabyteController != null)
return gigabyteController;
}
return null;
Vendor DetectVendor()
{
string manufacturer = motherboard.SMBios.Processors[0].ManufacturerName;
if (manufacturer.IndexOf("Intel", StringComparison.OrdinalIgnoreCase) != -1)
return Vendor.Intel;
if (manufacturer.IndexOf("Advanced Micro Devices", StringComparison.OrdinalIgnoreCase) != -1 || manufacturer.StartsWith("AMD", StringComparison.OrdinalIgnoreCase))
return Vendor.AMD;
return Vendor.Unknown;
}
}
private IGigabyteController FindGigabyteECUsingSmfi(LpcPort port, Chip chip, Vendor vendor)
{
port.Select(IT87XX_SMFI_LDN);
// Check if the SMFI logical device is enabled
byte enabled = port.ReadByte(IT87_LD_ACTIVE_REGISTER);
Thread.Sleep(1);
byte enabledVerify = port.ReadByte(IT87_LD_ACTIVE_REGISTER);
// The EC has no SMFI or it's RAM access is not enabled, assume the controller is not present
if (enabled != enabledVerify || enabled == 0)
return null;
// Read the host RAM address that maps to the Embedded Controller's RAM (two registers).
uint addressHi = 0;
uint addressHiVerify = 0;
uint address = port.ReadWord(IT87_SMFI_HLPC_RAM_BASE_ADDRESS_REGISTER);
if (chip == Chip.IT87952E)
addressHi = port.ReadByte(IT87_SMFI_HLPC_RAM_BASE_ADDRESS_REGISTER_HIGH);
Thread.Sleep(1);
uint addressVerify = port.ReadWord(IT87_SMFI_HLPC_RAM_BASE_ADDRESS_REGISTER);
if (chip == Chip.IT87952E)
addressHiVerify = port.ReadByte(IT87_SMFI_HLPC_RAM_BASE_ADDRESS_REGISTER_HIGH);
if ((address != addressVerify) || (addressHi != addressHiVerify))
return null;
// Address is xryy, Host Address is FFyyx000
// For IT87952E, Address is rzxryy, Host Address is (0xFC000000 | 0x0zyyx000)
uint hostAddress;
if (chip == Chip.IT87952E)
hostAddress = 0xFC000000;
else
hostAddress = 0xFF000000;
hostAddress |= (address & 0xF000) | ((address & 0xFF) << 16) | ((addressHi & 0xF) << 24);
return new IsaBridgeGigabyteController(hostAddress, vendor);
}
// ReSharper disable InconsistentNaming
private const byte BASE_ADDRESS_REGISTER = 0x60;
private const byte CHIP_ID_REGISTER = 0x20;
private const byte CHIP_REVISION_REGISTER = 0x21;
private const byte F71858_HARDWARE_MONITOR_LDN = 0x02;
private const byte FINTEK_HARDWARE_MONITOR_LDN = 0x04;
private const byte IT87_ENVIRONMENT_CONTROLLER_LDN = 0x04;
private const byte IT8705_GPIO_LDN = 0x05;
private const byte IT87XX_GPIO_LDN = 0x07;
// Shared Memory/Flash Interface
private const byte IT87XX_SMFI_LDN = 0x0F;
private const byte WINBOND_NUVOTON_HARDWARE_MONITOR_LDN = 0x0B;
private const ushort FINTEK_VENDOR_ID = 0x1934;
private const byte FINTEK_VENDOR_ID_REGISTER = 0x23;
private const byte IT87_CHIP_VERSION_REGISTER = 0x22;
private const byte IT87_SMFI_HLPC_RAM_BASE_ADDRESS_REGISTER = 0xF5;
private const byte IT87_SMFI_HLPC_RAM_BASE_ADDRESS_REGISTER_HIGH = 0xFC;
private const byte IT87_LD_ACTIVE_REGISTER = 0x30;
private readonly ushort[] REGISTER_PORTS = { 0x2E, 0x4E };
private readonly ushort[] VALUE_PORTS = { 0x2F, 0x4F };
// ReSharper restore InconsistentNaming
}

View File

@@ -0,0 +1,105 @@
// 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.
// Partial Copyright (C) Michael Möller <mmoeller@openhardwaremonitor.org> and Contributors.
// All Rights Reserved.
namespace LibreHardwareMonitor.Hardware.Motherboard.Lpc;
internal class LpcPort
{
public LpcPort(ushort registerPort, ushort valuePort)
{
RegisterPort = registerPort;
ValuePort = valuePort;
}
public ushort RegisterPort { get; }
public ushort ValuePort { get; }
public byte ReadByte(byte register)
{
Ring0.WriteIoPort(RegisterPort, register);
return Ring0.ReadIoPort(ValuePort);
}
public void WriteByte(byte register, byte value)
{
Ring0.WriteIoPort(RegisterPort, register);
Ring0.WriteIoPort(ValuePort, value);
}
public ushort ReadWord(byte register)
{
return (ushort)((ReadByte(register) << 8) | ReadByte((byte)(register + 1)));
}
public bool TryReadWord(byte register, out ushort value)
{
value = ReadWord(register);
return value != 0xFFFF;
}
public void Select(byte logicalDeviceNumber)
{
Ring0.WriteIoPort(RegisterPort, DEVICE_SELECT_REGISTER);
Ring0.WriteIoPort(ValuePort, logicalDeviceNumber);
}
public void WinbondNuvotonFintekEnter()
{
Ring0.WriteIoPort(RegisterPort, 0x87);
Ring0.WriteIoPort(RegisterPort, 0x87);
}
public void WinbondNuvotonFintekExit()
{
Ring0.WriteIoPort(RegisterPort, 0xAA);
}
public void NuvotonDisableIOSpaceLock()
{
byte options = ReadByte(NUVOTON_HARDWARE_MONITOR_IO_SPACE_LOCK);
// if the i/o space lock is enabled
if ((options & 0x10) > 0)
{
// disable the i/o space lock
WriteByte(NUVOTON_HARDWARE_MONITOR_IO_SPACE_LOCK, (byte)(options & ~0x10));
}
}
public void IT87Enter()
{
Ring0.WriteIoPort(RegisterPort, 0x87);
Ring0.WriteIoPort(RegisterPort, 0x01);
Ring0.WriteIoPort(RegisterPort, 0x55);
Ring0.WriteIoPort(RegisterPort, RegisterPort == 0x4E ? (byte)0xAA : (byte)0x55);
}
public void IT87Exit()
{
// 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()
{
Ring0.WriteIoPort(RegisterPort, 0x55);
}
public void SmscExit()
{
Ring0.WriteIoPort(RegisterPort, 0xAA);
}
// ReSharper disable InconsistentNaming
private const byte CONFIGURATION_CONTROL_REGISTER = 0x02;
private const byte DEVICE_SELECT_REGISTER = 0x07;
private const byte NUVOTON_HARDWARE_MONITOR_IO_SPACE_LOCK = 0x28;
// ReSharper restore InconsistentNaming
}

View File

@@ -0,0 +1,516 @@
// 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.
// Partial Copyright (C) Michael Möller <mmoeller@openhardwaremonitor.org> and Contributors.
// All Rights Reserved.
using System;
using System.Globalization;
using System.Text;
// ReSharper disable once InconsistentNaming
namespace LibreHardwareMonitor.Hardware.Motherboard.Lpc;
internal class W836XX : ISuperIO
{
private readonly ushort _address;
private readonly byte _revision;
private readonly bool[] _peciTemperature = Array.Empty<bool>();
private readonly byte[] _voltageBank = Array.Empty<byte>();
private readonly float _voltageGain = 0.008f;
private readonly byte[] _voltageRegister = Array.Empty<byte>();
// Added to control fans.
private readonly byte[] _fanPwmRegister = Array.Empty<byte>();
private readonly byte[] _fanPrimaryControlModeRegister = Array.Empty<byte>();
private readonly byte[] _fanPrimaryControlValue = Array.Empty<byte>();
private readonly byte[] _fanSecondaryControlModeRegister = Array.Empty<byte>();
private readonly byte[] _fanSecondaryControlValue = Array.Empty<byte>();
private readonly byte[] _fanTertiaryControlModeRegister = Array.Empty<byte>();
private readonly byte[] _fanTertiaryControlValue = Array.Empty<byte>();
private readonly byte[] _initialFanControlValue = Array.Empty<byte>();
private readonly byte[] _initialFanSecondaryControlValue = Array.Empty<byte>();
private readonly byte[] _initialFanTertiaryControlValue = Array.Empty<byte>();
private readonly bool[] _restoreDefaultFanPwmControlRequired = Array.Empty<bool>();
public W836XX(Chip chip, byte revision, ushort address)
{
_address = address;
_revision = revision;
Chip = chip;
if (!IsWinbondVendor())
return;
Temperatures = new float?[3];
_peciTemperature = new bool[3];
switch (chip)
{
case Chip.W83667HG:
case Chip.W83667HGB:
// note temperature sensor registers that read PECI
byte flag = ReadByte(0, TEMPERATURE_SOURCE_SELECT_REG);
_peciTemperature[0] = (flag & 0x04) != 0;
_peciTemperature[1] = (flag & 0x40) != 0;
_peciTemperature[2] = false;
break;
case Chip.W83627DHG:
case Chip.W83627DHGP:
// note temperature sensor registers that read PECI
byte sel = ReadByte(0, TEMPERATURE_SOURCE_SELECT_REG);
_peciTemperature[0] = (sel & 0x07) != 0;
_peciTemperature[1] = (sel & 0x70) != 0;
_peciTemperature[2] = false;
break;
default:
// no PECI support
_peciTemperature[0] = false;
_peciTemperature[1] = false;
_peciTemperature[2] = false;
break;
}
switch (chip)
{
case Chip.W83627EHF:
Voltages = new float?[10];
_voltageRegister = new byte[] { 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x50, 0x51, 0x52 };
_voltageBank = new byte[] { 0, 0, 0, 0, 0, 0, 0, 5, 5, 5 };
_voltageGain = 0.008f;
Fans = new float?[5];
_fanPwmRegister = new byte[] { 0x01, 0x03, 0x11 }; // Fan PWM values.
_fanPrimaryControlModeRegister = new byte[] { 0x04, 0x04, 0x12 }; // Primary control register.
_fanPrimaryControlValue = new byte[] { 0b11110011, 0b11001111, 0b11111001 }; // Values to gain control of fans.
_initialFanControlValue = new byte[3]; // To store primary default value.
_initialFanSecondaryControlValue = new byte[3]; // To store secondary default value.
Controls = new float?[3];
break;
case Chip.W83627DHG:
case Chip.W83627DHGP:
Voltages = new float?[9];
_voltageRegister = new byte[] { 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x50, 0x51 };
_voltageBank = new byte[] { 0, 0, 0, 0, 0, 0, 0, 5, 5 };
_voltageGain = 0.008f;
Fans = new float?[5];
_fanPwmRegister = new byte[] { 0x01, 0x03, 0x11 }; // Fan PWM values
_fanPrimaryControlModeRegister = new byte[] { 0x04, 0x04, 0x12 }; // added. Primary control register
_fanPrimaryControlValue = new byte[] { 0b11110011, 0b11001111, 0b11111001 }; // Values to gain control of fans
_initialFanControlValue = new byte[3]; // To store primary default value
_initialFanSecondaryControlValue = new byte[3]; // To store secondary default value.
Controls = new float?[3];
break;
case Chip.W83667HG:
case Chip.W83667HGB:
Voltages = new float?[9];
_voltageRegister = new byte[] { 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x50, 0x51 };
_voltageBank = new byte[] { 0, 0, 0, 0, 0, 0, 0, 5, 5 };
_voltageGain = 0.008f;
Fans = new float?[5];
_fanPwmRegister = new byte[] { 0x01, 0x03, 0x11 }; // Fan PWM values.
_fanPrimaryControlModeRegister = new byte[] { 0x04, 0x04, 0x12 }; // Primary control register.
_fanPrimaryControlValue = new byte[] { 0b11110011, 0b11001111, 0b11111001 }; // Values to gain control of fans.
_fanSecondaryControlModeRegister = new byte[] { 0x7c, 0x7c, 0x7c }; // Secondary control register for SmartFan4.
_fanSecondaryControlValue = new byte[] { 0b11101111, 0b11011111, 0b10111111 }; // Values for secondary register to gain control of fans.
_fanTertiaryControlModeRegister = new byte[] { 0x62, 0x7c, 0x62 }; // Tertiary control register. 2nd fan doesn't have Tertiary control, same as secondary to avoid change.
_fanTertiaryControlValue = new byte[] { 0b11101111, 0b11011111, 0b11011111 }; // Values for tertiary register to gain control of fans. 2nd fan doesn't have Tertiary control, same as secondary to avoid change.
_initialFanControlValue = new byte[3]; // To store primary default value.
_initialFanSecondaryControlValue = new byte[3]; // To store secondary default value.
_initialFanTertiaryControlValue = new byte[3]; // To store tertiary default value.
Controls = new float?[3];
break;
case Chip.W83627HF:
Voltages = new float?[7];
_voltageRegister = new byte[] { 0x20, 0x21, 0x22, 0x23, 0x24, 0x50, 0x51 };
_voltageBank = new byte[] { 0, 0, 0, 0, 0, 5, 5 };
_voltageGain = 0.016f;
Fans = new float?[3];
_fanPwmRegister = new byte[] { 0x5A, 0x5B }; // Fan PWM values.
Controls = new float?[2];
break;
case Chip.W83627THF:
Voltages = new float?[7];
_voltageRegister = new byte[] { 0x20, 0x21, 0x22, 0x23, 0x24, 0x50, 0x51 };
_voltageBank = new byte[] { 0, 0, 0, 0, 0, 5, 5 };
_voltageGain = 0.016f;
Fans = new float?[3];
_fanPwmRegister = new byte[] { 0x01, 0x03, 0x11 }; // Fan PWM values.
_fanPrimaryControlModeRegister = new byte[] { 0x04, 0x04, 0x12 }; // Primary control register.
_fanPrimaryControlValue = new byte[] { 0b11110011, 0b11001111, 0b11111001 }; // Values to gain control of fans.
_initialFanControlValue = new byte[3]; // To store primary default value.
Controls = new float?[3];
break;
case Chip.W83687THF:
Voltages = new float?[7];
_voltageRegister = new byte[] { 0x20, 0x21, 0x22, 0x23, 0x24, 0x50, 0x51 };
_voltageBank = new byte[] { 0, 0, 0, 0, 0, 5, 5 };
_voltageGain = 0.016f;
Fans = new float?[3];
break;
}
}
public Chip Chip { get; }
public float?[] Controls { get; } = Array.Empty<float?>();
public float?[] Fans { get; } = Array.Empty<float?>();
public float?[] Temperatures { get; } = Array.Empty<float?>();
public float?[] Voltages { get; } = Array.Empty<float?>();
public byte? ReadGpio(int index)
{
return null;
}
public void WriteGpio(int index, byte value)
{ }
public void SetControl(int index, byte? value)
{
if (index < 0 || index >= Controls.Length)
throw new ArgumentOutOfRangeException(nameof(index));
if (!Mutexes.WaitIsaBus(10))
return;
if (value.HasValue)
{
SaveDefaultFanPwmControl(index);
if (_fanPrimaryControlModeRegister.Length > 0)
{
WriteByte(0, _fanPrimaryControlModeRegister[index], (byte)(_fanPrimaryControlValue[index] & ReadByte(0, _fanPrimaryControlModeRegister[index])));
if (_fanSecondaryControlModeRegister.Length > 0)
{
if (_fanSecondaryControlModeRegister[index] != _fanPrimaryControlModeRegister[index])
{
WriteByte(0, _fanSecondaryControlModeRegister[index], (byte)(_fanSecondaryControlValue[index] & ReadByte(0, _fanSecondaryControlModeRegister[index])));
}
if (_fanTertiaryControlModeRegister.Length > 0 && _fanTertiaryControlModeRegister[index] != _fanSecondaryControlModeRegister[index])
{
WriteByte(0, _fanTertiaryControlModeRegister[index], (byte)(_fanTertiaryControlValue[index] & ReadByte(0, _fanTertiaryControlModeRegister[index])));
}
}
}
// set output value
WriteByte(0, _fanPwmRegister[index], value.Value);
}
else
{
RestoreDefaultFanPwmControl(index);
}
Mutexes.ReleaseIsaBus();
}
private void SaveDefaultFanPwmControl(int index) //added to save initial control values
{
if (_fanPrimaryControlModeRegister.Length > 0 &&
_initialFanControlValue.Length > 0 &&
_fanPrimaryControlValue.Length > 0 &&
_restoreDefaultFanPwmControlRequired.Length > 0 &&
!_restoreDefaultFanPwmControlRequired[index])
{
_initialFanControlValue[index] = ReadByte(0, _fanPrimaryControlModeRegister[index]);
if (_fanSecondaryControlModeRegister.Length > 0 && _initialFanSecondaryControlValue.Length > 0 && _fanSecondaryControlValue.Length > 0)
{
if (_fanSecondaryControlModeRegister[index] != _fanPrimaryControlModeRegister[index])
{
_initialFanSecondaryControlValue[index] = ReadByte(0, _fanSecondaryControlModeRegister[index]);
}
if (_fanTertiaryControlModeRegister.Length > 0 &&
_initialFanTertiaryControlValue.Length > 0 &&
_fanTertiaryControlValue.Length > 0 &&
_fanTertiaryControlModeRegister[index] != _fanSecondaryControlModeRegister[index])
{
_initialFanTertiaryControlValue[index] = ReadByte(0, _fanTertiaryControlModeRegister[index]);
}
}
_restoreDefaultFanPwmControlRequired[index] = true;
}
}
private void RestoreDefaultFanPwmControl(int index) //added to restore initial control values
{
if (_fanPrimaryControlModeRegister.Length > 0 &&
_initialFanControlValue.Length > 0 &&
_fanPrimaryControlValue.Length > 0 &&
_restoreDefaultFanPwmControlRequired.Length > 0 &&
_restoreDefaultFanPwmControlRequired[index])
{
WriteByte(0,
_fanPrimaryControlModeRegister[index],
(byte)((_initialFanControlValue[index] & ~_fanPrimaryControlValue[index]) |
ReadByte(0, _fanPrimaryControlModeRegister[index]))); //bitwise operands to change only desired bits
if (_fanSecondaryControlModeRegister.Length > 0 && _initialFanSecondaryControlValue.Length > 0 && _fanSecondaryControlValue.Length > 0)
{
if (_fanSecondaryControlModeRegister[index] != _fanPrimaryControlModeRegister[index])
{
WriteByte(0,
_fanSecondaryControlModeRegister[index],
(byte)((_initialFanSecondaryControlValue[index] & ~_fanSecondaryControlValue[index]) |
ReadByte(0, _fanSecondaryControlModeRegister[index]))); //bitwise operands to change only desired bits
}
if (_fanTertiaryControlModeRegister.Length > 0 &&
_initialFanTertiaryControlValue.Length > 0 &&
_fanTertiaryControlValue.Length > 0 &&
_fanTertiaryControlModeRegister[index] != _fanSecondaryControlModeRegister[index])
{
WriteByte(0,
_fanTertiaryControlModeRegister[index],
(byte)((_initialFanTertiaryControlValue[index] & ~_fanTertiaryControlValue[index]) | ReadByte(0, _fanTertiaryControlModeRegister[index]))); //bitwise operands to change only desired bits
}
}
_restoreDefaultFanPwmControlRequired[index] = false;
}
}
public void Update()
{
if (!Mutexes.WaitIsaBus(10))
return;
for (int i = 0; i < Voltages.Length; i++)
{
if (_voltageRegister[i] != VOLTAGE_VBAT_REG)
{
// two special VCore measurement modes for W83627THF
float fValue;
if ((Chip == Chip.W83627HF || Chip == Chip.W83627THF || Chip == Chip.W83687THF) && i == 0)
{
byte vrmConfiguration = ReadByte(0, 0x18);
int value = ReadByte(_voltageBank[i], _voltageRegister[i]);
if ((vrmConfiguration & 0x01) == 0)
fValue = 0.016f * value; // VRM8 formula
else
fValue = (0.00488f * value) + 0.69f; // VRM9 formula
}
else
{
int value = ReadByte(_voltageBank[i], _voltageRegister[i]);
fValue = _voltageGain * value;
}
if (fValue > 0)
Voltages[i] = fValue;
else
Voltages[i] = null;
}
else
{
// Battery voltage
bool valid = (ReadByte(0, 0x5D) & 0x01) > 0;
if (valid)
{
Voltages[i] = _voltageGain * ReadByte(5, VOLTAGE_VBAT_REG);
}
else
{
Voltages[i] = null;
}
}
}
for (int i = 0; i < Temperatures.Length; i++)
{
int value = (sbyte)ReadByte(TEMPERATURE_BANK[i], TEMPERATURE_REG[i]) << 1;
if (TEMPERATURE_BANK[i] > 0)
value |= ReadByte(TEMPERATURE_BANK[i], (byte)(TEMPERATURE_REG[i] + 1)) >> 7;
float temperature = value / 2.0f;
if (temperature is <= 125 and >= -55 && !_peciTemperature[i])
{
Temperatures[i] = temperature;
}
else
{
Temperatures[i] = null;
}
}
ulong bits = 0;
foreach (byte t in FAN_BIT_REG)
bits = (bits << 8) | ReadByte(0, t);
ulong newBits = bits;
for (int i = 0; i < Fans.Length; i++)
{
int count = ReadByte(FAN_TACHO_BANK[i], FAN_TACHO_REG[i]);
// assemble fan divisor
int divisorBits = (int)(
(((bits >> FAN_DIV_BIT2[i]) & 1) << 2) |
(((bits >> FAN_DIV_BIT1[i]) & 1) << 1) |
((bits >> FAN_DIV_BIT0[i]) & 1));
int divisor = 1 << divisorBits;
Fans[i] = count < 0xff ? 1.35e6f / (count * divisor) : 0;
switch (count)
{
// update fan divisor
case > 192 when divisorBits < 7:
divisorBits++;
break;
case < 96 when divisorBits > 0:
divisorBits--;
break;
}
newBits = SetBit(newBits, FAN_DIV_BIT2[i], (divisorBits >> 2) & 1);
newBits = SetBit(newBits, FAN_DIV_BIT1[i], (divisorBits >> 1) & 1);
newBits = SetBit(newBits, FAN_DIV_BIT0[i], divisorBits & 1);
}
for (int i = 0; i < Controls.Length; i++)
{
byte value = ReadByte(0, _fanPwmRegister[i]);
Controls[i] = (float)Math.Round(value * 100.0f / 0xFF);
}
Mutexes.ReleaseIsaBus();
}
public string GetReport()
{
StringBuilder r = new();
r.AppendLine("LPC " + GetType().Name);
r.AppendLine();
r.Append("Chip Id: 0x");
r.AppendLine(Chip.ToString("X"));
r.Append("Chip Revision: 0x");
r.AppendLine(_revision.ToString("X", CultureInfo.InvariantCulture));
r.Append("Base Address: 0x");
r.AppendLine(_address.ToString("X4", CultureInfo.InvariantCulture));
r.AppendLine();
if (!Mutexes.WaitIsaBus(100))
return r.ToString();
r.AppendLine("Hardware Monitor Registers");
r.AppendLine();
r.AppendLine(" 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F");
r.AppendLine();
for (int i = 0; i <= 0x7; i++)
{
r.Append(" ");
r.Append((i << 4).ToString("X2", CultureInfo.InvariantCulture));
r.Append(" ");
for (int j = 0; j <= 0xF; j++)
{
r.Append(" ");
r.Append(ReadByte(0, (byte)((i << 4) | j)).ToString("X2", CultureInfo.InvariantCulture));
}
r.AppendLine();
}
for (int k = 1; k <= 15; k++)
{
r.AppendLine("Bank " + k);
for (int i = 0x5; i < 0x6; i++)
{
r.Append(" ");
r.Append((i << 4).ToString("X2", CultureInfo.InvariantCulture));
r.Append(" ");
for (int j = 0; j <= 0xF; j++)
{
r.Append(" ");
r.Append(ReadByte((byte)k, (byte)((i << 4) | j)).ToString("X2", CultureInfo.InvariantCulture));
}
r.AppendLine();
}
}
r.AppendLine();
Mutexes.ReleaseIsaBus();
return r.ToString();
}
private byte ReadByte(byte bank, byte register)
{
Ring0.WriteIoPort((ushort)(_address + ADDRESS_REGISTER_OFFSET), BANK_SELECT_REGISTER);
Ring0.WriteIoPort((ushort)(_address + DATA_REGISTER_OFFSET), bank);
Ring0.WriteIoPort((ushort)(_address + ADDRESS_REGISTER_OFFSET), register);
return Ring0.ReadIoPort((ushort)(_address + DATA_REGISTER_OFFSET));
}
private void WriteByte(byte bank, byte register, byte value)
{
Ring0.WriteIoPort((ushort)(_address + ADDRESS_REGISTER_OFFSET), BANK_SELECT_REGISTER);
Ring0.WriteIoPort((ushort)(_address + DATA_REGISTER_OFFSET), bank);
Ring0.WriteIoPort((ushort)(_address + ADDRESS_REGISTER_OFFSET), register);
Ring0.WriteIoPort((ushort)(_address + DATA_REGISTER_OFFSET), value);
}
private bool IsWinbondVendor()
{
ushort vendorId = (ushort)((ReadByte(HIGH_BYTE, VENDOR_ID_REGISTER) << 8) | ReadByte(0, VENDOR_ID_REGISTER));
return vendorId == WINBOND_VENDOR_ID;
}
private static ulong SetBit(ulong target, int bit, int value)
{
if ((value & 1) != value)
throw new ArgumentException("Value must be one bit only.");
if (bit is < 0 or > 63)
throw new ArgumentException("Bit out of range.");
ulong mask = (ulong)1 << bit;
return value > 0 ? target | mask : target & ~mask;
}
// ReSharper disable InconsistentNaming
private const byte ADDRESS_REGISTER_OFFSET = 0x05;
private const byte BANK_SELECT_REGISTER = 0x4E;
private const byte DATA_REGISTER_OFFSET = 0x06;
private const byte HIGH_BYTE = 0x80;
private const byte TEMPERATURE_SOURCE_SELECT_REG = 0x49;
private const byte VENDOR_ID_REGISTER = 0x4F;
private const byte VOLTAGE_VBAT_REG = 0x51;
private const ushort WINBOND_VENDOR_ID = 0x5CA3;
private readonly byte[] FAN_BIT_REG = { 0x47, 0x4B, 0x4C, 0x59, 0x5D };
private readonly byte[] FAN_DIV_BIT0 = { 36, 38, 30, 8, 10 };
private readonly byte[] FAN_DIV_BIT1 = { 37, 39, 31, 9, 11 };
private readonly byte[] FAN_DIV_BIT2 = { 5, 6, 7, 23, 15 };
private readonly byte[] FAN_TACHO_BANK = { 0, 0, 0, 0, 5 };
private readonly byte[] FAN_TACHO_REG = { 0x28, 0x29, 0x2A, 0x3F, 0x53 };
private readonly byte[] TEMPERATURE_BANK = { 1, 2, 0 };
private readonly byte[] TEMPERATURE_REG = { 0x50, 0x50, 0x27 };
// ReSharper restore InconsistentNaming
}

View File

@@ -0,0 +1,56 @@
// 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.
// Partial Copyright (C) Michael Möller <mmoeller@openhardwaremonitor.org> and Contributors.
// All Rights Reserved.
using System.Diagnostics.CodeAnalysis;
namespace LibreHardwareMonitor.Hardware.Motherboard;
[SuppressMessage("ReSharper", "IdentifierTypo")]
[SuppressMessage("ReSharper", "CommentTypo")]
[SuppressMessage("ReSharper", "InconsistentNaming")]
public 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
}

View File

@@ -0,0 +1,261 @@
// 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.
// Partial Copyright (C) Michael Möller <mmoeller@openhardwaremonitor.org> and Contributors.
// All Rights Reserved.
// ReSharper disable InconsistentNaming
using System.Diagnostics.CodeAnalysis;
namespace LibreHardwareMonitor.Hardware.Motherboard;
[SuppressMessage("ReSharper", "IdentifierTypo")]
[SuppressMessage("ReSharper", "CommentTypo")]
public enum Model
{
// ASRock
_880GMH_USB3,
A320M_HDV,
AB350_Pro4,
AB350M,
AB350M_HDV,
AB350M_Pro4,
AOD790GX_128M,
B450_Pro4,
B450_Steel_Legend,
B450M_Pro4,
B450M_Steel_Legend,
B85M_DGS,
Fatal1ty_AB350_Gaming_K4,
P55_Deluxe,
X399_Phantom_Gaming_6,
Z77Pro4M,
X570_Pro4,
X570_Taichi,
X570_Phantom_Gaming_ITX,
Z690_Extreme,
Z690_Steel_Legend,
Z790_Pro_RS,
X570_Phantom_Gaming_4,
Z790_Taichi,
Z790_Nova_WiFi,
B650M_C,
H61M_DGS,
// ASUS
CROSSHAIR_III_FORMULA,
ROG_CROSSHAIR_VIII_HERO,
ROG_CROSSHAIR_VIII_HERO_WIFI,
ROG_CROSSHAIR_VIII_DARK_HERO,
ROG_CROSSHAIR_VIII_FORMULA,
ROG_CROSSHAIR_VIII_IMPACT,
ROG_STRIX_X470_I,
ROG_CROSSHAIR_X670E_EXTREME,
ROG_CROSSHAIR_X670E_HERO,
ROG_CROSSHAIR_X670E_GENE,
ROG_STRIX_X670E_A_GAMING_WIFI,
ROG_STRIX_X670E_E_GAMING_WIFI,
ROG_STRIX_X670E_F_GAMING_WIFI,
PROART_X670E_CREATOR_WIFI,
ROG_STRIX_X570_E_GAMING,
ROG_STRIX_X570_E_GAMING_WIFI_II,
ROG_STRIX_X570_F_GAMING,
ROG_STRIX_X570_I_GAMING,
ROG_STRIX_B550_E_GAMING,
ROG_STRIX_B550_F_GAMING_WIFI,
ROG_STRIX_B550_I_GAMING,
ROG_STRIX_Z390_E_GAMING,
ROG_STRIX_Z390_F_GAMING,
ROG_STRIX_Z390_I_GAMING,
ROG_STRIX_Z690_A_GAMING_WIFI_D4,
ROG_MAXIMUS_XI_FORMULA,
ROG_MAXIMUS_XII_Z490_FORMULA,
ROG_MAXIMUS_X_HERO_WIFI_AC,
ROG_MAXIMUS_Z690_FORMULA,
ROG_MAXIMUS_Z690_HERO,
ROG_MAXIMUS_Z690_EXTREME_GLACIAL,
ROG_STRIX_Z790_I_GAMING_WIFI,
ROG_STRIX_Z790_E_GAMING_WIFI,
M2N_SLI_Deluxe,
M4A79XTD_EVO,
P5W_DH_Deluxe,
P6T,
P6X58D_E,
P8P67,
P8P67_EVO,
P8P67_M_PRO,
P8P67_PRO,
P8Z77_V,
P9X79,
PRIME_B650_PLUS,
PRIME_X370_PRO,
PRIME_X470_PRO,
PRIME_X570_PRO,
PROART_X570_CREATOR_WIFI,
PRO_WS_X570_ACE,
RAMPAGE_EXTREME,
RAMPAGE_II_GENE,
ROG_MAXIMUS_X_APEX,
ROG_ZENITH_EXTREME,
ROG_ZENITH_II_EXTREME,
TUF_X470_PLUS_GAMING,
Z170_A,
B150M_C,
B150M_C_D3,
TUF_GAMING_X570_PLUS_WIFI,
TUF_GAMING_B550M_PLUS_WIFI,
ROG_MAXIMUS_Z790_HERO,
ROG_MAXIMUS_Z790_DARK_HERO,
PRIME_Z690_A,
ROG_MAXIMUS_Z790_FORMULA,
ROG_MAXIMUS_XII_HERO_WIFI,
//BIOSTAR
B660GTN,
X670E_Valkyrie,
// DFI
LP_BI_P45_T2RS_Elite,
LP_DK_P55_T3EH9,
// ECS
A890GXM_A,
// MSI
B350_Gaming_Plus,
B360M_PRO_VDH,
B450A_PRO,
B550A_PRO,
B650M_Gaming_Plus_Wifi,
Z270_PC_MATE,
Z77_MS7751,
Z68_MS7672,
X570_Gaming_Plus,
// EVGA
X58_SLI_Classified,
X58_3X_SLI,
// Gigabyte
_965P_S3,
_970A_DS3P,
_970A_UD3,
AB350_Gaming_3,
AX370_Gaming_5,
AX370_Gaming_K7,
B360_AORUS_GAMING_3_WIFI_CF,
B550_AORUS_MASTER,
B550_AORUS_PRO,
B550_AORUS_PRO_AC,
B550_AORUS_PRO_AX,
B550_VISION_D,
B550_AORUS_ELITE,
B550_AORUS_ELITE_AX,
B550_GAMING_X,
B550_UD_AC,
B550M_AORUS_PRO,
B550M_AORUS_PRO_AX,
B550M_AORUS_ELITE,
B550M_GAMING,
B550M_DS3H,
B550M_DS3H_AC,
B550M_S2H,
B550M_H,
B550I_AORUS_PRO_AX,
B560M_AORUS_ELITE,
B560M_AORUS_PRO,
B560M_AORUS_PRO_AX,
B560I_AORUS_PRO_AX,
B660_DS3H_DDR4,
B660_DS3H_AC_DDR4,
B660M_DS3H_AX_DDR4,
EP45_DS3R,
EP45_UD3R,
EX58_EXTREME,
EX58_UD3R,
G41M_COMBO,
G41MT_S2,
G41MT_S2P,
H55_USB3,
H55N_USB3,
H61M_DS2_REV_1_2,
H61M_USB3_B3_REV_2_0,
H67A_UD3H_B3,
H67A_USB3_B3,
H97_D3H,
H81M_HD3,
B75M_D3H,
MA770T_UD3,
MA770T_UD3P,
MA785GM_US2H,
MA785GMT_UD2H,
MA78LM_S2H,
MA790X_UD3P,
P35_DS3,
P35_DS3L,
P55_UD4,
P55A_UD3,
P55M_UD4,
P67A_UD3_B3,
P67A_UD3R_B3,
P67A_UD4_B3,
P8Z68_V_PRO,
X38_DS5,
X399_AORUS_Gaming_7,
X58A_UD3R,
X79_UD3,
Z390_AORUS_ULTRA,
Z390_AORUS_PRO,
Z390_M_GAMING,
Z390_UD,
Z68A_D3H_B3,
Z68AP_D3,
Z68X_UD3H_B3,
Z68X_UD7_B3,
Z68XP_UD3R,
Z690_AORUS_PRO,
Z690_AORUS_ULTRA,
Z690_AORUS_MASTER,
Z690_GAMING_X_DDR4,
Z790_AORUS_PRO_X,
Z790_UD,
Z790_UD_AC,
Z790_GAMING_X,
Z790_GAMING_X_AX,
Z170N_WIFI,
B450_AORUS_M,
B450_AORUS_PRO,
B450_GAMING_X,
B450_AORUS_ELITE,
B450M_AORUS_ELITE,
B450M_GAMING,
B450_I_AORUS_PRO_WIFI,
B450M_DS3H,
B450M_S2H,
B450M_H,
B450M_K,
X470_AORUS_GAMING_7_WIFI,
X570_AORUS_MASTER,
X570_AORUS_PRO,
X570_GAMING_X,
X570_AORUS_ULTRA,
B650_AORUS_ELITE,
B650_AORUS_ELITE_AX,
B650_AORUS_ELITE_V2,
B650_AORUS_ELITE_AX_V2,
B650_AORUS_ELITE_AX_ICE,
B650E_AORUS_ELITE_AX_ICE,
B650M_AORUS_PRO,
B650M_AORUS_PRO_AX,
B650M_AORUS_ELITE,
B650M_AORUS_ELITE_AX,
X870E_AORUS_PRO,
X870E_AORUS_PRO_ICE,
// Shuttle
FH67,
// Unknown
Unknown
}

View File

@@ -0,0 +1,206 @@
// 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.
// Partial Copyright (C) Michael Möller <mmoeller@openhardwaremonitor.org> and Contributors.
// All Rights Reserved.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using LibreHardwareMonitor.Hardware.Motherboard.Lpc;
using LibreHardwareMonitor.Hardware.Motherboard.Lpc.EC;
using OperatingSystem = LibreHardwareMonitor.Software.OperatingSystem;
namespace LibreHardwareMonitor.Hardware.Motherboard;
/// <summary>
/// Represents the motherboard of a computer with its <see cref="LpcIO" /> and <see cref="EmbeddedController" /> as <see cref="SubHardware" />.
/// </summary>
public class Motherboard : IHardware
{
private readonly LMSensors _lmSensors;
private readonly LpcIO _lpcIO;
private readonly string _name;
private readonly ISettings _settings;
private string _customName;
/// <summary>
/// Creates motherboard instance by retrieving information from <see cref="LibreHardwareMonitor.Hardware.SMBios" /> and creates a new <see cref="SubHardware" /> based on data from <see cref="LpcIO" />
/// and <see cref="EmbeddedController" />.
/// </summary>
/// <param name="smBios"><see cref="LibreHardwareMonitor.Hardware.SMBios" /> table containing motherboard data.</param>
/// <param name="settings">Additional settings passed by <see cref="IComputer" />.</param>
public Motherboard(SMBios smBios, ISettings settings)
{
IReadOnlyList<ISuperIO> superIO;
_settings = settings;
SMBios = smBios;
Manufacturer = smBios.Board == null ? Manufacturer.Unknown : Identification.GetManufacturer(smBios.Board.ManufacturerName);
Model = smBios.Board == null ? Model.Unknown : Identification.GetModel(smBios.Board.ProductName);
if (smBios.Board != null)
{
if (!string.IsNullOrEmpty(smBios.Board.ProductName))
{
if (Manufacturer == Manufacturer.Unknown)
_name = smBios.Board.ProductName;
else
_name = Manufacturer + " " + smBios.Board.ProductName;
}
else
{
_name = Manufacturer.ToString();
}
}
else
{
_name = nameof(Manufacturer.Unknown);
}
_customName = settings.GetValue(new Identifier(Identifier, "name").ToString(), _name);
if (OperatingSystem.IsUnix)
{
_lmSensors = new LMSensors();
superIO = _lmSensors.SuperIO;
}
else
{
_lpcIO = new LpcIO(this);
superIO = _lpcIO.SuperIO;
}
EmbeddedController embeddedController = EmbeddedController.Create(Model, settings);
List<IHardware> subHardwareList = new List<IHardware>();
// there may be more than 1 of the same SuperIO chip
// group by chip
foreach (IGrouping<Chip, ISuperIO> group in superIO.GroupBy(x => x.Chip))
{
// index by group
foreach ((ISuperIO superIo, int i) in group.Select((x, i) => (x, i)))
{
subHardwareList.Add(new SuperIOHardware(this, superIo, Manufacturer, Model, settings, i));
}
}
if (embeddedController != null)
subHardwareList.Add(embeddedController);
SubHardware = subHardwareList.ToArray();
}
/// <inheritdoc />
public event SensorEventHandler SensorAdded;
/// <inheritdoc />
public event SensorEventHandler SensorRemoved;
/// <inheritdoc />
public HardwareType HardwareType => HardwareType.Motherboard;
/// <inheritdoc />
public Identifier Identifier => new("motherboard");
/// <summary>
/// Gets the <see cref="LibreHardwareMonitor.Hardware.Motherboard.Manufacturer" />.
/// </summary>
public Manufacturer Manufacturer { get; }
/// <summary>
/// Gets the <see cref="LibreHardwareMonitor.Hardware.Motherboard.Model" />.
/// </summary>
public Model Model { get; }
/// <summary>
/// Gets the name obtained from <see cref="LibreHardwareMonitor.Hardware.SMBios" />.
/// </summary>
public string Name
{
get { return _customName; }
set
{
_customName = !string.IsNullOrEmpty(value) ? value : _name;
_settings.SetValue(new Identifier(Identifier, "name").ToString(), _customName);
}
}
/// <inheritdoc />
/// <returns>Always <see langword="null" /></returns>
public virtual IHardware Parent
{
get { return null; }
}
/// <inheritdoc />
public virtual IDictionary<string, string> Properties => new SortedDictionary<string, string>();
/// <inheritdoc />
public ISensor[] Sensors
{
get { return Array.Empty<ISensor>(); }
}
/// <summary>
/// Gets the <see cref="LibreHardwareMonitor.Hardware.SMBios" /> information.
/// </summary>
public SMBios SMBios { get; }
/// <inheritdoc />
public IHardware[] SubHardware { get; }
/// <inheritdoc />
public string GetReport()
{
StringBuilder r = new();
r.AppendLine("Motherboard");
r.AppendLine();
r.Append(SMBios.GetReport());
if (_lpcIO != null)
r.Append(_lpcIO.GetReport());
return r.ToString();
}
/// <summary>
/// Motherboard itself cannot be updated. Update <see cref="SubHardware" /> instead.
/// </summary>
public void Update()
{ }
/// <inheritdoc />
public void Accept(IVisitor visitor)
{
if (visitor == null)
throw new ArgumentNullException(nameof(visitor));
visitor.VisitHardware(this);
}
/// <inheritdoc />
public void Traverse(IVisitor visitor)
{
foreach (IHardware hardware in SubHardware)
hardware.Accept(visitor);
}
/// <summary>
/// Closes <see cref="SubHardware" /> using <see cref="Hardware.Close" />.
/// </summary>
public void Close()
{
_lmSensors?.Close();
foreach (IHardware iHardware in SubHardware)
{
if (iHardware is Hardware hardware)
hardware.Close();
}
}
}

View File

@@ -0,0 +1,33 @@
// 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.
// Partial Copyright (C) Michael Möller <mmoeller@openhardwaremonitor.org> and Contributors.
// All Rights Reserved.
using System.Collections.Generic;
namespace LibreHardwareMonitor.Hardware.Motherboard;
internal class MotherboardGroup : IGroup
{
private readonly Motherboard[] _motherboards;
public MotherboardGroup(SMBios smbios, ISettings settings)
{
_motherboards = new Motherboard[1];
_motherboards[0] = new Motherboard(smbios, settings);
}
public IReadOnlyList<IHardware> Hardware => _motherboards;
public void Close()
{
foreach (Motherboard mainboard in _motherboards)
mainboard.Close();
}
public string GetReport()
{
return null;
}
}

View File

@@ -0,0 +1,13 @@
namespace LibreHardwareMonitor.Hardware.Motherboard;
internal class Temperature
{
public readonly int Index;
public readonly string Name;
public Temperature(string name, int index)
{
Name = name;
Index = index;
}
}

View File

@@ -0,0 +1,24 @@
namespace LibreHardwareMonitor.Hardware.Motherboard;
internal class Voltage
{
public readonly bool Hidden;
public readonly int Index;
public readonly string Name;
public readonly float Rf;
public readonly float Ri;
public readonly float Vf;
public Voltage(string name, int index, bool hidden = false) : this(name, index, 0, 1, 0, hidden)
{ }
public Voltage(string name, int index, float ri, float rf, float vf = 0, bool hidden = false)
{
Name = name;
Index = index;
Ri = ri;
Rf = rf;
Vf = vf;
Hidden = hidden;
}
}