Added first experimental support for fan control on the NCT677X super I/O chips.

This commit is contained in:
Michael Möller 2011-08-31 22:48:49 +00:00
parent 454962a72e
commit 14f60c38e3
7 changed files with 151 additions and 5 deletions

View File

@ -16,7 +16,7 @@
The Initial Developer of the Original Code is
Michael Möller <m.moeller@gmx.ch>.
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 @@ namespace OpenHardwareMonitor.Hardware.LPC {
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 @@ namespace OpenHardwareMonitor.Hardware.LPC {
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 @@ namespace OpenHardwareMonitor.Hardware.LPC {
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();

View File

@ -16,7 +16,7 @@
The Initial Developer of the Original Code is
Michael Möller <m.moeller@gmx.ch>.
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 @@ namespace OpenHardwareMonitor.Hardware.LPC {
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();
}
}

View File

@ -54,6 +54,7 @@ namespace OpenHardwareMonitor.Hardware.LPC {
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 @@ namespace OpenHardwareMonitor.Hardware.LPC {
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 @@ namespace OpenHardwareMonitor.Hardware.LPC {
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();

View File

@ -116,6 +116,7 @@ namespace OpenHardwareMonitor.Hardware.LPC {
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 @@ namespace OpenHardwareMonitor.Hardware.LPC {
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 @@ namespace OpenHardwareMonitor.Hardware.LPC {
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 @@ namespace OpenHardwareMonitor.Hardware.LPC {
return null;
}
public void SetControl(int index, byte? value) { }
private string ReadFirstLine(Stream stream) {
StringBuilder sb = new StringBuilder();
try {

View File

@ -49,6 +49,7 @@ namespace OpenHardwareMonitor.Hardware.LPC {
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;
@ -64,6 +65,15 @@ namespace OpenHardwareMonitor.Hardware.LPC {
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
private const ushort NUVOTON_VENDOR_ID = 0x5CA3;
@ -84,9 +94,19 @@ namespace OpenHardwareMonitor.Hardware.LPC {
{ 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 @@ namespace OpenHardwareMonitor.Hardware.LPC {
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 @@ namespace OpenHardwareMonitor.Hardware.LPC {
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();
}

View File

@ -16,7 +16,7 @@
The Initial Developer of the Original Code is
Michael Möller <m.moeller@gmx.ch>.
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 @@ namespace OpenHardwareMonitor.Hardware.LPC {
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];
@ -111,6 +112,8 @@ namespace OpenHardwareMonitor.Hardware.LPC {
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 @@ namespace OpenHardwareMonitor.Hardware.LPC {
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))

View File

@ -50,6 +50,7 @@ namespace OpenHardwareMonitor.Hardware.Mainboard {
private readonly List<Sensor> voltages = new List<Sensor>();
private readonly List<Sensor> temperatures = new List<Sensor>();
private readonly List<Sensor> fans = new List<Sensor>();
private readonly List<Sensor> controls = new List<Sensor>();
private delegate float? ReadValueDelegate(int index);
private delegate void UpdateDelegate();
@ -58,6 +59,7 @@ namespace OpenHardwareMonitor.Hardware.Mainboard {
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 @@ namespace OpenHardwareMonitor.Hardware.Mainboard {
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<Voltage> v = new List<Voltage>();
List<Temperature> t = new List<Temperature>();
List<Fan> f = new List<Fan>();
List<Ctrl> c = new List<Ctrl>();
switch (superIO.Chip) {
case Chip.IT8712F:
@ -870,6 +874,9 @@ namespace OpenHardwareMonitor.Hardware.Mainboard {
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 @@ namespace OpenHardwareMonitor.Hardware.Mainboard {
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 @@ namespace OpenHardwareMonitor.Hardware.Mainboard {
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 @@ namespace OpenHardwareMonitor.Hardware.Mainboard {
}
}
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 @@ namespace OpenHardwareMonitor.Hardware.Mainboard {
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;
}
}
}
}