# HG changeset patch # User moel.mich # Date 1287331459 0 # Node ID 458a6c3de57932829b1f11e4c560b324556a5bea # Parent 97757a798918d044b912ce5a1d58ed729dbb4f3a Added code to read the additional fans on the ASRock P55 Deluxe mainboard via special GPIO switching. diff -r 97757a798918 -r 458a6c3de579 Hardware/LPC/F718XX.cs --- a/Hardware/LPC/F718XX.cs Sun Oct 17 08:21:33 2010 +0000 +++ b/Hardware/LPC/F718XX.cs Sun Oct 17 16:04:19 2010 +0000 @@ -65,6 +65,12 @@ 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 -r 97757a798918 -r 458a6c3de579 Hardware/LPC/ISuperIO.cs --- a/Hardware/LPC/ISuperIO.cs Sun Oct 17 08:21:33 2010 +0000 +++ b/Hardware/LPC/ISuperIO.cs Sun Oct 17 16:04:19 2010 +0000 @@ -44,6 +44,9 @@ float?[] Temperatures { get; } float?[] Fans { get; } + byte? ReadGPIO(int index); + void WriteGPIO(int index, byte value); + string GetReport(); void Update(); } diff -r 97757a798918 -r 458a6c3de579 Hardware/LPC/IT87XX.cs --- a/Hardware/LPC/IT87XX.cs Sun Oct 17 08:21:33 2010 +0000 +++ b/Hardware/LPC/IT87XX.cs Sun Oct 17 16:04:19 2010 +0000 @@ -45,6 +45,9 @@ 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 @@ 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 @@ } 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 @@ 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 @@ } 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 -r 97757a798918 -r 458a6c3de579 Hardware/LPC/LMSensors.cs --- a/Hardware/LPC/LMSensors.cs Sun Oct 17 08:21:33 2010 +0000 +++ b/Hardware/LPC/LMSensors.cs Sun Oct 17 16:04:19 2010 +0000 @@ -141,6 +141,12 @@ 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 -r 97757a798918 -r 458a6c3de579 Hardware/LPC/LPCIO.cs --- a/Hardware/LPC/LPCIO.cs Sun Oct 17 08:21:33 2010 +0000 +++ b/Hardware/LPC/LPCIO.cs Sun Oct 17 16:04:19 2010 +0000 @@ -64,10 +64,10 @@ 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 @@ if (id != 0 && id != 0xff) { WinbondFintekExit(); - ReportUnknownChip("Winbond / Fintek", ((id << 8) | revision)); + ReportUnknownChip("Winbond / Fintek", ((id << 8) | revision)); } } else { @@ -235,7 +235,7 @@ 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 @@ 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 @@ 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 @@ #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 @@ 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 @@ 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 @@ if (DetectIT87()) continue; if (DetectSMSC()) continue; - } + } } public LPCIO() { @@ -429,7 +446,7 @@ Detect(); - WinRing0.ReleaseIsaBusMutex(); + WinRing0.ReleaseIsaBusMutex(); } public ISuperIO[] SuperIO { diff -r 97757a798918 -r 458a6c3de579 Hardware/LPC/W836XX.cs --- a/Hardware/LPC/W836XX.cs Sun Oct 17 08:21:33 2010 +0000 +++ b/Hardware/LPC/W836XX.cs Sun Oct 17 16:04:19 2010 +0000 @@ -104,6 +104,12 @@ 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 -r 97757a798918 -r 458a6c3de579 Hardware/Mainboard/SuperIOHardware.cs --- a/Hardware/Mainboard/SuperIOHardware.cs Sun Oct 17 08:21:33 2010 +0000 +++ b/Hardware/Mainboard/SuperIOHardware.cs Sun Oct 17 16:04:19 2010 +0000 @@ -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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ } 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 @@ } 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 {