Hardware/LPC/LPCIO.cs
author moel.mich
Sun, 23 Sep 2012 18:37:43 +0000
changeset 380 573f1fff48b2
parent 353 b4e37f5b2669
permissions -rw-r--r--
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.
     1 /*
     2  
     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/.
     6  
     7   Copyright (C) 2009-2012 Michael Möller <mmoeller@openhardwaremonitor.org>
     8 	
     9 */
    10 
    11 using System;
    12 using System.Collections.Generic;
    13 using System.Globalization;
    14 using System.Text;
    15 using System.Threading;
    16 
    17 namespace OpenHardwareMonitor.Hardware.LPC {
    18   internal class LPCIO {
    19 
    20     private readonly List<ISuperIO> superIOs = new List<ISuperIO>();
    21     private readonly StringBuilder report = new StringBuilder();
    22 
    23     // I/O Ports
    24     private readonly ushort[] REGISTER_PORTS = new ushort[] { 0x2E, 0x4E };
    25     private readonly ushort[] VALUE_PORTS = new ushort[] { 0x2F, 0x4F };
    26 
    27     private ushort registerPort;
    28     private ushort valuePort;
    29 
    30     // Registers
    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;
    36 
    37     private byte ReadByte(byte register) {
    38       Ring0.WriteIoPort(registerPort, register);
    39       return Ring0.ReadIoPort(valuePort);
    40     }
    41 
    42     private ushort ReadWord(byte register) {
    43       return (ushort)((ReadByte(register) << 8) |
    44         ReadByte((byte)(register + 1)));
    45     }
    46 
    47     private void Select(byte logicalDeviceNumber) {
    48       Ring0.WriteIoPort(registerPort, DEVCIE_SELECT_REGISTER);
    49       Ring0.WriteIoPort(valuePort, logicalDeviceNumber);
    50     }
    51 
    52     private void ReportUnknownChip(string type, int chip) {
    53       report.Append("Chip ID: Unknown ");
    54       report.Append(type);
    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));
    59       report.Append("/0x");
    60       report.AppendLine(valuePort.ToString("X", CultureInfo.InvariantCulture));
    61       report.AppendLine();
    62     }
    63 
    64     #region Winbond, Nuvoton, Fintek
    65 
    66     private const byte FINTEK_VENDOR_ID_REGISTER = 0x23;
    67     private const ushort FINTEK_VENDOR_ID = 0x1934;
    68 
    69     private const byte WINBOND_NUVOTON_HARDWARE_MONITOR_LDN = 0x0B;
    70 
    71     private const byte F71858_HARDWARE_MONITOR_LDN = 0x02;
    72     private const byte FINTEK_HARDWARE_MONITOR_LDN = 0x04;
    73 
    74     private void WinbondNuvotonFintekEnter() {
    75       Ring0.WriteIoPort(registerPort, 0x87);
    76       Ring0.WriteIoPort(registerPort, 0x87);
    77     }
    78 
    79     private void WinbondNuvotonFintekExit() {
    80       Ring0.WriteIoPort(registerPort, 0xAA);
    81     }
    82 
    83     private bool DetectWinbondFintek() {
    84       WinbondNuvotonFintekEnter();
    85 
    86       byte logicalDeviceNumber = 0;
    87       byte id = ReadByte(CHIP_ID_REGISTER);
    88       byte revision = ReadByte(CHIP_REVISION_REGISTER);
    89       Chip chip = Chip.Unknown;
    90       switch (id) {
    91         case 0x05:
    92           switch (revision) {
    93             case 0x07:
    94               chip = Chip.F71858;
    95               logicalDeviceNumber = F71858_HARDWARE_MONITOR_LDN;
    96               break;
    97             case 0x41:
    98               chip = Chip.F71882;
    99               logicalDeviceNumber = FINTEK_HARDWARE_MONITOR_LDN;
   100               break;
   101           } break;
   102         case 0x06:
   103           switch (revision) {
   104             case 0x01:
   105               chip = Chip.F71862;
   106               logicalDeviceNumber = FINTEK_HARDWARE_MONITOR_LDN;
   107               break;
   108           } break;
   109         case 0x07:
   110           switch (revision) {
   111             case 0x23:
   112               chip = Chip.F71889F;
   113               logicalDeviceNumber = FINTEK_HARDWARE_MONITOR_LDN;
   114               break;
   115           } break;
   116         case 0x08:
   117           switch (revision) {
   118             case 0x14:
   119               chip = Chip.F71869;
   120               logicalDeviceNumber = FINTEK_HARDWARE_MONITOR_LDN;
   121               break;
   122           } break;
   123         case 0x09:
   124           switch (revision) {
   125             case 0x01:
   126               chip = Chip.F71808E;
   127               logicalDeviceNumber = FINTEK_HARDWARE_MONITOR_LDN;
   128               break;
   129             case 0x09:
   130               chip = Chip.F71889ED;
   131               logicalDeviceNumber = FINTEK_HARDWARE_MONITOR_LDN;
   132               break;
   133           } break;
   134         case 0x10:
   135           switch (revision) {
   136             case 0x05:
   137               chip = Chip.F71889AD;
   138               logicalDeviceNumber = FINTEK_HARDWARE_MONITOR_LDN;
   139               break;
   140           } break;
   141         case 0x52:
   142           switch (revision) {
   143             case 0x17:
   144             case 0x3A:
   145             case 0x41:
   146               chip = Chip.W83627HF;
   147               logicalDeviceNumber = WINBOND_NUVOTON_HARDWARE_MONITOR_LDN;
   148               break;
   149           } break;
   150         case 0x82:
   151           switch (revision & 0xF0) {
   152             case 0x80:
   153               chip = Chip.W83627THF;
   154               logicalDeviceNumber = WINBOND_NUVOTON_HARDWARE_MONITOR_LDN;
   155               break;
   156           } break;
   157         case 0x85:
   158           switch (revision) {
   159             case 0x41:
   160               chip = Chip.W83687THF;
   161               logicalDeviceNumber = WINBOND_NUVOTON_HARDWARE_MONITOR_LDN;
   162               break;
   163           } break;
   164         case 0x88:
   165           switch (revision & 0xF0) {
   166             case 0x50:
   167             case 0x60:
   168               chip = Chip.W83627EHF;
   169               logicalDeviceNumber = WINBOND_NUVOTON_HARDWARE_MONITOR_LDN;
   170               break;
   171           } break;
   172         case 0xA0:
   173           switch (revision & 0xF0) {
   174             case 0x20:
   175               chip = Chip.W83627DHG;
   176               logicalDeviceNumber = WINBOND_NUVOTON_HARDWARE_MONITOR_LDN;
   177               break;
   178           } break;
   179         case 0xA5:
   180           switch (revision & 0xF0) {
   181             case 0x10:
   182               chip = Chip.W83667HG;
   183               logicalDeviceNumber = WINBOND_NUVOTON_HARDWARE_MONITOR_LDN;
   184               break;
   185           } break;
   186         case 0xB0:
   187           switch (revision & 0xF0) {
   188             case 0x70:
   189               chip = Chip.W83627DHGP;
   190               logicalDeviceNumber = WINBOND_NUVOTON_HARDWARE_MONITOR_LDN;
   191               break;
   192           } break;
   193         case 0xB3:
   194           switch (revision & 0xF0) {
   195             case 0x50:
   196               chip = Chip.W83667HGB;
   197               logicalDeviceNumber = WINBOND_NUVOTON_HARDWARE_MONITOR_LDN;
   198               break;
   199           } break;
   200         case 0xB4:
   201           switch (revision & 0xF0) {
   202             case 0x70:
   203               chip = Chip.NCT6771F;
   204               logicalDeviceNumber = WINBOND_NUVOTON_HARDWARE_MONITOR_LDN;
   205               break;
   206           } break;
   207         case 0xC3:
   208           switch (revision & 0xF0) {
   209             case 0x30:
   210               chip = Chip.NCT6776F;
   211               logicalDeviceNumber = WINBOND_NUVOTON_HARDWARE_MONITOR_LDN;
   212               break;
   213           } break;
   214         case 0xC5:
   215           switch (revision & 0xF0) {
   216             case 0x60:
   217               chip = Chip.NCT6779D;
   218               logicalDeviceNumber = WINBOND_NUVOTON_HARDWARE_MONITOR_LDN;
   219               break;
   220           } break;
   221       }
   222       if (chip == Chip.Unknown) {
   223         if (id != 0 && id != 0xff) {
   224           WinbondNuvotonFintekExit();
   225 
   226           ReportUnknownChip("Winbond / Nuvoton / Fintek", 
   227             ((id << 8) | revision));
   228         }
   229       } else {
   230 
   231         Select(logicalDeviceNumber);
   232         ushort address = ReadWord(BASE_ADDRESS_REGISTER);
   233         Thread.Sleep(1);
   234         ushort verify = ReadWord(BASE_ADDRESS_REGISTER);
   235 
   236         ushort vendorID = ReadWord(FINTEK_VENDOR_ID_REGISTER);
   237 
   238         WinbondNuvotonFintekExit();
   239 
   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");
   247           report.AppendLine();
   248           return false;
   249         }
   250 
   251         // some Fintek chips have address register offset 0x05 added already
   252         if ((address & 0x07) == 0x05)
   253           address &= 0xFFF8;
   254 
   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));
   264           report.AppendLine();
   265           return false;
   266         }
   267 
   268         switch (chip) {
   269           case Chip.W83627DHG:
   270           case Chip.W83627DHGP:
   271           case Chip.W83627EHF:
   272           case Chip.W83627HF:
   273           case Chip.W83627THF:
   274           case Chip.W83667HG:
   275           case Chip.W83667HGB:
   276           case Chip.W83687THF:
   277             superIOs.Add(new W836XX(chip, revision, address));
   278             break;
   279           case Chip.NCT6771F:
   280           case Chip.NCT6776F:
   281           case Chip.NCT6779D:
   282             superIOs.Add(new NCT677X(chip, revision, address));
   283             break;
   284           case Chip.F71858:
   285           case Chip.F71862:
   286           case Chip.F71869:
   287           case Chip.F71882:
   288           case Chip.F71889AD:
   289           case Chip.F71889ED:
   290           case Chip.F71889F:
   291           case Chip.F71808E:
   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));
   301               report.AppendLine();
   302               return false;
   303             }
   304             superIOs.Add(new F718XX(chip, address));
   305             break;
   306           default: break;
   307         }
   308 
   309         return true;
   310       }
   311 
   312       return false;
   313     }
   314 
   315     #endregion
   316 
   317     #region ITE
   318 
   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;
   323 
   324     private void IT87Enter() {
   325       Ring0.WriteIoPort(registerPort, 0x87);
   326       Ring0.WriteIoPort(registerPort, 0x01);
   327       Ring0.WriteIoPort(registerPort, 0x55);
   328       Ring0.WriteIoPort(registerPort, 0x55);
   329     }
   330 
   331     private void IT87Exit() {
   332       Ring0.WriteIoPort(registerPort, CONFIGURATION_CONTROL_REGISTER);
   333       Ring0.WriteIoPort(valuePort, 0x02);
   334     }
   335 
   336     private bool DetectIT87() {
   337 
   338       // IT87XX can enter only on port 0x2E
   339       if (registerPort != 0x2E)
   340         return false;
   341 
   342       IT87Enter();
   343 
   344       ushort chipID = ReadWord(CHIP_ID_REGISTER);
   345       Chip chip;
   346       switch (chipID) {
   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;
   358       }
   359       if (chip == Chip.Unknown) {
   360         if (chipID != 0 && chipID != 0xffff) {
   361           IT87Exit();
   362 
   363           ReportUnknownChip("ITE", chipID);
   364         }
   365       } else {
   366         Select(IT87_ENVIRONMENT_CONTROLLER_LDN);
   367         ushort address = ReadWord(BASE_ADDRESS_REGISTER);
   368         Thread.Sleep(1);
   369         ushort verify = ReadWord(BASE_ADDRESS_REGISTER);
   370 
   371         byte version = (byte)(ReadByte(IT87_CHIP_VERSION_REGISTER) & 0x0F);
   372 
   373         ushort gpioAddress;
   374         ushort gpioVerify;
   375         if (chip == Chip.IT8705F) {
   376           Select(IT8705_GPIO_LDN);
   377           gpioAddress = ReadWord(BASE_ADDRESS_REGISTER);
   378           Thread.Sleep(1);
   379           gpioVerify = ReadWord(BASE_ADDRESS_REGISTER);
   380         } else {
   381           Select(IT87XX_GPIO_LDN);
   382           gpioAddress = ReadWord(BASE_ADDRESS_REGISTER + 2);
   383           Thread.Sleep(1);
   384           gpioVerify = ReadWord(BASE_ADDRESS_REGISTER + 2);
   385         }
   386         
   387         IT87Exit();
   388 
   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));
   395           report.AppendLine();
   396           return false;
   397         }
   398 
   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));
   406           report.AppendLine();
   407           return false;
   408         }
   409 
   410         superIOs.Add(new IT87XX(chip, address, gpioAddress, version));
   411         return true;
   412       }
   413 
   414       return false;
   415     }
   416 
   417     #endregion
   418 
   419     #region SMSC
   420 
   421     private void SMSCEnter() {
   422       Ring0.WriteIoPort(registerPort, 0x55);
   423     }
   424 
   425     private void SMSCExit() {
   426       Ring0.WriteIoPort(registerPort, 0xAA);
   427     }
   428 
   429     private bool DetectSMSC() {
   430       SMSCEnter();
   431 
   432       ushort chipID = ReadWord(CHIP_ID_REGISTER);
   433       Chip chip;
   434       switch (chipID) {
   435         default: chip = Chip.Unknown; break;
   436       }
   437       if (chip == Chip.Unknown) {
   438         if (chipID != 0 && chipID != 0xffff) {
   439           SMSCExit();
   440 
   441           ReportUnknownChip("SMSC", chipID);
   442         }
   443       } else {
   444         SMSCExit();
   445         return true;
   446       }
   447 
   448       return false;
   449     }
   450 
   451     #endregion
   452 
   453     private void Detect() {
   454 
   455       for (int i = 0; i < REGISTER_PORTS.Length; i++) {
   456         registerPort = REGISTER_PORTS[i];
   457         valuePort = VALUE_PORTS[i];
   458 
   459         if (DetectWinbondFintek()) continue;
   460 
   461         if (DetectIT87()) continue;
   462 
   463         if (DetectSMSC()) continue;
   464       }
   465     }
   466 
   467     public LPCIO() {
   468       if (!Ring0.IsOpen)
   469         return;
   470 
   471       if (!Ring0.WaitIsaBusMutex(100))
   472         return;
   473 
   474       Detect();
   475 
   476       Ring0.ReleaseIsaBusMutex();
   477     }
   478 
   479     public ISuperIO[] SuperIO {
   480       get {
   481         return superIOs.ToArray();
   482       }
   483     }
   484 
   485     public string GetReport() {
   486       if (report.Length > 0) {
   487         return "LPCIO" + Environment.NewLine + Environment.NewLine + report;
   488       } else
   489         return null;
   490     }
   491   }
   492 }