Hardware/LPC/IT87XX.cs
author moel.mich
Mon, 24 May 2010 15:27:46 +0000
changeset 126 2354fdb91ac4
parent 122 3ef997c53b50
child 130 80065ab20b84
permissions -rw-r--r--
Extended the ITE super I/O voltage reading by adding hidden voltage sensors for unknown channels. Added a few known DFI and Gigabyte mainboard voltage configurations.
     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.Drawing;
    41 using System.Text;
    42 
    43 namespace OpenHardwareMonitor.Hardware.LPC {
    44   public class IT87XX : LPCHardware, IHardware {
    45         
    46     private bool available = false;
    47     private ushort address;
    48 
    49     private readonly ushort addressReg;
    50     private readonly ushort dataReg;
    51 
    52     private List<Sensor> voltages = new List<Sensor>(9);    
    53     private List<Sensor> temperatures = new List<Sensor>(3);    
    54     private Sensor[] fans;
    55    
    56     // Consts
    57     private const byte ITE_VENDOR_ID = 0x90;
    58        
    59     // Environment Controller
    60     private const byte ADDRESS_REGISTER_OFFSET = 0x05;
    61     private const byte DATA_REGISTER_OFFSET = 0x06;
    62 
    63     // Environment Controller Registers    
    64     private const byte CONFIGURATION_REGISTER = 0x00;
    65     private const byte TEMPERATURE_BASE_REG = 0x29;
    66     private const byte VENDOR_ID_REGISTER = 0x58;
    67     private const byte FAN_TACHOMETER_16_BIT_ENABLE_REGISTER = 0x0c;
    68     private byte[] FAN_TACHOMETER_REG = 
    69       new byte[] { 0x0d, 0x0e, 0x0f, 0x80, 0x82 };
    70     private byte[] FAN_TACHOMETER_EXT_REG =
    71       new byte[] { 0x18, 0x19, 0x1a, 0x81, 0x83 };
    72     private const byte VOLTAGE_BASE_REG = 0x20;
    73 
    74     private byte ReadByte(byte register, out bool valid) {
    75       WinRing0.WriteIoPortByte(addressReg, register);
    76       byte value = WinRing0.ReadIoPortByte(dataReg);
    77       valid = register == WinRing0.ReadIoPortByte(addressReg);
    78       return value;
    79     }
    80 
    81     public IT87XX(Chip chip, ushort address, Mainboard.Manufacturer 
    82       mainboardManufacturer, Mainboard.Model mainboardModel) : base (chip) {
    83       
    84       this.address = address;
    85       this.addressReg = (ushort)(address + ADDRESS_REGISTER_OFFSET);
    86       this.dataReg = (ushort)(address + DATA_REGISTER_OFFSET);
    87       
    88       // Check vendor id
    89       bool valid;
    90       byte vendorId = ReadByte(VENDOR_ID_REGISTER, out valid);       
    91       if (!valid || vendorId != ITE_VENDOR_ID)
    92         return;
    93 
    94       // Bit 0x10 of the configuration register should always be 1
    95       if ((ReadByte(CONFIGURATION_REGISTER, out valid) & 0x10) == 0)
    96         return;
    97       if (!valid)
    98         return;
    99 
   100       string[] temperatureLabels;
   101       List<Voltage> voltageConfigs = new List<Voltage>();
   102       switch (mainboardManufacturer) {
   103         case Mainboard.Manufacturer.DFI:
   104           switch (mainboardModel) {
   105             case Mainboard.Model.LP_BI_P45_T2RS_Elite:
   106               voltageConfigs.Add(new Voltage("CPU VCore", 0));
   107               voltageConfigs.Add(new Voltage("FSB VTT", 1));
   108               voltageConfigs.Add(new Voltage("+3.3V", 2));
   109               voltageConfigs.Add(new Voltage("+5V", 3, 6.8f, 10, 0));
   110               voltageConfigs.Add(new Voltage("+12V", 4, 30, 10, 0));
   111               voltageConfigs.Add(new Voltage("NB Core", 5));
   112               voltageConfigs.Add(new Voltage("VDIMM", 6));
   113               voltageConfigs.Add(new Voltage("+5VSB", 7, 6.8f, 10, 0));
   114               voltageConfigs.Add(new Voltage("VBat", 8));
   115               temperatureLabels = new string[] {
   116                 "CPU", "System", "Chipset" };
   117               break;
   118             case Mainboard.Model.LP_DK_P55_T3eH9:
   119               voltageConfigs.Add(new Voltage("CPU VCore", 0));
   120               voltageConfigs.Add(new Voltage("VTT", 1));
   121               voltageConfigs.Add(new Voltage("+3.3V", 2));
   122               voltageConfigs.Add(new Voltage("+5V", 3, 6.8f, 10, 0));
   123               voltageConfigs.Add(new Voltage("+12V", 4, 30, 10, 0));
   124               voltageConfigs.Add(new Voltage("CPU PLL", 5));
   125               voltageConfigs.Add(new Voltage("DRAM", 6));
   126               voltageConfigs.Add(new Voltage("+5VSB", 7, 6.8f, 10, 0));
   127               voltageConfigs.Add(new Voltage("VBat", 8));
   128               temperatureLabels = new string[] {
   129                 "Chipset", "CPU PWM", "CPU" };
   130               break;
   131             default:
   132               voltageConfigs.Add(new Voltage("CPU VCore", 0));
   133               voltageConfigs.Add(new Voltage("VTT", 1, true));
   134               voltageConfigs.Add(new Voltage("+3.3V", 2, true));
   135               voltageConfigs.Add(new Voltage("+5V", 3, 6.8f, 10, 0, true));
   136               voltageConfigs.Add(new Voltage("+12V", 4, 30, 10, 0, true));
   137               voltageConfigs.Add(new Voltage("Voltage #6", 5, true));
   138               voltageConfigs.Add(new Voltage("DRAM", 6, true));
   139               voltageConfigs.Add(new Voltage("+5VSB", 7, 6.8f, 10, 0, true));
   140               voltageConfigs.Add(new Voltage("VBat", 8));
   141               temperatureLabels = new string[] {
   142                 "Temperature #1", "Temperature #2", "Temperature #3" };
   143               break;
   144           }
   145           break;
   146 
   147         case Mainboard.Manufacturer.Gigabyte:
   148           switch (mainboardModel) {            
   149             case Mainboard.Model.EP45_DS3R:
   150             case Mainboard.Model.P35_DS3:
   151               voltageConfigs.Add(new Voltage("CPU VCore", 0));
   152               voltageConfigs.Add(new Voltage("DRAM", 1));
   153               voltageConfigs.Add(new Voltage("+3.3V", 2));
   154               voltageConfigs.Add(new Voltage("+5V", 3, 6.8f, 10, 0));
   155               voltageConfigs.Add(new Voltage("+12V", 7, 27, 9.1f, 0));
   156               voltageConfigs.Add(new Voltage("VBat", 8));    
   157               break;
   158             case Mainboard.Model.GA_MA785GMT_UD2H:
   159               voltageConfigs.Add(new Voltage("CPU VCore", 0));
   160               voltageConfigs.Add(new Voltage("DRAM", 1));
   161               voltageConfigs.Add(new Voltage("+3.3V", 2));
   162               voltageConfigs.Add(new Voltage("+5V", 3, 6.8f, 10, 0));
   163               voltageConfigs.Add(new Voltage("+12V", 4, 27, 9.1f, 0));
   164               voltageConfigs.Add(new Voltage("VBat", 8));   
   165               break;
   166             default:
   167               voltageConfigs.Add(new Voltage("CPU VCore", 0));
   168               voltageConfigs.Add(new Voltage("DRAM", 1, true));
   169               voltageConfigs.Add(new Voltage("+3.3V", 2, true));              
   170               voltageConfigs.Add(new Voltage("+5V", 3, 6.8f, 10, 0, true));
   171               voltageConfigs.Add(new Voltage("Voltage #5", 4, true));
   172               voltageConfigs.Add(new Voltage("Voltage #6", 5, true));
   173               voltageConfigs.Add(new Voltage("Voltage #7", 6, true));
   174               voltageConfigs.Add(new Voltage("+12V", 7, 27, 9.1f, 0, true));
   175               voltageConfigs.Add(new Voltage("VBat", 8));              
   176               break;
   177           }
   178           temperatureLabels = new string[] { "System", "CPU" };
   179           break; 
   180 
   181         default:
   182           voltageConfigs.Add(new Voltage("CPU VCore", 0));
   183           voltageConfigs.Add(new Voltage("Voltage #2", 1, true));
   184           voltageConfigs.Add(new Voltage("Voltage #3", 2, true));
   185           voltageConfigs.Add(new Voltage("Voltage #4", 3, true));
   186           voltageConfigs.Add(new Voltage("Voltage #5", 4, true));
   187           voltageConfigs.Add(new Voltage("Voltage #6", 5, true));
   188           voltageConfigs.Add(new Voltage("Voltage #7", 6, true));
   189           voltageConfigs.Add(new Voltage("Voltage #8", 7, true));
   190           voltageConfigs.Add(new Voltage("VBat", 8));
   191           temperatureLabels = new string[] {
   192             "Temperature #1", "Temperature #2", "Temperature #3" };
   193           break;
   194       }
   195 
   196       string formula = "Voltage = value + (value - Vf) * Ri / Rf.";
   197       foreach (Voltage voltage in voltageConfigs)
   198         voltages.Add(new Sensor(voltage.Name, voltage.Index, voltage.Hidden, 
   199           null, SensorType.Voltage, this, new ParameterDescription[] {
   200           new ParameterDescription("Ri [kΩ]", "Input resistance.\n" + 
   201             formula, voltage.Ri),
   202           new ParameterDescription("Rf [kΩ]", "Reference resistance.\n" + 
   203             formula, voltage.Rf),
   204           new ParameterDescription("Vf [V]", "Reference voltage.\n" + 
   205             formula, voltage.Vf)
   206           }));  
   207 
   208       for (int i = 0; i < temperatureLabels.Length; i++)
   209         if (temperatureLabels[i] != null) {
   210           temperatures.Add(new Sensor(temperatureLabels[i], i, null,
   211             SensorType.Temperature, this, new ParameterDescription[] {
   212             new ParameterDescription("Offset [°C]", "Temperature offset.", 0)
   213           }));
   214         }
   215 
   216       fans = new Sensor[5];
   217       for (int i = 0; i < fans.Length; i++)
   218         fans[i] = new Sensor("Fan #" + (i + 1), i, SensorType.Fan, this);           
   219 
   220       available = true;
   221     }
   222 
   223     public bool IsAvailable {
   224       get { return available; } 
   225     }
   226 
   227     public override string GetReport() {
   228       StringBuilder r = new StringBuilder();
   229 
   230       r.AppendLine("LPC " + this.GetType().Name);
   231       r.AppendLine();
   232       r.Append("Chip ID: 0x"); r.AppendLine(chip.ToString("X"));
   233       r.Append("Chip Name: "); r.AppendLine(name);
   234       r.Append("Base Address: 0x"); r.AppendLine(address.ToString("X4"));
   235       r.AppendLine();
   236       r.AppendLine("Environment Controller Registers");
   237       r.AppendLine();
   238 
   239       r.AppendLine("      00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F");
   240       r.AppendLine();
   241       for (int i = 0; i <= 0xA; i++) {
   242         r.Append(" "); r.Append((i << 4).ToString("X2")); r.Append("  ");
   243         for (int j = 0; j <= 0xF; j++) {
   244           r.Append(" ");
   245           bool valid;
   246           byte value = ReadByte((byte)((i << 4) | j), out valid);
   247           if (valid)
   248             r.Append(value.ToString("X2"));
   249           else
   250             r.Append("??");
   251         }
   252         r.AppendLine();
   253       }
   254       r.AppendLine();
   255 
   256       return r.ToString();
   257     }
   258 
   259     public override void Update() {
   260 
   261       foreach (Sensor sensor in voltages) {
   262         bool valid;
   263         float value = 0.001f * ((int)ReadByte(
   264           (byte)(VOLTAGE_BASE_REG + sensor.Index), out valid) << 4);
   265         if (!valid)
   266           continue;
   267 
   268         sensor.Value = value + (value - sensor.Parameters[2].Value) *
   269           sensor.Parameters[0].Value / sensor.Parameters[1].Value;
   270         if (value > 0)
   271           ActivateSensor(sensor);        
   272       }
   273 
   274       foreach (Sensor sensor in temperatures) {
   275         bool valid;
   276         sbyte value = (sbyte)ReadByte(
   277           (byte)(TEMPERATURE_BASE_REG + sensor.Index), out valid);
   278         if (!valid)
   279           continue;
   280 
   281         sensor.Value = value + sensor.Parameters[0].Value;
   282         if (value < sbyte.MaxValue && value > 0)
   283           ActivateSensor(sensor);        
   284       }
   285 
   286       foreach (Sensor sensor in fans) {
   287         bool valid;
   288         int value = ReadByte(FAN_TACHOMETER_REG[sensor.Index], out valid);
   289         if (!valid) 
   290           continue;
   291         value |= ReadByte(FAN_TACHOMETER_EXT_REG[sensor.Index], out valid) << 8;
   292         if (!valid)
   293           continue;
   294 
   295         if (value > 0x3f) {
   296           sensor.Value = (value < 0xffff) ? 1.35e6f / ((value) * 2) : 0;
   297           if (sensor.Value > 0)
   298             ActivateSensor(sensor);
   299         } else {
   300           sensor.Value = null;
   301         }
   302       }      
   303     }
   304 
   305     private class Voltage {
   306       public readonly string Name;
   307       public readonly int Index;
   308       public readonly float Ri;
   309       public readonly float Rf;
   310       public readonly float Vf;
   311       public readonly bool Hidden;
   312 
   313       public Voltage(string name, int index) :
   314         this(name, index, 0, 1, 0, false) { }
   315 
   316       public Voltage(string name, int index, bool hidden) :
   317         this(name, index, 0, 1, 0, hidden) { }
   318 
   319       public Voltage(string name, int index, float ri, float rf, float vf) :
   320         this(name, index, ri, rf, vf, false) { }
   321 
   322       public Voltage(string name, int index, float ri, float rf, float vf, 
   323         bool hidden) 
   324       {
   325         this.Name = name;
   326         this.Index = index;
   327         this.Ri = ri;
   328         this.Rf = rf;
   329         this.Vf = vf;
   330         this.Hidden = hidden;
   331       }
   332     }
   333   }
   334 }