Hardware/LPC/NCT677X.cs
author moel.mich
Sat, 25 Jun 2011 14:46:28 +0000
changeset 304 16a86362c2ca
parent 265 961c07a3bd78
child 323 3f2d9ebacf38
permissions -rw-r--r--
Changed the maximum buffer size for double buffering of controls that isn't disposed after each draw call to the size of the screen. This should reduce the memory allocation and disposing on each sensor update. Also page faults are no longer increasing with this change.
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@265
    19
  Portions created by the Initial Developer are Copyright (C) 2010-2011
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@276
    50
    private readonly float?[] temperatures = new float?[4];
moel@265
    51
    private readonly float?[] fans = new float?[0];
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@276
    76
      { 0x027, 0x73, 0x75, 0x77, 0x150, 0x250, 0x62B, 0x62C, 0x62D };
moel@245
    77
    private readonly ushort[] TEMPERATURE_HALF_REG = 
moel@276
    78
      { 0, 0x74, 0x76, 0x78, 0x151, 0x251, 0x62E, 0x62E, 0x62E };    
moel@245
    79
    private readonly ushort[] TEMPERATURE_SRC_REG = 
moel@276
    80
      { 0x621, 0x100, 0x200, 0x300, 0x622, 0x623, 0x624, 0x625, 0x626 };
moel@276
    81
    private readonly int[] TEMPERATURE_HALF_BIT =
moel@276
    82
      { -1, 7, 7, 7, 7, 7, 0, 1, 2 };
moel@245
    83
    private readonly ushort[] VOLTAGE_REG = 
moel@245
    84
      { 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x550, 0x551 };
moel@265
    85
    private readonly ushort[] FAN_RPM_REG = 
moel@265
    86
      { 0x656, 0x658, 0x65A, 0x65C, 0x65E};
moel@265
    87
moel@265
    88
    private readonly int minFanRPM;
moel@245
    89
moel@276
    90
    private enum SourceNCT6771F : byte {
moel@245
    91
      SYSTIN = 1,
moel@245
    92
      CPUTIN = 2,
moel@245
    93
      AUXTIN = 3,
moel@245
    94
      SMBUSMASTER = 4,
moel@276
    95
      PECI_0 = 5, 
moel@276
    96
      PECI_1 = 6, 
moel@276
    97
      PECI_2 = 7,
moel@276
    98
      PECI_3 = 8,
moel@276
    99
      PECI_4 = 9,
moel@276
   100
      PECI_5 = 10,
moel@276
   101
      PECI_6 = 11,
moel@276
   102
      PECI_7 = 12,
moel@245
   103
      PCH_CHIP_CPU_MAX_TEMP = 13,
moel@245
   104
      PCH_CHIP_TEMP = 14,
moel@245
   105
      PCH_CPU_TEMP = 15,
moel@245
   106
      PCH_MCH_TEMP = 16, 
moel@245
   107
      PCH_DIM0_TEMP = 17,
moel@245
   108
      PCH_DIM1_TEMP = 18,
moel@245
   109
      PCH_DIM2_TEMP = 19,
moel@245
   110
      PCH_DIM3_TEMP = 20
moel@245
   111
    }
moel@245
   112
moel@276
   113
    private enum SourceNCT6776F : byte {
moel@276
   114
      SYSTIN = 1,
moel@276
   115
      CPUTIN = 2,
moel@276
   116
      AUXTIN = 3,
moel@276
   117
      SMBUSMASTER_0 = 4,
moel@276
   118
      SMBUSMASTER_1 = 5,
moel@276
   119
      SMBUSMASTER_2 = 6,
moel@276
   120
      SMBUSMASTER_3 = 7,
moel@276
   121
      SMBUSMASTER_4 = 8,
moel@276
   122
      SMBUSMASTER_5 = 9,
moel@276
   123
      SMBUSMASTER_6 = 10,
moel@276
   124
      SMBUSMASTER_7 = 11,
moel@276
   125
      PECI_0 = 12,
moel@276
   126
      PECI_1 = 13,
moel@276
   127
      PCH_CHIP_CPU_MAX_TEMP = 14,
moel@276
   128
      PCH_CHIP_TEMP = 15,
moel@276
   129
      PCH_CPU_TEMP = 16,
moel@276
   130
      PCH_MCH_TEMP = 17,
moel@276
   131
      PCH_DIM0_TEMP = 18,
moel@276
   132
      PCH_DIM1_TEMP = 19,
moel@276
   133
      PCH_DIM2_TEMP = 20,
moel@276
   134
      PCH_DIM3_TEMP = 21,
moel@276
   135
      BYTE_TEMP = 22
moel@276
   136
    }
