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-2012 Michael Möller <mmoeller@openhardwaremonitor.org>
12 using System.Collections.Generic;
13 using System.Globalization;
15 using System.Threading;
17 namespace OpenHardwareMonitor.Hardware.LPC {
18 internal class LPCIO {
20 private readonly List<ISuperIO> superIOs = new List<ISuperIO>();
21 private readonly StringBuilder report = new StringBuilder();
24 private readonly ushort[] REGISTER_PORTS = new ushort[] { 0x2E, 0x4E };
25 private readonly ushort[] VALUE_PORTS = new ushort[] { 0x2F, 0x4F };
27 private ushort registerPort;
28 private ushort valuePort;
31 private const byte CONFIGURATION_CONTROL_REGISTER = 0x02;
32 private const byte DEVCIE_SELECT_REGISTER = 0x07;
33 private const byte CHIP_ID_REGISTER = 0x20;
34 private const byte CHIP_REVISION_REGISTER = 0x21;
35 private const byte BASE_ADDRESS_REGISTER = 0x60;
37 private byte ReadByte(byte register) {
38 Ring0.WriteIoPort(registerPort, register);
39 return Ring0.ReadIoPort(valuePort);
42 private ushort ReadWord(byte register) {
43 return (ushort)((ReadByte(register) << 8) |
44 ReadByte((byte)(register + 1)));
47 private void Select(byte logicalDeviceNumber) {
48 Ring0.WriteIoPort(registerPort, DEVCIE_SELECT_REGISTER);
49 Ring0.WriteIoPort(valuePort, logicalDeviceNumber);
52 private void ReportUnknownChip(string type, int chip) {
53 report.Append("Chip ID: Unknown ");
55 report.Append(" with ID 0x");
56 report.Append(chip.ToString("X", CultureInfo.InvariantCulture));
57 report.Append(" at 0x");
58 report.Append(registerPort.ToString("X", CultureInfo.InvariantCulture));
60 report.AppendLine(valuePort.ToString("X", CultureInfo.InvariantCulture));
64 #region Winbond, Nuvoton, Fintek
66 private const byte FINTEK_VENDOR_ID_REGISTER = 0x23;
67 private const ushort FINTEK_VENDOR_ID = 0x1934;
69 private const byte WINBOND_NUVOTON_HARDWARE_MONITOR_LDN = 0x0B;
71 private const byte F71858_HARDWARE_MONITOR_LDN = 0x02;
72 private const byte FINTEK_HARDWARE_MONITOR_LDN = 0x04;
74 private void WinbondNuvotonFintekEnter() {
75 Ring0.WriteIoPort(registerPort, 0x87);
76 Ring0.WriteIoPort(registerPort, 0x87);
79 private void WinbondNuvotonFintekExit() {
80 Ring0.WriteIoPort(registerPort, 0xAA);
83 private bool DetectWinbondFintek() {
84 WinbondNuvotonFintekEnter();
86 byte logicalDeviceNumber = 0;
87 byte id = ReadByte(CHIP_ID_REGISTER);
88 byte revision = ReadByte(CHIP_REVISION_REGISTER);
89 Chip chip = Chip.Unknown;
95 logicalDeviceNumber = F71858_HARDWARE_MONITOR_LDN;
99 logicalDeviceNumber = FINTEK_HARDWARE_MONITOR_LDN;
106 logicalDeviceNumber = FINTEK_HARDWARE_MONITOR_LDN;
113 logicalDeviceNumber = FINTEK_HARDWARE_MONITOR_LDN;
120 logicalDeviceNumber = FINTEK_HARDWARE_MONITOR_LDN;
127 logicalDeviceNumber = FINTEK_HARDWARE_MONITOR_LDN;
130 chip = Chip.F71889ED;
131 logicalDeviceNumber = FINTEK_HARDWARE_MONITOR_LDN;
137 chip = Chip.F71889AD;
138 logicalDeviceNumber = FINTEK_HARDWARE_MONITOR_LDN;
146 chip = Chip.W83627HF;
147 logicalDeviceNumber = WINBOND_NUVOTON_HARDWARE_MONITOR_LDN;
151 switch (revision & 0xF0) {
153 chip = Chip.W83627THF;
154 logicalDeviceNumber = WINBOND_NUVOTON_HARDWARE_MONITOR_LDN;
160 chip = Chip.W83687THF;
161 logicalDeviceNumber = WINBOND_NUVOTON_HARDWARE_MONITOR_LDN;
165 switch (revision & 0xF0) {
168 chip = Chip.W83627EHF;
169 logicalDeviceNumber = WINBOND_NUVOTON_HARDWARE_MONITOR_LDN;
173 switch (revision & 0xF0) {
175 chip = Chip.W83627DHG;
176 logicalDeviceNumber = WINBOND_NUVOTON_HARDWARE_MONITOR_LDN;
180 switch (revision & 0xF0) {
182 chip = Chip.W83667HG;
183 logicalDeviceNumber = WINBOND_NUVOTON_HARDWARE_MONITOR_LDN;
187 switch (revision & 0xF0) {
189 chip = Chip.W83627DHGP;
190 logicalDeviceNumber = WINBOND_NUVOTON_HARDWARE_MONITOR_LDN;
194 switch (revision & 0xF0) {
196 chip = Chip.W83667HGB;
197 logicalDeviceNumber = WINBOND_NUVOTON_HARDWARE_MONITOR_LDN;
201 switch (revision & 0xF0) {
203 chip = Chip.NCT6771F;
204 logicalDeviceNumber = WINBOND_NUVOTON_HARDWARE_MONITOR_LDN;
208 switch (revision & 0xF0) {
210 chip = Chip.NCT6776F;
211 logicalDeviceNumber = WINBOND_NUVOTON_HARDWARE_MONITOR_LDN;
215 switch (revision & 0xF0) {
217 chip = Chip.NCT6779D;
218 logicalDeviceNumber = WINBOND_NUVOTON_HARDWARE_MONITOR_LDN;
222 if (chip == Chip.Unknown) {
223 if (id != 0 && id != 0xff) {
224 WinbondNuvotonFintekExit();
226 ReportUnknownChip("Winbond / Nuvoton / Fintek",
227 ((id << 8) | revision));
231 Select(logicalDeviceNumber);
232 ushort address = ReadWord(BASE_ADDRESS_REGISTER);
234 ushort verify = ReadWord(BASE_ADDRESS_REGISTER);
236 ushort vendorID = ReadWord(FINTEK_VENDOR_ID_REGISTER);
238 WinbondNuvotonFintekExit();
240 if (address != verify) {
241 report.Append("Chip ID: 0x");
242 report.AppendLine(chip.ToString("X"));
243 report.Append("Chip revision: 0x");
244 report.AppendLine(revision.ToString("X",
245 CultureInfo.InvariantCulture));
246 report.AppendLine("Error: Address verification failed");
251 // some Fintek chips have address register offset 0x05 added already
252 if ((address & 0x07) == 0x05)
255 if (address < 0x100 || (address & 0xF007) != 0) {
256 report.Append("Chip ID: 0x");
257 report.AppendLine(chip.ToString("X"));
258 report.Append("Chip revision: 0x");
259 report.AppendLine(revision.ToString("X",
260 CultureInfo.InvariantCulture));
261 report.Append("Error: Invalid address 0x");
262 report.AppendLine(address.ToString("X",
263 CultureInfo.InvariantCulture));
270 case Chip.W83627DHGP:
277 superIOs.Add(new W836XX(chip, revision, address));
282 superIOs.Add(new NCT677X(chip, revision, address));
292 if (vendorID != FINTEK_VENDOR_ID) {
293 report.Append("Chip ID: 0x");
294 report.AppendLine(chip.ToString("X"));
295 report.Append("Chip revision: 0x");
296 report.AppendLine(revision.ToString("X",
297 CultureInfo.InvariantCulture));
298 report.Append("Error: Invalid vendor ID 0x");
299 report.AppendLine(vendorID.ToString("X",
300 CultureInfo.InvariantCulture));
304 superIOs.Add(new F718XX(chip, address));
319 private const byte IT87_ENVIRONMENT_CONTROLLER_LDN = 0x04;
320 private const byte IT8705_GPIO_LDN = 0x05;
321 private const byte IT87XX_GPIO_LDN = 0x07;
322 private const byte IT87_CHIP_VERSION_REGISTER = 0x22;
324 private void IT87Enter() {
325 Ring0.WriteIoPort(registerPort, 0x87);
326 Ring0.WriteIoPort(registerPort, 0x01);
327 Ring0.WriteIoPort(registerPort, 0x55);
328 Ring0.WriteIoPort(registerPort, 0x55);
331 private void IT87Exit() {
332 Ring0.WriteIoPort(registerPort, CONFIGURATION_CONTROL_REGISTER);
333 Ring0.WriteIoPort(valuePort, 0x02);
336 private bool DetectIT87() {
338 // IT87XX can enter only on port 0x2E
339 if (registerPort != 0x2E)
344 ushort chipID = ReadWord(CHIP_ID_REGISTER);
347 case 0x8705: chip = Chip.IT8705F; break;
348 case 0x8712: chip = Chip.IT8712F; break;
349 case 0x8716: chip = Chip.IT8716F; break;
350 case 0x8718: chip = Chip.IT8718F; break;
351 case 0x8720: chip = Chip.IT8720F; break;
352 case 0x8721: chip = Chip.IT8721F; break;
353 case 0x8726: chip = Chip.IT8726F; break;
354 case 0x8728: chip = Chip.IT8728F; break;
355 case 0x8771: chip = Chip.IT8771E; break;
356 case 0x8772: chip = Chip.IT8772E; break;
357 default: chip = Chip.Unknown; break;
359 if (chip == Chip.Unknown) {
360 if (chipID != 0 && chipID != 0xffff) {
363 ReportUnknownChip("ITE", chipID);
366 Select(IT87_ENVIRONMENT_CONTROLLER_LDN);
367 ushort address = ReadWord(BASE_ADDRESS_REGISTER);
369 ushort verify = ReadWord(BASE_ADDRESS_REGISTER);
371 byte version = (byte)(ReadByte(IT87_CHIP_VERSION_REGISTER) & 0x0F);
375 if (chip == Chip.IT8705F) {
376 Select(IT8705_GPIO_LDN);
377 gpioAddress = ReadWord(BASE_ADDRESS_REGISTER);
379 gpioVerify = ReadWord(BASE_ADDRESS_REGISTER);
381 Select(IT87XX_GPIO_LDN);
382 gpioAddress = ReadWord(BASE_ADDRESS_REGISTER + 2);
384 gpioVerify = ReadWord(BASE_ADDRESS_REGISTER + 2);
389 if (address != verify || address < 0x100 || (address & 0xF007) != 0) {
390 report.Append("Chip ID: 0x");
391 report.AppendLine(chip.ToString("X"));
392 report.Append("Error: Invalid address 0x");
393 report.AppendLine(address.ToString("X",
394 CultureInfo.InvariantCulture));
399 if (gpioAddress != gpioVerify || gpioAddress < 0x100 ||
400 (gpioAddress & 0xF007) != 0) {
401 report.Append("Chip ID: 0x");
402 report.AppendLine(chip.ToString("X"));
403 report.Append("Error: Invalid GPIO address 0x");
404 report.AppendLine(gpioAddress.ToString("X",
405 CultureInfo.InvariantCulture));
410 superIOs.Add(new IT87XX(chip, address, gpioAddress, version));
421 private void SMSCEnter() {
422 Ring0.WriteIoPort(registerPort, 0x55);
425 private void SMSCExit() {
426 Ring0.WriteIoPort(registerPort, 0xAA);
429 private bool DetectSMSC() {
432 ushort chipID = ReadWord(CHIP_ID_REGISTER);
435 default: chip = Chip.Unknown; break;
437 if (chip == Chip.Unknown) {
438 if (chipID != 0 && chipID != 0xffff) {
441 ReportUnknownChip("SMSC", chipID);
453 private void Detect() {
455 for (int i = 0; i < REGISTER_PORTS.Length; i++) {
456 registerPort = REGISTER_PORTS[i];
457 valuePort = VALUE_PORTS[i];
459 if (DetectWinbondFintek()) continue;
461 if (DetectIT87()) continue;
463 if (DetectSMSC()) continue;
471 if (!Ring0.WaitIsaBusMutex(100))
476 Ring0.ReleaseIsaBusMutex();
479 public ISuperIO[] SuperIO {
481 return superIOs.ToArray();
485 public string GetReport() {
486 if (report.Length > 0) {
487 return "LPCIO" + Environment.NewLine + Environment.NewLine + report;