* Try and migrate the old GigabyteController stuff with PawnIO * Bring back WinRing0 era GigabyteController stuff * ISABridge use the PawnIO module with its built-in logic * Ecio uses LpcIO directly (not sure about the initialization logic in TryCreate() to make this work) * Code-review * Fix inverted logic * Remove IsaBridgeEc field init * Format document * Combine logic * Gigabyte Implementation best attempt * Update IsaBridgeGigabyteController.cs * Cleanup and fix enablind logic for Isa version * Add debug logs * Update IsaBridgeGigabyteController.cs * Code review * Unmap + restore the mmio state is done through the closing of the module. * Fix boolean logic * Restore the fan control byte instead * Fallback to ECIO if FanControl enable byte is 0xFF + add logs to ECIO * Port back to validation logic * Allow for one or the other MMIO to be 0 * Wrap enter/exit mmio logic + enter/exit each time * Keep state of EcioPort enable * Missing dispose + close order fix * Update IsaBridgeGigabyteController.cs * Remove empty line before TryCreate method * Code review * Remove try/finally for SW * Cleanup debug log methods * Add DEBUG_LOG define conditional * Misc * Misc --------- Co-authored-by: PhyxionNL <7643972+PhyxionNL@users.noreply.github.com>
213 lines
5.9 KiB
C#
213 lines
5.9 KiB
C#
// 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;
|
|
using LibreHardwareMonitor.PawnIo;
|
|
|
|
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 readonly IsaBridgeEc _isaBridgeEc;
|
|
private readonly MMIOMapping _mmio;
|
|
private bool? _enabled;
|
|
private bool? _restoreEnabled;
|
|
private const int ControllerEnableRegister = 0x47;
|
|
private const uint ControllerFanControlArea = 0x900;
|
|
|
|
private IsaBridgeGigabyteController(IsaBridgeEc isaBridgeEc, MMIOMapping mmio)
|
|
{
|
|
_isaBridgeEc = isaBridgeEc;
|
|
_mmio = mmio;
|
|
}
|
|
|
|
public static bool TryCreate(out IsaBridgeGigabyteController isaBridgeGigabyteController)
|
|
{
|
|
isaBridgeGigabyteController = null;
|
|
IsaBridgeEc _isaBridgeEc = new IsaBridgeEc();
|
|
|
|
// find
|
|
if (!_isaBridgeEc.FindSuperIoMMIO(out _, out MMIOMapping secondMmio))
|
|
{
|
|
_isaBridgeEc.Close();
|
|
return false;
|
|
}
|
|
|
|
if (!_isaBridgeEc.GetOriginalState(out MMIOState originalState))
|
|
{
|
|
_isaBridgeEc.Close();
|
|
return false;
|
|
}
|
|
|
|
if (!EnterMmio(_isaBridgeEc, originalState))
|
|
{
|
|
_isaBridgeEc.Close();
|
|
return false;
|
|
}
|
|
|
|
// if we get 0xFF, we can't use the IsaBridgeGigabyteController
|
|
if (!_isaBridgeEc.ReadMmio(
|
|
superIoIndex: secondMmio.Index,
|
|
offset: ControllerFanControlArea + ControllerEnableRegister,
|
|
size: 1,
|
|
value: out byte readvaluebyte) ||
|
|
readvaluebyte == 0xFF)
|
|
{
|
|
_isaBridgeEc.Close();
|
|
return false;
|
|
}
|
|
|
|
if (!ExitMmio(_isaBridgeEc))
|
|
{
|
|
_isaBridgeEc.Close();
|
|
return false;
|
|
}
|
|
|
|
isaBridgeGigabyteController = new IsaBridgeGigabyteController(_isaBridgeEc, secondMmio);
|
|
|
|
return true;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Enable/Disable Fan Control
|
|
/// </summary>
|
|
/// <param name="enabled"></param>
|
|
/// <returns>true on success</returns>
|
|
public bool Enable(bool enabled)
|
|
{
|
|
bool isEntered = false;
|
|
|
|
/// use a try finaly + the <see cref="isEntered" /> to get a safe
|
|
/// <see cref="EnterMmio(IsaBridgeEc, MMIOState?)"/> and <see cref="ExitMmio(IsaBridgeEc)"/> pattern
|
|
try
|
|
{
|
|
// get initial state if missing
|
|
if (_enabled is null)
|
|
{
|
|
isEntered = EnterMmio(_isaBridgeEc);
|
|
if (!isEntered)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
if (!_isaBridgeEc.ReadMmio(
|
|
superIoIndex: _mmio.Index,
|
|
offset: ControllerFanControlArea + ControllerEnableRegister,
|
|
size: 1,
|
|
value: out byte readvaluebyte))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
bool readValue = Convert.ToBoolean(readvaluebyte);
|
|
_restoreEnabled ??= readValue;
|
|
_enabled = Convert.ToBoolean(readvaluebyte);
|
|
}
|
|
|
|
// if already enabled, return
|
|
if (_enabled == enabled)
|
|
{
|
|
return true;
|
|
}
|
|
|
|
if (!isEntered)
|
|
{
|
|
// we didn't enter in the initial state block, enter now
|
|
isEntered = EnterMmio(_isaBridgeEc);
|
|
if (!isEntered)
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
|
|
// write the value
|
|
byte writeValue = Convert.ToByte(enabled);
|
|
if (!_isaBridgeEc.WriteMmio(
|
|
superIoIndex: _mmio.Index,
|
|
offset: ControllerFanControlArea + ControllerEnableRegister,
|
|
size: 1,
|
|
value: writeValue))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
Thread.Sleep(500);
|
|
|
|
_enabled = enabled;
|
|
|
|
return true;
|
|
}
|
|
finally
|
|
{
|
|
// safe exit from any return above
|
|
if (isEntered)
|
|
{
|
|
ExitMmio(_isaBridgeEc);
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Restore settings back to initial values
|
|
/// </summary>
|
|
public void Restore()
|
|
{
|
|
if (_restoreEnabled is null)
|
|
{
|
|
return;
|
|
}
|
|
|
|
Enable(_restoreEnabled.Value);
|
|
}
|
|
|
|
public void Dispose()
|
|
{
|
|
Restore();
|
|
_isaBridgeEc.Close();
|
|
}
|
|
|
|
private static bool EnterMmio(IsaBridgeEc isaBridgeEc, MMIOState? currentState = null)
|
|
{
|
|
if (!isaBridgeEc.Map())
|
|
{
|
|
return false;
|
|
}
|
|
|
|
if (currentState is null || (currentState != MMIOState.MMIO_Enabled4E && currentState != MMIOState.MMIO_EnabledBoth))
|
|
{
|
|
if (!isaBridgeEc.TrySetState(MMIOState.MMIO_Enabled4E))
|
|
{
|
|
isaBridgeEc.Unmap();
|
|
return false;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
private static bool ExitMmio(IsaBridgeEc isaBridgeEc)
|
|
{
|
|
if (!isaBridgeEc.TrySetState(MMIOState.MMIO_Original))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
if (!isaBridgeEc.Unmap())
|
|
{
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
}
|