moel@276
   137
moel@245
   138
    public NCT677X(Chip chip, byte revision, ushort port) {
moel@245
   139
      this.chip = chip;
moel@245
   140
      this.revision = revision;
moel@245
   141
      this.port = port;
moel@245
   142
moel@245
   143
      if (!IsNuvotonVendor())
moel@265
   144
        return;
moel@265
   145
moel@265
   146
      switch (chip) {
moel@265
   147
        case LPC.Chip.NCT6771F:
moel@265
   148
          fans = new float?[4];
moel@265
   149
          // min value RPM value with 16-bit fan counter
moel@265
   150
          minFanRPM = (int)(1.35e6 / 0xFFFF);
moel@265
   151
          break;
moel@265
   152
        case LPC.Chip.NCT6776F:
moel@265
   153
          fans = new float?[5];
moel@265
   154
          // min value RPM value with 13-bit fan counter
moel@265
   155
          minFanRPM = (int)(1.35e6 / 0x1FFF);
moel@265
   156
          break;        
moel@265
   157
      }
moel@245
   158
    }
moel@245
   159
moel@245
   160
    private bool IsNuvotonVendor() {
moel@245
   161
      return ((ReadByte(VENDOR_ID_HIGH_REGISTER) << 8) |
moel@245
   162
        ReadByte(VENDOR_ID_LOW_REGISTER)) == NUVOTON_VENDOR_ID;
moel@245
   163
    }
moel@245
   164
moel@245
   165
    public byte? ReadGPIO(int index) {
moel@245
   166
      return null;
moel@245
   167
    }
moel@245
   168
moel@245
   169
    public void WriteGPIO(int index, byte value) { }
moel@245
   170
moel@245
   171
    public Chip Chip { get { return chip; } }
moel@245
   172
    public float?[] Voltages { get { return voltages; } }
moel@245
   173
    public float?[] Temperatures { get { return temperatures; } }
moel@245
   174
    public float?[] Fans { get { return fans; } }
moel@245
   175
moel@245
   176
    public void Update() {
moel@245
   177
      if (!Ring0.WaitIsaBusMutex(10))
moel@245
   178
        return;
moel@245
   179
moel@245
   180
      for (int i = 0; i < voltages.Length; i++) {
moel@245
   181
        float value = 0.008f * ReadByte(VOLTAGE_REG[i]);
moel@245
   182
        bool valid = value > 0;
moel@245
   183
moel@245
   184
        // check if battery voltage monitor is enabled
moel@245
   185
        if (valid && VOLTAGE_REG[i] == VOLTAGE_VBAT_REG) 
moel@245
   186
          valid = (ReadByte(0x005D) & 0x01) > 0;
moel@245
   187
moel@245
   188
        voltages[i] = valid ? value : (float?)null;
moel@245
   189
      }
moel@245
   190
moel@276
   191
      for (int i = TEMPERATURE_REG.Length - 1; i >= 0 ; i--) {
moel@246
   192
        int value = ((sbyte)ReadByte(TEMPERATURE_REG[i])) << 1;
moel@245
   193
        if (TEMPERATURE_HALF_BIT[i] > 0) {
moel@246
   194
          value |= ((ReadByte(TEMPERATURE_HALF_REG[i]) >>
moel@245
   195
            TEMPERATURE_HALF_BIT[i]) & 0x1);
moel@245
   196
        }
moel@245
   197
moel@276
   198
        byte source = ReadByte(TEMPERATURE_SRC_REG[i]);
moel@245
   199
moel@246
   200
        float? temperature = 0.5f * value;
moel@246
   201
        if (temperature > 125 || temperature < -55)
moel@246
   202
          temperature = null;
moel@246
   203
moel@276
   204
        switch (chip) {
moel@276
   205
          case Chip.NCT6771F:
moel@276
   206
            switch ((SourceNCT6771F)source) {
moel@276
   207
              case SourceNCT6771F.PECI_0: temperatures[0] = temperature; break;
moel@276
   208
              case SourceNCT6771F.CPUTIN: temperatures[1] = temperature; break;
moel@276
   209
              case SourceNCT6771F.AUXTIN: temperatures[2] = temperature; break;
moel@276
   210
              case SourceNCT6771F.SYSTIN: temperatures[3] = temperature; break;
moel@276
   211
              
moel@276
   212
            } break;
moel@276
   213
          case Chip.NCT6776F:
moel@276
   214
            switch ((SourceNCT6776F)source) {
moel@276
   215
              case SourceNCT6776F.PECI_0: temperatures[0] = temperature; break;
moel@276
   216
              case SourceNCT6776F.CPUTIN: temperatures[1] = temperature; break;
moel@276
   217
              case SourceNCT6776F.AUXTIN: temperatures[2] = temperature; break;
moel@276
   218
              case SourceNCT6776F.SYSTIN: temperatures[3] = temperature; break;              
moel@276
   219
            } break;
moel@276
   220
        }  
moel@245
   221
      }
moel@245
   222
moel@245
   223
      for (int i = 0; i < fans.Length; i++) {
moel@245
   224
        byte high = ReadByte(FAN_RPM_REG[i]);
moel@245
   225
        byte low = ReadByte((ushort)(FAN_RPM_REG[i] + 1));
moel@265
   226
        int value = (high << 8) | low;
moel@265
   227
moel@265
   228
        fans[i] = value > minFanRPM ? value : 0;
moel@245
   229
      }
moel@245
   230
moel@245
   231
      Ring0.ReleaseIsaBusMutex();
moel@245
   232
    }
