# HG changeset patch # User moel.mich # Date 1314830929 0 # Node ID 3f2d9ebacf38a7ed9562696130c47d4df8c07639 # Parent 523c19d10a864363320a533a4033c26dec69e773 Added first experimental support for fan control on the NCT677X super I/O chips. diff -r 523c19d10a86 -r 3f2d9ebacf38 Hardware/LPC/F718XX.cs --- a/Hardware/LPC/F718XX.cs Mon Aug 29 18:41:06 2011 +0000 +++ b/Hardware/LPC/F718XX.cs Wed Aug 31 22:48:49 2011 +0000 @@ -16,7 +16,7 @@ The Initial Developer of the Original Code is Michael Möller . - Portions created by the Initial Developer are Copyright (C) 2009-2010 + Portions created by the Initial Developer are Copyright (C) 2009-2011 the Initial Developer. All Rights Reserved. Contributor(s): @@ -47,6 +47,7 @@ private readonly float?[] voltages; private readonly float?[] temperatures; private readonly float?[] fans; + private readonly float?[] controls; // Hardware Monitor private const byte ADDRESS_REGISTER_OFFSET = 0x05; @@ -71,6 +72,8 @@ public void WriteGPIO(int index, byte value) { } + public void SetControl(int index, byte? value) { } + public F718XX(Chip chip, ushort address) { this.address = address; this.chip = chip; @@ -78,12 +81,14 @@ voltages = new float?[chip == Chip.F71858 ? 3 : 9]; temperatures = new float?[3]; fans = new float?[chip == Chip.F71882 || chip == Chip.F71858? 4 : 3]; + controls = new float?[0]; } public Chip Chip { get { return chip; } } public float?[] Voltages { get { return voltages; } } public float?[] Temperatures { get { return temperatures; } } public float?[] Fans { get { return fans; } } + public float?[] Controls { get { return controls; } } public string GetReport() { StringBuilder r = new StringBuilder(); diff -r 523c19d10a86 -r 3f2d9ebacf38 Hardware/LPC/ISuperIO.cs --- a/Hardware/LPC/ISuperIO.cs Mon Aug 29 18:41:06 2011 +0000 +++ b/Hardware/LPC/ISuperIO.cs Wed Aug 31 22:48:49 2011 +0000 @@ -16,7 +16,7 @@ The Initial Developer of the Original Code is Michael Möller . - Portions created by the Initial Developer are Copyright (C) 2009-2010 + Portions created by the Initial Developer are Copyright (C) 2009-2011 the Initial Developer. All Rights Reserved. Contributor(s): @@ -40,14 +40,21 @@ Chip Chip { get; } + // get voltage, temperature, fan and control channel values float?[] Voltages { get; } float?[] Temperatures { get; } float?[] Fans { get; } + float?[] Controls { get; } + // set control value, null = auto + void SetControl(int index, byte? value); + + // read and write GPIO byte? ReadGPIO(int index); void WriteGPIO(int index, byte value); string GetReport(); + void Update(); } } diff -r 523c19d10a86 -r 3f2d9ebacf38 Hardware/LPC/IT87XX.cs --- a/Hardware/LPC/IT87XX.cs Mon Aug 29 18:41:06 2011 +0000 +++ b/Hardware/LPC/IT87XX.cs Wed Aug 31 22:48:49 2011 +0000 @@ -54,6 +54,7 @@ private readonly float?[] voltages = new float?[0]; private readonly float?[] temperatures = new float?[0]; private readonly float?[] fans = new float?[0]; + private readonly float?[] controls = new float?[0]; private readonly float voltageGain; private readonly bool has16bitFanCounter; @@ -103,6 +104,8 @@ Ring0.WriteIoPort((ushort)(gpioAddress + index), value); } + public void SetControl(int index, byte? value) { } + public IT87XX(Chip chip, ushort address, ushort gpioAddress, byte version) { this.address = address; @@ -166,6 +169,7 @@ public float?[] Voltages { get { return voltages; } } public float?[] Temperatures { get { return temperatures; } } public float?[] Fans { get { return fans; } } + public float?[] Controls { get { return controls; } } public string GetReport() { StringBuilder r = new StringBuilder(); diff -r 523c19d10a86 -r 3f2d9ebacf38 Hardware/LPC/LMSensors.cs --- a/Hardware/LPC/LMSensors.cs Mon Aug 29 18:41:06 2011 +0000 +++ b/Hardware/LPC/LMSensors.cs Wed Aug 31 22:48:49 2011 +0000 @@ -116,6 +116,7 @@ private readonly float?[] voltages; private readonly float?[] temperatures; private readonly float?[] fans; + private readonly float?[] controls; private readonly FileStream[] voltageStreams; private readonly FileStream[] temperatureStreams; @@ -125,7 +126,7 @@ public float?[] Voltages { get { return voltages; } } public float?[] Temperatures { get { return temperatures; } } public float?[] Fans { get { return fans; } } - + public float?[] Controls { get { return controls; } } public LMChip(Chip chip, string path) { this.path = path; @@ -151,6 +152,8 @@ for (int i = 0; i < fanPaths.Length; i++) fanStreams[i] = new FileStream(fanPaths[i], FileMode.Open, FileAccess.Read, FileShare.ReadWrite); + + this.controls = new float?[0]; } public byte? ReadGPIO(int index) { @@ -163,6 +166,8 @@ return null; } + public void SetControl(int index, byte? value) { } + private string ReadFirstLine(Stream stream) { StringBuilder sb = new StringBuilder(); try { diff -r 523c19d10a86 -r 3f2d9ebacf38 Hardware/LPC/NCT677X.cs --- a/Hardware/LPC/NCT677X.cs Mon Aug 29 18:41:06 2011 +0000 +++ b/Hardware/LPC/NCT677X.cs Wed Aug 31 22:48:49 2011 +0000 @@ -49,6 +49,7 @@ private readonly float?[] voltages = new float?[9]; private readonly float?[] temperatures = new float?[4]; private readonly float?[] fans = new float?[0]; + private readonly float?[] controls = new float?[3]; // Hardware Monitor private const uint ADDRESS_REGISTER_OFFSET = 0x05; @@ -62,6 +63,15 @@ Ring0.WriteIoPort(port + DATA_REGISTER_OFFSET, bank); Ring0.WriteIoPort(port + ADDRESS_REGISTER_OFFSET, register); return Ring0.ReadIoPort(port + DATA_REGISTER_OFFSET); + } + + private void WriteByte(ushort address, byte value) { + byte bank = (byte)(address >> 8); + byte register = (byte)(address & 0xFF); + Ring0.WriteIoPort(port + ADDRESS_REGISTER_OFFSET, BANK_SELECT_REGISTER); + Ring0.WriteIoPort(port + DATA_REGISTER_OFFSET, bank); + Ring0.WriteIoPort(port + ADDRESS_REGISTER_OFFSET, register); + Ring0.WriteIoPort(port + DATA_REGISTER_OFFSET, value); } // Consts @@ -84,9 +94,19 @@ { 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x550, 0x551 }; private readonly ushort[] FAN_RPM_REG = { 0x656, 0x658, 0x65A, 0x65C, 0x65E}; + private readonly ushort[] FAN_PWM_OUT_REG = + { 0x001, 0x003, 0x011 }; + private readonly ushort[] FAN_PWM_COMMAND_REG = + { 0x109, 0x209, 0x309 }; + private readonly ushort[] FAN_CONTROL_MODE_REG = + { 0x102, 0x202, 0x302 }; private readonly int minFanRPM; + private bool[] restoreDefaultFanControlRequired = { false, false, false }; + private byte[] initialFanControlMode = new byte[3]; + private byte[] initialFanPwmCommand = new byte[3]; + private enum SourceNCT6771F : byte { SYSTIN = 1, CPUTIN = 2, @@ -168,10 +188,47 @@ public void WriteGPIO(int index, byte value) { } + + private void SaveDefaultFanControl(int index) { + if (!restoreDefaultFanControlRequired[index]) { + initialFanControlMode[index] = ReadByte(FAN_CONTROL_MODE_REG[index]); + initialFanPwmCommand[index] = ReadByte(FAN_PWM_COMMAND_REG[index]); + restoreDefaultFanControlRequired[index] = true; + } + } + + private void RestoreDefaultFanControl(int index) { + if (restoreDefaultFanControlRequired[index]) { + WriteByte(FAN_CONTROL_MODE_REG[index], initialFanControlMode[index]); + WriteByte(FAN_PWM_COMMAND_REG[index], initialFanPwmCommand[index]); + restoreDefaultFanControlRequired[index] = false; + } + } + + public void SetControl(int index, byte? value) { + if (!Ring0.WaitIsaBusMutex(10)) + return; + + if (value.HasValue) { + SaveDefaultFanControl(index); + + // set manual mode + WriteByte(FAN_CONTROL_MODE_REG[index], 0); + + // set output value + WriteByte(FAN_PWM_COMMAND_REG[index], value.Value); + } else { + RestoreDefaultFanControl(index); + } + + Ring0.ReleaseIsaBusMutex(); + } + public Chip Chip { get { return chip; } } public float?[] Voltages { get { return voltages; } } public float?[] Temperatures { get { return temperatures; } } public float?[] Fans { get { return fans; } } + public float?[] Controls { get { return controls; } } public void Update() { if (!Ring0.WaitIsaBusMutex(10)) @@ -228,6 +285,11 @@ fans[i] = value > minFanRPM ? value : 0; } + for (int i = 0; i < controls.Length; i++) { + int value = ReadByte(FAN_PWM_OUT_REG[i]); + controls[i] = value / 2.55f; + } + Ring0.ReleaseIsaBusMutex(); } diff -r 523c19d10a86 -r 3f2d9ebacf38 Hardware/LPC/W836XX.cs --- a/Hardware/LPC/W836XX.cs Mon Aug 29 18:41:06 2011 +0000 +++ b/Hardware/LPC/W836XX.cs Wed Aug 31 22:48:49 2011 +0000 @@ -16,7 +16,7 @@ The Initial Developer of the Original Code is Michael Möller . - Portions created by the Initial Developer are Copyright (C) 2009-2010 + Portions created by the Initial Developer are Copyright (C) 2009-2011 the Initial Developer. All Rights Reserved. Contributor(s): @@ -50,6 +50,7 @@ private readonly float?[] voltages = new float?[0]; private readonly float?[] temperatures = new float?[0]; private readonly float?[] fans = new float?[0]; + private readonly float?[] controls = new float?[0]; private readonly bool[] peciTemperature = new bool[0]; private readonly byte[] voltageRegister = new byte[0]; @@ -110,7 +111,9 @@ } public void WriteGPIO(int index, byte value) { } - + + public void SetControl(int index, byte? value) { } + public W836XX(Chip chip, byte revision, ushort address) { this.address = address; this.revision = revision; @@ -201,6 +204,7 @@ public float?[] Voltages { get { return voltages; } } public float?[] Temperatures { get { return temperatures; } } public float?[] Fans { get { return fans; } } + public float?[] Controls { get { return controls; } } public void Update() { if (!Ring0.WaitIsaBusMutex(10)) diff -r 523c19d10a86 -r 3f2d9ebacf38 Hardware/Mainboard/SuperIOHardware.cs --- a/Hardware/Mainboard/SuperIOHardware.cs Mon Aug 29 18:41:06 2011 +0000 +++ b/Hardware/Mainboard/SuperIOHardware.cs Wed Aug 31 22:48:49 2011 +0000 @@ -50,6 +50,7 @@ private readonly List voltages = new List(); private readonly List temperatures = new List(); private readonly List fans = new List(); + private readonly List controls = new List(); private delegate float? ReadValueDelegate(int index); private delegate void UpdateDelegate(); @@ -58,6 +59,7 @@ private readonly ReadValueDelegate readVoltage; private readonly ReadValueDelegate readTemperature; private readonly ReadValueDelegate readFan; + private readonly ReadValueDelegate readControl; // delegate for post update mainboard specific code private readonly UpdateDelegate postUpdate; @@ -77,12 +79,14 @@ this.readVoltage = (index) => superIO.Voltages[index]; this.readTemperature = (index) => superIO.Temperatures[index]; this.readFan = (index) => superIO.Fans[index]; + this.readControl = (index) => superIO.Controls[index]; this.postUpdate = () => { }; List v = new List(); List t = new List(); List f = new List(); + List c = new List(); switch (superIO.Chip) { case Chip.IT8712F: @@ -870,6 +874,9 @@ f.Add(new Fan("CPU Fan", 1)); f.Add(new Fan("Power Fan", 2)); f.Add(new Fan("Chassis Fan #2", 3)); + c.Add(new Ctrl("Chassis Fan #2", 0)); + c.Add(new Ctrl("CPU Fan", 1)); + c.Add(new Ctrl("Chassis Fan #1", 2)); break; case Model.P8P67_M_PRO: // NCT6776F v.Add(new Voltage("CPU VCore", 0)); @@ -934,6 +941,8 @@ t.Add(new Temperature("Temperature #" + (i + 1), i)); for (int i = 0; i < superIO.Fans.Length; i++) f.Add(new Fan("Fan #" + (i + 1), i)); + for (int i = 0; i < superIO.Controls.Length; i++) + c.Add(new Ctrl("Fan Control #" + (i + 1), i)); break; } @@ -967,6 +976,30 @@ this, settings); fans.Add(sensor); } + + foreach (Ctrl ctrl in c) { + int index = ctrl.Index; + if (index < superIO.Controls.Length) { + Sensor sensor = new Sensor(ctrl.Name, index, SensorType.Control, + this, settings); + Control control = new Control(sensor, settings, 0, 100); + control.ControlModeChanged += (cc) => { + if (cc.ControlMode == ControlMode.Default) { + superIO.SetControl(index, null); + } else { + superIO.SetControl(index, (byte)(cc.SoftwareValue * 2.55)); + } + }; + control.SoftwareControlValueChanged += (cc) => { + if (cc.ControlMode == ControlMode.Software) + superIO.SetControl(index, (byte)(cc.SoftwareValue * 2.55)); + }; + if (control.ControlMode == ControlMode.Software) + superIO.SetControl(index, (byte)(control.SoftwareValue * 2.55)); + sensor.Control = control; + controls.Add(sensor); + } + } } public override HardwareType HardwareType { @@ -1011,9 +1044,25 @@ } } + foreach (Sensor sensor in controls) { + float? value = readControl(sensor.Index); + if (value.HasValue) { + sensor.Value = value; + ActivateSensor(sensor); + } + } + postUpdate(); } + public override void Close() { + foreach (Sensor sensor in controls) { + // restore all controls back to default + superIO.SetControl(sensor.Index, null); + } + base.Close(); + } + private class Voltage { public readonly string Name; public readonly int Index; @@ -1064,5 +1113,15 @@ this.Index = index; } } + + private class Ctrl { + public readonly string Name; + public readonly int Index; + + public Ctrl(string name, int index) { + this.Name = name; + this.Index = index; + } + } } }