Added first experimental support for fan control on the NCT677X super I/O chips.
authormoel.mich
Wed, 31 Aug 2011 22:48:49 +0000
changeset 3233f2d9ebacf38
parent 322 523c19d10a86
child 324 c6ee430d6995
Added first experimental support for fan control on the NCT677X super I/O chips.
Hardware/LPC/F718XX.cs
Hardware/LPC/ISuperIO.cs
Hardware/LPC/IT87XX.cs
Hardware/LPC/LMSensors.cs
Hardware/LPC/NCT677X.cs
Hardware/LPC/W836XX.cs
Hardware/Mainboard/SuperIOHardware.cs
     1.1 --- a/Hardware/LPC/F718XX.cs	Mon Aug 29 18:41:06 2011 +0000
     1.2 +++ b/Hardware/LPC/F718XX.cs	Wed Aug 31 22:48:49 2011 +0000
     1.3 @@ -16,7 +16,7 @@
     1.4  
     1.5    The Initial Developer of the Original Code is 
     1.6    Michael Möller <m.moeller@gmx.ch>.
     1.7 -  Portions created by the Initial Developer are Copyright (C) 2009-2010
     1.8 +  Portions created by the Initial Developer are Copyright (C) 2009-2011
     1.9    the Initial Developer. All Rights Reserved.
    1.10  
    1.11    Contributor(s):
    1.12 @@ -47,6 +47,7 @@
    1.13      private readonly float?[] voltages;
    1.14      private readonly float?[] temperatures;
    1.15      private readonly float?[] fans;
    1.16 +    private readonly float?[] controls;
    1.17  
    1.18      // Hardware Monitor
    1.19      private const byte ADDRESS_REGISTER_OFFSET = 0x05;
    1.20 @@ -71,6 +72,8 @@
    1.21  
    1.22      public void WriteGPIO(int index, byte value) { }
    1.23  
    1.24 +    public void SetControl(int index, byte? value) { }   
    1.25 +
    1.26      public F718XX(Chip chip, ushort address) {
    1.27        this.address = address;
    1.28        this.chip = chip;
    1.29 @@ -78,12 +81,14 @@
    1.30        voltages = new float?[chip == Chip.F71858 ? 3 : 9];
    1.31        temperatures = new float?[3];
    1.32        fans = new float?[chip == Chip.F71882 || chip == Chip.F71858? 4 : 3];
    1.33 +      controls = new float?[0];
    1.34      }
    1.35  
    1.36      public Chip Chip { get { return chip; } }
    1.37      public float?[] Voltages { get { return voltages; } }
    1.38      public float?[] Temperatures { get { return temperatures; } }
    1.39      public float?[] Fans { get { return fans; } }
    1.40 +    public float?[] Controls { get { return controls; } }
    1.41  
    1.42      public string GetReport() {
    1.43        StringBuilder r = new StringBuilder();
     2.1 --- a/Hardware/LPC/ISuperIO.cs	Mon Aug 29 18:41:06 2011 +0000
     2.2 +++ b/Hardware/LPC/ISuperIO.cs	Wed Aug 31 22:48:49 2011 +0000
     2.3 @@ -16,7 +16,7 @@
     2.4  
     2.5    The Initial Developer of the Original Code is 
     2.6    Michael Möller <m.moeller@gmx.ch>.
     2.7 -  Portions created by the Initial Developer are Copyright (C) 2009-2010
     2.8 +  Portions created by the Initial Developer are Copyright (C) 2009-2011
     2.9    the Initial Developer. All Rights Reserved.
    2.10  
    2.11    Contributor(s):
    2.12 @@ -40,14 +40,21 @@
    2.13  
    2.14      Chip Chip { get; }
    2.15  
    2.16 +    // get voltage, temperature, fan and control channel values
    2.17      float?[] Voltages { get; }
    2.18      float?[] Temperatures { get; }
    2.19      float?[] Fans { get; }
    2.20 +    float?[] Controls { get; }
    2.21  
    2.22 +    // set control value, null = auto    
    2.23 +    void SetControl(int index, byte? value);         
    2.24 +
    2.25 +    // read and write GPIO
    2.26      byte? ReadGPIO(int index);
    2.27      void WriteGPIO(int index, byte value);
    2.28  
    2.29      string GetReport();
    2.30 +
    2.31      void Update();
    2.32    }
    2.33  }
     3.1 --- a/Hardware/LPC/IT87XX.cs	Mon Aug 29 18:41:06 2011 +0000
     3.2 +++ b/Hardware/LPC/IT87XX.cs	Wed Aug 31 22:48:49 2011 +0000
     3.3 @@ -54,6 +54,7 @@
     3.4      private readonly float?[] voltages = new float?[0];
     3.5      private readonly float?[] temperatures = new float?[0];
     3.6      private readonly float?[] fans = new float?[0];
     3.7 +    private readonly float?[] controls = new float?[0];
     3.8  
     3.9      private readonly float voltageGain;
    3.10      private readonly bool has16bitFanCounter;
    3.11 @@ -103,6 +104,8 @@
    3.12        Ring0.WriteIoPort((ushort)(gpioAddress + index), value);
    3.13      }
    3.14  
    3.15 +    public void SetControl(int index, byte? value) { }   
    3.16 +
    3.17      public IT87XX(Chip chip, ushort address, ushort gpioAddress, byte version) {
    3.18  
    3.19        this.address = address;
    3.20 @@ -166,6 +169,7 @@
    3.21      public float?[] Voltages { get { return voltages; } }
    3.22      public float?[] Temperatures { get { return temperatures; } }
    3.23      public float?[] Fans { get { return fans; } }
    3.24 +    public float?[] Controls { get { return controls; } }
    3.25  
    3.26      public string GetReport() {
    3.27        StringBuilder r = new StringBuilder();
     4.1 --- a/Hardware/LPC/LMSensors.cs	Mon Aug 29 18:41:06 2011 +0000
     4.2 +++ b/Hardware/LPC/LMSensors.cs	Wed Aug 31 22:48:49 2011 +0000
     4.3 @@ -116,6 +116,7 @@
     4.4        private readonly float?[] voltages;
     4.5        private readonly float?[] temperatures;
     4.6        private readonly float?[] fans;
     4.7 +      private readonly float?[] controls;
     4.8  
     4.9        private readonly FileStream[] voltageStreams;
    4.10        private readonly FileStream[] temperatureStreams;
    4.11 @@ -125,7 +126,7 @@
    4.12        public float?[] Voltages { get { return voltages; } }
    4.13        public float?[] Temperatures { get { return temperatures; } }
    4.14        public float?[] Fans { get { return fans; } }
    4.15 -
    4.16 +      public float?[] Controls { get { return controls; } }
    4.17  
    4.18        public LMChip(Chip chip, string path) {
    4.19          this.path = path;
    4.20 @@ -151,6 +152,8 @@
    4.21          for (int i = 0; i < fanPaths.Length; i++)
    4.22            fanStreams[i] = new FileStream(fanPaths[i],
    4.23              FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
    4.24 +
    4.25 +        this.controls = new float?[0];
    4.26        }
    4.27  
    4.28        public byte? ReadGPIO(int index) {
    4.29 @@ -163,6 +166,8 @@
    4.30          return null;
    4.31        }
    4.32  
    4.33 +      public void SetControl(int index, byte? value) { }   
    4.34 +
    4.35        private string ReadFirstLine(Stream stream) {
    4.36          StringBuilder sb = new StringBuilder();
    4.37          try {
     5.1 --- a/Hardware/LPC/NCT677X.cs	Mon Aug 29 18:41:06 2011 +0000
     5.2 +++ b/Hardware/LPC/NCT677X.cs	Wed Aug 31 22:48:49 2011 +0000
     5.3 @@ -49,6 +49,7 @@
     5.4      private readonly float?[] voltages = new float?[9];
     5.5      private readonly float?[] temperatures = new float?[4];
     5.6      private readonly float?[] fans = new float?[0];
     5.7 +    private readonly float?[] controls = new float?[3];
     5.8  
     5.9      // Hardware Monitor
    5.10      private const uint ADDRESS_REGISTER_OFFSET = 0x05;
    5.11 @@ -62,6 +63,15 @@
    5.12        Ring0.WriteIoPort(port + DATA_REGISTER_OFFSET, bank);
    5.13        Ring0.WriteIoPort(port + ADDRESS_REGISTER_OFFSET, register);
    5.14        return Ring0.ReadIoPort(port + DATA_REGISTER_OFFSET);
    5.15 +    }
    5.16 +
    5.17 +    private void WriteByte(ushort address, byte value) {
    5.18 +      byte bank = (byte)(address >> 8);
    5.19 +      byte register = (byte)(address & 0xFF);
    5.20 +      Ring0.WriteIoPort(port + ADDRESS_REGISTER_OFFSET, BANK_SELECT_REGISTER);
    5.21 +      Ring0.WriteIoPort(port + DATA_REGISTER_OFFSET, bank);
    5.22 +      Ring0.WriteIoPort(port + ADDRESS_REGISTER_OFFSET, register);
    5.23 +      Ring0.WriteIoPort(port + DATA_REGISTER_OFFSET, value);
    5.24      } 
    5.25  
    5.26      // Consts 
    5.27 @@ -84,9 +94,19 @@
    5.28        { 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x550, 0x551 };
    5.29      private readonly ushort[] FAN_RPM_REG = 
    5.30        { 0x656, 0x658, 0x65A, 0x65C, 0x65E};
    5.31 +    private readonly ushort[] FAN_PWM_OUT_REG = 
    5.32 +      { 0x001, 0x003, 0x011 };
    5.33 +    private readonly ushort[] FAN_PWM_COMMAND_REG = 
    5.34 +      { 0x109, 0x209, 0x309 };
    5.35 +    private readonly ushort[] FAN_CONTROL_MODE_REG = 
    5.36 +      { 0x102, 0x202, 0x302 };
    5.37  
    5.38      private readonly int minFanRPM;
    5.39  
    5.40 +    private bool[] restoreDefaultFanControlRequired = { false, false, false };
    5.41 +    private byte[] initialFanControlMode = new byte[3];
    5.42 +    private byte[] initialFanPwmCommand = new byte[3];
    5.43 +
    5.44      private enum SourceNCT6771F : byte {
    5.45        SYSTIN = 1,
    5.46        CPUTIN = 2,
    5.47 @@ -168,10 +188,47 @@
    5.48  
    5.49      public void WriteGPIO(int index, byte value) { }
    5.50  
    5.51 +
    5.52 +    private void SaveDefaultFanControl(int index) {
    5.53 +      if (!restoreDefaultFanControlRequired[index]) {
    5.54 +        initialFanControlMode[index] = ReadByte(FAN_CONTROL_MODE_REG[index]);
    5.55 +        initialFanPwmCommand[index] = ReadByte(FAN_PWM_COMMAND_REG[index]);
    5.56 +        restoreDefaultFanControlRequired[index] = true;
    5.57 +      }
    5.58 +    }
    5.59 +
    5.60 +    private void RestoreDefaultFanControl(int index) {
    5.61 +      if (restoreDefaultFanControlRequired[index]) {
    5.62 +        WriteByte(FAN_CONTROL_MODE_REG[index], initialFanControlMode[index]);
    5.63 +        WriteByte(FAN_PWM_COMMAND_REG[index], initialFanPwmCommand[index]);
    5.64 +        restoreDefaultFanControlRequired[index] = false;
    5.65 +      }
    5.66 +    }
    5.67 +
    5.68 +    public void SetControl(int index, byte? value) {
    5.69 +      if (!Ring0.WaitIsaBusMutex(10))
    5.70 +        return;
    5.71 +
    5.72 +      if (value.HasValue) {
    5.73 +        SaveDefaultFanControl(index);
    5.74 +
    5.75 +        // set manual mode
    5.76 +        WriteByte(FAN_CONTROL_MODE_REG[index], 0);
    5.77 +
    5.78 +        // set output value
    5.79 +        WriteByte(FAN_PWM_COMMAND_REG[index], value.Value);  
    5.80 +      } else {
    5.81 +        RestoreDefaultFanControl(index);
    5.82 +      }
    5.83 +
    5.84 +      Ring0.ReleaseIsaBusMutex();
    5.85 +    }   
    5.86 +
    5.87      public Chip Chip { get { return chip; } }
    5.88      public float?[] Voltages { get { return voltages; } }
    5.89      public float?[] Temperatures { get { return temperatures; } }
    5.90      public float?[] Fans { get { return fans; } }
    5.91 +    public float?[] Controls { get { return controls; } }
    5.92  
    5.93      public void Update() {
    5.94        if (!Ring0.WaitIsaBusMutex(10))
    5.95 @@ -228,6 +285,11 @@
    5.96          fans[i] = value > minFanRPM ? value : 0;
    5.97        }
    5.98  
    5.99 +      for (int i = 0; i < controls.Length; i++) {
   5.100 +        int value = ReadByte(FAN_PWM_OUT_REG[i]);
   5.101 +        controls[i] = value / 2.55f;
   5.102 +      }
   5.103 +
   5.104        Ring0.ReleaseIsaBusMutex();
   5.105      }
   5.106  
     6.1 --- a/Hardware/LPC/W836XX.cs	Mon Aug 29 18:41:06 2011 +0000
     6.2 +++ b/Hardware/LPC/W836XX.cs	Wed Aug 31 22:48:49 2011 +0000
     6.3 @@ -16,7 +16,7 @@
     6.4  
     6.5    The Initial Developer of the Original Code is 
     6.6    Michael Möller <m.moeller@gmx.ch>.
     6.7 -  Portions created by the Initial Developer are Copyright (C) 2009-2010
     6.8 +  Portions created by the Initial Developer are Copyright (C) 2009-2011
     6.9    the Initial Developer. All Rights Reserved.
    6.10  
    6.11    Contributor(s):
    6.12 @@ -50,6 +50,7 @@
    6.13      private readonly float?[] voltages = new float?[0];
    6.14      private readonly float?[] temperatures = new float?[0];    
    6.15      private readonly float?[] fans = new float?[0];
    6.16 +    private readonly float?[] controls = new float?[0];
    6.17  
    6.18      private readonly bool[] peciTemperature = new bool[0];
    6.19      private readonly byte[] voltageRegister = new byte[0];
    6.20 @@ -110,7 +111,9 @@
    6.21      }
    6.22  
    6.23      public void WriteGPIO(int index, byte value) { }
    6.24 -   
    6.25 +
    6.26 +    public void SetControl(int index, byte? value) { }   
    6.27 +
    6.28      public W836XX(Chip chip, byte revision, ushort address) {
    6.29        this.address = address;
    6.30        this.revision = revision;
    6.31 @@ -201,6 +204,7 @@
    6.32      public float?[] Voltages { get { return voltages; } }
    6.33      public float?[] Temperatures { get { return temperatures; } }
    6.34      public float?[] Fans { get { return fans; } }
    6.35 +    public float?[] Controls { get { return controls; } }
    6.36  
    6.37      public void Update() {
    6.38        if (!Ring0.WaitIsaBusMutex(10))
     7.1 --- a/Hardware/Mainboard/SuperIOHardware.cs	Mon Aug 29 18:41:06 2011 +0000
     7.2 +++ b/Hardware/Mainboard/SuperIOHardware.cs	Wed Aug 31 22:48:49 2011 +0000
     7.3 @@ -50,6 +50,7 @@
     7.4      private readonly List<Sensor> voltages = new List<Sensor>();
     7.5      private readonly List<Sensor> temperatures = new List<Sensor>();
     7.6      private readonly List<Sensor> fans = new List<Sensor>();
     7.7 +    private readonly List<Sensor> controls = new List<Sensor>();
     7.8  
     7.9      private delegate float? ReadValueDelegate(int index);
    7.10      private delegate void UpdateDelegate();
    7.11 @@ -58,6 +59,7 @@
    7.12      private readonly ReadValueDelegate readVoltage;
    7.13      private readonly ReadValueDelegate readTemperature;
    7.14      private readonly ReadValueDelegate readFan;
    7.15 +    private readonly ReadValueDelegate readControl;
    7.16  
    7.17      // delegate for post update mainboard specific code
    7.18      private readonly UpdateDelegate postUpdate;
    7.19 @@ -77,12 +79,14 @@
    7.20        this.readVoltage = (index) => superIO.Voltages[index];
    7.21        this.readTemperature = (index) => superIO.Temperatures[index];
    7.22        this.readFan = (index) => superIO.Fans[index];
    7.23 +      this.readControl = (index) => superIO.Controls[index];
    7.24  
    7.25        this.postUpdate = () => { };
    7.26  
    7.27        List<Voltage> v = new List<Voltage>();
    7.28        List<Temperature> t = new List<Temperature>();
    7.29        List<Fan> f = new List<Fan>();
    7.30 +      List<Ctrl> c = new List<Ctrl>();
    7.31  
    7.32        switch (superIO.Chip) {
    7.33          case Chip.IT8712F:
    7.34 @@ -870,6 +874,9 @@
    7.35                    f.Add(new Fan("CPU Fan", 1));
    7.36                    f.Add(new Fan("Power Fan", 2));
    7.37                    f.Add(new Fan("Chassis Fan #2", 3));
    7.38 +                  c.Add(new Ctrl("Chassis Fan #2", 0));
    7.39 +                  c.Add(new Ctrl("CPU Fan", 1));
    7.40 +                  c.Add(new Ctrl("Chassis Fan #1", 2));
    7.41                    break;
    7.42                  case Model.P8P67_M_PRO: // NCT6776F
    7.43                    v.Add(new Voltage("CPU VCore", 0));
    7.44 @@ -934,6 +941,8 @@
    7.45              t.Add(new Temperature("Temperature #" + (i + 1), i));
    7.46            for (int i = 0; i < superIO.Fans.Length; i++)
    7.47              f.Add(new Fan("Fan #" + (i + 1), i));
    7.48 +          for (int i = 0; i < superIO.Controls.Length; i++)
    7.49 +            c.Add(new Ctrl("Fan Control #" + (i + 1), i));
    7.50            break;
    7.51        }
    7.52  
    7.53 @@ -967,6 +976,30 @@
    7.54              this, settings);
    7.55            fans.Add(sensor);
    7.56          }
    7.57 +
    7.58 +      foreach (Ctrl ctrl in c) {
    7.59 +        int index = ctrl.Index;
    7.60 +        if (index < superIO.Controls.Length) {
    7.61 +          Sensor sensor = new Sensor(ctrl.Name, index, SensorType.Control,
    7.62 +            this, settings);
    7.63 +          Control control = new Control(sensor, settings, 0, 100);
    7.64 +          control.ControlModeChanged += (cc) => {
    7.65 +            if (cc.ControlMode == ControlMode.Default) {
    7.66 +              superIO.SetControl(index, null);
    7.67 +            } else {
    7.68 +              superIO.SetControl(index, (byte)(cc.SoftwareValue * 2.55));
    7.69 +            }
    7.70 +          };
    7.71 +          control.SoftwareControlValueChanged += (cc) => {
    7.72 +            if (cc.ControlMode == ControlMode.Software) 
    7.73 +              superIO.SetControl(index, (byte)(cc.SoftwareValue * 2.55));
    7.74 +          };
    7.75 +          if (control.ControlMode == ControlMode.Software) 
    7.76 +            superIO.SetControl(index, (byte)(control.SoftwareValue * 2.55));
    7.77 +          sensor.Control = control;
    7.78 +          controls.Add(sensor);
    7.79 +        }
    7.80 +      }
    7.81      }
    7.82  
    7.83      public override HardwareType HardwareType {
    7.84 @@ -1011,9 +1044,25 @@
    7.85          }
    7.86        }
    7.87  
    7.88 +      foreach (Sensor sensor in controls) {
    7.89 +        float? value = readControl(sensor.Index);
    7.90 +        if (value.HasValue) {
    7.91 +          sensor.Value = value;
    7.92 +          ActivateSensor(sensor);
    7.93 +        }
    7.94 +      }
    7.95 +
    7.96        postUpdate();
    7.97      }
    7.98  
    7.99 +    public override void Close() {
   7.100 +      foreach (Sensor sensor in controls) {
   7.101 +        // restore all controls back to default
   7.102 +        superIO.SetControl(sensor.Index, null);
   7.103 +      }
   7.104 +      base.Close();
   7.105 +    }
   7.106 +
   7.107      private class Voltage {
   7.108        public readonly string Name;
   7.109        public readonly int Index;
   7.110 @@ -1064,5 +1113,15 @@
   7.111          this.Index = index;
   7.112        }
   7.113      }
   7.114 +
   7.115 +    private class Ctrl {
   7.116 +      public readonly string Name;
   7.117 +      public readonly int Index;
   7.118 +
   7.119 +      public Ctrl(string name, int index) {
   7.120 +        this.Name = name;
   7.121 +        this.Index = index;
   7.122 +      }
   7.123 +    }
   7.124    }
   7.125  }