Added code to read the additional fans on the ASRock P55 Deluxe mainboard via special GPIO switching.
authormoel.mich
Sun, 17 Oct 2010 16:04:19 +0000
changeset 228458a6c3de579
parent 227 97757a798918
child 229 940d86b60be7
Added code to read the additional fans on the ASRock P55 Deluxe mainboard via special GPIO switching.
Hardware/LPC/F718XX.cs
Hardware/LPC/ISuperIO.cs
Hardware/LPC/IT87XX.cs
Hardware/LPC/LMSensors.cs
Hardware/LPC/LPCIO.cs
Hardware/LPC/W836XX.cs
Hardware/Mainboard/SuperIOHardware.cs
     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 {