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