Added code to read the additional fans on the ASRock P55 Deluxe mainboard via special GPIO switching.
1.1 --- a/Hardware/LPC/F718XX.cs Sun Oct 17 08:21:33 2010 +0000
1.2 +++ b/Hardware/LPC/F718XX.cs Sun Oct 17 16:04:19 2010 +0000
1.3 @@ -65,6 +65,12 @@
1.4 return WinRing0.ReadIoPortByte((ushort)(address + DATA_REGISTER_OFFSET));
1.5 }
1.6
1.7 + public byte? ReadGPIO(int index) {
1.8 + return null;
1.9 + }
1.10 +
1.11 + public void WriteGPIO(int index, byte value) { }
1.12 +
1.13 public F718XX(Chip chip, ushort address) {
1.14 this.address = address;
1.15 this.chip = chip;
2.1 --- a/Hardware/LPC/ISuperIO.cs Sun Oct 17 08:21:33 2010 +0000
2.2 +++ b/Hardware/LPC/ISuperIO.cs Sun Oct 17 16:04:19 2010 +0000
2.3 @@ -44,6 +44,9 @@
2.4 float?[] Temperatures { get; }
2.5 float?[] Fans { get; }
2.6
2.7 + byte? ReadGPIO(int index);
2.8 + void WriteGPIO(int index, byte value);
2.9 +
2.10 string GetReport();
2.11 void Update();
2.12 }
3.1 --- a/Hardware/LPC/IT87XX.cs Sun Oct 17 08:21:33 2010 +0000
3.2 +++ b/Hardware/LPC/IT87XX.cs Sun Oct 17 16:04:19 2010 +0000
3.3 @@ -45,6 +45,9 @@
3.4 private readonly Chip chip;
3.5 private readonly byte version;
3.6
3.7 + private readonly ushort gpioAddress;
3.8 + private readonly int gpioCount;
3.9 +
3.10 private readonly ushort addressReg;
3.11 private readonly ushort dataReg;
3.12
3.13 @@ -77,16 +80,31 @@
3.14 byte value = WinRing0.ReadIoPortByte(dataReg);
3.15 valid = register == WinRing0.ReadIoPortByte(addressReg);
3.16 return value;
3.17 - }
3.18 + }
3.19
3.20 - public IT87XX(Chip chip, ushort address, byte version) {
3.21 + public byte? ReadGPIO(int index) {
3.22 + if (index >= gpioCount)
3.23 + return null;
3.24 +
3.25 + return WinRing0.ReadIoPortByte((ushort)(gpioAddress + index));
3.26 + }
3.27 +
3.28 + public void WriteGPIO(int index, byte value) {
3.29 + if (index >= gpioCount)
3.30 + return;
3.31 +
3.32 + WinRing0.WriteIoPortByte((ushort)(gpioAddress + index), value);
3.33 + }
3.34 +
3.35 + public IT87XX(Chip chip, ushort address, ushort gpioAddress, byte version) {
3.36
3.37 this.address = address;
3.38 this.chip = chip;
3.39 this.version = version;
3.40 this.addressReg = (ushort)(address + ADDRESS_REGISTER_OFFSET);
3.41 this.dataReg = (ushort)(address + DATA_REGISTER_OFFSET);
3.42 -
3.43 + this.gpioAddress = gpioAddress;
3.44 +
3.45 // Check vendor id
3.46 bool valid;
3.47 byte vendorId = ReadByte(VENDOR_ID_REGISTER, out valid);
3.48 @@ -109,6 +127,20 @@
3.49 } else {
3.50 voltageGain = 0.016f;
3.51 }
3.52 +
3.53 + // Set the number of GPIO sets
3.54 + switch (chip) {
3.55 + case Chip.IT8712F:
3.56 + case Chip.IT8716F:
3.57 + case Chip.IT8718F:
3.58 + case Chip.IT8726F:
3.59 + gpioCount = 5;
3.60 + break;
3.61 + case Chip.IT8720F:
3.62 + case Chip.IT8721F:
3.63 + gpioCount = 8;
3.64 + break;
3.65 + }
3.66 }
3.67
3.68 public Chip Chip { get { return chip; } }
3.69 @@ -126,6 +158,8 @@
3.70 version.ToString("X", CultureInfo.InvariantCulture));
3.71 r.Append("Base Address: 0x"); r.AppendLine(
3.72 address.ToString("X4", CultureInfo.InvariantCulture));
3.73 + r.Append("GPIO Address: 0x"); r.AppendLine(
3.74 + gpioAddress.ToString("X4", CultureInfo.InvariantCulture));
3.75 r.AppendLine();
3.76
3.77 if (!WinRing0.WaitIsaBusMutex(100))
3.78 @@ -150,6 +184,16 @@
3.79 }
3.80 r.AppendLine();
3.81
3.82 + r.AppendLine("GPIO Registers");
3.83 + r.AppendLine();
3.84 + for (int i = 0; i < gpioCount; i++) {
3.85 + r.Append(" ");
3.86 + r.Append(ReadGPIO(i).Value.ToString("X2",
3.87 + CultureInfo.InvariantCulture));
3.88 + }
3.89 + r.AppendLine();
3.90 + r.AppendLine();
3.91 +
3.92 WinRing0.ReleaseIsaBusMutex();
3.93
3.94 return r.ToString();
4.1 --- a/Hardware/LPC/LMSensors.cs Sun Oct 17 08:21:33 2010 +0000
4.2 +++ b/Hardware/LPC/LMSensors.cs Sun Oct 17 16:04:19 2010 +0000
4.3 @@ -141,6 +141,12 @@
4.4 fanReaders[i] = new StreamReader(fanPaths[i]);
4.5 }
4.6
4.7 + public byte? ReadGPIO(int index) {
4.8 + return null;
4.9 + }
4.10 +
4.11 + public void WriteGPIO(int index, byte value) { }
4.12 +
4.13 public string GetReport() {
4.14 return null;
4.15 }
5.1 --- a/Hardware/LPC/LPCIO.cs Sun Oct 17 08:21:33 2010 +0000
5.2 +++ b/Hardware/LPC/LPCIO.cs Sun Oct 17 16:04:19 2010 +0000
5.3 @@ -64,10 +64,10 @@
5.4 private byte ReadByte(byte register) {
5.5 WinRing0.WriteIoPortByte(registerPort, register);
5.6 return WinRing0.ReadIoPortByte(valuePort);
5.7 - }
5.8 + }
5.9
5.10 private ushort ReadWord(byte register) {
5.11 - return (ushort)((ReadByte(register) << 8) |
5.12 + return (ushort)((ReadByte(register) << 8) |
5.13 ReadByte((byte)(register + 1)));
5.14 }
5.15
5.16 @@ -218,7 +218,7 @@
5.17 if (id != 0 && id != 0xff) {
5.18 WinbondFintekExit();
5.19
5.20 - ReportUnknownChip("Winbond / Fintek", ((id << 8) | revision));
5.21 + ReportUnknownChip("Winbond / Fintek", ((id << 8) | revision));
5.22 }
5.23 } else {
5.24
5.25 @@ -235,7 +235,7 @@
5.26 report.Append("Chip ID: 0x");
5.27 report.AppendLine(chip.ToString("X"));
5.28 report.Append("Chip revision: 0x");
5.29 - report.AppendLine(revision.ToString("X",
5.30 + report.AppendLine(revision.ToString("X",
5.31 CultureInfo.InvariantCulture));
5.32 report.AppendLine("Error: Address verification failed");
5.33 report.AppendLine();
5.34 @@ -250,10 +250,10 @@
5.35 report.Append("Chip ID: 0x");
5.36 report.AppendLine(chip.ToString("X"));
5.37 report.Append("Chip revision: 0x");
5.38 - report.AppendLine(revision.ToString("X",
5.39 + report.AppendLine(revision.ToString("X",
5.40 CultureInfo.InvariantCulture));
5.41 report.Append("Error: Invalid address 0x");
5.42 - report.AppendLine(address.ToString("X",
5.43 + report.AppendLine(address.ToString("X",
5.44 CultureInfo.InvariantCulture));
5.45 report.AppendLine();
5.46 return false;
5.47 @@ -280,10 +280,10 @@
5.48 report.Append("Chip ID: 0x");
5.49 report.AppendLine(chip.ToString("X"));
5.50 report.Append("Chip revision: 0x");
5.51 - report.AppendLine(revision.ToString("X",
5.52 + report.AppendLine(revision.ToString("X",
5.53 CultureInfo.InvariantCulture));
5.54 report.Append("Error: Invalid vendor ID 0x");
5.55 - report.AppendLine(vendorID.ToString("X",
5.56 + report.AppendLine(vendorID.ToString("X",
5.57 CultureInfo.InvariantCulture));
5.58 report.AppendLine();
5.59 return false;
5.60 @@ -304,6 +304,7 @@
5.61 #region ITE
5.62
5.63 private const byte IT87_ENVIRONMENT_CONTROLLER_LDN = 0x04;
5.64 + private const byte IT87_GPIO_LDN = 0x07;
5.65 private const byte IT87_CHIP_VERSION_REGISTER = 0x22;
5.66
5.67 private void IT87Enter() {
5.68 @@ -351,6 +352,11 @@
5.69
5.70 byte version = (byte)(ReadByte(IT87_CHIP_VERSION_REGISTER) & 0x0F);
5.71
5.72 + Select(IT87_GPIO_LDN);
5.73 + ushort gpioAddress = ReadWord(BASE_ADDRESS_REGISTER + 2);
5.74 + Thread.Sleep(1);
5.75 + ushort gpioVerify = ReadWord(BASE_ADDRESS_REGISTER + 2);
5.76 +
5.77 IT87Exit();
5.78
5.79 if (address != verify || address < 0x100 || (address & 0xF007) != 0) {
5.80 @@ -363,7 +369,18 @@
5.81 return false;
5.82 }
5.83
5.84 - superIOs.Add(new IT87XX(chip, address, version));
5.85 + if (gpioAddress != gpioVerify || gpioAddress < 0x100 ||
5.86 + (gpioAddress & 0xF007) != 0) {
5.87 + report.Append("Chip ID: 0x");
5.88 + report.AppendLine(chip.ToString("X"));
5.89 + report.Append("Error: Invalid GPIO address 0x");
5.90 + report.AppendLine(gpioAddress.ToString("X",
5.91 + CultureInfo.InvariantCulture));
5.92 + report.AppendLine();
5.93 + return false;
5.94 + }
5.95 +
5.96 + superIOs.Add(new IT87XX(chip, address, gpioAddress, version));
5.97 return true;
5.98 }
5.99
5.100 @@ -417,7 +434,7 @@
5.101 if (DetectIT87()) continue;
5.102
5.103 if (DetectSMSC()) continue;
5.104 - }
5.105 + }
5.106 }
5.107
5.108 public LPCIO() {
5.109 @@ -429,7 +446,7 @@
5.110
5.111 Detect();
5.112
5.113 - WinRing0.ReleaseIsaBusMutex();
5.114 + WinRing0.ReleaseIsaBusMutex();
5.115 }
5.116
5.117 public ISuperIO[] SuperIO {
6.1 --- a/Hardware/LPC/W836XX.cs Sun Oct 17 08:21:33 2010 +0000
6.2 +++ b/Hardware/LPC/W836XX.cs Sun Oct 17 16:04:19 2010 +0000
6.3 @@ -104,6 +104,12 @@
6.4 WinRing0.WriteIoPortByte(
6.5 (ushort)(address + DATA_REGISTER_OFFSET), value);
6.6 }
6.7 +
6.8 + public byte? ReadGPIO(int index) {
6.9 + return null;
6.10 + }
6.11 +
6.12 + public void WriteGPIO(int index, byte value) { }
6.13
6.14 public W836XX(Chip chip, byte revision, ushort address) {
6.15 this.address = address;
7.1 --- a/Hardware/Mainboard/SuperIOHardware.cs Sun Oct 17 08:21:33 2010 +0000
7.2 +++ b/Hardware/Mainboard/SuperIOHardware.cs Sun Oct 17 16:04:19 2010 +0000
7.3 @@ -35,8 +35,10 @@
7.4
7.5 */
7.6
7.7 +using System;
7.8 using System.Collections.Generic;
7.9 using System.Globalization;
7.10 +using System.Threading;
7.11 using OpenHardwareMonitor.Hardware.LPC;
7.12
7.13 namespace OpenHardwareMonitor.Hardware.Mainboard {
7.14 @@ -50,6 +52,20 @@
7.15 private readonly List<Sensor> temperatures = new List<Sensor>();
7.16 private readonly List<Sensor> fans = new List<Sensor>();
7.17
7.18 + private delegate float? ReadValueDelegate(int index);
7.19 + private delegate void UpdateDelegate();
7.20 +
7.21 + // delegates for mainboard specific sensor reading code
7.22 + private readonly ReadValueDelegate readVoltage;
7.23 + private readonly ReadValueDelegate readTemperature;
7.24 + private readonly ReadValueDelegate readFan;
7.25 +
7.26 + // delegate for post update mainboard specific code
7.27 + private readonly UpdateDelegate postUpdate;
7.28 +
7.29 + // mainboard specific mutex
7.30 + private readonly Mutex mutex;
7.31 +
7.32 public SuperIOHardware(Mainboard mainboard, ISuperIO superIO,
7.33 Manufacturer manufacturer, Model model, ISettings settings)
7.34 {
7.35 @@ -57,6 +73,12 @@
7.36 this.superIO = superIO;
7.37 this.name = ChipName.GetName(superIO.Chip);
7.38
7.39 + this.readVoltage = (index) => superIO.Voltages[index];
7.40 + this.readTemperature = (index) => superIO.Temperatures[index];
7.41 + this.readFan = (index) => superIO.Fans[index];
7.42 +
7.43 + this.postUpdate = () => { };
7.44 +
7.45 List<Voltage> v = new List<Voltage>();
7.46 List<Temperature> t = new List<Temperature>();
7.47 List<Fan> f = new List<Fan>();
7.48 @@ -119,6 +141,7 @@
7.49 case Manufacturer.ASRock:
7.50 switch (model) {
7.51 case Model.P55_Deluxe: // IT8720F
7.52 +
7.53 v.Add(new Voltage("CPU VCore", 0));
7.54 v.Add(new Voltage("+3.3V", 2));
7.55 v.Add(new Voltage("+12V", 4, 30, 10));
7.56 @@ -128,8 +151,54 @@
7.57 t.Add(new Temperature("Motherboard", 1));
7.58 f.Add(new Fan("CPU Fan", 0));
7.59 f.Add(new Fan("Chassis Fan #1", 1));
7.60 - // fan channel 2 can connect to 3 different fan headers
7.61 - // which fan is read is configured with gpio 83-85
7.62 +
7.63 + // this mutex is also used by the official ASRock tool
7.64 + mutex = new Mutex(false, "ASRockOCMark");
7.65 +
7.66 + bool exclusiveAccess = false;
7.67 + try {
7.68 + exclusiveAccess = mutex.WaitOne(10, false);
7.69 + } catch (AbandonedMutexException) { }
7.70 + catch (InvalidOperationException) { }
7.71 +
7.72 + // only read additional fans if we get exclusive access
7.73 + if (exclusiveAccess) {
7.74 +
7.75 + f.Add(new Fan("Chassis Fan #2", 2));
7.76 + f.Add(new Fan("Chassis Fan #3", 3));
7.77 + f.Add(new Fan("Power Fan", 4));
7.78 +
7.79 + readFan = (index) => {
7.80 + if (index < 2) {
7.81 + return superIO.Fans[index];
7.82 + } else {
7.83 + // get GPIO 80-87
7.84 + byte? gpio = superIO.ReadGPIO(7);
7.85 + if (!gpio.HasValue)
7.86 + return null;
7.87 +
7.88 + // read the last 3 fans based on GPIO 83-85
7.89 + int[] masks = { 0x05, 0x03, 0x06 };
7.90 + return (((gpio.Value >> 3) & 0x07) ==
7.91 + masks[index - 2]) ? superIO.Fans[2] : null;
7.92 + }
7.93 + };
7.94 +
7.95 + int fanIndex = 0;
7.96 + postUpdate = () => {
7.97 + // get GPIO 80-87
7.98 + byte? gpio = superIO.ReadGPIO(7);
7.99 + if (!gpio.HasValue)
7.100 + return;
7.101 +
7.102 + // prepare the GPIO 83-85 for the next update
7.103 + int[] masks = { 0x05, 0x03, 0x06 };
7.104 + superIO.WriteGPIO(7,
7.105 + (byte)((gpio.Value & 0xC7) | (masks[fanIndex] << 3)));
7.106 + fanIndex = (fanIndex + 1) % 3;
7.107 + };
7.108 + }
7.109 +
7.110 break;
7.111 default:
7.112 v.Add(new Voltage("CPU VCore", 0));
7.113 @@ -741,7 +810,7 @@
7.114 superIO.Update();
7.115
7.116 foreach (Sensor sensor in voltages) {
7.117 - float? value = superIO.Voltages[sensor.Index];
7.118 + float? value = readVoltage(sensor.Index);
7.119 if (value.HasValue) {
7.120 sensor.Value = value + (value - sensor.Parameters[2].Value) *
7.121 sensor.Parameters[0].Value / sensor.Parameters[1].Value;
7.122 @@ -750,7 +819,7 @@
7.123 }
7.124
7.125 foreach (Sensor sensor in temperatures) {
7.126 - float? value = superIO.Temperatures[sensor.Index];
7.127 + float? value = readTemperature(sensor.Index);
7.128 if (value.HasValue) {
7.129 sensor.Value = value + sensor.Parameters[0].Value;
7.130 ActivateSensor(sensor);
7.131 @@ -758,13 +827,15 @@
7.132 }
7.133
7.134 foreach (Sensor sensor in fans) {
7.135 - float? value = superIO.Fans[sensor.Index];
7.136 + float? value = readFan(sensor.Index);
7.137 if (value.HasValue) {
7.138 sensor.Value = value;
7.139 if (value.Value > 0)
7.140 ActivateSensor(sensor);
7.141 }
7.142 }
7.143 +
7.144 + postUpdate();
7.145 }
7.146
7.147 private class Voltage {