Hardware/LPC/IT87XX.cs
author moel.mich
Sat, 31 Dec 2011 17:31:04 +0000
changeset 324 c6ee430d6995
parent 320 df3493f75225
child 341 5172a92c5c20
permissions -rw-r--r--
Modified and extended version of the patch v4 by Roland Reinl (see Issue 256). Main differences to the original patch: DeviceIoControl refactorings removed, SmartAttribute is now descriptive only and does not hold any state, report is written as one 80 columns table, sensors are created only for meaningful values and without duplicates (remaining life, temperatures, host writes and reads). Also the current implementation should really preserve all the functionality of the old system. Additionally there is now a simple SMART devices emulation class (DebugSmart) that can be used in place of WindowsSmart for testing with reported data.
moel@16
     1
/*
moel@16
     2
  
moel@16
     3
  Version: MPL 1.1/GPL 2.0/LGPL 2.1
moel@16
     4
moel@16
     5
  The contents of this file are subject to the Mozilla Public License Version
moel@16
     6
  1.1 (the "License"); you may not use this file except in compliance with
moel@16
     7
  the License. You may obtain a copy of the License at
moel@16
     8
 
moel@16
     9
  http://www.mozilla.org/MPL/
moel@16
    10
moel@16
    11
  Software distributed under the License is distributed on an "AS IS" basis,
moel@16
    12
  WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
moel@16
    13
  for the specific language governing rights and limitations under the License.
moel@16
    14
moel@16
    15
  The Original Code is the Open Hardware Monitor code.
moel@16
    16
moel@16
    17
  The Initial Developer of the Original Code is 
moel@16
    18
  Michael Möller <m.moeller@gmx.ch>.
moel@319
    19
  Portions created by the Initial Developer are Copyright (C) 2009-2011
moel@16
    20
  the Initial Developer. All Rights Reserved.
moel@16
    21
moel@16
    22
  Contributor(s):
moel@16
    23
moel@16
    24
  Alternatively, the contents of this file may be used under the terms of
moel@16
    25
  either the GNU General Public License Version 2 or later (the "GPL"), or
moel@16
    26
  the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
moel@16
    27
  in which case the provisions of the GPL or the LGPL are applicable instead
moel@16
    28
  of those above. If you wish to allow use of your version of this file only
moel@16
    29
  under the terms of either the GPL or the LGPL, and not to allow others to
moel@16
    30
  use your version of this file under the terms of the MPL, indicate your
moel@16
    31
  decision by deleting the provisions above and replace them with the notice
moel@16
    32
  and other provisions required by the GPL or the LGPL. If you do not delete
moel@16
    33
  the provisions above, a recipient may use your version of this file under
moel@16
    34
  the terms of any one of the MPL, the GPL or the LGPL.
moel@16
    35
 
moel@16
    36
*/
moel@16
    37
moel@166
    38
using System.Globalization;
moel@16
    39
using System.Text;
moel@16
    40
moel@16
    41
