Hardware/LPC/LPCIO.cs
author moel.mich
Sat, 17 Jul 2010 13:25:42 +0000
changeset 155 8ffea928daad
parent 145 673c2ad36db2
child 163 67be1c62f950
permissions -rw-r--r--
Fixed Issue 91.
     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.Text;
    41 using System.Threading;
    42 
    43 namespace OpenHardwareMonitor.Hardware.LPC {
    44   public class LPCIO {
    45 
    46     private List<ISuperIO> superIOs = new List<ISuperIO>();
    47     private StringBuilder report = new StringBuilder();
    48 
    49     private Chip chip = Chip.Unknown;
    50 
    51     // I/O Ports
    52     private ushort[] REGISTER_PORTS = new ushort[] { 0x2e, 0x4e };
    53     private ushort[] VALUE_PORTS = new ushort[] { 0x2f, 0x4f };
    54 
    55     private ushort registerPort;
    56     private ushort valuePort;
    57 
    58     // Registers
    59     private const byte CONFIGURATION_CONTROL_REGISTER = 0x02;
    60     private const byte DEVCIE_SELECT_REGISTER = 0x07;
    61     private const byte CHIP_ID_REGISTER = 0x20;
    62     private const byte CHIP_REVISION_REGISTER = 0x21;
    63     private const byte BASE_ADDRESS_REGISTER = 0x60;
    64 
    65     private byte ReadByte(byte register) {
    66       WinRing0.WriteIoPortByte(registerPort, register);
    67       return WinRing0.ReadIoPortByte(valuePort);
    68     } 
    69 
    70     private ushort ReadWord(byte register) {
    71       return (ushort)((ReadByte(register) << 8) | 
    72         ReadByte((byte)(register + 1)));
    73     }
    74 
    75     private void Select(byte logicalDeviceNumber) {
    76       WinRing0.WriteIoPortByte(registerPort, DEVCIE_SELECT_REGISTER);
    77       WinRing0.WriteIoPortByte(valuePort, logicalDeviceNumber);
    78     }
    79 
    80     // ITE
    81     private const byte IT87_ENVIRONMENT_CONTROLLER_LDN = 0x04;
    82     private const byte IT87_CHIP_VERSION_REGISTER = 0x22;
    83 
    84     private void IT87Enter() {
    85       WinRing0.WriteIoPortByte(registerPort, 0x87);
    86       WinRing0.WriteIoPortByte(registerPort, 0x01);
    87       WinRing0.WriteIoPortByte(registerPort, 0x55);
    88       WinRing0.WriteIoPortByte(registerPort, 0x55);
    89     }
    90 
    91     private void IT87Exit() {
    92       WinRing0.WriteIoPortByte(registerPort, CONFIGURATION_CONTROL_REGISTER);
    93       WinRing0.WriteIoPortByte(valuePort, 0x02);
    94     }
    95 
    96     // Winbond, Fintek
    97     private const byte FINTEK_VENDOR_ID_REGISTER = 0x23;
    98     private const ushort FINTEK_VENDOR_ID = 0x1934;
    99 
   100     private const byte WINBOND_HARDWARE_MONITOR_LDN = 0x0B;
   101 
   102     private const byte F71858_HARDWARE_MONITOR_LDN = 0x02;
   103     private const byte FINTEK_HARDWARE_MONITOR_LDN = 0x04;
   104 
   105     private void WinbondFintekEnter() {
   106       WinRing0.WriteIoPortByte(registerPort, 0x87);
   107       WinRing0.WriteIoPortByte(registerPort, 0x87);
   108     }
   109 
   110     private void WinbondFintekExit() {
   111       WinRing0.WriteIoPortByte(registerPort, 0xAA);      
   112     }
   113 
   114     // SMSC
   115     private void SMSCEnter() {
   116       WinRing0.WriteIoPortByte(registerPort, 0x55);
   117     }
   118 
   119     private void SMSCExit() {
   120       WinRing0.WriteIoPortByte(registerPort, 0xAA);
   121     }
   122 
   123     public LPCIO() {
   124       if (!WinRing0.IsAvailable)
   125         return;
   126 
   127       for (int i = 0; i < REGISTER_PORTS.Length; i++) {
   128         registerPort = REGISTER_PORTS[i];
   129         valuePort = VALUE_PORTS[i];
   130 
   131         WinbondFintekEnter();
   132 
   133         byte logicalDeviceNumber;
   134         byte id = ReadByte(CHIP_ID_REGISTER);
   135         byte revision = ReadByte(CHIP_REVISION_REGISTER);
   136         chip = Chip.Unknown;
   137         logicalDeviceNumber = 0;
   138         switch (id) {
   139           case 0x05:
   140             switch (revision) {
   141               case 0x07:
   142                 chip = Chip.F71858;
   143                 logicalDeviceNumber = F71858_HARDWARE_MONITOR_LDN;
   144                 break;
   145               case 0x41:
   146                 chip = Chip.F71882;
   147                 logicalDeviceNumber = FINTEK_HARDWARE_MONITOR_LDN;
   148                 break;              
   149             } break;
   150           case 0x06:
   151             switch (revision) {             
   152               case 0x01:
   153                 chip = Chip.F71862;
   154                 logicalDeviceNumber = FINTEK_HARDWARE_MONITOR_LDN;
   155                 break;              
   156             } break;
   157           case 0x07:
   158             switch (revision) {
   159               case 0x23:
   160                 chip = Chip.F71889F;
   161                 logicalDeviceNumber = FINTEK_HARDWARE_MONITOR_LDN;
   162                 break;              
   163             } break;
   164           case 0x08:
   165             switch (revision) {
   166               case 0x14:
   167                 chip = Chip.F71869;
   168                 logicalDeviceNumber = FINTEK_HARDWARE_MONITOR_LDN;
   169                 break;              
   170             } break;
   171           case 0x09:
   172             switch (revision) {
   173               case 0x09:
   174                 chip = Chip.F71889ED;
   175                 logicalDeviceNumber = FINTEK_HARDWARE_MONITOR_LDN;
   176                 break;              
   177             } break;
   178           case 0x52:
   179             switch (revision) {
   180               case 0x17:
   181               case 0x3A:
   182               case 0x41:
   183                 chip = Chip.W83627HF;
   184                 logicalDeviceNumber = WINBOND_HARDWARE_MONITOR_LDN;
   185                 break;             
   186             } break;
   187           case 0x82:
   188             switch (revision & 0xF0) {
   189               case 0x80:
   190                 chip = Chip.W83627THF;
   191                 logicalDeviceNumber = WINBOND_HARDWARE_MONITOR_LDN;
   192                 break;
   193             } break;
   194           case 0x85:
   195             switch (revision) {
   196               case 0x41:
   197                 chip = Chip.W83687THF;
   198                 logicalDeviceNumber = WINBOND_HARDWARE_MONITOR_LDN;
   199                 break;
   200             } break;
   201           case 0x88:
   202             switch (revision & 0xF0) {
   203               case 0x50:
   204               case 0x60:
   205                 chip = Chip.W83627EHF;
   206                 logicalDeviceNumber = WINBOND_HARDWARE_MONITOR_LDN;
   207                 break;
   208             } break;
   209           case 0xA0:
   210             switch (revision & 0xF0) {
   211               case 0x20: 
   212                 chip = Chip.W83627DHG;
   213                 logicalDeviceNumber = WINBOND_HARDWARE_MONITOR_LDN;  
   214                 break;             
   215             } break;
   216           case 0xA5:
   217             switch (revision & 0xF0) {
   218               case 0x10:
   219                 chip = Chip.W83667HG;
   220                 logicalDeviceNumber = WINBOND_HARDWARE_MONITOR_LDN;
   221                 break;
   222             } break;
   223           case 0xB0:
   224             switch (revision & 0xF0) {
   225               case 0x70:
   226                 chip = Chip.W83627DHGP;
   227                 logicalDeviceNumber = WINBOND_HARDWARE_MONITOR_LDN;
   228                 break;             
   229             } break;
   230           case 0xB3:
   231             switch (revision & 0xF0) {
   232               case 0x50:
   233                 chip = Chip.W83667HGB;
   234                 logicalDeviceNumber = WINBOND_HARDWARE_MONITOR_LDN;
   235                 break;
   236             } break; 
   237         }
   238         if (chip == Chip.Unknown) {
   239           if (id != 0 && id != 0xff) {
   240             WinbondFintekExit();
   241 
   242             report.Append("Chip ID: Unknown Winbond / Fintek with ID 0x"); 
   243             report.AppendLine(((id << 8) | revision).ToString("X"));
   244             report.AppendLine();
   245           }
   246         } else {
   247 
   248           Select(logicalDeviceNumber);
   249           ushort address = ReadWord(BASE_ADDRESS_REGISTER);          
   250           Thread.Sleep(1);
   251           ushort verify = ReadWord(BASE_ADDRESS_REGISTER);
   252 
   253           ushort vendorID = ReadWord(FINTEK_VENDOR_ID_REGISTER);
   254 
   255           WinbondFintekExit();
   256 
   257           if (address != verify) {            
   258             report.Append("Chip ID: 0x"); 
   259             report.AppendLine(chip.ToString("X"));
   260             report.Append("Chip revision: 0x"); 
   261             report.AppendLine(revision.ToString("X"));
   262             report.AppendLine("Error: Address verification failed");
   263             report.AppendLine();
   264             return;
   265           }
   266 
   267           // some Fintek chips have address register offset 0x05 added already
   268           if ((address & 0x07) == 0x05)
   269             address &= 0xFFF8;
   270 
   271           if (address < 0x100 || (address & 0xF007) != 0) {            
   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             report.Append("Error: Invalid address 0x");
   277             report.AppendLine(address.ToString("X"));
   278             report.AppendLine();
   279             return;
   280           }
   281 
   282           switch (chip) {
   283             case Chip.W83627DHG:
   284             case Chip.W83627DHGP:
   285             case Chip.W83627EHF:
   286             case Chip.W83627HF:
   287             case Chip.W83627THF:
   288             case Chip.W83667HG:
   289             case Chip.W83667HGB:
   290             case Chip.W83687THF:
   291               superIOs.Add(new W836XX(chip, revision, address));
   292               break;
   293             case Chip.F71858:
   294             case Chip.F71862:
   295             case Chip.F71869:
   296             case Chip.F71882:
   297             case Chip.F71889ED:
   298             case Chip.F71889F:
   299               if (vendorID != FINTEK_VENDOR_ID) {
   300                 report.Append("Chip ID: 0x");
   301                 report.AppendLine(chip.ToString("X"));
   302                 report.Append("Chip revision: 0x");
   303                 report.AppendLine(revision.ToString("X"));
   304                 report.Append("Error: Invalid vendor ID 0x");
   305                 report.AppendLine(vendorID.ToString("X"));
   306                 report.AppendLine();
   307                 return;
   308               }
   309               superIOs.Add(new F718XX(chip, address));
   310               break;
   311             default: break;
   312           }
   313           
   314           return;
   315         }
   316 
   317         IT87Enter();
   318 
   319         ushort chipID = ReadWord(CHIP_ID_REGISTER);
   320         switch (chipID) {
   321           case 0x8712: chip = Chip.IT8712F; break;
   322           case 0x8716: chip = Chip.IT8716F; break;
   323           case 0x8718: chip = Chip.IT8718F; break;
   324           case 0x8720: chip = Chip.IT8720F; break;
   325           case 0x8726: chip = Chip.IT8726F; break; 
   326           default: chip = Chip.Unknown; break;
   327         }
   328         if (chip == Chip.Unknown) {
   329           if (chipID != 0 && chipID != 0xffff) {
   330             IT87Exit();
   331 
   332             report.Append("Chip ID: Unknown ITE with ID 0x");
   333             report.AppendLine(chipID.ToString("X"));
   334             report.AppendLine();
   335           }
   336         } else {          
   337           Select(IT87_ENVIRONMENT_CONTROLLER_LDN);
   338           ushort address = ReadWord(BASE_ADDRESS_REGISTER);
   339           Thread.Sleep(1);
   340           ushort verify = ReadWord(BASE_ADDRESS_REGISTER);
   341 
   342           byte version = (byte)(ReadByte(IT87_CHIP_VERSION_REGISTER) & 0x0F);
   343 
   344           IT87Exit();
   345 
   346           if (address != verify || address < 0x100 || (address & 0xF007) != 0) {
   347             report.Append("Chip ID: 0x");
   348             report.AppendLine(chip.ToString("X"));            
   349             report.Append("Error: Invalid address 0x");
   350             report.AppendLine(address.ToString("X"));
   351             report.AppendLine();
   352             return;
   353           }
   354 
   355          superIOs.Add(new IT87XX(chip, address, version));
   356 
   357           return;
   358         }
   359 
   360         SMSCEnter();
   361 
   362         chipID = ReadWord(CHIP_ID_REGISTER);
   363         switch (chipID) {
   364           default: chip = Chip.Unknown; break;
   365         }
   366         if (chip == Chip.Unknown) {
   367           if (chipID != 0 && chipID != 0xffff) {
   368             SMSCExit();
   369 
   370             report.Append("Chip ID: Unknown SMSC with ID 0x");
   371             report.AppendLine(chipID.ToString("X"));
   372             report.AppendLine();
   373           }
   374         } else {
   375           SMSCExit();
   376 
   377           return;
   378         }
   379       }   
   380     }
   381 
   382     public ISuperIO[] SuperIO {
   383       get {
   384         return superIOs.ToArray();
   385       }
   386     }
   387 
   388     public string GetReport() {
   389       if (report.Length > 0) {
   390         report.Insert(0, "LPCIO" + Environment.NewLine +
   391           Environment.NewLine);        
   392         return report.ToString();
   393       } else
   394         return null;
   395     }
   396   }
   397 }