Hardware/LPC/W836XX.cs
author moel.mich
Sun, 23 Sep 2012 18:37:43 +0000
changeset 380 573f1fff48b2
parent 323 3f2d9ebacf38
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@34
     1
/*
moel@34
     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@34
     6
 
moel@344
     7
  Copyright (C) 2009-2011 Michael Möller <mmoeller@openhardwaremonitor.org>
moel@344
     8
	
moel@34
     9
*/
moel@34
    10
moel@34
    11
using System;
moel@166
    12
using System.Globalization;
moel@34
    13
using System.Text;
moel@34
    14
moel@34
    15
namespace OpenHardwareMonitor.Hardware.LPC {
moel@165
    16
  internal class W836XX : ISuperIO {
moel@34
    17
moel@195
    18
    private readonly ushort address;
moel@195
    19
    private readonly byte revision;
moel@34
    20
moel@195
    21
    private readonly Chip chip;
moel@34
    22
moel@195
    23
    private readonly float?[] voltages = new float?[0];
moel@195
    24
    private readonly float?[] temperatures = new float?[0];    
moel@195
    25
    private readonly float?[] fans = new float?[0];
moel@323
    26
    private readonly float?[] controls = new float?[0];
moel@34
    27
moel@195
    28
    private readonly bool[] peciTemperature = new bool[0];
moel@195
    29
    private readonly byte[] voltageRegister = new byte[0];
moel@195
    30
    private readonly byte[] voltageBank = new byte[0];
moel@195
    31
    private readonly float voltageGain = 0.008f;
moel@34
    32
moel@34
    33
    // Consts 
moel@34
    34
    private const ushort WINBOND_VENDOR_ID = 0x5CA3;
moel@34
    35
    private const byte HIGH_BYTE = 0x80;
moel@34
    36
moel@34
    37
    // Hardware Monitor
moel@34
    38
    private const byte ADDRESS_REGISTER_OFFSET = 0x05;
moel@34
    39
    private const byte DATA_REGISTER_OFFSET = 0x06;
moel@34
    40
moel@34
    41
    // Hardware Monitor Registers
moel@130
    42
    private const byte VOLTAGE_VBAT_REG = 0x51;
moel@54
    43
    private const byte BANK_SELECT_REGISTER = 0x4E;
moel@34
    44
    private const byte VENDOR_ID_REGISTER = 0x4F;
moel@56
    45
    private const byte TEMPERATURE_SOURCE_SELECT_REG = 0x49;
moel@56
    46
moel@195
    47
    private readonly byte[] TEMPERATURE_REG = new byte[] { 0x50, 0x50, 0x27 };
moel@195
    48
    private readonly byte[] TEMPERATURE_BANK = new byte[] { 1, 2, 0 };
moel@34
    49
moel@195
    50
    private readonly byte[] FAN_TACHO_REG = 
moel@195
    51
      new byte[] { 0x28, 0x29, 0x2A, 0x3F, 0x53 };
moel@195
    52
    private readonly byte[] FAN_TACHO_BANK = 
moel@195
    53
      new byte[] { 0, 0, 0, 0, 5 };       
moel@195
    54
    private readonly byte[] FAN_BIT_REG =
moel@195
    55
      new byte[] { 0x47, 0x4B, 0x4C, 0x59, 0x5D };
moel@195
    56
    private readonly byte[] FAN_DIV_BIT0 = new byte[] { 36, 38, 30, 8, 10 };
moel@195
    57
    private readonly byte[] FAN_DIV_BIT1 = new byte[] { 37, 39, 31, 9, 11 };
moel@195
    58
    private readonly byte[] FAN_DIV_BIT2 = new byte[] { 5, 6, 7, 23, 15 };
moel@34
    59
moel@34
    60
    private byte ReadByte(byte bank, byte register) {
moel@236
    61
      Ring0.WriteIoPort(
moel@34
    62
         (ushort)(address + ADDRESS_REGISTER_OFFSET), BANK_SELECT_REGISTER);
moel@236
    63
      Ring0.WriteIoPort(
moel@34
    64
         (ushort)(address + DATA_REGISTER_OFFSET), bank);
moel@236
    65
      Ring0.WriteIoPort(
moel@34
    66
         (ushort)(address + ADDRESS_REGISTER_OFFSET), register);
moel@236
    67
      return Ring0.ReadIoPort(
moel@34
    68
        (ushort)(address + DATA_REGISTER_OFFSET));
moel@130
    69
    } 
moel@34
    70
moel@56
    71
    private void WriteByte(byte bank, byte register, byte value) {
moel@236
    72
      Ring0.WriteIoPort(
moel@56
    73
         (ushort)(address + ADDRESS_REGISTER_OFFSET), BANK_SELECT_REGISTER);
moel@236
    74
      Ring0.WriteIoPort(
moel@56
    75
         (ushort)(address + DATA_REGISTER_OFFSET), bank);
moel@236
    76
      Ring0.WriteIoPort(
moel@56
    77
         (ushort)(address + ADDRESS_REGISTER_OFFSET), register);
moel@236
    78
      Ring0.WriteIoPort(
moel@56
    79
         (ushort)(address + DATA_REGISTER_OFFSET), value); 
moel@56
    80
    }
moel@228
    81
moel@228
    82
    public byte? ReadGPIO(int index) {
moel@228
    83
      return null;
moel@228
    84
    }
moel@228
    85
moel@228
    86
    public void WriteGPIO(int index, byte value) { }
moel@323
    87
moel@323
    88
    public void SetControl(int index, byte? value) { }   
moel@323
    89
moel@130
    90
    public W836XX(Chip chip, byte revision, ushort address) {
moel@34
    91
      this.address = address;
moel@34
    92
      this.revision = revision;
moel@130
    93
      this.chip = chip;
moel@34
    94
moel@130
    95
      if (!IsWinbondVendor())
moel@130
    96
        return;
moel@130
    97
      
moel@130
    98
      temperatures = new float?[3];
moel@130
    99
      peciTemperature = new bool[3];
moel@56
   100
      switch (chip) {
moel@63
   101
        case Chip.W83667HG:
moel@63
   102
        case Chip.W83667HGB:
moel@130
   103
          // note temperature sensor registers that read PECI
moel@63
   104
          byte flag = ReadByte(0, TEMPERATURE_SOURCE_SELECT_REG);
moel@130
   105
          peciTemperature[0] = (flag & 0x04) != 0;
moel@130
   106
          peciTemperature[1] = (flag & 0x40) != 0;
moel@130
   107
          peciTemperature[2] = false;
moel@63
   108
          break;
moel@63
   109
        case Chip.W83627DHG:        
moel@63
   110
        case Chip.W83627DHGP:
moel@152
   111
          // note temperature sensor registers that read PECI
moel@56
   112
          byte sel = ReadByte(0, TEMPERATURE_SOURCE_SELECT_REG);
moel@130
   113
          peciTemperature[0] = (sel & 0x07) != 0;
moel@130
   114
          peciTemperature[1] = (sel & 0x70) != 0;
moel@130
   115
          peciTemperature[2] = false;
moel@56
   116
          break;
moel@56
   117
        default:
moel@130
   118
          // no PECI support
moel@130
   119
          peciTemperature[0] = false;
moel@130
   120
          peciTemperature[1] = false;
moel@130
   121
          peciTemperature[2] = false;
moel@56
   122
          break;
moel@56
   123
      }
moel@34
   124
moel@34
   125
      switch (chip) {
moel@130
   126
        case Chip.W83627EHF:
moel@130
   127
          voltages = new float?[10];
moel@130
   128
          voltageRegister = new byte[] { 
moel@130
   129
            0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x50, 0x51, 0x52 };
moel@130
   130
          voltageBank = new byte[] { 0, 0, 0, 0, 0, 0, 0, 5, 5, 5 };
moel@130
   131
          voltageGain = 0.008f;
moel@130
   132
          fans = new float?[5];
moel@130
   133
          break;
moel@34
   134
        case Chip.W83627DHG:
moel@130
   135
        case Chip.W83627DHGP:        
moel@34
   136
        case Chip.W83667HG:
moel@130
   137
        case Chip.W83667HGB:
moel@130
   138
          voltages = new float?[9];
moel@130
   139
          voltageRegister = new byte[] { 
moel@130
   140
            0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x50, 0x51 };
moel@130
   141
          voltageBank = new byte[] { 0, 0, 0, 0, 0, 0, 0, 5, 5 };
moel@130
   142
          voltageGain = 0.008f;
moel@130
   143
          fans = new float?[5];
moel@34
   144
          break;
moel@54
   145
        case Chip.W83627HF:
moel@54
   146
        case Chip.W83627THF:
moel@67
   147
        case Chip.W83687THF:
moel@130
   148
          voltages = new float?[7];
moel@130
   149
          voltageRegister = new byte[] { 
moel@130
   150
            0x20, 0x21, 0x22, 0x23, 0x24, 0x50, 0x51 };
moel@130
   151
          voltageBank = new byte[] { 0, 0, 0, 0, 0, 5, 5 };
moel@130
   152
          voltageGain = 0.016f;
moel@130
   153
          fans = new float?[3];         
moel@34
   154
          break;
moel@34
   155
      }
moel@130
   156
    }    
moel@34
   157
moel@34
   158
    private bool IsWinbondVendor() {
moel@34
   159
      ushort vendorId =
moel@34
   160
        (ushort)((ReadByte(HIGH_BYTE, VENDOR_ID_REGISTER) << 8) |
moel@34
   161
           ReadByte(0, VENDOR_ID_REGISTER));
moel@34
   162
      return vendorId == WINBOND_VENDOR_ID;
moel@34
   163
    }
moel@34
   164
moel@167
   165
    private static ulong SetBit(ulong target, int bit, int value) {
moel@85
   166
      if ((value & 1) != value)
moel@85
   167
        throw new ArgumentException("Value must be one bit only.");
moel@85
   168
moel@85
   169
      if (bit < 0 || bit > 63)
moel@85
   170
        throw new ArgumentException("Bit out of range.");
moel@85
   171
moel@85
   172
      ulong mask = (((ulong)1) << bit);
moel@85
   173
      return value > 0 ? target | mask : target & ~mask;
moel@85
   174
    }
moel@85
   175
moel@130
   176
    public Chip Chip { get { return chip; } }
moel@130
   177
    public float?[] Voltages { get { return voltages; } }
moel@130
   178
    public float?[] Temperatures { get { return temperatures; } }
moel@130
   179
    public float?[] Fans { get { return fans; } }
moel@323
   180
    public float?[] Controls { get { return controls; } }
moel@56
   181
moel@130
   182
    public void Update() {
moel@236
   183
      if (!Ring0.WaitIsaBusMutex(10))
moel@162
   184
        return;
moel@130
   185
moel@130
   186
      for (int i = 0; i < voltages.Length; i++) {
moel@130
   187
        if (voltageRegister[i] != VOLTAGE_VBAT_REG) {
moel@58
   188
          // two special VCore measurement modes for W83627THF
moel@130
   189
          float fvalue;
moel@67
   190
          if ((chip == Chip.W83627HF || chip == Chip.W83627THF || 
moel@130
   191
            chip == Chip.W83687THF) && i == 0) 
moel@67
   192
          {
moel@58
   193
            byte vrmConfiguration = ReadByte(0, 0x18);
moel@130
   194
            int value = ReadByte(voltageBank[i], voltageRegister[i]);
moel@58
   195
            if ((vrmConfiguration & 0x01) == 0)
moel@130
   196
              fvalue = 0.016f * value; // VRM8 formula
moel@58
   197
            else
moel@130
   198
              fvalue = 0.00488f * value + 0.69f; // VRM9 formula
moel@58
   199
          } else {
moel@130
   200
            int value = ReadByte(voltageBank[i], voltageRegister[i]);
moel@130
   201
            fvalue = voltageGain * value;
moel@58
   202
          }
moel@130
   203
          if (fvalue > 0)
moel@130
   204
            voltages[i] = fvalue;
moel@130
   205
          else
moel@130
   206
            voltages[i] = null;
moel@34
   207
        } else {
moel@34
   208
          // Battery voltage
moel@34
   209
          bool valid = (ReadByte(0, 0x5D) & 0x01) > 0;
moel@34
   210
          if (valid) {
moel@130
   211
            voltages[i] = voltageGain * ReadByte(5, VOLTAGE_VBAT_REG);
moel@84
   212
          } else {
moel@130
   213
            voltages[i] = null;
moel@84
   214
          }
moel@34
   215
        }
moel@34
   216
      }
moel@34
   217
moel@130
   218
      for (int i = 0; i < temperatures.Length; i++) {
moel@130
   219
        int value = ((sbyte)ReadByte(TEMPERATURE_BANK[i], 
moel@130
   220
          TEMPERATURE_REG[i])) << 1;
moel@130
   221
        if (TEMPERATURE_BANK[i] > 0) 
moel@130
   222
          value |= ReadByte(TEMPERATURE_BANK[i],
moel@130
   223
            (byte)(TEMPERATURE_REG[i] + 1)) >> 7;
moel@63
   224
moel@56
   225
        float temperature = value / 2.0f;
moel@130
   226
        if (temperature <= 125 && temperature >= -55 && !peciTemperature[i]) {
moel@130
   227
          temperatures[i] = temperature;
moel@34
   228
        } else {
moel@130
   229
          temperatures[i] = null;
moel@34
   230
        }
moel@34
   231
      }
moel@34
   232
moel@85
   233
      ulong bits = 0;
moel@34
   234
      for (int i = 0; i < FAN_BIT_REG.Length; i++)
moel@34
   235
        bits = (bits << 8) | ReadByte(0, FAN_BIT_REG[i]);
moel@85
   236
      ulong newBits = bits;
moel@130
   237
      for (int i = 0; i < fans.Length; i++) {
moel@130
   238
        int count = ReadByte(FAN_TACHO_BANK[i], FAN_TACHO_REG[i]);
moel@85
   239
        
moel@85
   240
        // assemble fan divisor
moel@34
   241
        int divisorBits = (int)(
moel@130
   242
          (((bits >> FAN_DIV_BIT2[i]) & 1) << 2) |
moel@130
   243
          (((bits >> FAN_DIV_BIT1[i]) & 1) << 1) |
moel@130
   244
           ((bits >> FAN_DIV_BIT0[i]) & 1));
moel@34
   245
        int divisor = 1 << divisorBits;
moel@85
   246
       
moel@34
   247
        float value = (count < 0xff) ? 1.35e6f / (count * divisor) : 0;
moel@130
   248
        fans[i] = value;
moel@85
   249
moel@85
   250
        // update fan divisor
moel@85
   251
        if (count > 192 && divisorBits < 7) 
moel@85
   252
          divisorBits++;
moel@85
   253
        if (count < 96 && divisorBits > 0)
moel@85
   254
          divisorBits--;
moel@85
   255
moel@130
   256
        newBits = SetBit(newBits, FAN_DIV_BIT2[i], (divisorBits >> 2) & 1);
moel@130
   257
        newBits = SetBit(newBits, FAN_DIV_BIT1[i], (divisorBits >> 1) & 1);
moel@130
   258
        newBits = SetBit(newBits, FAN_DIV_BIT0[i], divisorBits & 1);
moel@85
   259
      }
moel@85
   260
     
moel@85
   261
      // write new fan divisors 
moel@85
   262
      for (int i = FAN_BIT_REG.Length - 1; i >= 0; i--) {
moel@85
   263
        byte oldByte = (byte)(bits & 0xFF);
moel@85
   264
        byte newByte = (byte)(newBits & 0xFF);
moel@85
   265
        bits = bits >> 8;
moel@85
   266
        newBits = newBits >> 8;
moel@85
   267
        if (oldByte != newByte) 
moel@85
   268
          WriteByte(0, FAN_BIT_REG[i], newByte);        
moel@85
   269
      }
moel@162
   270
moel@236
   271
      Ring0.ReleaseIsaBusMutex();
moel@34
   272
    }
moel@34
   273
moel@130
   274
    public string GetReport() {
moel@34
   275
      StringBuilder r = new StringBuilder();
moel@34
   276
moel@34
   277
      r.AppendLine("LPC " + this.GetType().Name);
moel@34
   278
      r.AppendLine();
moel@34
   279
      r.Append("Chip ID: 0x"); r.AppendLine(chip.ToString("X"));
moel@166
   280
      r.Append("Chip revision: 0x");
moel@166
   281
      r.AppendLine(revision.ToString("X", CultureInfo.InvariantCulture));
moel@166
   282
      r.Append("Base Adress: 0x");
moel@166
   283
      r.AppendLine(address.ToString("X4", CultureInfo.InvariantCulture));
moel@34
   284
      r.AppendLine();
moel@162
   285
moel@236
   286
      if (!Ring0.WaitIsaBusMutex(100))
moel@162
   287
        return r.ToString();
moel@162
   288
moel@34
   289
      r.AppendLine("Hardware Monitor Registers");
moel@34
   290
      r.AppendLine();
moel@34
   291
      r.AppendLine("      00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F");
moel@34
   292
      r.AppendLine();
moel@56
   293
      for (int i = 0; i <= 0x7; i++) {
moel@166
   294
        r.Append(" ");
moel@166
   295
        r.Append((i << 4).ToString("X2", CultureInfo.InvariantCulture)); 
moel@166
   296
        r.Append("  ");
moel@34
   297
        for (int j = 0; j <= 0xF; j++) {
moel@34
   298
          r.Append(" ");
moel@166
   299
          r.Append(ReadByte(0, (byte)((i << 4) | j)).ToString(
moel@166
   300
            "X2", CultureInfo.InvariantCulture));
moel@34
   301
        }
moel@34
   302
        r.AppendLine();
moel@34
   303
      }
moel@53
   304
      for (int k = 1; k <= 15; k++) {
moel@34
   305
        r.AppendLine("Bank " + k);
moel@34
   306
        for (int i = 0x5; i < 0x6; i++) {
moel@166
   307
          r.Append(" "); 
moel@166
   308
          r.Append((i << 4).ToString("X2", CultureInfo.InvariantCulture)); 
moel@166
   309
          r.Append("  ");
moel@34
   310
          for (int j = 0; j <= 0xF; j++) {
moel@34
   311
            r.Append(" ");
moel@166
   312
            r.Append(ReadByte((byte)(k), (byte)((i << 4) | j)).ToString(
moel@166
   313
              "X2", CultureInfo.InvariantCulture));
moel@34
   314
          }
moel@34
   315
          r.AppendLine();
moel@34
   316
        }
moel@34
   317
      }
moel@34
   318
      r.AppendLine();
moel@34
   319
moel@236
   320
      Ring0.ReleaseIsaBusMutex();
moel@162
   321
moel@34
   322
      return r.ToString();
moel@34
   323
    }
moel@130
   324
  } 
moel@34
   325
}