//#define ISA_BRIDGE_EC_DEBUG
using System.Diagnostics;
namespace LibreHardwareMonitor.PawnIo
{
public enum MMIOState
{
Unknown = -999,
MMIO_Original = -1,
MMIO_Disabled = 0,
MMIO_Enabled2E = 1,
MMIO_Enabled4E = 2,
MMIO_EnabledBoth = 3
};
public struct MMIOMapping
{
public int Index;
public long BaseAddress;
public long SuperIoSize;
public long ChipId;
}
public class IsaBridgeEc
{
private readonly PawnIo _pawnIO = PawnIo.LoadModuleFromResource(typeof(IsaBridgeEc).Assembly, $"{nameof(LibreHardwareMonitor)}.Resources.PawnIo.IsaBridgeEC.bin");
// ioctl_find_superio_mmio
public bool FindSuperIoMMIO(out MMIOMapping firstMmio, out MMIOMapping secondMmio)
{
long[] outArray = new long[6];
int ntStatusCode = _pawnIO.ExecuteHr("ioctl_find_superio_mmio", [], 0, outArray, 6, out uint returnSize);
Log($"FindSuperIoMMIO statusCode: {ntStatusCode}");
if (ntStatusCode != 0)
{
firstMmio = default;
secondMmio = default;
return false;
}
firstMmio = new MMIOMapping
{
Index = 0,
BaseAddress = outArray[0],
SuperIoSize = outArray[1],
ChipId = outArray[2]
};
secondMmio = new MMIOMapping
{
Index = 1,
BaseAddress = outArray[3],
SuperIoSize = outArray[4],
ChipId = outArray[5]
};
Log($"First MMIO - BaseAddress: 0x{firstMmio.BaseAddress:X}, SuperIoSize: 0x{firstMmio.SuperIoSize:X}, ChipId: 0x{firstMmio.ChipId:X}");
Log($"Second MMIO - BaseAddress: 0x{secondMmio.BaseAddress:X}, SuperIoSize: 0x{secondMmio.SuperIoSize:X}, ChipId: 0x{secondMmio.ChipId:X}");
return firstMmio.BaseAddress != 0 || secondMmio.BaseAddress != 0;
}
//ioctl_access_superio_mmio
public bool ReadMmio(long superIoIndex, long offset, long size, out byte value)
{
long[] inArray = new long[5] {
superIoIndex, // superio index
offset, // offset
size, // size
0, // is write?
0 // value (ignored for read)
};
long[] outarray = new long[1];
int ntStatusCode = _pawnIO.ExecuteHr("ioctl_access_superio_mmio", inArray, 5, outarray, 1, out uint returnSize);
Log($"ReadMmio statusCode: {ntStatusCode}, Read Value: 0x{outarray[0]:X} at SuperIoIndex {superIoIndex}, offset {offset}, size {size}");
value = (byte)outarray[0];
return ntStatusCode == 0;
}
//ioctl_access_superio_mmio
public bool WriteMmio(long superIoIndex, long offset, long size, byte value)
{
long[] inArray = new long[5] {
superIoIndex, // superio index
offset, // offset
size, // size
1, // is write?
value // value
};
long[] outarray = new long[1];
int ntStatusCode = _pawnIO.ExecuteHr("ioctl_access_superio_mmio", inArray, 5, outarray, 1, out uint returnSize);
Log($"WriteMmio statusCode: {ntStatusCode}, Written Value: 0x{value:X} at SuperIoIndex {superIoIndex}, offset {offset}, size {size}");
return ntStatusCode == 0;
}
// ioctl_map_superio_mmio
public bool Map()
{
int ntStatusCode = _pawnIO.ExecuteHr("ioctl_map_superio_mmio", [], 0, [], 0, out uint returnSize);
Log($"Map statusCode: {ntStatusCode}");
return ntStatusCode == 0;
}
// ioctl_unmap_superio_mmio
public bool Unmap()
{
int ntStatusCode = _pawnIO.ExecuteHr("ioctl_unmap_superio_mmio", [], 0, [], 0, out uint returnSize);
Log($"Unmap statusCode: {ntStatusCode}");
return ntStatusCode == 0;
}
// ioctl_access_superio_mmio
public bool GetOriginalState(out MMIOState state)
{
state = MMIOState.Unknown;
long[] outArray = new long[1];
int ntStatusCode = _pawnIO.ExecuteHr("ioctl_iomem_mmio_get_org_state", [], 0, outArray, 1, out uint returnSize);
Log($"GetOriginalState statusCode: {ntStatusCode}");
if (ntStatusCode != 0)
return false;
Log($"Original MMIO State: {(MMIOState)outArray[0]}");
state = (MMIOState)outArray[0];
return true;
}
public bool TryGetCurrentState(out MMIOState state)
{
state = MMIOState.Unknown;
long[] outArray = new long[1];
int ntStatusCode = _pawnIO.ExecuteHr("ioctl_iomem_mmio_get_cur_state", [], 0, outArray, 1, out uint returnSize);
if (ntStatusCode != 0)
return false;
state = (MMIOState)outArray[0];
return true;
}
public bool TrySetState(MMIOState state)
{
long[] inArray = new long[1];
inArray[0] = (long)state;
int ntStatusCode = _pawnIO.ExecuteHr("ioctl_iomem_mmio_set_state", inArray, 1, [], 0, out uint returnSize);
Log($"TrySetState to {state} statusCode: {ntStatusCode}");
if (ntStatusCode != 0)
return false;
return true;
}
public void Close() => _pawnIO.Close();
///
/// Writes a debug message to both the output window and a log file when ISA_BRIDGE_EC_DEBUG is defined.
///
/// The log entry is timestamped and appended to the file
/// 'PawnIo_IsaBridgeEc_DebugLog.txt' in the application's working directory. This method only produces output
/// when compiled with the ISA_BRIDGE_EC_DEBUG symbol defined.
/// The message to log. This should provide relevant information for debugging purposes.
[Conditional("DEBUG_LOG"), Conditional("ISA_BRIDGE_EC_DEBUG")]
private static void Log(string message)
{
Debug.WriteLine(message);
}
}
}