diff --git a/Hardware/LPC/F718XX.cs b/Hardware/LPC/F718XX.cs index 57e4867..6236f10 100644 --- a/Hardware/LPC/F718XX.cs +++ b/Hardware/LPC/F718XX.cs @@ -65,6 +65,12 @@ namespace OpenHardwareMonitor.Hardware.LPC { return WinRing0.ReadIoPortByte((ushort)(address + DATA_REGISTER_OFFSET)); } + public byte? ReadGPIO(int index) { + return null; + } + + public void WriteGPIO(int index, byte value) { } + public F718XX(Chip chip, ushort address) { this.address = address; this.chip = chip; diff --git a/Hardware/LPC/ISuperIO.cs b/Hardware/LPC/ISuperIO.cs index d8ce4c8..1877db8 100644 --- a/Hardware/LPC/ISuperIO.cs +++ b/Hardware/LPC/ISuperIO.cs @@ -44,6 +44,9 @@ namespace OpenHardwareMonitor.Hardware.LPC { float?[] Temperatures { get; } float?[] Fans { get; } + byte? ReadGPIO(int index); + void WriteGPIO(int index, byte value); + string GetReport(); void Update(); } diff --git a/Hardware/LPC/IT87XX.cs b/Hardware/LPC/IT87XX.cs index c9606d2..5fabd51 100644 --- a/Hardware/LPC/IT87XX.cs +++ b/Hardware/LPC/IT87XX.cs @@ -45,6 +45,9 @@ namespace OpenHardwareMonitor.Hardware.LPC { private readonly Chip chip; private readonly byte version; + private readonly ushort gpioAddress; + private readonly int gpioCount; + private readonly ushort addressReg; private readonly ushort dataReg; @@ -77,16 +80,31 @@ namespace OpenHardwareMonitor.Hardware.LPC { byte value = WinRing0.ReadIoPortByte(dataReg); valid = register == WinRing0.ReadIoPortByte(addressReg); return value; - } + } - public IT87XX(Chip chip, ushort address, byte version) { + public byte? ReadGPIO(int index) { + if (index >= gpioCount) + return null; + + return WinRing0.ReadIoPortByte((ushort)(gpioAddress + index)); + } + + public void WriteGPIO(int index, byte value) { + if (index >= gpioCount) + return; + + WinRing0.WriteIoPortByte((ushort)(gpioAddress + index), value); + } + + public IT87XX(Chip chip, ushort address, ushort gpioAddress, byte version) { this.address = address; this.chip = chip; this.version = version; this.addressReg = (ushort)(address + ADDRESS_REGISTER_OFFSET); this.dataReg = (ushort)(address + DATA_REGISTER_OFFSET); - + this.gpioAddress = gpioAddress; + // Check vendor id bool valid; byte vendorId = ReadByte(VENDOR_ID_REGISTER, out valid); @@ -109,6 +127,20 @@ namespace OpenHardwareMonitor.Hardware.LPC { } else { voltageGain = 0.016f; } + + // Set the number of GPIO sets + switch (chip) { + case Chip.IT8712F: + case Chip.IT8716F: + case Chip.IT8718F: + case Chip.IT8726F: + gpioCount = 5; + break; + case Chip.IT8720F: + case Chip.IT8721F: + gpioCount = 8; + break; + } } public Chip Chip { get { return chip; } } @@ -126,6 +158,8 @@ namespace OpenHardwareMonitor.Hardware.LPC { 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 (!WinRing0.WaitIsaBusMutex(100)) @@ -150,6 +184,16 @@ namespace OpenHardwareMonitor.Hardware.LPC { } r.AppendLine(); + r.AppendLine("GPIO Registers"); + r.AppendLine(); + for (int i = 0; i < gpioCount; i++) { + r.Append(" "); + r.Append(ReadGPIO(i).Value.ToString("X2", + CultureInfo.InvariantCulture)); + } + r.AppendLine(); + r.AppendLine(); + WinRing0.ReleaseIsaBusMutex(); return r.ToString(); diff --git a/Hardware/LPC/LMSensors.cs b/Hardware/LPC/LMSensors.cs index e7de090..ad782b0 100755 --- a/Hardware/LPC/LMSensors.cs +++ b/Hardware/LPC/LMSensors.cs @@ -141,6 +141,12 @@ namespace OpenHardwareMonitor.Hardware.LPC { fanReaders[i] = new StreamReader(fanPaths[i]); } + public byte? ReadGPIO(int index) { + return null; + } + + public void WriteGPIO(int index, byte value) { } + public string GetReport() { return null; } diff --git a/Hardware/LPC/LPCIO.cs b/Hardware/LPC/LPCIO.cs index a3ac5e6..e051cbc 100644 --- a/Hardware/LPC/LPCIO.cs +++ b/Hardware/LPC/LPCIO.cs @@ -64,10 +64,10 @@ namespace OpenHardwareMonitor.Hardware.LPC { private byte ReadByte(byte register) { WinRing0.WriteIoPortByte(registerPort, register); return WinRing0.ReadIoPortByte(valuePort); - } + } private ushort ReadWord(byte register) { - return (ushort)((ReadByte(register) << 8) | + return (ushort)((ReadByte(register) << 8) | ReadByte((byte)(register + 1))); } @@ -218,7 +218,7 @@ namespace OpenHardwareMonitor.Hardware.LPC { if (id != 0 && id != 0xff) { WinbondFintekExit(); - ReportUnknownChip("Winbond / Fintek", ((id << 8) | revision)); + ReportUnknownChip("Winbond / Fintek", ((id << 8) | revision)); } } else { @@ -235,7 +235,7 @@ namespace OpenHardwareMonitor.Hardware.LPC { report.Append("Chip ID: 0x"); report.AppendLine(chip.ToString("X")); report.Append("Chip revision: 0x"); - report.AppendLine(revision.ToString("X", + report.AppendLine(revision.ToString("X", CultureInfo.InvariantCulture)); report.AppendLine("Error: Address verification failed"); report.AppendLine(); @@ -250,10 +250,10 @@ namespace OpenHardwareMonitor.Hardware.LPC { report.Append("Chip ID: 0x"); report.AppendLine(chip.ToString("X")); report.Append("Chip revision: 0x"); - report.AppendLine(revision.ToString("X", + report.AppendLine(revision.ToString("X", CultureInfo.InvariantCulture)); report.Append("Error: Invalid address 0x"); - report.AppendLine(address.ToString("X", + report.AppendLine(address.ToString("X", CultureInfo.InvariantCulture)); report.AppendLine(); return false; @@ -280,10 +280,10 @@ namespace OpenHardwareMonitor.Hardware.LPC { report.Append("Chip ID: 0x"); report.AppendLine(chip.ToString("X")); report.Append("Chip revision: 0x"); - report.AppendLine(revision.ToString("X", + report.AppendLine(revision.ToString("X", CultureInfo.InvariantCulture)); report.Append("Error: Invalid vendor ID 0x"); - report.AppendLine(vendorID.ToString("X", + report.AppendLine(vendorID.ToString("X", CultureInfo.InvariantCulture)); report.AppendLine(); return false; @@ -304,6 +304,7 @@ namespace OpenHardwareMonitor.Hardware.LPC { #region ITE private const byte IT87_ENVIRONMENT_CONTROLLER_LDN = 0x04; + private const byte IT87_GPIO_LDN = 0x07; private const byte IT87_CHIP_VERSION_REGISTER = 0x22; private void IT87Enter() { @@ -351,6 +352,11 @@ namespace OpenHardwareMonitor.Hardware.LPC { byte version = (byte)(ReadByte(IT87_CHIP_VERSION_REGISTER) & 0x0F); + Select(IT87_GPIO_LDN); + ushort gpioAddress = ReadWord(BASE_ADDRESS_REGISTER + 2); + Thread.Sleep(1); + ushort gpioVerify = ReadWord(BASE_ADDRESS_REGISTER + 2); + IT87Exit(); if (address != verify || address < 0x100 || (address & 0xF007) != 0) { @@ -363,7 +369,18 @@ namespace OpenHardwareMonitor.Hardware.LPC { return false; } - superIOs.Add(new IT87XX(chip, address, version)); + 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)); return true; } @@ -417,7 +434,7 @@ namespace OpenHardwareMonitor.Hardware.LPC { if (DetectIT87()) continue; if (DetectSMSC()) continue; - } + } } public LPCIO() { @@ -429,7 +446,7 @@ namespace OpenHardwareMonitor.Hardware.LPC { Detect(); - WinRing0.ReleaseIsaBusMutex(); + WinRing0.ReleaseIsaBusMutex(); } public ISuperIO[] SuperIO { diff --git a/Hardware/LPC/W836XX.cs b/Hardware/LPC/W836XX.cs index 2435d83..97fc0e4 100644 --- a/Hardware/LPC/W836XX.cs +++ b/Hardware/LPC/W836XX.cs @@ -104,6 +104,12 @@ namespace OpenHardwareMonitor.Hardware.LPC { WinRing0.WriteIoPortByte( (ushort)(address + DATA_REGISTER_OFFSET), value); } + + public byte? ReadGPIO(int index) { + return null; + } + + public void WriteGPIO(int index, byte value) { } public W836XX(Chip chip, byte revision, ushort address) { this.address = address; diff --git a/Hardware/Mainboard/SuperIOHardware.cs b/Hardware/Mainboard/SuperIOHardware.cs index b8d2512..3777e3f 100644 --- a/Hardware/Mainboard/SuperIOHardware.cs +++ b/Hardware/Mainboard/SuperIOHardware.cs @@ -35,8 +35,10 @@ */ +using System; using System.Collections.Generic; using System.Globalization; +using System.Threading; using OpenHardwareMonitor.Hardware.LPC; namespace OpenHardwareMonitor.Hardware.Mainboard { @@ -50,6 +52,20 @@ namespace OpenHardwareMonitor.Hardware.Mainboard { private readonly List temperatures = new List(); private readonly List fans = new List(); + private delegate float? ReadValueDelegate(int index); + private delegate void UpdateDelegate(); + + // delegates for mainboard specific sensor reading code + private readonly ReadValueDelegate readVoltage; + private readonly ReadValueDelegate readTemperature; + private readonly ReadValueDelegate readFan; + + // delegate for post update mainboard specific code + private readonly UpdateDelegate postUpdate; + + // mainboard specific mutex + private readonly Mutex mutex; + public SuperIOHardware(Mainboard mainboard, ISuperIO superIO, Manufacturer manufacturer, Model model, ISettings settings) { @@ -57,6 +73,12 @@ namespace OpenHardwareMonitor.Hardware.Mainboard { this.superIO = superIO; this.name = ChipName.GetName(superIO.Chip); + this.readVoltage = (index) => superIO.Voltages[index]; + this.readTemperature = (index) => superIO.Temperatures[index]; + this.readFan = (index) => superIO.Fans[index]; + + this.postUpdate = () => { }; + List v = new List(); List t = new List(); List f = new List(); @@ -119,6 +141,7 @@ namespace OpenHardwareMonitor.Hardware.Mainboard { case Manufacturer.ASRock: switch (model) { case Model.P55_Deluxe: // IT8720F + v.Add(new Voltage("CPU VCore", 0)); v.Add(new Voltage("+3.3V", 2)); v.Add(new Voltage("+12V", 4, 30, 10)); @@ -128,8 +151,54 @@ namespace OpenHardwareMonitor.Hardware.Mainboard { t.Add(new Temperature("Motherboard", 1)); f.Add(new Fan("CPU Fan", 0)); f.Add(new Fan("Chassis Fan #1", 1)); - // fan channel 2 can connect to 3 different fan headers - // which fan is read is configured with gpio 83-85 + + // this mutex is also used by the official ASRock tool + mutex = new Mutex(false, "ASRockOCMark"); + + bool exclusiveAccess = false; + try { + exclusiveAccess = mutex.WaitOne(10, false); + } catch (AbandonedMutexException) { } + catch (InvalidOperationException) { } + + // only read additional fans if we get exclusive access + if (exclusiveAccess) { + + f.Add(new Fan("Chassis Fan #2", 2)); + f.Add(new Fan("Chassis Fan #3", 3)); + f.Add(new Fan("Power Fan", 4)); + + readFan = (index) => { + if (index < 2) { + return superIO.Fans[index]; + } else { + // get GPIO 80-87 + byte? gpio = superIO.ReadGPIO(7); + if (!gpio.HasValue) + return null; + + // read the last 3 fans based on GPIO 83-85 + int[] masks = { 0x05, 0x03, 0x06 }; + return (((gpio.Value >> 3) & 0x07) == + masks[index - 2]) ? superIO.Fans[2] : null; + } + }; + + int fanIndex = 0; + postUpdate = () => { + // get GPIO 80-87 + byte? gpio = superIO.ReadGPIO(7); + if (!gpio.HasValue) + return; + + // prepare the GPIO 83-85 for the next update + int[] masks = { 0x05, 0x03, 0x06 }; + superIO.WriteGPIO(7, + (byte)((gpio.Value & 0xC7) | (masks[fanIndex] << 3))); + fanIndex = (fanIndex + 1) % 3; + }; + } + break; default: v.Add(new Voltage("CPU VCore", 0)); @@ -741,7 +810,7 @@ namespace OpenHardwareMonitor.Hardware.Mainboard { superIO.Update(); foreach (Sensor sensor in voltages) { - float? value = superIO.Voltages[sensor.Index]; + float? value = readVoltage(sensor.Index); if (value.HasValue) { sensor.Value = value + (value - sensor.Parameters[2].Value) * sensor.Parameters[0].Value / sensor.Parameters[1].Value; @@ -750,7 +819,7 @@ namespace OpenHardwareMonitor.Hardware.Mainboard { } foreach (Sensor sensor in temperatures) { - float? value = superIO.Temperatures[sensor.Index]; + float? value = readTemperature(sensor.Index); if (value.HasValue) { sensor.Value = value + sensor.Parameters[0].Value; ActivateSensor(sensor); @@ -758,13 +827,15 @@ namespace OpenHardwareMonitor.Hardware.Mainboard { } foreach (Sensor sensor in fans) { - float? value = superIO.Fans[sensor.Index]; + float? value = readFan(sensor.Index); if (value.HasValue) { sensor.Value = value; if (value.Value > 0) ActivateSensor(sensor); } } + + postUpdate(); } private class Voltage {