Hardware/LPC/IT87XX.cs
author moel.mich
Sun, 23 Sep 2012 18:37:43 +0000
changeset 380 573f1fff48b2
parent 344 3145aadca3d2
child 382 ba6abd47a80c
permissions -rw-r--r--
Fixed Issue 387. The new implementation does not try to start a ring 0 driver that already exists, but could not be opened. It tries to delete the driver and install it new. The driver is now stored temporarily in the application folder. The driver is not correctly removed on system shutdown.
moel@16
     1
/*
moel@16
     2
 
moel@344
     3
  This Source Code Form is subject to the terms of the Mozilla Public
moel@344
     4
  License, v. 2.0. If a copy of the MPL was not distributed with this
moel@344
     5
  file, You can obtain one at http://mozilla.org/MPL/2.0/.
moel@16
     6
 
moel@344
     7
  Copyright (C) 2009-2012 Michael Möller <mmoeller@openhardwaremonitor.org>
moel@344
     8
	
moel@16
     9
*/
moel@16
    10
moel@166
    11
using System.Globalization;
moel@16
    12
using System.Text;
moel@16
    13
moel@16
    14
namespace OpenHardwareMonitor.Hardware.LPC {
moel@165
    15
  internal class IT87XX : ISuperIO {
moel@130
    16
       
moel@195
    17
    private readonly ushort address;
moel@195
    18
    private readonly Chip chip;
moel@195
    19
    private readonly byte version;
moel@16
    20
moel@228
    21
    private readonly ushort gpioAddress;
moel@228
    22
    private readonly int gpioCount;
moel@228
    23
moel@78
    24
    private readonly ushort addressReg;
moel@78
    25
    private readonly ushort dataReg;
moel@78
    26
moel@195
    27
    private readonly float?[] voltages = new float?[0];
moel@195
    28
    private readonly float?[] temperatures = new float?[0];
moel@195
    29
    private readonly float?[] fans = new float?[0];
moel@323
    30
    private readonly float?[] controls = new float?[0];
moel@170
    31
moel@170
    32
    private readonly float voltageGain;
moel@272
    33
    private readonly bool has16bitFanCounter;
moel@16
    34
   
moel@16
    35
    // Consts
moel@16
    36
    private const byte ITE_VENDOR_ID = 0x90;
moel@16
    37
       
moel@16
    38
    // Environment Controller
moel@16
    39
    private const byte ADDRESS_REGISTER_OFFSET = 0x05;
moel@16
    40
    private const byte DATA_REGISTER_OFFSET = 0x06;
moel@16
    41
moel@16
    42
    // Environment Controller Registers    
moel@16
    43
    private const byte CONFIGURATION_REGISTER = 0x00;
moel@16
    44
    private const byte TEMPERATURE_BASE_REG = 0x29;
moel@16
    45
    private const byte VENDOR_ID_REGISTER = 0x58;
moel@272
    46
    private const byte FAN_TACHOMETER_DIVISOR_REGISTER = 0x0B;
moel@195
    47
    private readonly byte[] FAN_TACHOMETER_REG = 
moel@16
    48
      new byte[] { 0x0d, 0x0e, 0x0f, 0x80, 0x82 };
moel@195
    49
    private readonly byte[] FAN_TACHOMETER_EXT_REG =
moel@16
    50
      new byte[] { 0x18, 0x19, 0x1a, 0x81, 0x83 };
moel@78
    51
    private const byte VOLTAGE_BASE_REG = 0x20;
moel@78
    52
moel@78
    53
    private byte ReadByte(byte register, out bool valid) {
moel@236
    54
      Ring0.WriteIoPort(addressReg, register);
moel@236
    55
      byte value = Ring0.ReadIoPort(dataReg);
moel@236
    56
      valid = register == Ring0.ReadIoPort(addressReg);
moel@78
    57
      return value;
moel@228
    58
    }
moel@16
    59
moel@247
    60
    private bool WriteByte(byte register, byte value) {
moel@247
    61
      Ring0.WriteIoPort(addressReg, register);
moel@247
    62
      Ring0.WriteIoPort(dataReg, value);
moel@272
    63
      return register == Ring0.ReadIoPort(addressReg); 
moel@320
    64
    }
moel@247
    65
moel@228
    66
    public byte? ReadGPIO(int index) {
moel@228
    67
      if (index >= gpioCount)
moel@228
    68
        return null;
moel@228
    69
moel@236
    70
      return Ring0.ReadIoPort((ushort)(gpioAddress + index));
moel@228
    71
    }
moel@228
    72
moel@228
    73
    public void WriteGPIO(int index, byte value) {
moel@228
    74
      if (index >= gpioCount)
moel@228
    75
        return;
moel@228
    76
moel@236
    77
      Ring0.WriteIoPort((ushort)(gpioAddress + index), value);
moel@341
    78
    } 
moel@228
    79
moel@323
    80
    public void SetControl(int index, byte? value) { }   
moel@323
    81
moel@228
    82
    public IT87XX(Chip chip, ushort address, ushort gpioAddress, byte version) {
moel@272
    83
moel@16
    84
      this.address = address;
moel@130
    85
      this.chip = chip;
moel@145
    86
      this.version = version;
moel@78
    87
      this.addressReg = (ushort)(address + ADDRESS_REGISTER_OFFSET);
moel@78
    88
      this.dataReg = (ushort)(address + DATA_REGISTER_OFFSET);
moel@228
    89
      this.gpioAddress = gpioAddress;
moel@228
    90
moel@16
    91
      // Check vendor id
moel@78
    92
      bool valid;
moel@78
    93
      byte vendorId = ReadByte(VENDOR_ID_REGISTER, out valid);       
moel@78
    94
      if (!valid || vendorId != ITE_VENDOR_ID)
moel@16
    95
        return;
moel@16
    96
moel@16
    97
      // Bit 0x10 of the configuration register should always be 1
moel@78
    98
      if ((ReadByte(CONFIGURATION_REGISTER, out valid) & 0x10) == 0)
moel@78
    99
        return;
moel@78
   100
      if (!valid)
moel@16
   101
        return;
moel@16
   102
moel@130
   103
      voltages = new float?[9];
moel@130
   104
      temperatures = new float?[3];
moel@353
   105
      fans = new float?[chip == Chip.IT8705F ? 3 : 5];
moel@170
   106
moel@320
   107
      // IT8721F, IT8728F and IT8772E use a 12mV resultion ADC, all others 16mV
moel@341
   108
      if (chip == Chip.IT8721F || chip == Chip.IT8728F || chip == Chip.IT8771E 
moel@341
   109
        || chip == Chip.IT8772E) 
moel@319
   110
      {
moel@170
   111
        voltageGain = 0.012f;
moel@170
   112
      } else {
moel@272
   113
        voltageGain = 0.016f;        
moel@272
   114
      }
moel@272
   115
moel@353
   116
      // older IT8705F and IT8721F revisions do not have 16-bit fan counters
moel@353
   117
      if ((chip == Chip.IT8705F && version < 3) || 
moel@353
   118
          (chip == Chip.IT8712F && version < 8)) 
moel@353
   119
      {
moel@272
   120
        has16bitFanCounter = false;
moel@272
   121
      } else {
moel@272
   122
        has16bitFanCounter = true;
moel@170
   123
      }
moel@228
   124
moel@228
   125
      // Set the number of GPIO sets
moel@228
   126
      switch (chip) {
moel@228
   127
        case Chip.IT8712F:
moel@228
   128
        case Chip.IT8716F:
moel@228
   129
        case Chip.IT8718F:
moel@228
   130
        case Chip.IT8726F:
moel@228
   131
          gpioCount = 5;
moel@228
   132
          break;
moel@228
   133
        case Chip.IT8720F:
moel@228
   134
        case Chip.IT8721F:
moel@228
   135
          gpioCount = 8;
moel@228
   136
          break;
moel@353
   137
        case Chip.IT8705F: 
moel@277
   138
        case Chip.IT8728F:
moel@341
   139
        case Chip.IT8771E:
moel@319
   140
        case Chip.IT8772E:
moel@277
   141
          gpioCount = 0;
moel@277
   142
          break;
moel@228
   143
      }
moel@16
   144
    }
moel@16
   145
moel@130
   146
    public Chip Chip { get { return chip; } }
moel@130
   147
    public float?[] Voltages { get { return voltages; } }
moel@130
   148
    public float?[] Temperatures { get { return temperatures; } }
moel@130
   149
    public float?[] Fans { get { return fans; } }
moel@323
   150
    public float?[] Controls { get { return controls; } }
moel@16
   151
moel@130
   152
    public string GetReport() {
moel@16
   153
      StringBuilder r = new StringBuilder();
moel@16
   154
moel@31
   155
      r.AppendLine("LPC " + this.GetType().Name);
moel@16
   156
      r.AppendLine();
moel@16
   157
      r.Append("Chip ID: 0x"); r.AppendLine(chip.ToString("X"));
moel@166
   158
      r.Append("Chip Version: 0x"); r.AppendLine(
moel@166
   159
        version.ToString("X", CultureInfo.InvariantCulture));
moel@166
   160
      r.Append("Base Address: 0x"); r.AppendLine(
moel@166
   161
        address.ToString("X4", CultureInfo.InvariantCulture));
moel@228
   162
      r.Append("GPIO Address: 0x"); r.AppendLine(
moel@228
   163
        gpioAddress.ToString("X4", CultureInfo.InvariantCulture));
moel@16
   164
      r.AppendLine();
moel@162
   165
moel@236
   166
      if (!Ring0.WaitIsaBusMutex(100))
moel@162
   167
        return r.ToString();
moel@162
   168
moel@16
   169
      r.AppendLine("Environment Controller Registers");
moel@16
   170
      r.AppendLine();
moel@16
   171
      r.AppendLine("      00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F");
moel@16
   172
      r.AppendLine();
moel@16
   173
      for (int i = 0; i <= 0xA; i++) {
moel@166
   174
        r.Append(" "); 
moel@166
   175
        r.Append((i << 4).ToString("X2", CultureInfo.InvariantCulture)); 
moel@166
   176
        r.Append("  ");
moel@16
   177
        for (int j = 0; j <= 0xF; j++) {
moel@16
   178
          r.Append(" ");
moel@78
   179
          bool valid;
moel@78
   180
          byte value = ReadByte((byte)((i << 4) | j), out valid);
moel@195
   181
          r.Append(
moel@195
   182
            valid ? value.ToString("X2", CultureInfo.InvariantCulture) : "??");
moel@16
   183
        }
moel@16
   184
        r.AppendLine();
moel@16
   185
      }
moel@16
   186
      r.AppendLine();
moel@16
   187
moel@228
   188
      r.AppendLine("GPIO Registers");
moel@228
   189
      r.AppendLine();
moel@228
   190
      for (int i = 0; i < gpioCount; i++) {
moel@228
   191
        r.Append(" ");
moel@228
   192
        r.Append(ReadGPIO(i).Value.ToString("X2",
moel@228
   193
          CultureInfo.InvariantCulture));
moel@228
   194
      }
moel@228
   195
      r.AppendLine();
moel@228
   196
      r.AppendLine();
moel@228
   197
moel@236
   198
      Ring0.ReleaseIsaBusMutex();
moel@162
   199
moel@16
   200
      return r.ToString();
moel@16
   201
    }
moel@16
   202
moel@130
   203
    public void Update() {
moel@236
   204
      if (!Ring0.WaitIsaBusMutex(10))
moel@162
   205
        return;
moel@16
   206
moel@130
   207
      for (int i = 0; i < voltages.Length; i++) {
moel@78
   208
        bool valid;
moel@170
   209
        
moel@170
   210
        float value = 
moel@170
   211
          voltageGain * ReadByte((byte)(VOLTAGE_BASE_REG + i), out valid);   
moel@170
   212
moel@130
   213
        if (!valid)
moel@130
   214
          continue;
moel@130
   215
        if (value > 0)
moel@130
   216
          voltages[i] = value;  
moel@130
   217
        else
moel@130
   218
          voltages[i] = null;
moel@130
   219
      }
moel@130
   220
moel@130
   221
      for (int i = 0; i < temperatures.Length; i++) {
moel@130
   222
        bool valid;
moel@130
   223
        sbyte value = (sbyte)ReadByte(
moel@130
   224
          (byte)(TEMPERATURE_BASE_REG + i), out valid);
moel@78
   225
        if (!valid)
moel@78
   226
          continue;
moel@78
   227
moel@130
   228
        if (value < sbyte.MaxValue && value > 0)
moel@130
   229
          temperatures[i] = value;
moel@130
   230
        else
moel@130
   231
          temperatures[i] = null;       
moel@16
   232
      }
moel@16
   233
moel@272
   234
      if (has16bitFanCounter) {
moel@272
   235
        for (int i = 0; i < fans.Length; i++) {
moel@272
   236
          bool valid;
moel@272
   237
          int value = ReadByte(FAN_TACHOMETER_REG[i], out valid);
moel@272
   238
          if (!valid)
moel@272
   239
            continue;
moel@272
   240
          value |= ReadByte(FAN_TACHOMETER_EXT_REG[i], out valid) << 8;
moel@272
   241
          if (!valid)
moel@272
   242
            continue;
moel@16
   243
moel@272
   244
          if (value > 0x3f) {
moel@272
   245
            fans[i] = (value < 0xffff) ? 1.35e6f / (value * 2) : 0;
moel@272
   246
          } else {
moel@272
   247
            fans[i] = null;
moel@272
   248
          }
moel@272
   249
        }
moel@272
   250
      } else {
moel@272
   251
        for (int i = 0; i < fans.Length; i++) {
moel@272
   252
          bool valid;
moel@272
   253
          int value = ReadByte(FAN_TACHOMETER_REG[i], out valid);
moel@272
   254
          if (!valid)
moel@272
   255
            continue;
moel@272
   256
moel@272
   257
          int divisor = 2;
moel@272
   258
          if (i < 2) {
moel@272
   259
            int divisors = ReadByte(FAN_TACHOMETER_DIVISOR_REGISTER, out valid);
moel@272
   260
            if (!valid)
moel@272
   261
              continue;
moel@272
   262
            divisor = 1 << ((divisors >> (3 * i)) & 0x7);
moel@272
   263
          }
moel@272
   264
moel@272
   265
          if (value > 0) {
moel@272
   266
            fans[i] = (value < 0xff) ? 1.35e6f / (value * divisor) : 0;
moel@272
   267
          } else {
moel@272
   268
            fans[i] = null;
moel@272
   269
          }
moel@16
   270
        }
moel@162
   271
      }
moel@162
   272
moel@236
   273
      Ring0.ReleaseIsaBusMutex();
moel@126
   274
    }
moel@130
   275
  } 
moel@16
   276
}