Hardware/LPC/LPCIO.cs
author paulwerelds
Tue, 21 Sep 2010 10:18:07 +0000
changeset 193 52ef1cf6b8e5
parent 169 3b2bcba8c02d
child 195 0ee888c485d5
permissions -rw-r--r--
Added thermal and voltage/frequency MSRs for K8 CPUs, fixed chars-per-line limit
     1 /*
     2   
     3   Version: MPL 1.1/GPL 2.0/LGPL 2.1
     4 
     5   The contents of this file are subject to the Mozilla Public License Version
     6   1.1 (the "License"); you may not use this file except in compliance with
     7   the License. You may obtain a copy of the License at
     8  
     9   http://www.mozilla.org/MPL/
    10 
    11   Software distributed under the License is distributed on an "AS IS" basis,
    12   WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
    13   for the specific language governing rights and limitations under the License.
    14 
    15   The Original Code is the Open Hardware Monitor code.
    16 
    17   The Initial Developer of the Original Code is 
    18   Michael Möller <m.moeller@gmx.ch>.
    19   Portions created by the Initial Developer are Copyright (C) 2009-2010
    20   the Initial Developer. All Rights Reserved.
    21 
    22   Contributor(s):
    23 
    24   Alternatively, the contents of this file may be used under the terms of
    25   either the GNU General Public License Version 2 or later (the "GPL"), or
    26   the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
    27   in which case the provisions of the GPL or the LGPL are applicable instead
    28   of those above. If you wish to allow use of your version of this file only
    29   under the terms of either the GPL or the LGPL, and not to allow others to
    30   use your version of this file under the terms of the MPL, indicate your
    31   decision by deleting the provisions above and replace them with the notice
    32   and other provisions required by the GPL or the LGPL. If you do not delete
    33   the provisions above, a recipient may use your version of this file under
    34   the terms of any one of the MPL, the GPL or the LGPL.
    35  
    36 */
    37 
    38 using System;
    39 using System.Collections.Generic;
    40 using System.Globalization;
    41 using System.Text;
    42 using System.Threading;
    43 
    44 namespace OpenHardwareMonitor.Hardware.LPC {
    45   internal class LPCIO {
    46 
    47     private List<ISuperIO> superIOs = new List<ISuperIO>();
    48     private StringBuilder report = new StringBuilder();
    49 
    50     // I/O Ports
    51     private ushort[] REGISTER_PORTS = new ushort[] { 0x2E, 0x4E };
    52     private ushort[] VALUE_PORTS = new ushort[] { 0x2F, 0x4F };
    53 
    54     private ushort registerPort;
    55     private ushort valuePort;
    56 
    57     // Registers
    58     private const byte CONFIGURATION_CONTROL_REGISTER = 0x02;
    59     private const byte DEVCIE_SELECT_REGISTER = 0x07;
    60     private const byte CHIP_ID_REGISTER = 0x20;
    61     private const byte CHIP_REVISION_REGISTER = 0x21;
    62     private const byte BASE_ADDRESS_REGISTER = 0x60;
    63 
    64     private byte ReadByte(byte register) {
    65       WinRing0.WriteIoPortByte(registerPort, register);
    66       return WinRing0.ReadIoPortByte(valuePort);
    67     } 
    68 
    69     private ushort ReadWord(byte register) {
    70       return (ushort)((ReadByte(register) << 8) | 
    71         ReadByte((byte)(register + 1)));
    72     }
    73 
    74     private void Select(byte logicalDeviceNumber) {
    75       WinRing0.WriteIoPortByte(registerPort, DEVCIE_SELECT_REGISTER);
    76       WinRing0.WriteIoPortByte(valuePort, logicalDeviceNumber);
    77     }
    78 
    79     private void ReportUnknownChip(string type, int chip) {
    80       report.Append("Chip ID: Unknown ");
    81       report.Append(type);
    82       report.Append(" with ID 0x");
    83       report.Append(chip.ToString("X", CultureInfo.InvariantCulture));
    84       report.Append(" at 0x");
    85       report.Append(registerPort.ToString("X", CultureInfo.InvariantCulture));
    86       report.Append("/0x");
    87       report.AppendLine(valuePort.ToString("X", CultureInfo.InvariantCulture));
    88       report.AppendLine();
    89     }
    90 
    91     #region Winbond, Fintek
    92 
    93     private const byte FINTEK_VENDOR_ID_REGISTER = 0x23;
    94     private const ushort FINTEK_VENDOR_ID = 0x1934;
    95 
    96     private const byte WINBOND_HARDWARE_MONITOR_LDN = 0x0B;
    97 
    98     private const byte F71858_HARDWARE_MONITOR_LDN = 0x02;
    99     private const byte FINTEK_HARDWARE_MONITOR_LDN = 0x04;
   100 
   101     private void WinbondFintekEnter() {
   102       WinRing0.WriteIoPortByte(registerPort, 0x87);
   103       WinRing0.WriteIoPortByte(registerPort, 0x87);
   104     }
   105 
   106     private void WinbondFintekExit() {
   107       WinRing0.WriteIoPortByte(registerPort, 0xAA);
   108     }
   109 
   110     private bool DetectWinbondFintek() {
   111       WinbondFintekEnter();
   112 
   113       byte logicalDeviceNumber;
   114       byte id = ReadByte(CHIP_ID_REGISTER);
   115       byte revision = ReadByte(CHIP_REVISION_REGISTER);
   116       Chip chip = Chip.Unknown;
   117       logicalDeviceNumber = 0;
   118       switch (id) {
   119         case 0x05:
   120           switch (revision) {
   121             case 0x07:
   122               chip = Chip.F71858;
   123               logicalDeviceNumber = F71858_HARDWARE_MONITOR_LDN;
   124               break;
   125             case 0x41:
   126               chip = Chip.F71882;
   127               logicalDeviceNumber = FINTEK_HARDWARE_MONITOR_LDN;
   128               break;
   129           } break;
   130         case 0x06:
   131           switch (revision) {
   132             case 0x01:
   133               chip = Chip.F71862;
   134               logicalDeviceNumber = FINTEK_HARDWARE_MONITOR_LDN;
   135               break;
   136           } break;
   137         case 0x07:
   138           switch (revision) {
   139             case 0x23:
   140               chip = Chip.F71889F;
   141               logicalDeviceNumber = FINTEK_HARDWARE_MONITOR_LDN;
   142               break;
   143           } break;
   144         case 0x08:
   145           switch (revision) {
   146             case 0x14:
   147               chip = Chip.F71869;
   148               logicalDeviceNumber = FINTEK_HARDWARE_MONITOR_LDN;
   149               break;
   150           } break;
   151         case 0x09:
   152           switch (revision) {
   153             case 0x09:
   154               chip = Chip.F71889ED;
   155               logicalDeviceNumber = FINTEK_HARDWARE_MONITOR_LDN;
   156               break;
   157           } break;
   158         case 0x52:
   159           switch (revision) {
   160             case 0x17:
   161             case 0x3A:
   162             case 0x41:
   163               chip = Chip.W83627HF;
   164               logicalDeviceNumber = WINBOND_HARDWARE_MONITOR_LDN;
   165               break;
   166           } break;
   167         case 0x82:
   168           switch (revision & 0xF0) {
   169             case 0x80:
   170               chip = Chip.W83627THF;
   171               logicalDeviceNumber = WINBOND_HARDWARE_MONITOR_LDN;
   172               break;
   173           } break;
   174         case 0x85:
   175           switch (revision) {
   176             case 0x41:
   177               chip = Chip.W83687THF;
   178               logicalDeviceNumber = WINBOND_HARDWARE_MONITOR_LDN;
   179               break;
   180           } break;
   181         case 0x88:
   182           switch (revision & 0xF0) {
   183             case 0x50:
   184             case 0x60:
   185               chip = Chip.W83627EHF;
   186               logicalDeviceNumber = WINBOND_HARDWARE_MONITOR_LDN;
   187               break;
   188           } break;
   189         case 0xA0:
   190           switch (revision & 0xF0) {
   191             case 0x20:
   192               chip = Chip.W83627DHG;
   193               logicalDeviceNumber = WINBOND_HARDWARE_MONITOR_LDN;
   194               break;
   195           } break;
   196         case 0xA5:
   197           switch (revision & 0xF0) {
   198             case 0x10:
   199               chip = Chip.W83667HG;
   200               logicalDeviceNumber = WINBOND_HARDWARE_MONITOR_LDN;
   201               break;
   202           } break;
   203         case 0xB0:
   204           switch (revision & 0xF0) {
   205             case 0x70:
   206               chip = Chip.W83627DHGP;
   207               logicalDeviceNumber = WINBOND_HARDWARE_MONITOR_LDN;
   208               break;
   209           } break;
   210         case 0xB3:
   211           switch (revision & 0xF0) {
   212             case 0x50:
   213               chip = Chip.W83667HGB;
   214               logicalDeviceNumber = WINBOND_HARDWARE_MONITOR_LDN;
   215               break;
   216           } break;
   217       }
   218       if (chip == Chip.Unknown) {
   219         if (id != 0 && id != 0xff) {
   220           WinbondFintekExit();
   221 
   222           ReportUnknownChip("Winbond / Fintek", ((id << 8) | revision));         
   223         }
   224       } else {
   225 
   226         Select(logicalDeviceNumber);
   227         ushort address = ReadWord(BASE_ADDRESS_REGISTER);
   228         Thread.Sleep(1);
   229         ushort verify = ReadWord(BASE_ADDRESS_REGISTER);
   230 
   231         ushort vendorID = ReadWord(FINTEK_VENDOR_ID_REGISTER);
   232 
   233         WinbondFintekExit();
   234 
   235         if (address != verify) {
   236           report.Append("Chip ID: 0x");
   237           report.AppendLine(chip.ToString("X"));
   238           report.Append("Chip revision: 0x");
   239           report.AppendLine(revision.ToString("X", 
   240             CultureInfo.InvariantCulture));
   241           report.AppendLine("Error: Address verification failed");
   242           report.AppendLine();
   243           return false;
   244         }
   245 
   246         // some Fintek chips have address register offset 0x05 added already
   247         if ((address & 0x07) == 0x05)
   248           address &= 0xFFF8;
   249 
   250         if (address < 0x100 || (address & 0xF007) != 0) {
   251           report.Append("Chip ID: 0x");
   252           report.AppendLine(chip.ToString("X"));
   253           report.Append("Chip revision: 0x");
   254           report.AppendLine(revision.ToString("X", 
   255             CultureInfo.InvariantCulture));
   256           report.Append("Error: Invalid address 0x");
   257           report.AppendLine(address.ToString("X", 
   258             CultureInfo.InvariantCulture));
   259           report.AppendLine();
   260           return false;
   261         }
   262 
   263         switch (chip) {
   264           case Chip.W83627DHG:
   265           case Chip.W83627DHGP:
   266           case Chip.W83627EHF:
   267           case Chip.W83627HF:
   268           case Chip.W83627THF:
   269           case Chip.W83667HG:
   270           case Chip.W83667HGB:
   271           case Chip.W83687THF:
   272             superIOs.Add(new W836XX(chip, revision, address));
   273             break;
   274           case Chip.F71858:
   275           case Chip.F71862:
   276           case Chip.F71869:
   277           case Chip.F71882:
   278           case Chip.F71889ED:
   279           case Chip.F71889F:
   280             if (vendorID != FINTEK_VENDOR_ID) {
   281               report.Append("Chip ID: 0x");
   282               report.AppendLine(chip.ToString("X"));
   283               report.Append("Chip revision: 0x");
   284               report.AppendLine(revision.ToString("X", 
   285                 CultureInfo.InvariantCulture));
   286               report.Append("Error: Invalid vendor ID 0x");
   287               report.AppendLine(vendorID.ToString("X", 
   288                 CultureInfo.InvariantCulture));
   289               report.AppendLine();
   290               return false;
   291             }
   292             superIOs.Add(new F718XX(chip, address));
   293             break;
   294           default: break;
   295         }
   296 
   297         return true;
   298       }
   299 
   300       return false;
   301     }
   302 
   303     #endregion
   304 
   305     #region ITE
   306 
   307     private const byte IT87_ENVIRONMENT_CONTROLLER_LDN = 0x04;
   308     private const byte IT87_CHIP_VERSION_REGISTER = 0x22;
   309 
   310     private void IT87Enter() {
   311       WinRing0.WriteIoPortByte(registerPort, 0x87);
   312       WinRing0.WriteIoPortByte(registerPort, 0x01);
   313       WinRing0.WriteIoPortByte(registerPort, 0x55);
   314       WinRing0.WriteIoPortByte(registerPort, 0x55);
   315     }
   316 
   317     private void IT87Exit() {
   318       WinRing0.WriteIoPortByte(registerPort, CONFIGURATION_CONTROL_REGISTER);
   319       WinRing0.WriteIoPortByte(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         default: chip = Chip.Unknown; break;
   340       }
   341       if (chip == Chip.Unknown) {
   342         if (chipID != 0 && chipID != 0xffff) {
   343           IT87Exit();
   344 
   345           ReportUnknownChip("ITE", chipID);
   346         }
   347       } else {
   348         Select(IT87_ENVIRONMENT_CONTROLLER_LDN);
   349         ushort address = ReadWord(BASE_ADDRESS_REGISTER);
   350         Thread.Sleep(1);
   351         ushort verify = ReadWord(BASE_ADDRESS_REGISTER);
   352 
   353         byte version = (byte)(ReadByte(IT87_CHIP_VERSION_REGISTER) & 0x0F);
   354 
   355         IT87Exit();
   356 
   357         if (address != verify || address < 0x100 || (address & 0xF007) != 0) {
   358           report.Append("Chip ID: 0x");
   359           report.AppendLine(chip.ToString("X"));
   360           report.Append("Error: Invalid address 0x");
   361           report.AppendLine(address.ToString("X",
   362             CultureInfo.InvariantCulture));
   363           report.AppendLine();
   364           return false;
   365         }
   366 
   367         superIOs.Add(new IT87XX(chip, address, version));
   368         return true;
   369       }
   370 
   371       return false;
   372     }
   373 
   374     #endregion
   375 
   376     #region SMSC
   377 
   378     private void SMSCEnter() {
   379       WinRing0.WriteIoPortByte(registerPort, 0x55);
   380     }
   381 
   382     private void SMSCExit() {
   383       WinRing0.WriteIoPortByte(registerPort, 0xAA);
   384     }
   385 
   386     private bool DetectSMSC() {
   387       SMSCEnter();
   388 
   389       ushort chipID = ReadWord(CHIP_ID_REGISTER);
   390       Chip chip;
   391       switch (chipID) {
   392         default: chip = Chip.Unknown; break;
   393       }
   394       if (chip == Chip.Unknown) {
   395         if (chipID != 0 && chipID != 0xffff) {
   396           SMSCExit();
   397 
   398           ReportUnknownChip("SMSC", chipID);
   399         }
   400       } else {
   401         SMSCExit();
   402         return true;
   403       }
   404 
   405       return false;
   406     }
   407 
   408     #endregion
   409 
   410     private void Detect() {
   411 
   412       for (int i = 0; i < REGISTER_PORTS.Length; i++) {
   413         registerPort = REGISTER_PORTS[i];
   414         valuePort = VALUE_PORTS[i];
   415 
   416         if (DetectWinbondFintek()) continue;
   417 
   418         if (DetectIT87()) continue;
   419 
   420         if (DetectSMSC()) continue;
   421       }  
   422     }
   423 
   424     public LPCIO() {
   425       if (!WinRing0.IsAvailable)
   426         return;
   427 
   428       if (!WinRing0.WaitIsaBusMutex(100))
   429         return;
   430 
   431       Detect();
   432 
   433       WinRing0.ReleaseIsaBusMutex();      
   434     }
   435 
   436     public ISuperIO[] SuperIO {
   437       get {
   438         return superIOs.ToArray();
   439       }
   440     }
   441 
   442     public string GetReport() {
   443       if (report.Length > 0) {
   444         return "LPCIO" + Environment.NewLine + Environment.NewLine + 
   445           report.ToString();
   446       } else
   447         return null;
   448     }
   449   }
   450 }