Hardware/LPC/LPCIO.cs
author moel.mich
Sun, 27 May 2012 14:23:31 +0000
changeset 344 3145aadca3d2
parent 341 5172a92c5c20
child 352 0899f651d5cf
permissions -rw-r--r--
Changed the license to the Mozilla Public License 2.0 and update the licensing information.
     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 0x09:
   126               chip = Chip.F71889ED;
   127               logicalDeviceNumber = FINTEK_HARDWARE_MONITOR_LDN;
   128               break;
   129           } break;
   130         case 0x10:
   131           switch (revision) {
   132             case 0x05:
   133               chip = Chip.F71889AD;
   134               logicalDeviceNumber = FINTEK_HARDWARE_MONITOR_LDN;
   135               break;
   136           } break;
   137         case 0x52:
   138           switch (revision) {
   139             case 0x17:
   140             case 0x3A:
   141             case 0x41:
   142               chip = Chip.W83627HF;
   143               logicalDeviceNumber = WINBOND_NUVOTON_HARDWARE_MONITOR_LDN;
   144               break;
   145           } break;
   146         case 0x82:
   147           switch (revision & 0xF0) {
   148             case 0x80:
   149               chip = Chip.W83627THF;
   150               logicalDeviceNumber = WINBOND_NUVOTON_HARDWARE_MONITOR_LDN;
   151               break;
   152           } break;
   153         case 0x85:
   154           switch (revision) {
   155             case 0x41:
   156               chip = Chip.W83687THF;
   157               logicalDeviceNumber = WINBOND_NUVOTON_HARDWARE_MONITOR_LDN;
   158               break;
   159           } break;
   160         case 0x88:
   161           switch (revision & 0xF0) {
   162             case 0x50:
   163             case 0x60:
   164               chip = Chip.W83627EHF;
   165               logicalDeviceNumber = WINBOND_NUVOTON_HARDWARE_MONITOR_LDN;
   166               break;
   167           } break;
   168         case 0xA0:
   169           switch (revision & 0xF0) {
   170             case 0x20:
   171               chip = Chip.W83627DHG;
   172               logicalDeviceNumber = WINBOND_NUVOTON_HARDWARE_MONITOR_LDN;
   173               break;
   174           } break;
   175         case 0xA5:
   176           switch (revision & 0xF0) {
   177             case 0x10:
   178               chip = Chip.W83667HG;
   179               logicalDeviceNumber = WINBOND_NUVOTON_HARDWARE_MONITOR_LDN;
   180               break;
   181           } break;
   182         case 0xB0:
   183           switch (revision & 0xF0) {
   184             case 0x70:
   185               chip = Chip.W83627DHGP;
   186               logicalDeviceNumber = WINBOND_NUVOTON_HARDWARE_MONITOR_LDN;
   187               break;
   188           } break;
   189         case 0xB3:
   190           switch (revision & 0xF0) {
   191             case 0x50:
   192               chip = Chip.W83667HGB;
   193               logicalDeviceNumber = WINBOND_NUVOTON_HARDWARE_MONITOR_LDN;
   194               break;
   195           } break;
   196         case 0xB4:
   197           switch (revision & 0xF0) {
   198             case 0x70:
   199               chip = Chip.NCT6771F;
   200               logicalDeviceNumber = WINBOND_NUVOTON_HARDWARE_MONITOR_LDN;
   201               break;
   202           } break;
   203         case 0xC3:
   204           switch (revision & 0xF0) {
   205             case 0x30:
   206               chip = Chip.NCT6776F;
   207               logicalDeviceNumber = WINBOND_NUVOTON_HARDWARE_MONITOR_LDN;
   208               break;
   209           } break;
   210       }
   211       if (chip == Chip.Unknown) {
   212         if (id != 0 && id != 0xff) {
   213           WinbondNuvotonFintekExit();
   214 
   215           ReportUnknownChip("Winbond / Nuvoton / Fintek", 
   216             ((id << 8) | revision));
   217         }
   218       } else {
   219 
   220         Select(logicalDeviceNumber);
   221         ushort address = ReadWord(BASE_ADDRESS_REGISTER);
   222         Thread.Sleep(1);
   223         ushort verify = ReadWord(BASE_ADDRESS_REGISTER);
   224 
   225         ushort vendorID = ReadWord(FINTEK_VENDOR_ID_REGISTER);
   226 
   227         WinbondNuvotonFintekExit();
   228 
   229         if (address != verify) {
   230           report.Append("Chip ID: 0x");
   231           report.AppendLine(chip.ToString("X"));
   232           report.Append("Chip revision: 0x");
   233           report.AppendLine(revision.ToString("X",
   234             CultureInfo.InvariantCulture));
   235           report.AppendLine("Error: Address verification failed");
   236           report.AppendLine();
   237           return false;
   238         }
   239 
   240         // some Fintek chips have address register offset 0x05 added already
   241         if ((address & 0x07) == 0x05)
   242           address &= 0xFFF8;
   243 
   244         if (address < 0x100 || (address & 0xF007) != 0) {
   245           report.Append("Chip ID: 0x");
   246           report.AppendLine(chip.ToString("X"));
   247           report.Append("Chip revision: 0x");
   248           report.AppendLine(revision.ToString("X",
   249             CultureInfo.InvariantCulture));
   250           report.Append("Error: Invalid address 0x");
   251           report.AppendLine(address.ToString("X",
   252             CultureInfo.InvariantCulture));
   253           report.AppendLine();
   254           return false;
   255         }
   256 
   257         switch (chip) {
   258           case Chip.W83627DHG:
   259           case Chip.W83627DHGP:
   260           case Chip.W83627EHF:
   261           case Chip.W83627HF:
   262           case Chip.W83627THF:
   263           case Chip.W83667HG:
   264           case Chip.W83667HGB:
   265           case Chip.W83687THF:
   266             superIOs.Add(new W836XX(chip, revision, address));
   267             break;
   268           case Chip.NCT6771F:
   269           case Chip.NCT6776F:
   270             superIOs.Add(new NCT677X(chip, revision, address));
   271             break;
   272           case Chip.F71858:
   273           case Chip.F71862:
   274           case Chip.F71869:
   275           case Chip.F71882:
   276           case Chip.F71889AD:
   277           case Chip.F71889ED:
   278           case Chip.F71889F:
   279             if (vendorID != FINTEK_VENDOR_ID) {
   280               report.Append("Chip ID: 0x");
   281               report.AppendLine(chip.ToString("X"));
   282               report.Append("Chip revision: 0x");
   283               report.AppendLine(revision.ToString("X",
   284                 CultureInfo.InvariantCulture));
   285               report.Append("Error: Invalid vendor ID 0x");
   286               report.AppendLine(vendorID.ToString("X",
   287                 CultureInfo.InvariantCulture));
   288               report.AppendLine();
   289               return false;
   290             }
   291             superIOs.Add(new F718XX(chip, address));
   292             break;
   293           default: break;
   294         }
   295 
   296         return true;
   297       }
   298 
   299       return false;
   300     }
   301 
   302     #endregion
   303 
   304     #region ITE
   305 
   306     private const byte IT87_ENVIRONMENT_CONTROLLER_LDN = 0x04;
   307     private const byte IT87_GPIO_LDN = 0x07;
   308     private const byte IT87_CHIP_VERSION_REGISTER = 0x22;
   309 
   310     private void IT87Enter() {
   311       Ring0.WriteIoPort(registerPort, 0x87);
   312       Ring0.WriteIoPort(registerPort, 0x01);
   313       Ring0.WriteIoPort(registerPort, 0x55);
   314       Ring0.WriteIoPort(registerPort, 0x55);
   315     }
   316 
   317     private void IT87Exit() {
   318       Ring0.WriteIoPort(registerPort, CONFIGURATION_CONTROL_REGISTER);
   319       Ring0.WriteIoPort(valuePort, 0x02);
   320     }
   321 
   322     private bool DetectIT87() {
   323 
   324       // IT87XX can enter only on port 0x2E
   325       if (registerPort != 0x2E)
   326         return false;
   327 
   328       IT87Enter();
   329 
   330       ushort chipID = ReadWord(CHIP_ID_REGISTER);
   331       Chip chip;
   332       switch (chipID) {
   333         case 0x8712: chip = Chip.IT8712F; break;
   334         case 0x8716: chip = Chip.IT8716F; break;
   335         case 0x8718: chip = Chip.IT8718F; break;
   336         case 0x8720: chip = Chip.IT8720F; break;
   337         case 0x8721: chip = Chip.IT8721F; break;
   338         case 0x8726: chip = Chip.IT8726F; break;
   339         case 0x8728: chip = Chip.IT8728F; break;
   340         case 0x8771: chip = Chip.IT8771E; break;
   341         case 0x8772: chip = Chip.IT8772E; break;
   342         default: chip = Chip.Unknown; break;
   343       }
   344       if (chip == Chip.Unknown) {
   345         if (chipID != 0 && chipID != 0xffff) {
   346           IT87Exit();
   347 
   348           ReportUnknownChip("ITE", chipID);
   349         }
   350       } else {
   351         Select(IT87_ENVIRONMENT_CONTROLLER_LDN);
   352         ushort address = ReadWord(BASE_ADDRESS_REGISTER);
   353         Thread.Sleep(1);
   354         ushort verify = ReadWord(BASE_ADDRESS_REGISTER);
   355 
   356         byte version = (byte)(ReadByte(IT87_CHIP_VERSION_REGISTER) & 0x0F);
   357 
   358         Select(IT87_GPIO_LDN);
   359         ushort gpioAddress = ReadWord(BASE_ADDRESS_REGISTER + 2);
   360         Thread.Sleep(1);
   361         ushort gpioVerify = ReadWord(BASE_ADDRESS_REGISTER + 2);
   362 
   363         IT87Exit();
   364 
   365         if (address != verify || address < 0x100 || (address & 0xF007) != 0) {
   366           report.Append("Chip ID: 0x");
   367           report.AppendLine(chip.ToString("X"));
   368           report.Append("Error: Invalid address 0x");
   369           report.AppendLine(address.ToString("X",
   370             CultureInfo.InvariantCulture));
   371           report.AppendLine();
   372           return false;
   373         }
   374 
   375         if (gpioAddress != gpioVerify || gpioAddress < 0x100 ||
   376           (gpioAddress & 0xF007) != 0) {
   377           report.Append("Chip ID: 0x");
   378           report.AppendLine(chip.ToString("X"));
   379           report.Append("Error: Invalid GPIO address 0x");
   380           report.AppendLine(gpioAddress.ToString("X",
   381             CultureInfo.InvariantCulture));
   382           report.AppendLine();
   383           return false;
   384         }
   385 
   386         superIOs.Add(new IT87XX(chip, address, gpioAddress, version));
   387         return true;
   388       }
   389 
   390       return false;
   391     }
   392 
   393     #endregion
   394 
   395     #region SMSC
   396 
   397     private void SMSCEnter() {
   398       Ring0.WriteIoPort(registerPort, 0x55);
   399     }
   400 
   401     private void SMSCExit() {
   402       Ring0.WriteIoPort(registerPort, 0xAA);
   403     }
   404 
   405     private bool DetectSMSC() {
   406       SMSCEnter();
   407 
   408       ushort chipID = ReadWord(CHIP_ID_REGISTER);
   409       Chip chip;
   410       switch (chipID) {
   411         default: chip = Chip.Unknown; break;
   412       }
   413       if (chip == Chip.Unknown) {
   414         if (chipID != 0 && chipID != 0xffff) {
   415           SMSCExit();
   416 
   417           ReportUnknownChip("SMSC", chipID);
   418         }
   419       } else {
   420         SMSCExit();
   421         return true;
   422       }
   423 
   424       return false;
   425     }
   426 
   427     #endregion
   428 
   429     private void Detect() {
   430 
   431       for (int i = 0; i < REGISTER_PORTS.Length; i++) {
   432         registerPort = REGISTER_PORTS[i];
   433         valuePort = VALUE_PORTS[i];
   434 
   435         if (DetectWinbondFintek()) continue;
   436 
   437         if (DetectIT87()) continue;
   438 
   439         if (DetectSMSC()) continue;
   440       }
   441     }
   442 
   443     public LPCIO() {
   444       if (!Ring0.IsOpen)
   445         return;
   446 
   447       if (!Ring0.WaitIsaBusMutex(100))
   448         return;
   449 
   450       Detect();
   451 
   452       Ring0.ReleaseIsaBusMutex();
   453     }
   454 
   455     public ISuperIO[] SuperIO {
   456       get {
   457         return superIOs.ToArray();
   458       }
   459     }
   460 
   461     public string GetReport() {
   462       if (report.Length > 0) {
   463         return "LPCIO" + Environment.NewLine + Environment.NewLine + report;
   464       } else
   465         return null;
   466     }
   467   }
   468 }