moel@245
   233
moel@245
   234
    public string GetReport() {
moel@245
   235
      StringBuilder r = new StringBuilder();
moel@245
   236
moel@245
   237
      r.AppendLine("LPC " + this.GetType().Name);
moel@245
   238
      r.AppendLine();
moel@245
   239
      r.Append("Chip ID: 0x"); r.AppendLine(chip.ToString("X"));
moel@245
   240
      r.Append("Chip revision: 0x");
moel@245
   241
      r.AppendLine(revision.ToString("X", CultureInfo.InvariantCulture));
moel@245
   242
      r.Append("Base Adress: 0x");
moel@245
   243
      r.AppendLine(port.ToString("X4", CultureInfo.InvariantCulture));
moel@245
   244
      r.AppendLine();
moel@245
   245
moel@245
   246
      if (!Ring0.WaitIsaBusMutex(100))
moel@245
   247
        return r.ToString();
moel@245
   248
moel@246
   249
      ushort[] addresses = new ushort[] { 
moel@246
   250
        0x000, 0x010, 0x020, 0x030, 0x040, 0x050, 0x060, 0x070,
moel@246
   251
        0x100, 0x110, 0x120, 0x130, 0x140, 0x150, 
moel@246
   252
        0x200,        0x220, 0x230, 0x240, 0x250,
moel@246
   253
        0x300,        0x320, 0x330, 0x340, 
moel@246
   254
        0x400, 0x410, 0x420,        0x440, 0x450, 0x460, 
moel@246
   255
        0x500,                             0x550, 
moel@246
   256
        0x600, 0x610 ,0x620, 0x630, 0x640, 0x650, 0x660, 0x670, 
moel@246
   257
        0xA00, 0xA10, 0xA20, 0xA30,        0xA50, 0xA60, 0xA70, 
moel@246
   258
        0xB00, 0xB10, 0xB20, 0xB30,        0xB50, 0xB60, 0xB70, 
moel@246
   259
        0xC00, 0xC10, 0xC20, 0xC30,        0xC50, 0xC60, 0xC70,
moel@246
   260
        0xD00, 0xD10, 0xD20, 0xD30,        0xD50, 0xD60, 
moel@246
   261
        0xE00, 0xE10, 0xE20, 0xE30, 
moel@246
   262
        0xF00, 0xF10, 0xF20, 0xF30};
moel@246
   263
moel@245
   264
      r.AppendLine("Hardware Monitor Registers");
moel@245
   265
      r.AppendLine();
moel@245
   266
      r.AppendLine("       00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F");
moel@245
   267
      r.AppendLine();
moel@246
   268
      foreach (ushort address in addresses) {
moel@245
   269
          r.Append(" ");
moel@246
   270
          r.Append(address.ToString("X3", CultureInfo.InvariantCulture));
moel@245
   271
          r.Append("  ");
moel@246
   272
          for (ushort j = 0; j <= 0xF; j++) {
moel@245
   273
            r.Append(" ");
moel@246
   274
            r.Append(ReadByte((ushort)(address | j)).ToString(
moel@245
   275
              "X2", CultureInfo.InvariantCulture));
moel@245
   276
          }
moel@245
   277
          r.AppendLine();
moel@245
   278
      }
moel@245
   279
      r.AppendLine();
moel@245
   280
moel@245
   281
      Ring0.ReleaseIsaBusMutex();
moel@245
   282
moel@245
   283
      return r.ToString();
moel@245
   284
    }
moel@245
   285
  }
moel@245
   286
}