namespace OpenHardwareMonitor.Hardware.LPC {
moel@165
    42
  internal class IT87XX : ISuperIO {
moel@130
    43
       
moel@195
    44
    private readonly ushort address;
moel@195
    45
    private readonly Chip chip;
moel@195
    46
    private readonly byte version;
moel@16
    47
moel@228
    48
    private readonly ushort gpioAddress;
moel@228
    49
    private readonly int gpioCount;
moel@228
    50
moel@78
    51
    private readonly ushort addressReg;
moel@78
    52
    private readonly ushort dataReg;
moel@78
    53
moel@195
    54
    private readonly float?[] voltages = new float?[0];
moel@195
    55
    private readonly float?[] temperatures = new float?[0];
moel@195
    56
    private readonly float?[] fans = new float?[0];
moel@323
    57
    private readonly float?[] controls = new float?[0];
moel@170
    58
moel@170
    59
    private readonly float voltageGain;
moel@272
    60
    private readonly bool has16bitFanCounter;
moel@16
    61
   
moel@16
    62
    // Consts
moel@16
    63
    private const byte ITE_VENDOR_ID = 0x90;
moel@16
    64
       
moel@16
    65
    // Environment Controller
moel@16
    66
    private const byte ADDRESS_REGISTER_OFFSET = 0x05;
moel@16
    67
    private const byte DATA_REGISTER_OFFSET = 0x06;
moel@16
    68
moel@16
    69
    // Environment Controller Registers    
moel@16
    70
    private const byte CONFIGURATION_REGISTER = 0x00;
moel@16
    71
    private const byte TEMPERATURE_BASE_REG = 0x29;
moel@16
    72
    private const byte VENDOR_ID_REGISTER = 0x58;
moel@272
    73
    private const byte FAN_TACHOMETER_DIVISOR_REGISTER = 0x0B;
moel@195
    74
    private readonly byte[] FAN_TACHOMETER_REG = 
moel@16
    75
      new byte[] { 0x0d, 0x0e, 0x0f, 0x80, 0x82 };
moel@195
    76
    private readonly byte[] FAN_TACHOMETER_EXT_REG =
moel@16
    77
      new byte[] { 0x18, 0x19, 0x1a, 0x81, 0x83 };
moel@78
    78
    private const byte VOLTAGE_BASE_REG = 0x20;
moel@78
    79
moel@78
    80
    private byte ReadByte(byte register, out bool valid) {
moel@236
    81
      Ring0.WriteIoPort(addressReg, register);
moel@236
    82
      byte value = Ring0.ReadIoPort(dataReg);
moel@236
    83
      valid = register == Ring0.ReadIoPort(addressReg);
moel@78
    84
      return value;
moel@228
    85
    }
moel@16
    86
moel@247
    87
    private bool WriteByte(byte register, byte value) {
moel@247
    88
      Ring0.WriteIoPort(addressReg, register);
moel@247
    89
      Ring0.WriteIoPort(dataReg, value);
moel@272
    90
      return register == Ring0.ReadIoPort(addressReg); 
moel@320
    91
    }
moel@247
    92
moel@228
    93
    public byte? ReadGPIO(int index) {
moel@228
    94
      if (index >= gpioCount)
moel@228
    95
        return null;
moel@228
    96
moel@236
    97
      return Ring0.ReadIoPort((ushort)(gpioAddress + index));
moel@228
    98
    }
moel@228
    99
moel@228
   100
    public void WriteGPIO(int index, byte value) {
moel@228
   101
      if (index >= gpioCount)
moel@228
   102
        return;
moel@228
   103
moel@236
   104
      Ring0.WriteIoPort((ushort)(gpioAddress + index), value);
moel@228
   105
    }
moel@228
   106
moel@323
   107
    public void SetControl(int index, byte? value) { }   
moel@323
   108
moel@228
   109
    public IT87XX(Chip chip, ushort address, ushort gpioAddress, byte version) {
moel@272
   110
moel@16
   111
      this.address = address;
moel@130
   112
      this.chip = chip;
moel@145
   113
      this.version = version;
moel@78
   114
      this.addressReg = (ushort)(address + ADDRESS_REGISTER_OFFSET);
moel@78
   115
      this.dataReg = (ushort)(address + DATA_REGISTER_OFFSET);
moel@228
   116
      this.gpioAddress = gpioAddress;
moel@228
   117
moel@16
   118
      // Check vendor id
moel@78
   119
      bool valid;
moel@78
   120
      byte vendorId = ReadByte(VENDOR_ID_REGISTER, out valid);       
moel@78
   121
      if (!valid || vendorId != ITE_VENDOR_ID)
moel@16
   122
        return;
moel@16
   123
moel@16
   124
      // Bit 0x10 of the configuration register should always be 1
moel@78
   125
      if ((ReadByte(CONFIGURATION_REGISTER, out valid) & 0x10) == 0)
moel@78
   126
        return;
moel@78
   127
      if (!valid)
moel@16
   128
        return;
moel@16
   129
moel@130
   130
      voltages = new float?[9];
moel@130
   131
      temperatures = new float?[3];
moel@130
   132
      fans = new float?[5];
moel@170
   133
moel@320
   134
      // IT8721F, IT8728F and IT8772E use a 12mV resultion ADC, all others 16mV
moel@319
   135
      if (chip == Chip.IT8721F || chip == Chip.IT8728F || chip == Chip.IT8772E) 
moel@319
   136
      {
moel@170
   137
        voltageGain = 0.012f;
moel@170
   138
      } else {
moel@272
   139
        voltageGain = 0.016f;        
moel@272
   140
      }
moel@272
   141
moel@272
   142
      // older IT8721F revision do not have 16-bit fan counters
moel@272
   143
      if (chip == Chip.IT8712F && version < 8) {
moel@272
   144
        has16bitFanCounter = false;
moel@272
   145
      } else {
moel@272
   146
        has16bitFanCounter = true;
moel@170
   147
      }
moel@228
   148
moel@228
   149
      // Set the number of GPIO sets
moel@228
   150
      switch (chip) {
moel@228
   151
        case Chip.IT8712F:
moel@228
   152
        case Chip.IT8716F:
moel@228
   153
        case Chip.IT8718F:
moel@228
   154
        case Chip.IT8726F:
moel@228
   155
          gpioCount = 5;
moel@228
   156
          break;
moel@228
   157
        case Chip.IT8720F:
moel@228
   158
        case Chip.IT8721F:
moel@228
   159
          gpioCount = 8;
moel@228
   160
          break;
moel@277
   161
        case Chip.IT8728F:
moel@319
   162
        case Chip.IT8772E:
moel@277
   163
          gpioCount = 0;
moel@277
   164
          break;
moel@228
   165
      }
moel@16
   166
    }
moel@16
   167
moel@130
   168
    public Chip Chip { get { return chip; } }
moel@130
   169
    public float?[] Voltages { get { return voltages; } }
moel@130
   170
    public float?[] Temperatures { get { return temperatures; } }
moel@130
   171
    public float?[] Fans { get { return fans; } }
moel@323
   172
    public float?[] Controls { get { return controls; } }
moel@16
   173
moel@130
   174
    public string GetReport() {
moel@16
   175
      StringBuilder r = new StringBuilder();
moel@16
   176
moel@31
   177
      r.AppendLine("LPC " + this.GetType().Name);
moel@16
   178
      r.AppendLine();
moel@16
   179
      r.Append("Chip ID: 0x"); r.AppendLine(chip.ToString("X"));
moel@166
   180
      r.Append("Chip Version: 0x"); r.AppendLine(
moel@166
   181
        version.ToString("X", CultureInfo.InvariantCulture));
moel@166
   182
      r.Append("Base Address: 0x"); r.AppendLine(
moel@166
   183
        address.ToString("X4", CultureInfo.InvariantCulture));
moel@228
   184
      r.Append("GPIO Address: 0x"); r.AppendLine(
moel@228
   185
        gpioAddress.ToString("X4", CultureInfo.InvariantCulture));
moel@16
   186
      r.AppendLine();
moel@162
   187
moel@236
   188
      if (!Ring0.WaitIsaBusMutex(100))
moel@162
   189
        return r.ToString();
moel@162
   190
moel@16
   191
      r.AppendLine("Environment Controller Registers");
moel@16
   192
      r.AppendLine();
moel@16
   193
      r.AppendLine("      00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F");
moel@16
   194
      r.AppendLine();
moel@16
   195
      for (int i = 0; i <= 0xA; i++) {
moel@166
   196
        r.Append(" "); 
moel@166
   197
        r.Append((i << 4).ToString("X2", CultureInfo.InvariantCulture)); 
moel@166
   198
        r.Append("  ");
moel@16
   199
        for (int j = 0; j <= 0xF; j++) {
moel@16
   200
          r.Append(" ");
moel@78
   201
          bool valid;
moel@78
   202
          byte value = ReadByte((byte)((i << 4) | j), out valid);
moel@195
   203
          r.Append(
moel@195
   204
            valid ? value.ToString("X2", CultureInfo.InvariantCulture) : "??");
moel@16
   205
        }
moel@16
   206
        r.AppendLine();
moel@16
   207
      }
moel@16
   208
      r.AppendLine();
moel@16
   209
moel@228
   210
      r.AppendLine("GPIO Registers");
moel@228
   211
      r.AppendLine();
moel@228
   212
      for (int i = 0; i < gpioCount; i++) {
moel@228
   213
        r.Append(" ");
moel@228
   214
        r.Append(ReadGPIO(i).Value.ToString("X2",
moel@228
   215
          CultureInfo.InvariantCulture));
moel@228
   216
      }
moel@228
   217
      r.AppendLine();
moel@228
   218
      r.AppendLine();
moel@228
   219
moel@236
   220
      Ring0.ReleaseIsaBusMutex();
moel@162
   221
moel@16
   222
      return r.ToString();
moel@16
   223
    }
moel@16
   224
moel@130
   225
    public void Update() {
moel@236
   226
      if (!Ring0.WaitIsaBusMutex(10))
moel@162
   227
        return;
moel@16
   228
moel@130
   229
      for (int i = 0; i < voltages.Length; i++) {
moel@78
   230
        bool valid;
moel@170
   231
        
moel@170
   232
        float value = 
moel@170
   233
          voltageGain * ReadByte((byte)(VOLTAGE_BASE_REG + i), out valid);   
moel@170
   234
moel@130
   235
        if (!valid)
moel@130
   236
          continue;
moel@130
   237
        if (value > 0)
moel@130
   238
          voltages[i] = value;  
moel@130
   239
        else
moel@130
   240
          voltages[i] = null;
moel@130
   241
      }
moel@130
   242
moel@130
   243
      for (int i = 0; i < temperatures.Length; i++) {
moel@130
   244
        bool valid;
moel@130
   245
        sbyte value = (sbyte)ReadByte(
moel@130
   246
          (byte)(TEMPERATURE_BASE_REG + i), out valid);
moel@78
   247
        if (!valid)
moel@78
   248
          continue;
moel@78
   249
moel@130
   250
        if (value < sbyte.MaxValue && value > 0)
moel@130
   251
          temperatures[i] = value;
moel@130
   252
        else
moel@130
   253
          temperatures[i] = null;       
moel@16
   254
      }
moel@16
   255
moel@272
   256
      if (has16bitFanCounter) {
moel@272
   257
        for (int i = 0; i < fans.Length; i++) {
moel@272
   258
          bool valid;
moel@272
   259
          int value = ReadByte(FAN_TACHOMETER_REG[i], out valid);
moel@272
   260
          if (!valid)
moel@272
   261
            continue;
moel@272
   262
          value |= ReadByte(FAN_TACHOMETER_EXT_REG[i], out valid) << 8;
moel@272
   263
          if (!valid)
moel@272
   264
            continue;
moel@16
   265
moel@272
   266
          if (value > 0x3f) {
moel@272
   267
            fans[i] = (value < 0xffff) ? 1.35e6f / (value * 2) : 0;
moel@272
   268
          } else {
moel@272
   269
            fans[i] = null;
moel@272
   270
          }
moel@272
   271
        }
moel@272
   272
      } else {
moel@272
   273
        for (int i = 0; i < fans.Length; i++) {
moel@272
   274
          bool valid;
moel@272
   275
          int value = ReadByte(FAN_TACHOMETER_REG[i], out valid);
moel@272
   276
          if (!valid)
moel@272
   277
            continue;
moel@272
   278
moel@272
   279
          int divisor = 2;
moel@272
   280
          if (i < 2) {
moel@272
   281
            int divisors = ReadByte(FAN_TACHOMETER_DIVISOR_REGISTER, out valid);
moel@272
   282
            if (!valid)
moel@272
   283
              continue;
moel@272
   284
            divisor = 1 << ((divisors >> (3 * i)) & 0x7);
moel@272
   285
          }
moel@272
   286
moel@272
   287
          if (value > 0) {
moel@272
   288
            fans[i] = (value < 0xff) ? 1.35e6f / (value * divisor) : 0;
moel@272
   289
          } else {
moel@272
   290
            fans[i] = null;
moel@272
   291
          }
moel@16
   292
        }
moel@162
   293
      }
moel@162
   294
moel@236
   295
      Ring0.ReleaseIsaBusMutex();
moel@126
   296
    }
moel@130
   297
  } 
moel@16
   298
}