Hardware/LPC/IT87XX.cs
author moel.mich
Sun, 21 Nov 2010 17:31:25 +0000
changeset 245 f8e72b2efcc0
parent 228 458a6c3de579
child 247 6dc755f1970e
permissions -rw-r--r--
Added first experimental support for the Nuvoton NCT6771F super I/O chip.
     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.Globalization;
    39 using System.Text;
    40 
    41 namespace OpenHardwareMonitor.Hardware.LPC {
    42   internal class IT87XX : ISuperIO {
    43        
    44     private readonly ushort address;
    45     private readonly Chip chip;
    46     private readonly byte version;
    47 
    48     private readonly ushort gpioAddress;
    49     private readonly int gpioCount;
    50 
    51     private readonly ushort addressReg;
    52     private readonly ushort dataReg;
    53 
    54     private readonly float?[] voltages = new float?[0];
    55     private readonly float?[] temperatures = new float?[0];
    56     private readonly float?[] fans = new float?[0];
    57 
    58     private readonly float voltageGain;
    59    
    60     // Consts
    61     private const byte ITE_VENDOR_ID = 0x90;
    62        
    63     // Environment Controller
    64     private const byte ADDRESS_REGISTER_OFFSET = 0x05;
    65     private const byte DATA_REGISTER_OFFSET = 0x06;
    66 
    67     // Environment Controller Registers    
    68     private const byte CONFIGURATION_REGISTER = 0x00;
    69     private const byte TEMPERATURE_BASE_REG = 0x29;
    70     private const byte VENDOR_ID_REGISTER = 0x58;
    71     private const byte FAN_TACHOMETER_16_BIT_ENABLE_REGISTER = 0x0c;
    72     private readonly byte[] FAN_TACHOMETER_REG = 
    73       new byte[] { 0x0d, 0x0e, 0x0f, 0x80, 0x82 };
    74     private readonly byte[] FAN_TACHOMETER_EXT_REG =
    75       new byte[] { 0x18, 0x19, 0x1a, 0x81, 0x83 };
    76     private const byte VOLTAGE_BASE_REG = 0x20;
    77 
    78     private byte ReadByte(byte register, out bool valid) {
    79       Ring0.WriteIoPort(addressReg, register);
    80       byte value = Ring0.ReadIoPort(dataReg);
    81       valid = register == Ring0.ReadIoPort(addressReg);
    82       return value;
    83     }
    84 
    85     public byte? ReadGPIO(int index) {
    86       if (index >= gpioCount)
    87         return null;
    88 
    89       return Ring0.ReadIoPort((ushort)(gpioAddress + index));
    90     }
    91 
    92     public void WriteGPIO(int index, byte value) {
    93       if (index >= gpioCount)
    94         return;
    95 
    96       Ring0.WriteIoPort((ushort)(gpioAddress + index), value);
    97     }
    98 
    99     public IT87XX(Chip chip, ushort address, ushort gpioAddress, byte version) {
   100       
   101       this.address = address;
   102       this.chip = chip;
   103       this.version = version;
   104       this.addressReg = (ushort)(address + ADDRESS_REGISTER_OFFSET);
   105       this.dataReg = (ushort)(address + DATA_REGISTER_OFFSET);
   106       this.gpioAddress = gpioAddress;
   107 
   108       // Check vendor id
   109       bool valid;
   110       byte vendorId = ReadByte(VENDOR_ID_REGISTER, out valid);       
   111       if (!valid || vendorId != ITE_VENDOR_ID)
   112         return;
   113 
   114       // Bit 0x10 of the configuration register should always be 1
   115       if ((ReadByte(CONFIGURATION_REGISTER, out valid) & 0x10) == 0)
   116         return;
   117       if (!valid)
   118         return;
   119 
   120       voltages = new float?[9];
   121       temperatures = new float?[3];
   122       fans = new float?[5];
   123 
   124       // The IT8721F uses a 12mV resultion ADC, all others 16mV
   125       if (chip == Chip.IT8721F) {
   126         voltageGain = 0.012f;
   127       } else {
   128         voltageGain = 0.016f;
   129       }
   130 
   131       // Set the number of GPIO sets
   132       switch (chip) {
   133         case Chip.IT8712F:
   134         case Chip.IT8716F:
   135         case Chip.IT8718F:
   136         case Chip.IT8726F:
   137           gpioCount = 5;
   138           break;
   139         case Chip.IT8720F:
   140         case Chip.IT8721F:
   141           gpioCount = 8;
   142           break;
   143       }
   144     }
   145 
   146     public Chip Chip { get { return chip; } }
   147     public float?[] Voltages { get { return voltages; } }
   148     public float?[] Temperatures { get { return temperatures; } }
   149     public float?[] Fans { get { return fans; } }
   150 
   151     public string GetReport() {
   152       StringBuilder r = new StringBuilder();
   153 
   154       r.AppendLine("LPC " + this.GetType().Name);
   155       r.AppendLine();
   156       r.Append("Chip ID: 0x"); r.AppendLine(chip.ToString("X"));
   157       r.Append("Chip Version: 0x"); r.AppendLine(
   158         version.ToString("X", CultureInfo.InvariantCulture));
   159       r.Append("Base Address: 0x"); r.AppendLine(
   160         address.ToString("X4", CultureInfo.InvariantCulture));
   161       r.Append("GPIO Address: 0x"); r.AppendLine(
   162         gpioAddress.ToString("X4", CultureInfo.InvariantCulture));
   163       r.AppendLine();
   164 
   165       if (!Ring0.WaitIsaBusMutex(100))
   166         return r.ToString();
   167 
   168       r.AppendLine("Environment Controller Registers");
   169       r.AppendLine();
   170       r.AppendLine("      00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F");
   171       r.AppendLine();
   172       for (int i = 0; i <= 0xA; i++) {
   173         r.Append(" "); 
   174         r.Append((i << 4).ToString("X2", CultureInfo.InvariantCulture)); 
   175         r.Append("  ");
   176         for (int j = 0; j <= 0xF; j++) {
   177           r.Append(" ");
   178           bool valid;
   179           byte value = ReadByte((byte)((i << 4) | j), out valid);
   180           r.Append(
   181             valid ? value.ToString("X2", CultureInfo.InvariantCulture) : "??");
   182         }
   183         r.AppendLine();
   184       }
   185       r.AppendLine();
   186 
   187       r.AppendLine("GPIO Registers");
   188       r.AppendLine();
   189       for (int i = 0; i < gpioCount; i++) {
   190         r.Append(" ");
   191         r.Append(ReadGPIO(i).Value.ToString("X2",
   192           CultureInfo.InvariantCulture));
   193       }
   194       r.AppendLine();
   195       r.AppendLine();
   196 
   197       Ring0.ReleaseIsaBusMutex();
   198 
   199       return r.ToString();
   200     }
   201 
   202     public void Update() {
   203       if (!Ring0.WaitIsaBusMutex(10))
   204         return;
   205 
   206       for (int i = 0; i < voltages.Length; i++) {
   207         bool valid;
   208         
   209         float value = 
   210           voltageGain * ReadByte((byte)(VOLTAGE_BASE_REG + i), out valid);   
   211 
   212         if (!valid)
   213           continue;
   214         if (value > 0)
   215           voltages[i] = value;  
   216         else
   217           voltages[i] = null;
   218       }
   219 
   220       for (int i = 0; i < temperatures.Length; i++) {
   221         bool valid;
   222         sbyte value = (sbyte)ReadByte(
   223           (byte)(TEMPERATURE_BASE_REG + i), out valid);
   224         if (!valid)
   225           continue;
   226 
   227         if (value < sbyte.MaxValue && value > 0)
   228           temperatures[i] = value;
   229         else
   230           temperatures[i] = null;       
   231       }
   232 
   233       for (int i = 0; i < fans.Length; i++) {
   234         bool valid;
   235         int value = ReadByte(FAN_TACHOMETER_REG[i], out valid);
   236         if (!valid) 
   237           continue;
   238         value |= ReadByte(FAN_TACHOMETER_EXT_REG[i], out valid) << 8;
   239         if (!valid)
   240           continue;
   241 
   242         if (value > 0x3f) {
   243           fans[i] = (value < 0xffff) ? 1.35e6f / ((value) * 2) : 0;
   244         } else {
   245           fans[i] = null;
   246         }
   247       }
   248 
   249       Ring0.ReleaseIsaBusMutex();
   250     }
   251   } 
   252 }