Fixed Issue 97.
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.Collections.Generic;
40 using System.Globalization;
43 namespace OpenHardwareMonitor.Hardware.LPC {
44 internal class W836XX : ISuperIO {
46 private ushort address;
47 private byte revision;
51 private float?[] voltages = new float?[0];
52 private float?[] temperatures = new float?[0];
53 private float?[] fans = new float?[0];
55 private bool[] peciTemperature = new bool[0];
56 private byte[] voltageRegister = new byte[0];
57 private byte[] voltageBank = new byte[0];
58 private float voltageGain = 0.008f;
61 private const ushort WINBOND_VENDOR_ID = 0x5CA3;
62 private const byte HIGH_BYTE = 0x80;
65 private const byte ADDRESS_REGISTER_OFFSET = 0x05;
66 private const byte DATA_REGISTER_OFFSET = 0x06;
68 // Hardware Monitor Registers
69 private const byte VOLTAGE_VBAT_REG = 0x51;
70 private const byte BANK_SELECT_REGISTER = 0x4E;
71 private const byte VENDOR_ID_REGISTER = 0x4F;
72 private const byte TEMPERATURE_SOURCE_SELECT_REG = 0x49;
74 private byte[] TEMPERATURE_REG = new byte[] { 0x50, 0x50, 0x27 };
75 private byte[] TEMPERATURE_BANK = new byte[] { 1, 2, 0 };
77 private byte[] FAN_TACHO_REG = new byte[] { 0x28, 0x29, 0x2A, 0x3F, 0x53 };
78 private byte[] FAN_TACHO_BANK = new byte[] { 0, 0, 0, 0, 5 };
79 private byte[] FAN_BIT_REG = new byte[] { 0x47, 0x4B, 0x4C, 0x59, 0x5D };
80 private byte[] FAN_DIV_BIT0 = new byte[] { 36, 38, 30, 8, 10 };
81 private byte[] FAN_DIV_BIT1 = new byte[] { 37, 39, 31, 9, 11 };
82 private byte[] FAN_DIV_BIT2 = new byte[] { 5, 6, 7, 23, 15 };
84 private byte ReadByte(byte bank, byte register) {
85 WinRing0.WriteIoPortByte(
86 (ushort)(address + ADDRESS_REGISTER_OFFSET), BANK_SELECT_REGISTER);
87 WinRing0.WriteIoPortByte(
88 (ushort)(address + DATA_REGISTER_OFFSET), bank);
89 WinRing0.WriteIoPortByte(
90 (ushort)(address + ADDRESS_REGISTER_OFFSET), register);
91 return WinRing0.ReadIoPortByte(
92 (ushort)(address + DATA_REGISTER_OFFSET));
95 private void WriteByte(byte bank, byte register, byte value) {
96 WinRing0.WriteIoPortByte(
97 (ushort)(address + ADDRESS_REGISTER_OFFSET), BANK_SELECT_REGISTER);
98 WinRing0.WriteIoPortByte(
99 (ushort)(address + DATA_REGISTER_OFFSET), bank);
100 WinRing0.WriteIoPortByte(
101 (ushort)(address + ADDRESS_REGISTER_OFFSET), register);
102 WinRing0.WriteIoPortByte(
103 (ushort)(address + DATA_REGISTER_OFFSET), value);
106 public W836XX(Chip chip, byte revision, ushort address) {
107 this.address = address;
108 this.revision = revision;
111 if (!IsWinbondVendor())
114 temperatures = new float?[3];
115 peciTemperature = new bool[3];
119 // note temperature sensor registers that read PECI
120 byte flag = ReadByte(0, TEMPERATURE_SOURCE_SELECT_REG);
121 peciTemperature[0] = (flag & 0x04) != 0;
122 peciTemperature[1] = (flag & 0x40) != 0;
123 peciTemperature[2] = false;
126 case Chip.W83627DHGP:
127 // note temperature sensor registers that read PECI
128 byte sel = ReadByte(0, TEMPERATURE_SOURCE_SELECT_REG);
129 peciTemperature[0] = (sel & 0x07) != 0;
130 peciTemperature[1] = (sel & 0x70) != 0;
131 peciTemperature[2] = false;
135 peciTemperature[0] = false;
136 peciTemperature[1] = false;
137 peciTemperature[2] = false;
143 voltages = new float?[10];
144 voltageRegister = new byte[] {
145 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x50, 0x51, 0x52 };
146 voltageBank = new byte[] { 0, 0, 0, 0, 0, 0, 0, 5, 5, 5 };
147 voltageGain = 0.008f;
148 fans = new float?[5];
151 case Chip.W83627DHGP:
154 voltages = new float?[9];
155 voltageRegister = new byte[] {
156 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x50, 0x51 };
157 voltageBank = new byte[] { 0, 0, 0, 0, 0, 0, 0, 5, 5 };
158 voltageGain = 0.008f;
159 fans = new float?[5];
164 voltages = new float?[7];
165 voltageRegister = new byte[] {
166 0x20, 0x21, 0x22, 0x23, 0x24, 0x50, 0x51 };
167 voltageBank = new byte[] { 0, 0, 0, 0, 0, 5, 5 };
168 voltageGain = 0.016f;
169 fans = new float?[3];
174 private bool IsWinbondVendor() {
176 (ushort)((ReadByte(HIGH_BYTE, VENDOR_ID_REGISTER) << 8) |
177 ReadByte(0, VENDOR_ID_REGISTER));
178 return vendorId == WINBOND_VENDOR_ID;
181 private static ulong SetBit(ulong target, int bit, int value) {
182 if ((value & 1) != value)
183 throw new ArgumentException("Value must be one bit only.");
185 if (bit < 0 || bit > 63)
186 throw new ArgumentException("Bit out of range.");
188 ulong mask = (((ulong)1) << bit);
189 return value > 0 ? target | mask : target & ~mask;
192 public Chip Chip { get { return chip; } }
193 public float?[] Voltages { get { return voltages; } }
194 public float?[] Temperatures { get { return temperatures; } }
195 public float?[] Fans { get { return fans; } }
197 public void Update() {
198 if (!WinRing0.WaitIsaBusMutex(10))
201 for (int i = 0; i < voltages.Length; i++) {
202 if (voltageRegister[i] != VOLTAGE_VBAT_REG) {
203 // two special VCore measurement modes for W83627THF
205 if ((chip == Chip.W83627HF || chip == Chip.W83627THF ||
206 chip == Chip.W83687THF) && i == 0)
208 byte vrmConfiguration = ReadByte(0, 0x18);
209 int value = ReadByte(voltageBank[i], voltageRegister[i]);
210 if ((vrmConfiguration & 0x01) == 0)
211 fvalue = 0.016f * value; // VRM8 formula
213 fvalue = 0.00488f * value + 0.69f; // VRM9 formula
215 int value = ReadByte(voltageBank[i], voltageRegister[i]);
216 fvalue = voltageGain * value;
219 voltages[i] = fvalue;
224 bool valid = (ReadByte(0, 0x5D) & 0x01) > 0;
226 voltages[i] = voltageGain * ReadByte(5, VOLTAGE_VBAT_REG);
233 for (int i = 0; i < temperatures.Length; i++) {
234 int value = ((sbyte)ReadByte(TEMPERATURE_BANK[i],
235 TEMPERATURE_REG[i])) << 1;
236 if (TEMPERATURE_BANK[i] > 0)
237 value |= ReadByte(TEMPERATURE_BANK[i],
238 (byte)(TEMPERATURE_REG[i] + 1)) >> 7;
240 float temperature = value / 2.0f;
241 if (temperature <= 125 && temperature >= -55 && !peciTemperature[i]) {
242 temperatures[i] = temperature;
244 temperatures[i] = null;
249 for (int i = 0; i < FAN_BIT_REG.Length; i++)
250 bits = (bits << 8) | ReadByte(0, FAN_BIT_REG[i]);
251 ulong newBits = bits;
252 for (int i = 0; i < fans.Length; i++) {
253 int count = ReadByte(FAN_TACHO_BANK[i], FAN_TACHO_REG[i]);
255 // assemble fan divisor
256 int divisorBits = (int)(
257 (((bits >> FAN_DIV_BIT2[i]) & 1) << 2) |
258 (((bits >> FAN_DIV_BIT1[i]) & 1) << 1) |
259 ((bits >> FAN_DIV_BIT0[i]) & 1));
260 int divisor = 1 << divisorBits;
262 float value = (count < 0xff) ? 1.35e6f / (count * divisor) : 0;
265 // update fan divisor
266 if (count > 192 && divisorBits < 7)
268 if (count < 96 && divisorBits > 0)
271 newBits = SetBit(newBits, FAN_DIV_BIT2[i], (divisorBits >> 2) & 1);
272 newBits = SetBit(newBits, FAN_DIV_BIT1[i], (divisorBits >> 1) & 1);
273 newBits = SetBit(newBits, FAN_DIV_BIT0[i], divisorBits & 1);
276 // write new fan divisors
277 for (int i = FAN_BIT_REG.Length - 1; i >= 0; i--) {
278 byte oldByte = (byte)(bits & 0xFF);
279 byte newByte = (byte)(newBits & 0xFF);
281 newBits = newBits >> 8;
282 if (oldByte != newByte)
283 WriteByte(0, FAN_BIT_REG[i], newByte);
286 WinRing0.ReleaseIsaBusMutex();
289 public string GetReport() {
290 StringBuilder r = new StringBuilder();
292 r.AppendLine("LPC " + this.GetType().Name);
294 r.Append("Chip ID: 0x"); r.AppendLine(chip.ToString("X"));
295 r.Append("Chip revision: 0x");
296 r.AppendLine(revision.ToString("X", CultureInfo.InvariantCulture));
297 r.Append("Base Adress: 0x");
298 r.AppendLine(address.ToString("X4", CultureInfo.InvariantCulture));
301 if (!WinRing0.WaitIsaBusMutex(100))
304 r.AppendLine("Hardware Monitor Registers");
306 r.AppendLine(" 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F");
308 for (int i = 0; i <= 0x7; i++) {
310 r.Append((i << 4).ToString("X2", CultureInfo.InvariantCulture));
312 for (int j = 0; j <= 0xF; j++) {
314 r.Append(ReadByte(0, (byte)((i << 4) | j)).ToString(
315 "X2", CultureInfo.InvariantCulture));
319 for (int k = 1; k <= 15; k++) {
320 r.AppendLine("Bank " + k);
321 for (int i = 0x5; i < 0x6; i++) {
323 r.Append((i << 4).ToString("X2", CultureInfo.InvariantCulture));
325 for (int j = 0; j <= 0xF; j++) {
327 r.Append(ReadByte((byte)(k), (byte)((i << 4) | j)).ToString(
328 "X2", CultureInfo.InvariantCulture));
335 WinRing0.ReleaseIsaBusMutex();