Fixed Issue 124.
3 Version: MPL 1.1/GPL 2.0/LGPL 2.1
5 The contents of this file are subject to the Mozilla Public License Version
6 1.1 (the "License"); you may not use this file except in compliance with
7 the License. You may obtain a copy of the License at
9 http://www.mozilla.org/MPL/
11 Software distributed under the License is distributed on an "AS IS" basis,
12 WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
13 for the specific language governing rights and limitations under the License.
15 The Original Code is the Open Hardware Monitor code.
17 The Initial Developer of the Original Code is
18 Michael Möller <m.moeller@gmx.ch>.
19 Portions created by the Initial Developer are Copyright (C) 2009-2010
20 the Initial Developer. All Rights Reserved.
24 Alternatively, the contents of this file may be used under the terms of
25 either the GNU General Public License Version 2 or later (the "GPL"), or
26 the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
27 in which case the provisions of the GPL or the LGPL are applicable instead
28 of those above. If you wish to allow use of your version of this file only
29 under the terms of either the GPL or the LGPL, and not to allow others to
30 use your version of this file under the terms of the MPL, indicate your
31 decision by deleting the provisions above and replace them with the notice
32 and other provisions required by the GPL or the LGPL. If you do not delete
33 the provisions above, a recipient may use your version of this file under
34 the terms of any one of the MPL, the GPL or the LGPL.
39 using System.Globalization;
42 namespace OpenHardwareMonitor.Hardware.LPC {
43 internal class W836XX : ISuperIO {
45 private readonly ushort address;
46 private readonly byte revision;
48 private readonly Chip chip;
50 private readonly float?[] voltages = new float?[0];
51 private readonly float?[] temperatures = new float?[0];
52 private readonly float?[] fans = new float?[0];
54 private readonly bool[] peciTemperature = new bool[0];
55 private readonly byte[] voltageRegister = new byte[0];
56 private readonly byte[] voltageBank = new byte[0];
57 private readonly float voltageGain = 0.008f;
60 private const ushort WINBOND_VENDOR_ID = 0x5CA3;
61 private const byte HIGH_BYTE = 0x80;
64 private const byte ADDRESS_REGISTER_OFFSET = 0x05;
65 private const byte DATA_REGISTER_OFFSET = 0x06;
67 // Hardware Monitor Registers
68 private const byte VOLTAGE_VBAT_REG = 0x51;
69 private const byte BANK_SELECT_REGISTER = 0x4E;
70 private const byte VENDOR_ID_REGISTER = 0x4F;
71 private const byte TEMPERATURE_SOURCE_SELECT_REG = 0x49;
73 private readonly byte[] TEMPERATURE_REG = new byte[] { 0x50, 0x50, 0x27 };
74 private readonly byte[] TEMPERATURE_BANK = new byte[] { 1, 2, 0 };
76 private readonly byte[] FAN_TACHO_REG =
77 new byte[] { 0x28, 0x29, 0x2A, 0x3F, 0x53 };
78 private readonly byte[] FAN_TACHO_BANK =
79 new byte[] { 0, 0, 0, 0, 5 };
80 private readonly byte[] FAN_BIT_REG =
81 new byte[] { 0x47, 0x4B, 0x4C, 0x59, 0x5D };
82 private readonly byte[] FAN_DIV_BIT0 = new byte[] { 36, 38, 30, 8, 10 };
83 private readonly byte[] FAN_DIV_BIT1 = new byte[] { 37, 39, 31, 9, 11 };
84 private readonly byte[] FAN_DIV_BIT2 = new byte[] { 5, 6, 7, 23, 15 };
86 private byte ReadByte(byte bank, byte register) {
87 WinRing0.WriteIoPortByte(
88 (ushort)(address + ADDRESS_REGISTER_OFFSET), BANK_SELECT_REGISTER);
89 WinRing0.WriteIoPortByte(
90 (ushort)(address + DATA_REGISTER_OFFSET), bank);
91 WinRing0.WriteIoPortByte(
92 (ushort)(address + ADDRESS_REGISTER_OFFSET), register);
93 return WinRing0.ReadIoPortByte(
94 (ushort)(address + DATA_REGISTER_OFFSET));
97 private void WriteByte(byte bank, byte register, byte value) {
98 WinRing0.WriteIoPortByte(
99 (ushort)(address + ADDRESS_REGISTER_OFFSET), BANK_SELECT_REGISTER);
100 WinRing0.WriteIoPortByte(
101 (ushort)(address + DATA_REGISTER_OFFSET), bank);
102 WinRing0.WriteIoPortByte(
103 (ushort)(address + ADDRESS_REGISTER_OFFSET), register);
104 WinRing0.WriteIoPortByte(
105 (ushort)(address + DATA_REGISTER_OFFSET), value);
108 public W836XX(Chip chip, byte revision, ushort address) {
109 this.address = address;
110 this.revision = revision;
113 if (!IsWinbondVendor())
116 temperatures = new float?[3];
117 peciTemperature = new bool[3];
121 // note temperature sensor registers that read PECI
122 byte flag = ReadByte(0, TEMPERATURE_SOURCE_SELECT_REG);
123 peciTemperature[0] = (flag & 0x04) != 0;
124 peciTemperature[1] = (flag & 0x40) != 0;
125 peciTemperature[2] = false;
128 case Chip.W83627DHGP:
129 // note temperature sensor registers that read PECI
130 byte sel = ReadByte(0, TEMPERATURE_SOURCE_SELECT_REG);
131 peciTemperature[0] = (sel & 0x07) != 0;
132 peciTemperature[1] = (sel & 0x70) != 0;
133 peciTemperature[2] = false;
137 peciTemperature[0] = false;
138 peciTemperature[1] = false;
139 peciTemperature[2] = false;
145 voltages = new float?[10];
146 voltageRegister = new byte[] {
147 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x50, 0x51, 0x52 };
148 voltageBank = new byte[] { 0, 0, 0, 0, 0, 0, 0, 5, 5, 5 };
149 voltageGain = 0.008f;
150 fans = new float?[5];
153 case Chip.W83627DHGP:
156 voltages = new float?[9];
157 voltageRegister = new byte[] {
158 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x50, 0x51 };
159 voltageBank = new byte[] { 0, 0, 0, 0, 0, 0, 0, 5, 5 };
160 voltageGain = 0.008f;
161 fans = new float?[5];
166 voltages = new float?[7];
167 voltageRegister = new byte[] {
168 0x20, 0x21, 0x22, 0x23, 0x24, 0x50, 0x51 };
169 voltageBank = new byte[] { 0, 0, 0, 0, 0, 5, 5 };
170 voltageGain = 0.016f;
171 fans = new float?[3];
176 private bool IsWinbondVendor() {
178 (ushort)((ReadByte(HIGH_BYTE, VENDOR_ID_REGISTER) << 8) |
179 ReadByte(0, VENDOR_ID_REGISTER));
180 return vendorId == WINBOND_VENDOR_ID;
183 private static ulong SetBit(ulong target, int bit, int value) {
184 if ((value & 1) != value)
185 throw new ArgumentException("Value must be one bit only.");
187 if (bit < 0 || bit > 63)
188 throw new ArgumentException("Bit out of range.");
190 ulong mask = (((ulong)1) << bit);
191 return value > 0 ? target | mask : target & ~mask;
194 public Chip Chip { get { return chip; } }
195 public float?[] Voltages { get { return voltages; } }
196 public float?[] Temperatures { get { return temperatures; } }
197 public float?[] Fans { get { return fans; } }
199 public void Update() {
200 if (!WinRing0.WaitIsaBusMutex(10))
203 for (int i = 0; i < voltages.Length; i++) {
204 if (voltageRegister[i] != VOLTAGE_VBAT_REG) {
205 // two special VCore measurement modes for W83627THF
207 if ((chip == Chip.W83627HF || chip == Chip.W83627THF ||
208 chip == Chip.W83687THF) && i == 0)
210 byte vrmConfiguration = ReadByte(0, 0x18);
211 int value = ReadByte(voltageBank[i], voltageRegister[i]);
212 if ((vrmConfiguration & 0x01) == 0)
213 fvalue = 0.016f * value; // VRM8 formula
215 fvalue = 0.00488f * value + 0.69f; // VRM9 formula
217 int value = ReadByte(voltageBank[i], voltageRegister[i]);
218 fvalue = voltageGain * value;
221 voltages[i] = fvalue;
226 bool valid = (ReadByte(0, 0x5D) & 0x01) > 0;
228 voltages[i] = voltageGain * ReadByte(5, VOLTAGE_VBAT_REG);
235 for (int i = 0; i < temperatures.Length; i++) {
236 int value = ((sbyte)ReadByte(TEMPERATURE_BANK[i],
237 TEMPERATURE_REG[i])) << 1;
238 if (TEMPERATURE_BANK[i] > 0)
239 value |= ReadByte(TEMPERATURE_BANK[i],
240 (byte)(TEMPERATURE_REG[i] + 1)) >> 7;
242 float temperature = value / 2.0f;
243 if (temperature <= 125 && temperature >= -55 && !peciTemperature[i]) {
244 temperatures[i] = temperature;
246 temperatures[i] = null;
251 for (int i = 0; i < FAN_BIT_REG.Length; i++)
252 bits = (bits << 8) | ReadByte(0, FAN_BIT_REG[i]);
253 ulong newBits = bits;
254 for (int i = 0; i < fans.Length; i++) {
255 int count = ReadByte(FAN_TACHO_BANK[i], FAN_TACHO_REG[i]);
257 // assemble fan divisor
258 int divisorBits = (int)(
259 (((bits >> FAN_DIV_BIT2[i]) & 1) << 2) |
260 (((bits >> FAN_DIV_BIT1[i]) & 1) << 1) |
261 ((bits >> FAN_DIV_BIT0[i]) & 1));
262 int divisor = 1 << divisorBits;
264 float value = (count < 0xff) ? 1.35e6f / (count * divisor) : 0;
267 // update fan divisor
268 if (count > 192 && divisorBits < 7)
270 if (count < 96 && divisorBits > 0)
273 newBits = SetBit(newBits, FAN_DIV_BIT2[i], (divisorBits >> 2) & 1);
274 newBits = SetBit(newBits, FAN_DIV_BIT1[i], (divisorBits >> 1) & 1);
275 newBits = SetBit(newBits, FAN_DIV_BIT0[i], divisorBits & 1);
278 // write new fan divisors
279 for (int i = FAN_BIT_REG.Length - 1; i >= 0; i--) {
280 byte oldByte = (byte)(bits & 0xFF);
281 byte newByte = (byte)(newBits & 0xFF);
283 newBits = newBits >> 8;
284 if (oldByte != newByte)
285 WriteByte(0, FAN_BIT_REG[i], newByte);
288 WinRing0.ReleaseIsaBusMutex();
291 public string GetReport() {
292 StringBuilder r = new StringBuilder();
294 r.AppendLine("LPC " + this.GetType().Name);
296 r.Append("Chip ID: 0x"); r.AppendLine(chip.ToString("X"));
297 r.Append("Chip revision: 0x");
298 r.AppendLine(revision.ToString("X", CultureInfo.InvariantCulture));
299 r.Append("Base Adress: 0x");
300 r.AppendLine(address.ToString("X4", CultureInfo.InvariantCulture));
303 if (!WinRing0.WaitIsaBusMutex(100))
306 r.AppendLine("Hardware Monitor Registers");
308 r.AppendLine(" 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F");
310 for (int i = 0; i <= 0x7; i++) {
312 r.Append((i << 4).ToString("X2", CultureInfo.InvariantCulture));
314 for (int j = 0; j <= 0xF; j++) {
316 r.Append(ReadByte(0, (byte)((i << 4) | j)).ToString(
317 "X2", CultureInfo.InvariantCulture));
321 for (int k = 1; k <= 15; k++) {
322 r.AppendLine("Bank " + k);
323 for (int i = 0x5; i < 0x6; i++) {
325 r.Append((i << 4).ToString("X2", CultureInfo.InvariantCulture));
327 for (int j = 0; j <= 0xF; j++) {
329 r.Append(ReadByte((byte)(k), (byte)((i << 4) | j)).ToString(
330 "X2", CultureInfo.InvariantCulture));
337 WinRing0.ReleaseIsaBusMutex();