Hardware/LPC/NCT677X.cs
author moel.mich
Thu, 17 Mar 2011 20:16:01 +0000
changeset 263 575f8d4c378d
parent 245 f8e72b2efcc0
child 265 961c07a3bd78
permissions -rw-r--r--
Fixed Issue 178.
moel@245
     1
/*
moel@245
     2
  
moel@245
     3
  Version: MPL 1.1/GPL 2.0/LGPL 2.1
moel@245
     4
moel@245
     5
  The contents of this file are subject to the Mozilla Public License Version
moel@245
     6
  1.1 (the "License"); you may not use this file except in compliance with
moel@245
     7
  the License. You may obtain a copy of the License at
moel@245
     8
 
moel@245
     9
  http://www.mozilla.org/MPL/
moel@245
    10
moel@245
    11
  Software distributed under the License is distributed on an "AS IS" basis,
moel@245
    12
  WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
moel@245
    13
  for the specific language governing rights and limitations under the License.
moel@245
    14
moel@245
    15
  The Original Code is the Open Hardware Monitor code.
moel@245
    16
moel@245
    17
  The Initial Developer of the Original Code is 
moel@245
    18
  Michael Möller <m.moeller@gmx.ch>.
moel@245
    19
  Portions created by the Initial Developer are Copyright (C) 2010
moel@245
    20
  the Initial Developer. All Rights Reserved.
moel@245
    21
moel@245
    22
  Contributor(s):
moel@245
    23
moel@245
    24
  Alternatively, the contents of this file may be used under the terms of
moel@245
    25
  either the GNU General Public License Version 2 or later (the "GPL"), or
moel@245
    26
  the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
moel@245
    27
  in which case the provisions of the GPL or the LGPL are applicable instead
moel@245
    28
  of those above. If you wish to allow use of your version of this file only
moel@245
    29
  under the terms of either the GPL or the LGPL, and not to allow others to
moel@245
    30
  use your version of this file under the terms of the MPL, indicate your
moel@245
    31
  decision by deleting the provisions above and replace them with the notice
moel@245
    32
  and other provisions required by the GPL or the LGPL. If you do not delete
moel@245
    33
  the provisions above, a recipient may use your version of this file under
moel@245
    34
  the terms of any one of the MPL, the GPL or the LGPL.
moel@245
    35
 
moel@245
    36
*/
moel@245
    37
moel@245
    38
using System.Globalization;
moel@245
    39
using System.Text;
moel@245
    40
moel@245
    41
