Hardware/LPC/LPCIO.cs
author StephaneLenclud
Thu, 18 Apr 2013 23:25:10 +0200
branchMiniDisplay
changeset 444 9b09e2ee0968
parent 413 362c5e77197d
child 454 f84878f52cd9
permissions -rw-r--r--
Front View plug-in does not init if no sensor added.
Fixing some format to make strings shorter.
Now trying to start SoundGraphAccess.exe process from same directory.
Packed mode now can display three sensors along with the current time.
     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 void WriteByte(byte register, byte value) {
    43       Ring0.WriteIoPort(registerPort, register);
    44       Ring0.WriteIoPort(valuePort, value);
    45     }
    46 
    47     private ushort ReadWord(byte register) {
    48       return (ushort)((ReadByte(register) << 8) |
    49         ReadByte((byte)(register + 1)));
    50     }
    51 
    52     private void Select(byte logicalDeviceNumber) {
    53       Ring0.WriteIoPort(registerPort, DEVCIE_SELECT_REGISTER);
    54       Ring0.WriteIoPort(valuePort, logicalDeviceNumber);
    55     }
    56 
    57     private void ReportUnknownChip(string type, int chip) {
    58       report.Append("Chip ID: Unknown ");
    59       report.Append(type);
    60       report.Append(" with ID 0x");
    61       report.Append(chip.ToString("X", CultureInfo.InvariantCulture));
    62       report.Append(" at 0x");
    63       report.Append(registerPort.ToString("X", CultureInfo.InvariantCulture));
    64       report.Append("/0x");
    65       report.AppendLine(valuePort.ToString("X", CultureInfo.InvariantCulture));
    66       report.AppendLine();
    67     }
    68 
    69     #region Winbond, Nuvoton, Fintek
    70 
    71     private const byte FINTEK_VENDOR_ID_REGISTER = 0x23;
    72     private const ushort FINTEK_VENDOR_ID = 0x1934;
    73 
    74     private const byte WINBOND_NUVOTON_HARDWARE_MONITOR_LDN = 0x0B;
    75 
    76     private const byte F71858_HARDWARE_MONITOR_LDN = 0x02;
    77     private const byte FINTEK_HARDWARE_MONITOR_LDN = 0x04;
    78 
    79     private const byte NUVOTON_HARDWARE_MONITOR_IO_SPACE_LOCK = 0x28;
    80 
    81     private void WinbondNuvotonFintekEnter() {
    82       Ring0.WriteIoPort(registerPort, 0x87);
    83       Ring0.WriteIoPort(registerPort, 0x87);
    84     }
    85 
    86     private void WinbondNuvotonFintekExit() {
    87       Ring0.WriteIoPort(registerPort, 0xAA);
    88     }
    89 
    90     private bool DetectWinbondFintek() {
    91       WinbondNuvotonFintekEnter();
    92 
    93       byte logicalDeviceNumber = 0;
    94       byte id = ReadByte(CHIP_ID_REGISTER);
    95       byte revision = ReadByte(CHIP_REVISION_REGISTER);
    96       Chip chip = Chip.Unknown;
    97       switch (id) {
    98         case 0x05:
    99           switch (revision) {
   100             case 0x07:
   101               chip = Chip.F71858;
   102               logicalDeviceNumber = F71858_HARDWARE_MONITOR_LDN;
   103               break;
   104             case 0x41:
   105               chip = Chip.F71882;
   106               logicalDeviceNumber = FINTEK_HARDWARE_MONITOR_LDN;
   107               break;
   108           } break;
   109         case 0x06:
   110           switch (revision) {
   111             case 0x01:
   112               chip = Chip.F71862;
   113               logicalDeviceNumber = FINTEK_HARDWARE_MONITOR_LDN;
   114               break;
   115           } break;
   116         case 0x07:
   117           switch (revision) {
   118             case 0x23:
   119               chip = Chip.F71889F;
   120               logicalDeviceNumber = FINTEK_HARDWARE_MONITOR_LDN;
   121               break;
   122           } break;
   123         case 0x08:
   124           switch (revision) {
   125             case 0x14:
   126               chip = Chip.F71869;
   127               logicalDeviceNumber = FINTEK_HARDWARE_MONITOR_LDN;
   128               break;
   129           } break;
   130         case 0x09:
   131           switch (revision) {
   132             case 0x01:
   133               chip = Chip.F71808E;
   134               logicalDeviceNumber = FINTEK_HARDWARE_MONITOR_LDN;
   135               break;
   136             case 0x09:
   137               chip = Chip.F71889ED;
   138               logicalDeviceNumber = FINTEK_HARDWARE_MONITOR_LDN;
   139               break;
   140           } break;
   141         case 0x10:
   142           switch (revision) {
   143             case 0x05:
   144               chip = Chip.F71889AD;
   145               logicalDeviceNumber = FINTEK_HARDWARE_MONITOR_LDN;
   146               break;
   147             case 0x07:
   148               chip = Chip.F71869A;
   149               logicalDeviceNumber = FINTEK_HARDWARE_MONITOR_LDN;
   150               break;
   151           } break;
   152         case 0x52:
   153           switch (revision) {
   154             case 0x17:
   155             case 0x3A:
   156             case 0x41:
   157               chip = Chip.W83627HF;
   158               logicalDeviceNumber = WINBOND_NUVOTON_HARDWARE_MONITOR_LDN;
   159               break;
   160           } break;
   161         case 0x82:
   162           switch (revision & 0xF0) {
   163             case 0x80:
   164               chip = Chip.W83627THF;
   165               logicalDeviceNumber = WINBOND_NUVOTON_HARDWARE_MONITOR_LDN;
   166               break;
   167           } break;
   168         case 0x85:
   169           switch (revision) {
   170             case 0x41:
   171               chip = Chip.W83687THF;
   172               logicalDeviceNumber = WINBOND_NUVOTON_HARDWARE_MONITOR_LDN;
   173               break;
   174           } break;
   175         case 0x88:
   176           switch (revision & 0xF0) {
   177             case 0x50:
   178             case 0x60:
   179               chip = Chip.W83627EHF;
   180               logicalDeviceNumber = WINBOND_NUVOTON_HARDWARE_MONITOR_LDN;
   181               break;
   182           } break;
   183         case 0xA0:
   184           switch (revision & 0xF0) {
   185             case 0x20:
   186               chip = Chip.W83627DHG;
   187               logicalDeviceNumber = WINBOND_NUVOTON_HARDWARE_MONITOR_LDN;
   188               break;
   189           } break;
   190         case 0xA5:
   191           switch (revision & 0xF0) {
   192             case 0x10:
   193               chip = Chip.W83667HG;
   194               logicalDeviceNumber = WINBOND_NUVOTON_HARDWARE_MONITOR_LDN;
   195               break;
   196           } break;
   197         case 0xB0:
   198           switch (revision & 0xF0) {
   199             case 0x70:
   200               chip = Chip.W83627DHGP;
   201               logicalDeviceNumber = WINBOND_NUVOTON_HARDWARE_MONITOR_LDN;
   202               break;
   203           } break;
   204         case 0xB3:
   205           switch (revision & 0xF0) {
   206             case 0x50:
   207               chip = Chip.W83667HGB;
   208               logicalDeviceNumber = WINBOND_NUVOTON_HARDWARE_MONITOR_LDN;
   209               break;
   210           } break;
   211         case 0xB4:
   212           switch (revision & 0xF0) {
   213             case 0x70:
   214               chip = Chip.NCT6771F;
   215               logicalDeviceNumber = WINBOND_NUVOTON_HARDWARE_MONITOR_LDN;
   216               break;
   217           } break;
   218         case 0xC3:
   219           switch (revision & 0xF0) {
   220             case 0x30:
   221               chip = Chip.NCT6776F;
   222               logicalDeviceNumber = WINBOND_NUVOTON_HARDWARE_MONITOR_LDN;
   223               break;
   224           } break;
   225         case 0xC5:
   226           switch (revision & 0xF0) {
   227             case 0x60:
   228               chip = Chip.NCT6779D;
   229               logicalDeviceNumber = WINBOND_NUVOTON_HARDWARE_MONITOR_LDN;
   230               break;
   231           } break;
   232         case 0xC8:
   233           switch (revision) {
   234             case 0x03:
   235               chip = Chip.NCT6791D;
   236               logicalDeviceNumber = WINBOND_NUVOTON_HARDWARE_MONITOR_LDN;
   237               break;
   238           } break;
   239       }
   240       if (chip == Chip.Unknown) {
   241         if (id != 0 && id != 0xff) {
   242           WinbondNuvotonFintekExit();
   243 
   244           ReportUnknownChip("Winbond / Nuvoton / Fintek", 
   245             ((id << 8) | revision));
   246         }
   247       } else {
   248 
   249         Select(logicalDeviceNumber);
   250         ushort address = ReadWord(BASE_ADDRESS_REGISTER);
   251         Thread.Sleep(1);
   252         ushort verify = ReadWord(BASE_ADDRESS_REGISTER);
   253 
   254         ushort vendorID = ReadWord(FINTEK_VENDOR_ID_REGISTER);
   255 
   256         // disable the hardware monitor i/o space lock on NCT6791D chips
   257         if (address == verify && chip == Chip.NCT6791D) {
   258           byte options = ReadByte(NUVOTON_HARDWARE_MONITOR_IO_SPACE_LOCK);
   259 
   260           // if the i/o space lock is enabled
   261           if ((options & 0x10) > 0) {
   262 
   263             // disable the i/o space lock
   264             WriteByte(NUVOTON_HARDWARE_MONITOR_IO_SPACE_LOCK,
   265               (byte)(options & ~0x10));
   266           }
   267         }
   268 
   269         WinbondNuvotonFintekExit();
   270 
   271         if (address != verify) {
   272           report.Append("Chip ID: 0x");
   273           report.AppendLine(chip.ToString("X"));
   274           report.Append("Chip revision: 0x");
   275           report.AppendLine(revision.ToString("X",
   276             CultureInfo.InvariantCulture));
   277           report.AppendLine("Error: Address verification failed");
   278           report.AppendLine();
   279           return false;
   280         }
   281 
   282         // some Fintek chips have address register offset 0x05 added already
   283         if ((address & 0x07) == 0x05)
   284           address &= 0xFFF8;
   285 
   286         if (address < 0x100 || (address & 0xF007) != 0) {
   287           report.Append("Chip ID: 0x");
   288           report.AppendLine(chip.ToString("X"));
   289           report.Append("Chip revision: 0x");
   290           report.AppendLine(revision.ToString("X",
   291             CultureInfo.InvariantCulture));
   292           report.Append("Error: Invalid address 0x");
   293           report.AppendLine(address.ToString("X",
   294             CultureInfo.InvariantCulture));
   295           report.AppendLine();
   296           return false;
   297         }
   298 
   299         switch (chip) {
   300           case Chip.W83627DHG:
   301           case Chip.W83627DHGP:
   302           case Chip.W83627EHF:
   303           case Chip.W83627HF:
   304           case Chip.W83627THF:
   305           case Chip.W83667HG:
   306           case Chip.W83667HGB:
   307           case Chip.W83687THF:
   308             superIOs.Add(new W836XX(chip, revision, address));
   309             break;
   310           case Chip.NCT6771F:
   311           case Chip.NCT6776F:
   312           case Chip.NCT6779D:
   313           case Chip.NCT6791D:
   314             superIOs.Add(new NCT677X(chip, revision, address));
   315             break;
   316           case Chip.F71858:
   317           case Chip.F71862:
   318           case Chip.F71869:
   319           case Chip.F71869A:
   320           case Chip.F71882:
   321           case Chip.F71889AD:
   322           case Chip.F71889ED:
   323           case Chip.F71889F:
   324           case Chip.F71808E:
   325             if (vendorID != FINTEK_VENDOR_ID) {
   326               report.Append("Chip ID: 0x");
   327               report.AppendLine(chip.ToString("X"));
   328               report.Append("Chip revision: 0x");
   329               report.AppendLine(revision.ToString("X",
   330                 CultureInfo.InvariantCulture));
   331               report.Append("Error: Invalid vendor ID 0x");
   332               report.AppendLine(vendorID.ToString("X",
   333                 CultureInfo.InvariantCulture));
   334               report.AppendLine();
   335               return false;
   336             }
   337             superIOs.Add(new F718XX(chip, address));
   338             break;
   339           default: break;
   340         }
   341 
   342         return true;
   343       }
   344 
   345       return false;
   346     }
   347 
   348     #endregion
   349 
   350     #region ITE
   351 
   352     private const byte IT87_ENVIRONMENT_CONTROLLER_LDN = 0x04;
   353     private const byte IT8705_GPIO_LDN = 0x05;
   354     private const byte IT87XX_GPIO_LDN = 0x07;
   355     private const byte IT87_CHIP_VERSION_REGISTER = 0x22;
   356 
   357     private void IT87Enter() {
   358       Ring0.WriteIoPort(registerPort, 0x87);
   359       Ring0.WriteIoPort(registerPort, 0x01);
   360       Ring0.WriteIoPort(registerPort, 0x55);
   361       Ring0.WriteIoPort(registerPort, 0x55);
   362     }
   363 
   364     private void IT87Exit() {
   365       Ring0.WriteIoPort(registerPort, CONFIGURATION_CONTROL_REGISTER);
   366       Ring0.WriteIoPort(valuePort, 0x02);
   367     }
   368 
   369     private bool DetectIT87() {
   370 
   371       // IT87XX can enter only on port 0x2E
   372       if (registerPort != 0x2E)
   373         return false;
   374 
   375       IT87Enter();
   376 
   377       ushort chipID = ReadWord(CHIP_ID_REGISTER);
   378       Chip chip;
   379       switch (chipID) {
   380         case 0x8705: chip = Chip.IT8705F; break;
   381         case 0x8712: chip = Chip.IT8712F; break;
   382         case 0x8716: chip = Chip.IT8716F; break;
   383         case 0x8718: chip = Chip.IT8718F; break;
   384         case 0x8720: chip = Chip.IT8720F; break;
   385         case 0x8721: chip = Chip.IT8721F; break;
   386         case 0x8726: chip = Chip.IT8726F; break;
   387         case 0x8728: chip = Chip.IT8728F; break;
   388         case 0x8771: chip = Chip.IT8771E; break;
   389         case 0x8772: chip = Chip.IT8772E; break;
   390         default: chip = Chip.Unknown; break;
   391       }
   392       if (chip == Chip.Unknown) {
   393         if (chipID != 0 && chipID != 0xffff) {
   394           IT87Exit();
   395 
   396           ReportUnknownChip("ITE", chipID);
   397         }
   398       } else {
   399         Select(IT87_ENVIRONMENT_CONTROLLER_LDN);
   400         ushort address = ReadWord(BASE_ADDRESS_REGISTER);
   401         Thread.Sleep(1);
   402         ushort verify = ReadWord(BASE_ADDRESS_REGISTER);
   403 
   404         byte version = (byte)(ReadByte(IT87_CHIP_VERSION_REGISTER) & 0x0F);
   405 
   406         ushort gpioAddress;
   407         ushort gpioVerify;
   408         if (chip == Chip.IT8705F) {
   409           Select(IT8705_GPIO_LDN);
   410           gpioAddress = ReadWord(BASE_ADDRESS_REGISTER);
   411           Thread.Sleep(1);
   412           gpioVerify = ReadWord(BASE_ADDRESS_REGISTER);
   413         } else {
   414           Select(IT87XX_GPIO_LDN);
   415           gpioAddress = ReadWord(BASE_ADDRESS_REGISTER + 2);
   416           Thread.Sleep(1);
   417           gpioVerify = ReadWord(BASE_ADDRESS_REGISTER + 2);
   418         }
   419         
   420         IT87Exit();
   421 
   422         if (address != verify || address < 0x100 || (address & 0xF007) != 0) {
   423           report.Append("Chip ID: 0x");
   424           report.AppendLine(chip.ToString("X"));
   425           report.Append("Error: Invalid address 0x");
   426           report.AppendLine(address.ToString("X",
   427             CultureInfo.InvariantCulture));
   428           report.AppendLine();
   429           return false;
   430         }
   431 
   432         if (gpioAddress != gpioVerify || gpioAddress < 0x100 ||
   433           (gpioAddress & 0xF007) != 0) {
   434           report.Append("Chip ID: 0x");
   435           report.AppendLine(chip.ToString("X"));
   436           report.Append("Error: Invalid GPIO address 0x");
   437           report.AppendLine(gpioAddress.ToString("X",
   438             CultureInfo.InvariantCulture));
   439           report.AppendLine();
   440           return false;
   441         }
   442 
   443         superIOs.Add(new IT87XX(chip, address, gpioAddress, version));
   444         return true;
   445       }
   446 
   447       return false;
   448     }
   449 
   450     #endregion
   451 
   452     #region SMSC
   453 
   454     private void SMSCEnter() {
   455       Ring0.WriteIoPort(registerPort, 0x55);
   456     }
   457 
   458     private void SMSCExit() {
   459       Ring0.WriteIoPort(registerPort, 0xAA);
   460     }
   461 
   462     private bool DetectSMSC() {
   463       SMSCEnter();
   464 
   465       ushort chipID = ReadWord(CHIP_ID_REGISTER);
   466       Chip chip;
   467       switch (chipID) {
   468         default: chip = Chip.Unknown; break;
   469       }
   470       if (chip == Chip.Unknown) {
   471         if (chipID != 0 && chipID != 0xffff) {
   472           SMSCExit();
   473 
   474           ReportUnknownChip("SMSC", chipID);
   475         }
   476       } else {
   477         SMSCExit();
   478         return true;
   479       }
   480 
   481       return false;
   482     }
   483 
   484     #endregion
   485 
   486     private void Detect() {
   487 
   488       for (int i = 0; i < REGISTER_PORTS.Length; i++) {
   489         registerPort = REGISTER_PORTS[i];
   490         valuePort = VALUE_PORTS[i];
   491 
   492         if (DetectWinbondFintek()) continue;
   493 
   494         if (DetectIT87()) continue;
   495 
   496         if (DetectSMSC()) continue;
   497       }
   498     }
   499 
   500     public LPCIO() {
   501       if (!Ring0.IsOpen)
   502         return;
   503 
   504       if (!Ring0.WaitIsaBusMutex(100))
   505         return;
   506 
   507       Detect();
   508 
   509       Ring0.ReleaseIsaBusMutex();
   510     }
   511 
   512     public ISuperIO[] SuperIO {
   513       get {
   514         return superIOs.ToArray();
   515       }
   516     }
   517 
   518     public string GetReport() {
   519       if (report.Length > 0) {
   520         return "LPCIO" + Environment.NewLine + Environment.NewLine + report;
   521       } else
   522         return null;
   523     }
   524   }
   525 }