Fixed Issue 387. The new implementation does not try to start a ring 0 driver that already exists, but could not be opened. It tries to delete the driver and install it new. The driver is now stored temporarily in the application folder. The driver is not correctly removed on system shutdown.
3 This Source Code Form is subject to the terms of the Mozilla Public
4 License, v. 2.0. If a copy of the MPL was not distributed with this
5 file, You can obtain one at http://mozilla.org/MPL/2.0/.
7 Copyright (C) 2009-2011 Michael Möller <mmoeller@openhardwaremonitor.org>
12 using System.Globalization;
15 namespace OpenHardwareMonitor.Hardware.LPC {
16 internal class W836XX : ISuperIO {
18 private readonly ushort address;
19 private readonly byte revision;
21 private readonly Chip chip;
23 private readonly float?[] voltages = new float?[0];
24 private readonly float?[] temperatures = new float?[0];
25 private readonly float?[] fans = new float?[0];
26 private readonly float?[] controls = new float?[0];
28 private readonly bool[] peciTemperature = new bool[0];
29 private readonly byte[] voltageRegister = new byte[0];
30 private readonly byte[] voltageBank = new byte[0];
31 private readonly float voltageGain = 0.008f;
34 private const ushort WINBOND_VENDOR_ID = 0x5CA3;
35 private const byte HIGH_BYTE = 0x80;
38 private const byte ADDRESS_REGISTER_OFFSET = 0x05;
39 private const byte DATA_REGISTER_OFFSET = 0x06;
41 // Hardware Monitor Registers
42 private const byte VOLTAGE_VBAT_REG = 0x51;
43 private const byte BANK_SELECT_REGISTER = 0x4E;
44 private const byte VENDOR_ID_REGISTER = 0x4F;
45 private const byte TEMPERATURE_SOURCE_SELECT_REG = 0x49;
47 private readonly byte[] TEMPERATURE_REG = new byte[] { 0x50, 0x50, 0x27 };
48 private readonly byte[] TEMPERATURE_BANK = new byte[] { 1, 2, 0 };
50 private readonly byte[] FAN_TACHO_REG =
51 new byte[] { 0x28, 0x29, 0x2A, 0x3F, 0x53 };
52 private readonly byte[] FAN_TACHO_BANK =
53 new byte[] { 0, 0, 0, 0, 5 };
54 private readonly byte[] FAN_BIT_REG =
55 new byte[] { 0x47, 0x4B, 0x4C, 0x59, 0x5D };
56 private readonly byte[] FAN_DIV_BIT0 = new byte[] { 36, 38, 30, 8, 10 };
57 private readonly byte[] FAN_DIV_BIT1 = new byte[] { 37, 39, 31, 9, 11 };
58 private readonly byte[] FAN_DIV_BIT2 = new byte[] { 5, 6, 7, 23, 15 };
60 private byte ReadByte(byte bank, byte register) {
62 (ushort)(address + ADDRESS_REGISTER_OFFSET), BANK_SELECT_REGISTER);
64 (ushort)(address + DATA_REGISTER_OFFSET), bank);
66 (ushort)(address + ADDRESS_REGISTER_OFFSET), register);
67 return Ring0.ReadIoPort(
68 (ushort)(address + DATA_REGISTER_OFFSET));
71 private void WriteByte(byte bank, byte register, byte value) {
73 (ushort)(address + ADDRESS_REGISTER_OFFSET), BANK_SELECT_REGISTER);
75 (ushort)(address + DATA_REGISTER_OFFSET), bank);
77 (ushort)(address + ADDRESS_REGISTER_OFFSET), register);
79 (ushort)(address + DATA_REGISTER_OFFSET), value);
82 public byte? ReadGPIO(int index) {
86 public void WriteGPIO(int index, byte value) { }
88 public void SetControl(int index, byte? value) { }
90 public W836XX(Chip chip, byte revision, ushort address) {
91 this.address = address;
92 this.revision = revision;
95 if (!IsWinbondVendor())
98 temperatures = new float?[3];
99 peciTemperature = new bool[3];
103 // note temperature sensor registers that read PECI
104 byte flag = ReadByte(0, TEMPERATURE_SOURCE_SELECT_REG);
105 peciTemperature[0] = (flag & 0x04) != 0;
106 peciTemperature[1] = (flag & 0x40) != 0;
107 peciTemperature[2] = false;
110 case Chip.W83627DHGP:
111 // note temperature sensor registers that read PECI
112 byte sel = ReadByte(0, TEMPERATURE_SOURCE_SELECT_REG);
113 peciTemperature[0] = (sel & 0x07) != 0;
114 peciTemperature[1] = (sel & 0x70) != 0;
115 peciTemperature[2] = false;
119 peciTemperature[0] = false;
120 peciTemperature[1] = false;
121 peciTemperature[2] = false;
127 voltages = new float?[10];
128 voltageRegister = new byte[] {
129 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x50, 0x51, 0x52 };
130 voltageBank = new byte[] { 0, 0, 0, 0, 0, 0, 0, 5, 5, 5 };
131 voltageGain = 0.008f;
132 fans = new float?[5];
135 case Chip.W83627DHGP:
138 voltages = new float?[9];
139 voltageRegister = new byte[] {
140 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x50, 0x51 };
141 voltageBank = new byte[] { 0, 0, 0, 0, 0, 0, 0, 5, 5 };
142 voltageGain = 0.008f;
143 fans = new float?[5];
148 voltages = new float?[7];
149 voltageRegister = new byte[] {
150 0x20, 0x21, 0x22, 0x23, 0x24, 0x50, 0x51 };
151 voltageBank = new byte[] { 0, 0, 0, 0, 0, 5, 5 };
152 voltageGain = 0.016f;
153 fans = new float?[3];
158 private bool IsWinbondVendor() {
160 (ushort)((ReadByte(HIGH_BYTE, VENDOR_ID_REGISTER) << 8) |
161 ReadByte(0, VENDOR_ID_REGISTER));
162 return vendorId == WINBOND_VENDOR_ID;
165 private static ulong SetBit(ulong target, int bit, int value) {
166 if ((value & 1) != value)
167 throw new ArgumentException("Value must be one bit only.");
169 if (bit < 0 || bit > 63)
170 throw new ArgumentException("Bit out of range.");
172 ulong mask = (((ulong)1) << bit);
173 return value > 0 ? target | mask : target & ~mask;
176 public Chip Chip { get { return chip; } }
177 public float?[] Voltages { get { return voltages; } }
178 public float?[] Temperatures { get { return temperatures; } }
179 public float?[] Fans { get { return fans; } }
180 public float?[] Controls { get { return controls; } }
182 public void Update() {
183 if (!Ring0.WaitIsaBusMutex(10))
186 for (int i = 0; i < voltages.Length; i++) {
187 if (voltageRegister[i] != VOLTAGE_VBAT_REG) {
188 // two special VCore measurement modes for W83627THF
190 if ((chip == Chip.W83627HF || chip == Chip.W83627THF ||
191 chip == Chip.W83687THF) && i == 0)
193 byte vrmConfiguration = ReadByte(0, 0x18);
194 int value = ReadByte(voltageBank[i], voltageRegister[i]);
195 if ((vrmConfiguration & 0x01) == 0)
196 fvalue = 0.016f * value; // VRM8 formula
198 fvalue = 0.00488f * value + 0.69f; // VRM9 formula
200 int value = ReadByte(voltageBank[i], voltageRegister[i]);
201 fvalue = voltageGain * value;
204 voltages[i] = fvalue;
209 bool valid = (ReadByte(0, 0x5D) & 0x01) > 0;
211 voltages[i] = voltageGain * ReadByte(5, VOLTAGE_VBAT_REG);
218 for (int i = 0; i < temperatures.Length; i++) {
219 int value = ((sbyte)ReadByte(TEMPERATURE_BANK[i],
220 TEMPERATURE_REG[i])) << 1;
221 if (TEMPERATURE_BANK[i] > 0)
222 value |= ReadByte(TEMPERATURE_BANK[i],
223 (byte)(TEMPERATURE_REG[i] + 1)) >> 7;
225 float temperature = value / 2.0f;
226 if (temperature <= 125 && temperature >= -55 && !peciTemperature[i]) {
227 temperatures[i] = temperature;
229 temperatures[i] = null;
234 for (int i = 0; i < FAN_BIT_REG.Length; i++)
235 bits = (bits << 8) | ReadByte(0, FAN_BIT_REG[i]);
236 ulong newBits = bits;
237 for (int i = 0; i < fans.Length; i++) {
238 int count = ReadByte(FAN_TACHO_BANK[i], FAN_TACHO_REG[i]);
240 // assemble fan divisor
241 int divisorBits = (int)(
242 (((bits >> FAN_DIV_BIT2[i]) & 1) << 2) |
243 (((bits >> FAN_DIV_BIT1[i]) & 1) << 1) |
244 ((bits >> FAN_DIV_BIT0[i]) & 1));
245 int divisor = 1 << divisorBits;
247 float value = (count < 0xff) ? 1.35e6f / (count * divisor) : 0;
250 // update fan divisor
251 if (count > 192 && divisorBits < 7)
253 if (count < 96 && divisorBits > 0)
256 newBits = SetBit(newBits, FAN_DIV_BIT2[i], (divisorBits >> 2) & 1);
257 newBits = SetBit(newBits, FAN_DIV_BIT1[i], (divisorBits >> 1) & 1);
258 newBits = SetBit(newBits, FAN_DIV_BIT0[i], divisorBits & 1);
261 // write new fan divisors
262 for (int i = FAN_BIT_REG.Length - 1; i >= 0; i--) {
263 byte oldByte = (byte)(bits & 0xFF);
264 byte newByte = (byte)(newBits & 0xFF);
266 newBits = newBits >> 8;
267 if (oldByte != newByte)
268 WriteByte(0, FAN_BIT_REG[i], newByte);
271 Ring0.ReleaseIsaBusMutex();
274 public string GetReport() {
275 StringBuilder r = new StringBuilder();
277 r.AppendLine("LPC " + this.GetType().Name);
279 r.Append("Chip ID: 0x"); r.AppendLine(chip.ToString("X"));
280 r.Append("Chip revision: 0x");
281 r.AppendLine(revision.ToString("X", CultureInfo.InvariantCulture));
282 r.Append("Base Adress: 0x");
283 r.AppendLine(address.ToString("X4", CultureInfo.InvariantCulture));
286 if (!Ring0.WaitIsaBusMutex(100))
289 r.AppendLine("Hardware Monitor Registers");
291 r.AppendLine(" 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F");
293 for (int i = 0; i <= 0x7; i++) {
295 r.Append((i << 4).ToString("X2", CultureInfo.InvariantCulture));
297 for (int j = 0; j <= 0xF; j++) {
299 r.Append(ReadByte(0, (byte)((i << 4) | j)).ToString(
300 "X2", CultureInfo.InvariantCulture));
304 for (int k = 1; k <= 15; k++) {
305 r.AppendLine("Bank " + k);
306 for (int i = 0x5; i < 0x6; i++) {
308 r.Append((i << 4).ToString("X2", CultureInfo.InvariantCulture));
310 for (int j = 0; j <= 0xF; j++) {
312 r.Append(ReadByte((byte)(k), (byte)((i << 4) | j)).ToString(
313 "X2", CultureInfo.InvariantCulture));
320 Ring0.ReleaseIsaBusMutex();