namespace OpenHardwareMonitor.Hardware.LPC {
moel@245
    42
  internal class NCT677X : ISuperIO {
moel@245
    43
moel@245
    44
    private readonly ushort port;
moel@245
    45
    private readonly byte revision;
moel@245
    46
moel@245
    47
    private readonly Chip chip;
moel@245
    48
moel@245
    49
    private readonly float?[] voltages = new float?[9];
moel@245
    50
    private readonly float?[] temperatures = new float?[3];
moel@245
    51
    private readonly float?[] fans = new float?[4];
moel@245
    52
moel@245
    53
    // Hardware Monitor
moel@245
    54
    private const uint ADDRESS_REGISTER_OFFSET = 0x05;
moel@245
    55
    private const uint DATA_REGISTER_OFFSET = 0x06;
moel@245
    56
    private const byte BANK_SELECT_REGISTER = 0x4E;
moel@245
    57
moel@245
    58
    private byte ReadByte(ushort address) {
moel@245
    59
      byte bank = (byte)(address >> 8);
moel@245
    60
      byte register = (byte)(address & 0xFF);
moel@245
    61
      Ring0.WriteIoPort(port + ADDRESS_REGISTER_OFFSET, BANK_SELECT_REGISTER);
moel@245
    62
      Ring0.WriteIoPort(port + DATA_REGISTER_OFFSET, bank);
moel@245
    63
      Ring0.WriteIoPort(port + ADDRESS_REGISTER_OFFSET, register);
moel@245
    64
      return Ring0.ReadIoPort(port + DATA_REGISTER_OFFSET);
moel@246
    65
    } 
moel@245
    66
moel@245
    67
    // Consts 
moel@245
    68
    private const ushort NUVOTON_VENDOR_ID = 0x5CA3;
moel@245
    69
moel@245
    70
    // Hardware Monitor Registers    
moel@245
    71
    private const ushort VENDOR_ID_HIGH_REGISTER = 0x804F;
moel@245
    72
    private const ushort VENDOR_ID_LOW_REGISTER = 0x004F;
moel@245
    73
    private const ushort VOLTAGE_VBAT_REG = 0x0551;
moel@245
    74
moel@245
    75
    private readonly ushort[] TEMPERATURE_REG = 
moel@245
    76
      { 0x150, 0x250, 0x27, 0x62B, 0x62C, 0x62D };
moel@245
    77
    private readonly ushort[] TEMPERATURE_HALF_REG = 
moel@245
    78
      { 0x151, 0x251, 0, 0x62E, 0x62E, 0x62E };    
moel@245
    79
    private readonly ushort[] TEMPERATURE_SRC_REG = 
moel@245
    80
      { 0x621, 0x622, 0x623, 0x624, 0x625, 0x626 };
moel@245
    81
    private readonly int[] TEMPERATURE_HALF_BIT = { 7, 7, -1, 0, 1, 2 };
moel@245
    82
    private readonly ushort[] VOLTAGE_REG = 
moel@245
    83
      { 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x550, 0x551 };
moel@245
    84
    private readonly ushort[] FAN_RPM_REG = { 0x656, 0x658, 0x65A, 0x65C};
moel@245
    85
moel@245
    86
    private enum TemperatureSource : byte {
moel@245
    87
      SYSTIN = 1,
moel@245
    88
      CPUTIN = 2,
moel@245
    89
      AUXTIN = 3,
moel@245
    90
      SMBUSMASTER = 4,
moel@245
    91
      PECI0 = 5, 
moel@245
    92
      PECI1 = 6, 
moel@245
    93
      PECI2 = 7,
moel@245
    94
      PECI3 = 8,
moel@245
    95
      PECI4 = 9,
moel@245
    96
      PECI5 = 10,
moel@245
    97
      PECI6 = 11,
moel@245
    98
      PECI7 = 12,
moel@245
    99
      PCH_CHIP_CPU_MAX_TEMP = 13,
moel@245
   100
      PCH_CHIP_TEMP = 14,
moel@245
   101
      PCH_CPU_TEMP = 15,
moel@245
   102
      PCH_MCH_TEMP = 16, 
moel@245
   103
      PCH_DIM0_TEMP = 17,
moel@245
   104
      PCH_DIM1_TEMP = 18,
moel@245
   105
      PCH_DIM2_TEMP = 19,
moel@245
   106
      PCH_DIM3_TEMP = 20
moel@245
   107
    }
moel@245
   108
moel@245
   109
    public NCT677X(Chip chip, byte revision, ushort port) {
moel@245
   110
      this.chip = chip;
moel@245
   111
      this.revision = revision;
moel@245
   112
      this.port = port;
moel@245
   113
moel@245
   114
      if (!IsNuvotonVendor())
moel@245
   115
        return;      
moel@245
   116
    }
moel@245
   117
moel@245
   118
    private bool IsNuvotonVendor() {
moel@245
   119
      return ((ReadByte(VENDOR_ID_HIGH_REGISTER) << 8) |
moel@245
   120
        ReadByte(VENDOR_ID_LOW_REGISTER)) == NUVOTON_VENDOR_ID;
moel@245
   121
    }
moel@245
   122
moel@245
   123
    public byte? ReadGPIO(int index) {
moel@245
   124
      return null;
moel@245
   125
    }
moel@245
   126
moel@245
   127
    public void WriteGPIO(int index, byte value) { }
moel@245
   128
moel@245
   129
    public Chip Chip { get { return chip; } }
moel@245
   130
    public float?[] Voltages { get { return voltages; } }
moel@245
   131
    public float?[] Temperatures { get { return temperatures; } }
moel@245
   132
    public float?[] Fans { get { return fans; } }
moel@245
   133
moel@245
   134
    public void Update() {
moel@245
   135
      if (!Ring0.WaitIsaBusMutex(10))
moel@245
   136
        return;
moel@245
   137
moel@245
   138
      for (int i = 0; i < voltages.Length; i++) {
moel@245
   139
        float value = 0.008f * ReadByte(VOLTAGE_REG[i]);
moel@245
   140
        bool valid = value > 0;
moel@245
   141
moel@245
   142
        // check if battery voltage monitor is enabled
moel@245
   143
        if (valid && VOLTAGE_REG[i] == VOLTAGE_VBAT_REG) 
moel@245
   144
          valid = (ReadByte(0x005D) & 0x01) > 0;
moel@245
   145
moel@245
   146
        voltages[i] = valid ? value : (float?)null;
moel@245
   147
      }
moel@245
   148
moel@245
   149
      for (int i = 0; i < TEMPERATURE_REG.Length; i++) {
moel@246
   150
        int value = ((sbyte)ReadByte(TEMPERATURE_REG[i])) << 1;
moel@245
   151
        if (TEMPERATURE_HALF_BIT[i] > 0) {
moel@246
   152
          value |= ((ReadByte(TEMPERATURE_HALF_REG[i]) >>
moel@245
   153
            TEMPERATURE_HALF_BIT[i]) & 0x1);
moel@245
   154
        }
moel@245
   155
moel@245
   156
        TemperatureSource source = (TemperatureSource)
moel@245
   157
          ReadByte(TEMPERATURE_SRC_REG[i]);
moel@245
   158
moel@246
   159
        float? temperature = 0.5f * value;
moel@246
   160
        if (temperature > 125 || temperature < -55)
moel@246
   161
          temperature = null;
moel@246
   162
moel@245
   163
        switch (source) {
moel@246
   164
          case TemperatureSource.CPUTIN: temperatures[0] = temperature; break;
moel@246
   165
          case TemperatureSource.AUXTIN: temperatures[1] = temperature; break;
moel@246
   166
          case TemperatureSource.SYSTIN: temperatures[2] = temperature; break;
moel@245
   167
        }
moel@245
   168
      }
moel@245
   169
moel@245
   170
      for (int i = 0; i < fans.Length; i++) {
moel@245
   171
        byte high = ReadByte(FAN_RPM_REG[i]);
moel@245
   172
        byte low = ReadByte((ushort)(FAN_RPM_REG[i] + 1));
moel@245
   173
        fans[i] = (high << 8) | low;
moel@245
   174
      }
moel@245
   175
moel@245
   176
      Ring0.ReleaseIsaBusMutex();
moel@245
   177
    }
moel@245
   178
moel@245
   179
    public string GetReport() {
moel@245
   180
      StringBuilder r = new StringBuilder();
moel@245
   181
moel@245
   182
      r.AppendLine("LPC " + this.GetType().Name);
moel@245
   183
      r.AppendLine();
moel@245
   184
      r.Append("Chip ID: 0x"); r.AppendLine(chip.ToString("X"));
moel@245
   185
      r.Append("Chip revision: 0x");
moel@245
   186
      r.AppendLine(revision.ToString("X", CultureInfo.InvariantCulture));
moel@245
   187
      r.Append("Base Adress: 0x");
moel@245
   188
      r.AppendLine(port.ToString("X4", CultureInfo.InvariantCulture));
moel@245
   189
      r.AppendLine();
moel@245
   190
moel@245
   191
      if (!Ring0.WaitIsaBusMutex(100))
moel@245
   192
        return r.ToString();
moel@245
   193
moel@246
   194
      ushort[] addresses = new ushort[] { 
moel@246
   195
        0x000, 0x010, 0x020, 0x030, 0x040, 0x050, 0x060, 0x070,
moel@246
   196
        0x100, 0x110, 0x120, 0x130, 0x140, 0x150, 
moel@246
   197
        0x200,        0x220, 0x230, 0x240, 0x250,
moel@246
   198
        0x300,        0x320, 0x330, 0x340, 
moel@246
   199
        0x400, 0x410, 0x420,        0x440, 0x450, 0x460, 
moel@246
   200
        0x500,                             0x550, 
moel@246
   201
        0x600, 0x610 ,0x620, 0x630, 0x640, 0x650, 0x660, 0x670, 
moel@246
   202
        0xA00, 0xA10, 0xA20, 0xA30,        0xA50, 0xA60, 0xA70, 
moel@246
   203
        0xB00, 0xB10, 0xB20, 0xB30,        0xB50, 0xB60, 0xB70, 
moel@246
   204
        0xC00, 0xC10, 0xC20, 0xC30,        0xC50, 0xC60, 0xC70,
moel@246
   205
        0xD00, 0xD10, 0xD20, 0xD30,        0xD50, 0xD60, 
moel@246
   206
        0xE00, 0xE10, 0xE20, 0xE30, 
moel@246
   207
        0xF00, 0xF10, 0xF20, 0xF30};
moel@246
   208
moel@245
   209
      r.AppendLine("Hardware Monitor Registers");
moel@245
   210
      r.AppendLine();
moel@245
   211
      r.AppendLine("       00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F");
moel@245
   212
      r.AppendLine();
moel@246
   213
      foreach (ushort address in addresses) {
moel@245
   214
          r.Append(" ");
moel@246
   215
          r.Append(address.ToString("X3", CultureInfo.InvariantCulture));
moel@245
   216
          r.Append("  ");
moel@246
   217
          for (ushort j = 0; j <= 0xF; j++) {
moel@245
   218
            r.Append(" ");
moel@246
   219
            r.Append(ReadByte((ushort)(address | j)).ToString(
moel@245
   220
              "X2", CultureInfo.InvariantCulture));
moel@245
   221
          }
moel@245
   222
          r.AppendLine();
moel@245
   223
      }
moel@245
   224
      r.AppendLine();
moel@245
   225
moel@245
   226
      Ring0.ReleaseIsaBusMutex();
moel@245
   227
moel@245
   228
      return r.ToString();
moel@245
   229
    }
moel@245
   230
  }
moel@245
   231
}