Hardware/LPC/LPCIO.cs
author moel.mich
Sun, 15 Aug 2010 17:56:57 +0000
changeset 168 7f90baeb96b0
parent 166 fa9dfbfc4145
child 169 3b2bcba8c02d
permissions -rw-r--r--
Fixed Issue 104.
     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     // ITE
    80     private const byte IT87_ENVIRONMENT_CONTROLLER_LDN = 0x04;
    81     private const byte IT87_CHIP_VERSION_REGISTER = 0x22;
    82 
    83     private void IT87Enter() {
    84       WinRing0.WriteIoPortByte(registerPort, 0x87);
    85       WinRing0.WriteIoPortByte(registerPort, 0x01);
    86       WinRing0.WriteIoPortByte(registerPort, 0x55);
    87       WinRing0.WriteIoPortByte(registerPort, 0x55);
    88     }
    89 
    90     private void IT87Exit() {
    91       WinRing0.WriteIoPortByte(registerPort, CONFIGURATION_CONTROL_REGISTER);
    92       WinRing0.WriteIoPortByte(valuePort, 0x02);
    93     }
    94 
    95     // Winbond, Fintek
    96     private const byte FINTEK_VENDOR_ID_REGISTER = 0x23;
    97     private const ushort FINTEK_VENDOR_ID = 0x1934;
    98 
    99     private const byte WINBOND_HARDWARE_MONITOR_LDN = 0x0B;
   100 
   101     private const byte F71858_HARDWARE_MONITOR_LDN = 0x02;
   102     private const byte FINTEK_HARDWARE_MONITOR_LDN = 0x04;
   103 
   104     private void WinbondFintekEnter() {
   105       WinRing0.WriteIoPortByte(registerPort, 0x87);
   106       WinRing0.WriteIoPortByte(registerPort, 0x87);
   107     }
   108 
   109     private void WinbondFintekExit() {
   110       WinRing0.WriteIoPortByte(registerPort, 0xAA);      
   111     }
   112 
   113     // SMSC
   114     private void SMSCEnter() {
   115       WinRing0.WriteIoPortByte(registerPort, 0x55);
   116     }
   117 
   118     private void SMSCExit() {
   119       WinRing0.WriteIoPortByte(registerPort, 0xAA);
   120     }
   121 
   122     private void ReportUnknownChip(string type, int chip) {
   123       report.Append("Chip ID: Unknown ");
   124       report.Append(type);
   125       report.Append(" with ID 0x");
   126       report.Append(chip.ToString("X", CultureInfo.InvariantCulture));
   127       report.Append(" at 0x");
   128       report.Append(registerPort.ToString("X", CultureInfo.InvariantCulture));
   129       report.Append("/0x");
   130       report.AppendLine(valuePort.ToString("X", CultureInfo.InvariantCulture));
   131       report.AppendLine();
   132     }
   133 
   134     private bool DetectWinbondFintek() {
   135       WinbondFintekEnter();
   136 
   137       byte logicalDeviceNumber;
   138       byte id = ReadByte(CHIP_ID_REGISTER);
   139       byte revision = ReadByte(CHIP_REVISION_REGISTER);
   140       Chip chip = Chip.Unknown;
   141       logicalDeviceNumber = 0;
   142       switch (id) {
   143         case 0x05:
   144           switch (revision) {
   145             case 0x07:
   146               chip = Chip.F71858;
   147               logicalDeviceNumber = F71858_HARDWARE_MONITOR_LDN;
   148               break;
   149             case 0x41:
   150               chip = Chip.F71882;
   151               logicalDeviceNumber = FINTEK_HARDWARE_MONITOR_LDN;
   152               break;
   153           } break;
   154         case 0x06:
   155           switch (revision) {
   156             case 0x01:
   157               chip = Chip.F71862;
   158               logicalDeviceNumber = FINTEK_HARDWARE_MONITOR_LDN;
   159               break;
   160           } break;
   161         case 0x07:
   162           switch (revision) {
   163             case 0x23:
   164               chip = Chip.F71889F;
   165               logicalDeviceNumber = FINTEK_HARDWARE_MONITOR_LDN;
   166               break;
   167           } break;
   168         case 0x08:
   169           switch (revision) {
   170             case 0x14:
   171               chip = Chip.F71869;
   172               logicalDeviceNumber = FINTEK_HARDWARE_MONITOR_LDN;
   173               break;
   174           } break;
   175         case 0x09:
   176           switch (revision) {
   177             case 0x09:
   178               chip = Chip.F71889ED;
   179               logicalDeviceNumber = FINTEK_HARDWARE_MONITOR_LDN;
   180               break;
   181           } break;
   182         case 0x52:
   183           switch (revision) {
   184             case 0x17:
   185             case 0x3A:
   186             case 0x41:
   187               chip = Chip.W83627HF;
   188               logicalDeviceNumber = WINBOND_HARDWARE_MONITOR_LDN;
   189               break;
   190           } break;
   191         case 0x82:
   192           switch (revision & 0xF0) {
   193             case 0x80:
   194               chip = Chip.W83627THF;
   195               logicalDeviceNumber = WINBOND_HARDWARE_MONITOR_LDN;
   196               break;
   197           } break;
   198         case 0x85:
   199           switch (revision) {
   200             case 0x41:
   201               chip = Chip.W83687THF;
   202               logicalDeviceNumber = WINBOND_HARDWARE_MONITOR_LDN;
   203               break;
   204           } break;
   205         case 0x88:
   206           switch (revision & 0xF0) {
   207             case 0x50:
   208             case 0x60:
   209               chip = Chip.W83627EHF;
   210               logicalDeviceNumber = WINBOND_HARDWARE_MONITOR_LDN;
   211               break;
   212           } break;
   213         case 0xA0:
   214           switch (revision & 0xF0) {
   215             case 0x20:
   216               chip = Chip.W83627DHG;
   217               logicalDeviceNumber = WINBOND_HARDWARE_MONITOR_LDN;
   218               break;
   219           } break;
   220         case 0xA5:
   221           switch (revision & 0xF0) {
   222             case 0x10:
   223               chip = Chip.W83667HG;
   224               logicalDeviceNumber = WINBOND_HARDWARE_MONITOR_LDN;
   225               break;
   226           } break;
   227         case 0xB0:
   228           switch (revision & 0xF0) {
   229             case 0x70:
   230               chip = Chip.W83627DHGP;
   231               logicalDeviceNumber = WINBOND_HARDWARE_MONITOR_LDN;
   232               break;
   233           } break;
   234         case 0xB3:
   235           switch (revision & 0xF0) {
   236             case 0x50:
   237               chip = Chip.W83667HGB;
   238               logicalDeviceNumber = WINBOND_HARDWARE_MONITOR_LDN;
   239               break;
   240           } break;
   241       }
   242       if (chip == Chip.Unknown) {
   243         if (id != 0 && id != 0xff) {
   244           WinbondFintekExit();
   245 
   246           ReportUnknownChip("Winbond / Fintek", ((id << 8) | revision));         
   247         }
   248       } else {
   249 
   250         Select(logicalDeviceNumber);
   251         ushort address = ReadWord(BASE_ADDRESS_REGISTER);
   252         Thread.Sleep(1);
   253         ushort verify = ReadWord(BASE_ADDRESS_REGISTER);
   254 
   255         ushort vendorID = ReadWord(FINTEK_VENDOR_ID_REGISTER);
   256 
   257         WinbondFintekExit();
   258 
   259         if (address != verify) {
   260           report.Append("Chip ID: 0x");
   261           report.AppendLine(chip.ToString("X"));
   262           report.Append("Chip revision: 0x");
   263           report.AppendLine(revision.ToString("X", 
   264             CultureInfo.InvariantCulture));
   265           report.AppendLine("Error: Address verification failed");
   266           report.AppendLine();
   267           return false;
   268         }
   269 
   270         // some Fintek chips have address register offset 0x05 added already
   271         if ((address & 0x07) == 0x05)
   272           address &= 0xFFF8;
   273 
   274         if (address < 0x100 || (address & 0xF007) != 0) {
   275           report.Append("Chip ID: 0x");
   276           report.AppendLine(chip.ToString("X"));
   277           report.Append("Chip revision: 0x");
   278           report.AppendLine(revision.ToString("X", 
   279             CultureInfo.InvariantCulture));
   280           report.Append("Error: Invalid address 0x");
   281           report.AppendLine(address.ToString("X", 
   282             CultureInfo.InvariantCulture));
   283           report.AppendLine();
   284           return false;
   285         }
   286 
   287         switch (chip) {
   288           case Chip.W83627DHG:
   289           case Chip.W83627DHGP:
   290           case Chip.W83627EHF:
   291           case Chip.W83627HF:
   292           case Chip.W83627THF:
   293           case Chip.W83667HG:
   294           case Chip.W83667HGB:
   295           case Chip.W83687THF:
   296             superIOs.Add(new W836XX(chip, revision, address));
   297             break;
   298           case Chip.F71858:
   299           case Chip.F71862:
   300           case Chip.F71869:
   301           case Chip.F71882:
   302           case Chip.F71889ED:
   303           case Chip.F71889F:
   304             if (vendorID != FINTEK_VENDOR_ID) {
   305               report.Append("Chip ID: 0x");
   306               report.AppendLine(chip.ToString("X"));
   307               report.Append("Chip revision: 0x");
   308               report.AppendLine(revision.ToString("X", 
   309                 CultureInfo.InvariantCulture));
   310               report.Append("Error: Invalid vendor ID 0x");
   311               report.AppendLine(vendorID.ToString("X", 
   312                 CultureInfo.InvariantCulture));
   313               report.AppendLine();
   314               return false;
   315             }
   316             superIOs.Add(new F718XX(chip, address));
   317             break;
   318           default: break;
   319         }
   320 
   321         return true;
   322       }
   323 
   324       return false;
   325     }
   326 
   327     private bool DetectIT87() {
   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     private bool DetectSMSC() {
   374       SMSCEnter();
   375 
   376       ushort chipID = ReadWord(CHIP_ID_REGISTER);
   377       Chip chip;
   378       switch (chipID) {
   379         default: chip = Chip.Unknown; break;
   380       }
   381       if (chip == Chip.Unknown) {
   382         if (chipID != 0 && chipID != 0xffff) {
   383           SMSCExit();
   384 
   385           ReportUnknownChip("SMSC", chipID);
   386         }
   387       } else {
   388         SMSCExit();
   389         return true;
   390       }
   391 
   392       return false;
   393     }
   394 
   395     private void Detect() {
   396 
   397       for (int i = 0; i < REGISTER_PORTS.Length; i++) {
   398         registerPort = REGISTER_PORTS[i];
   399         valuePort = VALUE_PORTS[i];
   400 
   401         if (DetectWinbondFintek()) continue;
   402 
   403         if (DetectIT87()) continue;
   404 
   405         if (DetectSMSC()) continue;
   406       }  
   407     }
   408 
   409     public LPCIO() {
   410       if (!WinRing0.IsAvailable)
   411         return;
   412 
   413       if (!WinRing0.WaitIsaBusMutex(100))
   414         return;
   415 
   416       Detect();
   417 
   418       WinRing0.ReleaseIsaBusMutex();      
   419     }
   420 
   421     public ISuperIO[] SuperIO {
   422       get {
   423         return superIOs.ToArray();
   424       }
   425     }
   426 
   427     public string GetReport() {
   428       if (report.Length > 0) {
   429         report.Insert(0, "LPCIO" + Environment.NewLine +
   430           Environment.NewLine);        
   431         return report.ToString();
   432       } else
   433         return null;
   434     }
   435   }
   436 }