first commit
This commit is contained in:
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,632 @@
|
||||
// This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
|
||||
// If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
// Copyright (C) LibreHardwareMonitor and Contributors.
|
||||
// All Rights Reserved.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace LibreHardwareMonitor.Hardware.Motherboard.Lpc.EC;
|
||||
|
||||
public abstract class EmbeddedController : Hardware
|
||||
{
|
||||
// If you are updating board information, please consider sharing your changes with the corresponding Linux driver.
|
||||
// You can do that at https://github.com/zeule/asus-ec-sensors or contribute directly to Linux HWMON.
|
||||
// If you are adding a new board, please share DSDT table for the board at https://github.com/zeule/asus-ec-sensors.
|
||||
// https://dortania.github.io/Getting-Started-With-ACPI/Manual/dump.html
|
||||
private static readonly BoardInfo[] _boards =
|
||||
{
|
||||
new(Model.PRIME_X470_PRO,
|
||||
BoardFamily.Amd400,
|
||||
ECSensor.TempChipset,
|
||||
ECSensor.TempCPU,
|
||||
ECSensor.TempMB,
|
||||
ECSensor.TempVrm,
|
||||
ECSensor.TempVrm,
|
||||
ECSensor.FanCPUOpt,
|
||||
ECSensor.CurrCPU,
|
||||
ECSensor.VoltageCPU),
|
||||
new(Model.PRIME_X570_PRO,
|
||||
BoardFamily.Amd500,
|
||||
ECSensor.TempChipset,
|
||||
ECSensor.TempCPU,
|
||||
ECSensor.TempMB,
|
||||
ECSensor.TempVrm,
|
||||
ECSensor.TempTSensor,
|
||||
ECSensor.FanChipset),
|
||||
new(Model.PROART_X570_CREATOR_WIFI,
|
||||
BoardFamily.Amd500,
|
||||
ECSensor.TempChipset,
|
||||
ECSensor.TempCPU,
|
||||
ECSensor.TempMB,
|
||||
ECSensor.TempVrm,
|
||||
ECSensor.TempTSensor,
|
||||
ECSensor.FanCPUOpt,
|
||||
ECSensor.CurrCPU,
|
||||
ECSensor.VoltageCPU),
|
||||
new(Model.PRO_WS_X570_ACE,
|
||||
BoardFamily.Amd500,
|
||||
ECSensor.TempChipset,
|
||||
ECSensor.TempCPU,
|
||||
ECSensor.TempMB,
|
||||
ECSensor.TempVrm,
|
||||
ECSensor.FanChipset,
|
||||
ECSensor.CurrCPU,
|
||||
ECSensor.VoltageCPU),
|
||||
new(new[] { Model.ROG_CROSSHAIR_VIII_HERO, Model.ROG_CROSSHAIR_VIII_HERO_WIFI, Model.ROG_CROSSHAIR_VIII_FORMULA },
|
||||
BoardFamily.Amd500,
|
||||
ECSensor.TempChipset,
|
||||
ECSensor.TempCPU,
|
||||
ECSensor.TempMB,
|
||||
ECSensor.TempTSensor,
|
||||
ECSensor.TempVrm,
|
||||
ECSensor.TempWaterIn,
|
||||
ECSensor.TempWaterOut,
|
||||
ECSensor.FanCPUOpt,
|
||||
ECSensor.FanChipset,
|
||||
ECSensor.FanWaterFlow,
|
||||
ECSensor.CurrCPU,
|
||||
ECSensor.VoltageCPU),
|
||||
new(Model.ROG_CROSSHAIR_X670E_EXTREME,
|
||||
BoardFamily.Amd600,
|
||||
ECSensor.TempWaterIn,
|
||||
ECSensor.TempWaterOut,
|
||||
ECSensor.FanCPUOpt),
|
||||
new(Model.ROG_CROSSHAIR_X670E_HERO,
|
||||
BoardFamily.Amd600,
|
||||
ECSensor.TempWaterIn,
|
||||
ECSensor.TempWaterOut,
|
||||
ECSensor.FanCPUOpt),
|
||||
new(Model.ROG_CROSSHAIR_X670E_GENE,
|
||||
BoardFamily.Amd600,
|
||||
ECSensor.TempWaterIn,
|
||||
ECSensor.TempWaterOut,
|
||||
ECSensor.FanCPUOpt),
|
||||
new(Model.ROG_STRIX_X670E_E_GAMING_WIFI,
|
||||
BoardFamily.Amd600,
|
||||
ECSensor.TempWaterIn,
|
||||
ECSensor.TempWaterOut,
|
||||
ECSensor.FanCPUOpt),
|
||||
new(Model.ROG_STRIX_X670E_F_GAMING_WIFI,
|
||||
BoardFamily.Amd600,
|
||||
ECSensor.TempWaterIn,
|
||||
ECSensor.TempWaterOut,
|
||||
ECSensor.FanCPUOpt),
|
||||
new(Model.ROG_CROSSHAIR_VIII_DARK_HERO,
|
||||
BoardFamily.Amd500,
|
||||
ECSensor.TempChipset,
|
||||
ECSensor.TempCPU,
|
||||
ECSensor.TempMB,
|
||||
ECSensor.TempTSensor,
|
||||
ECSensor.TempVrm,
|
||||
ECSensor.TempWaterIn,
|
||||
ECSensor.TempWaterOut,
|
||||
ECSensor.FanCPUOpt,
|
||||
ECSensor.FanWaterFlow,
|
||||
ECSensor.CurrCPU,
|
||||
ECSensor.VoltageCPU),
|
||||
new(Model.ROG_CROSSHAIR_VIII_IMPACT,
|
||||
BoardFamily.Amd500,
|
||||
ECSensor.TempChipset,
|
||||
ECSensor.TempCPU,
|
||||
ECSensor.TempMB,
|
||||
ECSensor.TempTSensor,
|
||||
ECSensor.TempVrm,
|
||||
ECSensor.FanChipset,
|
||||
ECSensor.CurrCPU,
|
||||
ECSensor.VoltageCPU),
|
||||
new(Model.ROG_STRIX_B550_E_GAMING,
|
||||
BoardFamily.Amd500,
|
||||
ECSensor.TempChipset,
|
||||
ECSensor.TempCPU,
|
||||
ECSensor.TempMB,
|
||||
ECSensor.TempTSensor,
|
||||
ECSensor.TempVrm,
|
||||
ECSensor.FanCPUOpt),
|
||||
new(Model.ROG_STRIX_B550_I_GAMING,
|
||||
BoardFamily.Amd500,
|
||||
ECSensor.TempChipset,
|
||||
ECSensor.TempCPU,
|
||||
ECSensor.TempMB,
|
||||
ECSensor.TempTSensor,
|
||||
ECSensor.TempVrm,
|
||||
ECSensor.FanVrmHS,
|
||||
ECSensor.CurrCPU,
|
||||
ECSensor.VoltageCPU),
|
||||
new(Model.ROG_STRIX_X570_E_GAMING,
|
||||
BoardFamily.Amd500,
|
||||
ECSensor.TempChipset,
|
||||
ECSensor.TempCPU,
|
||||
ECSensor.TempMB,
|
||||
ECSensor.TempTSensor,
|
||||
ECSensor.TempVrm,
|
||||
ECSensor.FanChipset,
|
||||
ECSensor.CurrCPU,
|
||||
ECSensor.VoltageCPU),
|
||||
new(Model.ROG_STRIX_X570_E_GAMING_WIFI_II,
|
||||
BoardFamily.Amd500,
|
||||
ECSensor.TempChipset,
|
||||
ECSensor.TempCPU,
|
||||
ECSensor.TempMB,
|
||||
ECSensor.TempTSensor,
|
||||
ECSensor.TempVrm),
|
||||
new(Model.ROG_STRIX_X570_F_GAMING,
|
||||
BoardFamily.Amd500,
|
||||
ECSensor.TempChipset,
|
||||
ECSensor.TempCPU,
|
||||
ECSensor.TempMB,
|
||||
ECSensor.TempTSensor,
|
||||
ECSensor.FanChipset),
|
||||
new(Model.ROG_STRIX_X570_I_GAMING,
|
||||
BoardFamily.Amd500,
|
||||
ECSensor.TempTSensor,
|
||||
ECSensor.FanVrmHS,
|
||||
ECSensor.FanChipset,
|
||||
ECSensor.CurrCPU,
|
||||
ECSensor.VoltageCPU,
|
||||
ECSensor.TempChipset,
|
||||
ECSensor.TempVrm),
|
||||
new(Model.ROG_STRIX_Z390_E_GAMING,
|
||||
BoardFamily.Intel300,
|
||||
ECSensor.TempVrm,
|
||||
ECSensor.TempChipset,
|
||||
ECSensor.TempTSensor,
|
||||
ECSensor.FanCPUOpt),
|
||||
new(Model.ROG_STRIX_Z390_F_GAMING,
|
||||
BoardFamily.Intel300,
|
||||
ECSensor.TempVrm,
|
||||
ECSensor.TempChipset,
|
||||
ECSensor.TempTSensor,
|
||||
ECSensor.FanCPUOpt),
|
||||
new(Model.ROG_STRIX_Z390_I_GAMING,
|
||||
BoardFamily.Intel300,
|
||||
ECSensor.TempVrm,
|
||||
ECSensor.TempChipset,
|
||||
ECSensor.TempTSensor),
|
||||
new(Model.ROG_MAXIMUS_XI_FORMULA,
|
||||
BoardFamily.Intel300,
|
||||
ECSensor.TempVrm,
|
||||
ECSensor.TempChipset,
|
||||
ECSensor.TempWaterIn,
|
||||
ECSensor.TempWaterOut,
|
||||
ECSensor.TempTSensor,
|
||||
ECSensor.FanCPUOpt),
|
||||
new(Model.ROG_MAXIMUS_XII_Z490_FORMULA,
|
||||
BoardFamily.Intel400,
|
||||
ECSensor.TempTSensor,
|
||||
ECSensor.TempVrm,
|
||||
ECSensor.TempWaterIn,
|
||||
ECSensor.TempWaterOut,
|
||||
ECSensor.FanWaterFlow),
|
||||
new(Model.ROG_STRIX_Z690_A_GAMING_WIFI_D4,
|
||||
BoardFamily.Intel600,
|
||||
ECSensor.TempTSensor,
|
||||
ECSensor.TempVrm),
|
||||
new(Model.ROG_MAXIMUS_Z690_HERO,
|
||||
BoardFamily.Intel600,
|
||||
ECSensor.TempTSensor,
|
||||
ECSensor.TempWaterIn,
|
||||
ECSensor.TempWaterOut,
|
||||
ECSensor.FanWaterFlow),
|
||||
new(Model.ROG_MAXIMUS_Z690_FORMULA,
|
||||
BoardFamily.Intel600,
|
||||
ECSensor.TempTSensor,
|
||||
ECSensor.TempVrm,
|
||||
ECSensor.TempWaterIn,
|
||||
ECSensor.TempWaterOut,
|
||||
ECSensor.TempWaterBlockIn,
|
||||
ECSensor.FanWaterFlow),
|
||||
new(Model.ROG_MAXIMUS_Z690_EXTREME_GLACIAL,
|
||||
BoardFamily.Intel600,
|
||||
ECSensor.TempVrm,
|
||||
ECSensor.TempWaterIn,
|
||||
ECSensor.TempWaterOut,
|
||||
ECSensor.TempWaterBlockIn,
|
||||
ECSensor.FanWaterFlow),
|
||||
new(Model.ROG_MAXIMUS_Z790_HERO,
|
||||
BoardFamily.Intel700,
|
||||
ECSensor.TempVrm,
|
||||
ECSensor.TempTSensor,
|
||||
ECSensor.TempWaterIn,
|
||||
ECSensor.TempWaterOut,
|
||||
ECSensor.FanWaterFlow,
|
||||
ECSensor.FanCPUOpt),
|
||||
new(Model.ROG_MAXIMUS_Z790_DARK_HERO,
|
||||
BoardFamily.Intel700,
|
||||
ECSensor.TempVrm,
|
||||
ECSensor.FanCPUOpt,
|
||||
ECSensor.TempTSensor,
|
||||
ECSensor.TempWaterIn,
|
||||
ECSensor.TempWaterOut,
|
||||
ECSensor.FanWaterFlow),
|
||||
new(Model.Z170_A,
|
||||
BoardFamily.Intel100,
|
||||
ECSensor.TempTSensor,
|
||||
ECSensor.TempChipset,
|
||||
ECSensor.FanWaterPump,
|
||||
ECSensor.CurrCPU,
|
||||
ECSensor.VoltageCPU),
|
||||
new(Model.PRIME_Z690_A,
|
||||
BoardFamily.Intel600,
|
||||
ECSensor.TempTSensor,
|
||||
ECSensor.TempVrm),
|
||||
new(Model.ROG_STRIX_Z790_I_GAMING_WIFI,
|
||||
BoardFamily.Intel700,
|
||||
ECSensor.TempTSensor,
|
||||
ECSensor.TempTSensor2),
|
||||
new(Model.ROG_STRIX_Z790_E_GAMING_WIFI,
|
||||
BoardFamily.Intel700,
|
||||
ECSensor.TempWaterIn),
|
||||
new(Model.ROG_MAXIMUS_Z790_FORMULA,
|
||||
BoardFamily.Intel700,
|
||||
ECSensor.TempWaterIn,
|
||||
ECSensor.TempWaterOut),
|
||||
new(Model.ROG_MAXIMUS_XII_HERO_WIFI,
|
||||
BoardFamily.Intel400,
|
||||
ECSensor.TempTSensor,
|
||||
ECSensor.TempChipset,
|
||||
ECSensor.TempVrm,
|
||||
ECSensor.TempWaterIn,
|
||||
ECSensor.TempWaterOut,
|
||||
ECSensor.CurrCPU,
|
||||
ECSensor.FanCPUOpt,
|
||||
ECSensor.FanWaterFlow),
|
||||
};
|
||||
|
||||
private static readonly Dictionary<BoardFamily, Dictionary<ECSensor, EmbeddedControllerSource>> _knownSensors = new()
|
||||
{
|
||||
{
|
||||
BoardFamily.Amd400, new Dictionary<ECSensor, EmbeddedControllerSource>() // no chipset fans in this generation
|
||||
{
|
||||
{ ECSensor.TempChipset, new EmbeddedControllerSource("Chipset", SensorType.Temperature, 0x003a) },
|
||||
{ ECSensor.TempCPU, new EmbeddedControllerSource("CPU", SensorType.Temperature, 0x003b) },
|
||||
{ ECSensor.TempMB, new EmbeddedControllerSource("Motherboard", SensorType.Temperature, 0x003c) },
|
||||
{ ECSensor.TempTSensor, new EmbeddedControllerSource("T Sensor", SensorType.Temperature, 0x003d, blank: -40) },
|
||||
{ ECSensor.TempVrm, new EmbeddedControllerSource("VRM", SensorType.Temperature, 0x003e) },
|
||||
{ ECSensor.VoltageCPU, new EmbeddedControllerSource("CPU Core", SensorType.Voltage, 0x00a2, 2, factor: 1e-3f) },
|
||||
{ ECSensor.FanCPUOpt, new EmbeddedControllerSource("CPU Optional Fan", SensorType.Fan, 0x00bc, 2) },
|
||||
{ ECSensor.FanVrmHS, new EmbeddedControllerSource("VRM Heat Sink Fan", SensorType.Fan, 0x00b2, 2) },
|
||||
{ ECSensor.FanWaterFlow, new EmbeddedControllerSource("Water flow", SensorType.Flow, 0x00b4, 2, factor: 1.0f / 42f * 60f) },
|
||||
{ ECSensor.CurrCPU, new EmbeddedControllerSource("CPU", SensorType.Current, 0x00f4) },
|
||||
{ ECSensor.TempWaterIn, new EmbeddedControllerSource("Water In", SensorType.Temperature, 0x010d, blank: -40) },
|
||||
{ ECSensor.TempWaterOut, new EmbeddedControllerSource("Water Out", SensorType.Temperature, 0x010b, blank: -40) }
|
||||
}
|
||||
},
|
||||
{
|
||||
BoardFamily.Amd500, new Dictionary<ECSensor, EmbeddedControllerSource>
|
||||
{
|
||||
{ ECSensor.TempChipset, new EmbeddedControllerSource("Chipset", SensorType.Temperature, 0x003a) },
|
||||
{ ECSensor.TempCPU, new EmbeddedControllerSource("CPU", SensorType.Temperature, 0x003b) },
|
||||
{ ECSensor.TempMB, new EmbeddedControllerSource("Motherboard", SensorType.Temperature, 0x003c) },
|
||||
{ ECSensor.TempTSensor, new EmbeddedControllerSource("T Sensor", SensorType.Temperature, 0x003d, blank: -40) },
|
||||
{ ECSensor.TempVrm, new EmbeddedControllerSource("VRM", SensorType.Temperature, 0x003e) },
|
||||
{ ECSensor.VoltageCPU, new EmbeddedControllerSource("CPU Core", SensorType.Voltage, 0x00a2, 2, factor: 1e-3f) },
|
||||
{ ECSensor.FanCPUOpt, new EmbeddedControllerSource("CPU Optional Fan", SensorType.Fan, 0x00b0, 2) },
|
||||
{ ECSensor.FanVrmHS, new EmbeddedControllerSource("VRM Heat Sink Fan", SensorType.Fan, 0x00b2, 2) },
|
||||
{ ECSensor.FanChipset, new EmbeddedControllerSource("Chipset Fan", SensorType.Fan, 0x00b4, 2) },
|
||||
// TODO: "why 42?" is a silly question, I know, but still, why? On the serious side, it might be 41.6(6)
|
||||
{ ECSensor.FanWaterFlow, new EmbeddedControllerSource("Water flow", SensorType.Flow, 0x00bc, 2, factor: 1.0f / 42f * 60f) },
|
||||
{ ECSensor.CurrCPU, new EmbeddedControllerSource("CPU", SensorType.Current, 0x00f4) },
|
||||
{ ECSensor.TempWaterIn, new EmbeddedControllerSource("Water In", SensorType.Temperature, 0x0100, blank: -40) },
|
||||
{ ECSensor.TempWaterOut, new EmbeddedControllerSource("Water Out", SensorType.Temperature, 0x0101, blank: -40) }
|
||||
}
|
||||
},
|
||||
{
|
||||
BoardFamily.Amd600, new Dictionary<ECSensor, EmbeddedControllerSource>
|
||||
{
|
||||
{ ECSensor.FanCPUOpt, new EmbeddedControllerSource("CPU Optional Fan", SensorType.Fan, 0x00b0, 2) },
|
||||
{ ECSensor.TempWaterIn, new EmbeddedControllerSource("Water In", SensorType.Temperature, 0x0100, blank: -40) },
|
||||
{ ECSensor.TempWaterOut, new EmbeddedControllerSource("Water Out", SensorType.Temperature, 0x0101, blank: -40) }
|
||||
}
|
||||
},
|
||||
{
|
||||
BoardFamily.Intel100, new Dictionary<ECSensor, EmbeddedControllerSource>
|
||||
{
|
||||
{ ECSensor.TempChipset, new EmbeddedControllerSource("Chipset", SensorType.Temperature, 0x003a) },
|
||||
{ ECSensor.TempTSensor, new EmbeddedControllerSource("T Sensor", SensorType.Temperature, 0x003d, blank: -40) },
|
||||
{ ECSensor.FanWaterPump, new EmbeddedControllerSource("Water Pump", SensorType.Fan, 0x00bc, 2) },
|
||||
{ ECSensor.CurrCPU, new EmbeddedControllerSource("CPU", SensorType.Current, 0x00f4) },
|
||||
{ ECSensor.VoltageCPU, new EmbeddedControllerSource("CPU Core", SensorType.Voltage, 0x00a2, 2, factor: 1e-3f) }
|
||||
}
|
||||
},
|
||||
{
|
||||
BoardFamily.Intel300, new Dictionary<ECSensor, EmbeddedControllerSource>
|
||||
{
|
||||
{ ECSensor.TempVrm, new EmbeddedControllerSource("VRM", SensorType.Temperature, 0x003e) },
|
||||
{ ECSensor.TempChipset, new EmbeddedControllerSource("Chipset", SensorType.Temperature, 0x003a) },
|
||||
{ ECSensor.TempTSensor, new EmbeddedControllerSource("T Sensor", SensorType.Temperature, 0x003d, blank: -40) },
|
||||
{ ECSensor.TempWaterIn, new EmbeddedControllerSource("Water In", SensorType.Temperature, 0x0100, blank: -40) },
|
||||
{ ECSensor.TempWaterOut, new EmbeddedControllerSource("Water Out", SensorType.Temperature, 0x0101, blank: -40) },
|
||||
{ ECSensor.FanCPUOpt, new EmbeddedControllerSource("CPU Optional Fan", SensorType.Fan, 0x00b0, 2) }
|
||||
}
|
||||
},
|
||||
{
|
||||
BoardFamily.Intel400, new Dictionary<ECSensor, EmbeddedControllerSource>
|
||||
{
|
||||
{ ECSensor.TempChipset, new EmbeddedControllerSource("Chipset", SensorType.Temperature, 0x003a) },
|
||||
{ ECSensor.TempTSensor, new EmbeddedControllerSource("T Sensor", SensorType.Temperature, 0x003d, blank: -40) },
|
||||
{ ECSensor.TempVrm, new EmbeddedControllerSource("VRM", SensorType.Temperature, 0x003e) },
|
||||
{ ECSensor.FanCPUOpt, new EmbeddedControllerSource("CPU Optional Fan", SensorType.Fan, 0x00b0, 2) },
|
||||
{ ECSensor.FanWaterFlow, new EmbeddedControllerSource("Water Flow", SensorType.Flow, 0x00be, 2, factor: 1.0f / 42f * 60f) }, // todo: need validation for this calculation
|
||||
{ ECSensor.CurrCPU, new EmbeddedControllerSource("CPU", SensorType.Current, 0x00f4) },
|
||||
{ ECSensor.TempWaterIn, new EmbeddedControllerSource("Water In", SensorType.Temperature, 0x0100, blank: -40) },
|
||||
{ ECSensor.TempWaterOut, new EmbeddedControllerSource("Water Out", SensorType.Temperature, 0x0101, blank: -40) },
|
||||
}
|
||||
},
|
||||
{
|
||||
BoardFamily.Intel600, new Dictionary<ECSensor, EmbeddedControllerSource>
|
||||
{
|
||||
{ ECSensor.TempTSensor, new EmbeddedControllerSource("T Sensor", SensorType.Temperature, 0x003d, blank: -40) },
|
||||
{ ECSensor.TempVrm, new EmbeddedControllerSource("VRM", SensorType.Temperature, 0x003e) },
|
||||
{ ECSensor.TempWaterIn, new EmbeddedControllerSource("Water In", SensorType.Temperature, 0x0100, blank: -40) },
|
||||
{ ECSensor.TempWaterOut, new EmbeddedControllerSource("Water Out", SensorType.Temperature, 0x0101, blank: -40) },
|
||||
{ ECSensor.TempWaterBlockIn, new EmbeddedControllerSource("Water Block In", SensorType.Temperature, 0x0102, blank: -40) },
|
||||
{ ECSensor.FanWaterFlow, new EmbeddedControllerSource("Water Flow", SensorType.Flow, 0x00be, 2, factor: 1.0f / 42f * 60f) } // todo: need validation for this calculation
|
||||
}
|
||||
},
|
||||
{
|
||||
BoardFamily.Intel700, new Dictionary<ECSensor, EmbeddedControllerSource>
|
||||
{
|
||||
{ ECSensor.TempVrm, new EmbeddedControllerSource("VRM", SensorType.Temperature, 0x0033) },
|
||||
{ ECSensor.FanCPUOpt, new EmbeddedControllerSource("CPU Optional Fan", SensorType.Fan, 0x00b0, 2) },
|
||||
{ ECSensor.TempTSensor, new EmbeddedControllerSource("T Sensor", SensorType.Temperature, 0x0109, blank: -40) },
|
||||
{ ECSensor.TempTSensor2, new EmbeddedControllerSource("T Sensor 2", SensorType.Temperature, 0x105, blank: -40) },
|
||||
{ ECSensor.TempWaterIn, new EmbeddedControllerSource("Water In", SensorType.Temperature, 0x0100, blank: -40) },
|
||||
{ ECSensor.TempWaterOut, new EmbeddedControllerSource("Water Out", SensorType.Temperature, 0x0101, blank: -40) },
|
||||
{ ECSensor.FanWaterFlow, new EmbeddedControllerSource("Water Flow", SensorType.Flow, 0x00be, 2, factor: 1.0f / 42f * 60f) } // todo: need validation for this calculation
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
private readonly byte[] _data;
|
||||
private readonly ushort[] _registers;
|
||||
private readonly List<Sensor> _sensors;
|
||||
|
||||
private readonly IReadOnlyList<EmbeddedControllerSource> _sources;
|
||||
|
||||
protected EmbeddedController(IEnumerable<EmbeddedControllerSource> sources, ISettings settings) : base("Embedded Controller", new Identifier("lpc", "ec"), settings)
|
||||
{
|
||||
// sorting by address, which implies sorting by bank, for optimized EC access
|
||||
var sourcesList = sources.ToList();
|
||||
sourcesList.Sort((left, right) => left.Register.CompareTo(right.Register));
|
||||
_sources = sourcesList;
|
||||
var indices = new Dictionary<SensorType, int>();
|
||||
foreach (SensorType t in Enum.GetValues(typeof(SensorType)))
|
||||
{
|
||||
indices.Add(t, 0);
|
||||
}
|
||||
|
||||
_sensors = new List<Sensor>();
|
||||
List<ushort> registers = new();
|
||||
foreach (EmbeddedControllerSource s in _sources)
|
||||
{
|
||||
int index = indices[s.Type];
|
||||
indices[s.Type] = index + 1;
|
||||
_sensors.Add(new Sensor(s.Name, index, s.Type, this, settings));
|
||||
for (int i = 0; i < s.Size; ++i)
|
||||
{
|
||||
registers.Add((ushort)(s.Register + i));
|
||||
}
|
||||
|
||||
ActivateSensor(_sensors[_sensors.Count - 1]);
|
||||
}
|
||||
|
||||
_registers = registers.ToArray();
|
||||
_data = new byte[_registers.Length];
|
||||
}
|
||||
|
||||
public override HardwareType HardwareType => HardwareType.EmbeddedController;
|
||||
|
||||
internal static EmbeddedController Create(Model model, ISettings settings)
|
||||
{
|
||||
var boards = _boards.Where(b => b.Models.Contains(model)).ToList();
|
||||
switch (boards.Count)
|
||||
{
|
||||
case 0:
|
||||
return null;
|
||||
case > 1:
|
||||
throw new MultipleBoardRecordsFoundException(model.ToString());
|
||||
}
|
||||
|
||||
BoardInfo board = boards[0];
|
||||
IEnumerable<EmbeddedControllerSource> sources = board.Sensors.Select(ecs => _knownSensors[board.Family][ecs]);
|
||||
|
||||
return Environment.OSVersion.Platform switch
|
||||
{
|
||||
PlatformID.Win32NT => new WindowsEmbeddedController(sources, settings),
|
||||
_ => null
|
||||
};
|
||||
}
|
||||
|
||||
public override void Update()
|
||||
{
|
||||
if (!TryUpdateData())
|
||||
{
|
||||
// just skip this update cycle?
|
||||
return;
|
||||
}
|
||||
|
||||
int readRegister = 0;
|
||||
for (int si = 0; si < _sensors.Count; ++si)
|
||||
{
|
||||
int val = _sources[si].Size switch
|
||||
{
|
||||
1 => _sources[si].Type switch { SensorType.Temperature => unchecked((sbyte)_data[readRegister]), _ => _data[readRegister] },
|
||||
2 => unchecked((short)((_data[readRegister] << 8) + _data[readRegister + 1])),
|
||||
_ => 0
|
||||
};
|
||||
|
||||
readRegister += _sources[si].Size;
|
||||
|
||||
_sensors[si].Value = val != _sources[si].Blank ? val * _sources[si].Factor : null;
|
||||
}
|
||||
}
|
||||
|
||||
public override string GetReport()
|
||||
{
|
||||
StringBuilder r = new();
|
||||
|
||||
r.AppendLine("EC " + GetType().Name);
|
||||
r.AppendLine("Embedded Controller Registers");
|
||||
r.AppendLine();
|
||||
r.AppendLine(" 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F");
|
||||
r.AppendLine();
|
||||
|
||||
try
|
||||
{
|
||||
using IEmbeddedControllerIO embeddedControllerIO = AcquireIOInterface();
|
||||
ushort[] src = new ushort[0x100];
|
||||
byte[] data = new byte[0x100];
|
||||
for (ushort i = 0; i < src.Length; ++i)
|
||||
{
|
||||
src[i] = i;
|
||||
}
|
||||
|
||||
embeddedControllerIO.Read(src, data);
|
||||
for (int i = 0; i <= 0xF; ++i)
|
||||
{
|
||||
r.Append(" ");
|
||||
r.Append((i << 4).ToString("X2", CultureInfo.InvariantCulture));
|
||||
r.Append(" ");
|
||||
for (int j = 0; j <= 0xF; ++j)
|
||||
{
|
||||
byte address = (byte)(i << 4 | j);
|
||||
r.Append(" ");
|
||||
r.Append(data[address].ToString("X2", CultureInfo.InvariantCulture));
|
||||
}
|
||||
|
||||
r.AppendLine();
|
||||
}
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
r.AppendLine(e.Message);
|
||||
}
|
||||
|
||||
return r.ToString();
|
||||
}
|
||||
|
||||
protected abstract IEmbeddedControllerIO AcquireIOInterface();
|
||||
|
||||
private bool TryUpdateData()
|
||||
{
|
||||
try
|
||||
{
|
||||
using IEmbeddedControllerIO embeddedControllerIO = AcquireIOInterface();
|
||||
embeddedControllerIO.Read(_registers, _data);
|
||||
return true;
|
||||
}
|
||||
catch (IOException)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private enum ECSensor
|
||||
{
|
||||
/// <summary>Chipset temperature [℃]</summary>
|
||||
TempChipset,
|
||||
|
||||
/// <summary>CPU temperature [℃]</summary>
|
||||
TempCPU,
|
||||
|
||||
/// <summary>motherboard temperature [℃]</summary>
|
||||
TempMB,
|
||||
|
||||
/// <summary>"T_Sensor" temperature sensor reading [℃]</summary>
|
||||
TempTSensor,
|
||||
|
||||
/// <summary>"T_Sensor 2" temperature sensor reading [℃]</summary>
|
||||
TempTSensor2,
|
||||
|
||||
/// <summary>VRM temperature [℃]</summary>
|
||||
TempVrm,
|
||||
|
||||
/// <summary>CPU Core voltage [mV]</summary>
|
||||
VoltageCPU,
|
||||
|
||||
/// <summary>CPU_Opt fan [RPM]</summary>
|
||||
FanCPUOpt,
|
||||
|
||||
/// <summary>VRM heat sink fan [RPM]</summary>
|
||||
FanVrmHS,
|
||||
|
||||
/// <summary>Chipset fan [RPM]</summary>
|
||||
FanChipset,
|
||||
|
||||
/// <summary>Water Pump [RPM]</summary>
|
||||
FanWaterPump,
|
||||
|
||||
/// <summary>Water flow sensor reading [RPM]</summary>
|
||||
FanWaterFlow,
|
||||
|
||||
/// <summary>CPU current [A]</summary>
|
||||
CurrCPU,
|
||||
|
||||
/// <summary>"Water_In" temperature sensor reading [℃]</summary>
|
||||
TempWaterIn,
|
||||
|
||||
/// <summary>"Water_Out" temperature sensor reading [℃]</summary>
|
||||
TempWaterOut,
|
||||
|
||||
/// <summary>Water block temperature sensor reading [℃]</summary>
|
||||
TempWaterBlockIn,
|
||||
Max
|
||||
}
|
||||
|
||||
private enum BoardFamily
|
||||
{
|
||||
Amd400,
|
||||
Amd500,
|
||||
Amd600,
|
||||
Intel100,
|
||||
Intel300,
|
||||
Intel400,
|
||||
Intel600,
|
||||
Intel700
|
||||
}
|
||||
|
||||
private struct BoardInfo
|
||||
{
|
||||
public BoardInfo(Model[] models, BoardFamily family, params ECSensor[] sensors)
|
||||
{
|
||||
Models = models;
|
||||
Family = family;
|
||||
Sensors = sensors;
|
||||
}
|
||||
|
||||
public BoardInfo(Model model, BoardFamily family, params ECSensor[] sensors)
|
||||
{
|
||||
Models = new[] { model };
|
||||
Family = family;
|
||||
Sensors = sensors;
|
||||
}
|
||||
|
||||
public Model[] Models { get; }
|
||||
|
||||
public BoardFamily Family { get; }
|
||||
|
||||
public ECSensor[] Sensors { get; }
|
||||
}
|
||||
|
||||
public class IOException : System.IO.IOException
|
||||
{
|
||||
public IOException(string message) : base($"ACPI embedded controller I/O error: {message}")
|
||||
{ }
|
||||
}
|
||||
|
||||
public class BadConfigurationException : Exception
|
||||
{
|
||||
public BadConfigurationException(string message) : base(message)
|
||||
{ }
|
||||
}
|
||||
|
||||
public class MultipleBoardRecordsFoundException : BadConfigurationException
|
||||
{
|
||||
public MultipleBoardRecordsFoundException(string model) : base($"Multiple board records refer to the same model '{model}'")
|
||||
{ }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
// This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
|
||||
// If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
// Copyright (C) LibreHardwareMonitor and Contributors.
|
||||
// All Rights Reserved.
|
||||
|
||||
namespace LibreHardwareMonitor.Hardware.Motherboard.Lpc.EC;
|
||||
|
||||
public delegate float EmbeddedControllerReader(IEmbeddedControllerIO ecIO, ushort register);
|
||||
@@ -0,0 +1,31 @@
|
||||
// This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
|
||||
// If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
// Copyright (C) LibreHardwareMonitor and Contributors.
|
||||
// All Rights Reserved.
|
||||
|
||||
namespace LibreHardwareMonitor.Hardware.Motherboard.Lpc.EC;
|
||||
|
||||
public class EmbeddedControllerSource
|
||||
{
|
||||
public EmbeddedControllerSource(string name, SensorType type, ushort register, byte size = 1, float factor = 1.0f, int blank = int.MaxValue)
|
||||
{
|
||||
Name = name;
|
||||
|
||||
Register = register;
|
||||
Size = size;
|
||||
Type = type;
|
||||
Factor = factor;
|
||||
Blank = blank;
|
||||
}
|
||||
|
||||
public string Name { get; }
|
||||
public ushort Register { get; }
|
||||
public byte Size { get; }
|
||||
public float Factor { get; }
|
||||
|
||||
public int Blank { get; }
|
||||
|
||||
public EmbeddedControllerReader Reader { get; }
|
||||
|
||||
public SensorType Type { get; }
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
// This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
|
||||
// If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
// Copyright (C) LibreHardwareMonitor and Contributors.
|
||||
// All Rights Reserved.
|
||||
|
||||
using System;
|
||||
|
||||
namespace LibreHardwareMonitor.Hardware.Motherboard.Lpc.EC;
|
||||
|
||||
public interface IEmbeddedControllerIO : IDisposable
|
||||
{
|
||||
void Read(ushort[] registers, byte[] data);
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
// This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
|
||||
// If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
// Copyright (C) LibreHardwareMonitor and Contributors.
|
||||
// All Rights Reserved.
|
||||
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace LibreHardwareMonitor.Hardware.Motherboard.Lpc.EC;
|
||||
|
||||
public class WindowsEmbeddedController : EmbeddedController
|
||||
{
|
||||
public WindowsEmbeddedController(IEnumerable<EmbeddedControllerSource> sources, ISettings settings) : base(sources, settings)
|
||||
{ }
|
||||
|
||||
protected override IEmbeddedControllerIO AcquireIOInterface()
|
||||
{
|
||||
return new WindowsEmbeddedControllerIO();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,248 @@
|
||||
// This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
|
||||
// If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
// Copyright (C) LibreHardwareMonitor and Contributors.
|
||||
// All Rights Reserved.
|
||||
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Threading;
|
||||
|
||||
namespace LibreHardwareMonitor.Hardware.Motherboard.Lpc.EC;
|
||||
|
||||
/// <summary>
|
||||
/// An unsafe but universal implementation for the ACPI Embedded Controller IO interface for Windows
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// It is unsafe because of possible race condition between this application and the PC firmware when
|
||||
/// writing to the EC registers. For a safe approach ACPI/WMI methods have to be used, but those are
|
||||
/// different for each motherboard model.
|
||||
/// </remarks>
|
||||
public class WindowsEmbeddedControllerIO : IEmbeddedControllerIO
|
||||
{
|
||||
private const int FailuresBeforeSkip = 20;
|
||||
private const int MaxRetries = 5;
|
||||
|
||||
// implementation
|
||||
private const int WaitSpins = 50;
|
||||
private bool _disposed;
|
||||
|
||||
private int _waitReadFailures;
|
||||
|
||||
public WindowsEmbeddedControllerIO()
|
||||
{
|
||||
if (!Mutexes.WaitEc(10))
|
||||
{
|
||||
throw new BusMutexLockingFailedException();
|
||||
}
|
||||
}
|
||||
|
||||
public void Read(ushort[] registers, byte[] data)
|
||||
{
|
||||
Trace.Assert(registers.Length <= data.Length,
|
||||
"data buffer length has to be greater or equal to the registers array length");
|
||||
|
||||
byte bank = 0;
|
||||
byte prevBank = SwitchBank(bank);
|
||||
|
||||
// oops... somebody else is working with the EC too
|
||||
Trace.WriteLineIf(prevBank != 0, "Concurrent access to the ACPI EC detected.\nRace condition possible.");
|
||||
|
||||
// read registers minimizing bank switches.
|
||||
for (int i = 0; i < registers.Length; i++)
|
||||
{
|
||||
byte regBank = (byte)(registers[i] >> 8);
|
||||
byte regIndex = (byte)(registers[i] & 0xFF);
|
||||
// registers are sorted by bank
|
||||
if (regBank > bank)
|
||||
{
|
||||
bank = SwitchBank(regBank);
|
||||
}
|
||||
data[i] = ReadByte(regIndex);
|
||||
}
|
||||
|
||||
SwitchBank(prevBank);
|
||||
}
|
||||
|
||||
private byte ReadByte(byte register)
|
||||
{
|
||||
return ReadLoop<byte>(register, ReadByteOp);
|
||||
}
|
||||
|
||||
private void WriteByte(byte register, byte value)
|
||||
{
|
||||
WriteLoop(register, value, WriteByteOp);
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
if (!_disposed)
|
||||
{
|
||||
_disposed = true;
|
||||
Mutexes.ReleaseEc();
|
||||
}
|
||||
}
|
||||
|
||||
private byte SwitchBank(byte bank)
|
||||
{
|
||||
byte previous = ReadByte(0xFF);
|
||||
WriteByte(0xFF, bank);
|
||||
return previous;
|
||||
}
|
||||
|
||||
private TResult ReadLoop<TResult>(byte register, ReadOp<TResult> op) where TResult : new()
|
||||
{
|
||||
TResult result = new();
|
||||
|
||||
for (int i = 0; i < MaxRetries; i++)
|
||||
{
|
||||
if (op(register, out result))
|
||||
{
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private void WriteLoop<TValue>(byte register, TValue value, WriteOp<TValue> op)
|
||||
{
|
||||
for (int i = 0; i < MaxRetries; i++)
|
||||
{
|
||||
if (op(register, value))
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private bool WaitForStatus(Status status, bool isSet)
|
||||
{
|
||||
for (int i = 0; i < WaitSpins; i++)
|
||||
{
|
||||
byte value = ReadIOPort(Port.Command);
|
||||
|
||||
if (((byte)status & (!isSet ? value : (byte)~value)) == 0)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
Thread.Sleep(1);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private bool WaitRead()
|
||||
{
|
||||
if (_waitReadFailures > FailuresBeforeSkip)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (WaitForStatus(Status.OutputBufferFull, true))
|
||||
{
|
||||
_waitReadFailures = 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
_waitReadFailures++;
|
||||
return false;
|
||||
}
|
||||
|
||||
private bool WaitWrite()
|
||||
{
|
||||
return WaitForStatus(Status.InputBufferFull, false);
|
||||
}
|
||||
|
||||
private byte ReadIOPort(Port port)
|
||||
{
|
||||
return Ring0.ReadIoPort((uint)port);
|
||||
}
|
||||
|
||||
private void WriteIOPort(Port port, byte datum)
|
||||
{
|
||||
Ring0.WriteIoPort((uint)port, datum);
|
||||
}
|
||||
|
||||
public class BusMutexLockingFailedException : EmbeddedController.IOException
|
||||
{
|
||||
public BusMutexLockingFailedException()
|
||||
: base("could not lock ISA bus mutex")
|
||||
{ }
|
||||
}
|
||||
|
||||
private delegate bool ReadOp<TParam>(byte register, out TParam p);
|
||||
|
||||
private delegate bool WriteOp<in TParam>(byte register, TParam p);
|
||||
|
||||
// see the ACPI specification chapter 12
|
||||
private enum Port : byte
|
||||
{
|
||||
Command = 0x66,
|
||||
Data = 0x62
|
||||
}
|
||||
|
||||
private enum Command : byte
|
||||
{
|
||||
Read = 0x80, // RD_EC
|
||||
Write = 0x81, // WR_EC
|
||||
BurstEnable = 0x82, // BE_EC
|
||||
BurstDisable = 0x83, // BD_EC
|
||||
Query = 0x84 // QR_EC
|
||||
}
|
||||
|
||||
private enum Status : byte
|
||||
{
|
||||
OutputBufferFull = 0x01, // EC_OBF
|
||||
InputBufferFull = 0x02, // EC_IBF
|
||||
Command = 0x08, // CMD
|
||||
BurstMode = 0x10, // BURST
|
||||
SciEventPending = 0x20, // SCI_EVT
|
||||
SmiEventPending = 0x40 // SMI_EVT
|
||||
}
|
||||
|
||||
#region Read/Write ops
|
||||
|
||||
protected bool ReadByteOp(byte register, out byte value)
|
||||
{
|
||||
if (WaitWrite())
|
||||
{
|
||||
WriteIOPort(Port.Command, (byte)Command.Read);
|
||||
|
||||
if (WaitWrite())
|
||||
{
|
||||
WriteIOPort(Port.Data, register);
|
||||
|
||||
if (WaitWrite() && WaitRead())
|
||||
{
|
||||
value = ReadIOPort(Port.Data);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
value = 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
protected bool WriteByteOp(byte register, byte value)
|
||||
{
|
||||
if (WaitWrite())
|
||||
{
|
||||
WriteIOPort(Port.Command, (byte)Command.Write);
|
||||
if (WaitWrite())
|
||||
{
|
||||
WriteIOPort(Port.Data, register);
|
||||
if (WaitWrite())
|
||||
{
|
||||
WriteIOPort(Port.Data, value);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -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
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user