Hardware/LPC/LPCIO.cs
author moel.mich
Tue, 17 Aug 2010 20:25:27 +0000
changeset 169 3b2bcba8c02d
parent 167 b7cc9d09aefe
child 170 31858ba46e9c
permissions -rw-r--r--
Restricted ITE detection to port 0x2E.
     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 0x8726: chip = Chip.IT8726F; break;
   338         default: chip = Chip.Unknown; break;
   339       }
   340       if (chip == Chip.Unknown) {
   341         if (chipID != 0 && chipID != 0xffff) {
   342           IT87Exit();
   343 
   344           ReportUnknownChip("ITE", chipID);
   345         }
   346       } else {
   347         Select(IT87_ENVIRONMENT_CONTROLLER_LDN);
   348         ushort address = ReadWord(BASE_ADDRESS_REGISTER);
   349         Thread.Sleep(1);
   350         ushort verify = ReadWord(BASE_ADDRESS_REGISTER);
   351 
   352         byte version = (byte)(ReadByte(IT87_CHIP_VERSION_REGISTER) & 0x0F);
   353 
   354         IT87Exit();
   355 
   356         if (address != verify || address < 0x100 || (address & 0xF007) != 0) {
   357           report.Append("Chip ID: 0x");
   358           report.AppendLine(chip.ToString("X"));
   359           report.Append("Error: Invalid address 0x");
   360           report.AppendLine(address.ToString("X",
   361             CultureInfo.InvariantCulture));
   362           report.AppendLine();
   363           return false;
   364         }
   365 
   366         superIOs.Add(new IT87XX(chip, address, version));
   367         return true;
   368       }
   369 
   370       return false;
   371     }
   372 
   373     #endregion
   374 
   375     #region SMSC
   376 
   377     private void SMSCEnter() {
   378       WinRing0.WriteIoPortByte(registerPort, 0x55);
   379     }
   380 
   381     private void SMSCExit() {
   382       WinRing0.WriteIoPortByte(registerPort, 0xAA);
   383     }
   384 
   385     private bool DetectSMSC() {
   386       SMSCEnter();
   387 
   388       ushort chipID = ReadWord(CHIP_ID_REGISTER);
   389       Chip chip;
   390       switch (chipID) {
   391         default: chip = Chip.Unknown; break;
   392       }
   393       if (chip == Chip.Unknown) {
   394         if (chipID != 0 && chipID != 0xffff) {
   395           SMSCExit();
   396 
   397           ReportUnknownChip("SMSC", chipID);
   398         }
   399       } else {
   400         SMSCExit();
   401         return true;
   402       }
   403 
   404       return false;
   405     }
   406 
   407     #endregion
   408 
   409     private void Detect() {
   410 
   411       for (int i = 0; i < REGISTER_PORTS.Length; i++) {
   412         registerPort = REGISTER_PORTS[i];
   413         valuePort = VALUE_PORTS[i];
   414 
   415         if (DetectWinbondFintek()) continue;
   416 
   417         if (DetectIT87()) continue;
   418 
   419         if (DetectSMSC()) continue;
   420       }  
   421     }
   422 
   423     public LPCIO() {
   424       if (!WinRing0.IsAvailable)
   425         return;
   426 
   427       if (!WinRing0.WaitIsaBusMutex(100))
   428         return;
   429 
   430       Detect();
   431 
   432       WinRing0.ReleaseIsaBusMutex();      
   433     }
   434 
   435     public ISuperIO[] SuperIO {
   436       get {
   437         return superIOs.ToArray();
   438       }
   439     }
   440 
   441     public string GetReport() {
   442       if (report.Length > 0) {
   443         return "LPCIO" + Environment.NewLine + Environment.NewLine + 
   444           report.ToString();
   445       } else
   446         return null;
   447     }
   448   }
   449 }