Hardware/LPC/W836XX.cs
author moel.mich
Sat, 02 Oct 2010 18:15:46 +0000
changeset 206 1fa8eddc24a7
parent 182 4801e9eaf979
child 228 458a6c3de579
permissions -rw-r--r--
Replaced HttpUtility.UrlEncode with Uri.EscapeDataString and deleted the reference to the System.Web assembly. The System.Web assembly seems to be missing on some .NET 4.0 installations (and the overhead of using it is a bit large, just for the UrlEncode method).
moel@34
     1
/*
moel@34
     2
  
moel@34
     3
  Version: MPL 1.1/GPL 2.0/LGPL 2.1
moel@34
     4
moel@34
     5
  The contents of this file are subject to the Mozilla Public License Version
moel@34
     6
  1.1 (the "License"); you may not use this file except in compliance with
moel@34
     7
  the License. You may obtain a copy of the License at
moel@34
     8
 
moel@34
     9
  http://www.mozilla.org/MPL/
moel@34
    10
moel@34
    11
  Software distributed under the License is distributed on an "AS IS" basis,
moel@34
    12
  WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
moel@34
    13
  for the specific language governing rights and limitations under the License.
moel@34
    14
moel@34
    15
  The Original Code is the Open Hardware Monitor code.
moel@34
    16
moel@34
    17
  The Initial Developer of the Original Code is 
moel@34
    18
  Michael Möller <m.moeller@gmx.ch>.
moel@34
    19
  Portions created by the Initial Developer are Copyright (C) 2009-2010
moel@34
    20
  the Initial Developer. All Rights Reserved.
moel@34
    21
moel@34
    22
  Contributor(s):
moel@34
    23
moel@34
    24
  Alternatively, the contents of this file may be used under the terms of
moel@34
    25
  either the GNU General Public License Version 2 or later (the "GPL"), or
moel@34
    26
  the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
moel@34
    27
  in which case the provisions of the GPL or the LGPL are applicable instead
moel@34
    28
  of those above. If you wish to allow use of your version of this file only
moel@34
    29
  under the terms of either the GPL or the LGPL, and not to allow others to
moel@34
    30
  use your version of this file under the terms of the MPL, indicate your
moel@34
    31
  decision by deleting the provisions above and replace them with the notice
moel@34
    32
  and other provisions required by the GPL or the LGPL. If you do not delete
moel@34
    33
  the provisions above, a recipient may use your version of this file under
moel@34
    34
  the terms of any one of the MPL, the GPL or the LGPL.
moel@34
    35
 
moel@34
    36
*/
moel@34
    37
moel@34
    38
using System;
moel@166
    39
using System.Globalization;
moel@34
    40
using System.Text;
moel@34
    41
moel@34
    42
namespace OpenHardwareMonitor.Hardware.LPC {
moel@165
    43
  internal class W836XX : ISuperIO {
moel@34
    44
moel@195
    45
    private readonly ushort address;
moel@195
    46
    private readonly byte revision;
moel@34
    47
moel@195
    48
    private readonly Chip chip;
moel@34
    49
moel@195
    50
    private readonly float?[] voltages = new float?[0];
moel@195
    51
    private readonly float?[] temperatures = new float?[0];    
moel@195
    52
    private readonly float?[] fans = new float?[0];
moel@34
    53
moel@195
    54
    private readonly bool[] peciTemperature = new bool[0];
moel@195
    55
    private readonly byte[] voltageRegister = new byte[0];
moel@195
    56
    private readonly byte[] voltageBank = new byte[0];
moel@195
    57
    private readonly float voltageGain = 0.008f;
moel@34
    58
moel@34
    59
    // Consts 
moel@34
    60
    private const ushort WINBOND_VENDOR_ID = 0x5CA3;
moel@34
    61
    private const byte HIGH_BYTE = 0x80;
moel@34
    62
moel@34
    63
    // Hardware Monitor
moel@34
    64
    private const byte ADDRESS_REGISTER_OFFSET = 0x05;
moel@34
    65
    private const byte DATA_REGISTER_OFFSET = 0x06;
moel@34
    66
moel@34
    67
    // Hardware Monitor Registers
moel@130
    68
    private const byte VOLTAGE_VBAT_REG = 0x51;
moel@54
    69
    private const byte BANK_SELECT_REGISTER = 0x4E;
moel@34
    70
    private const byte VENDOR_ID_REGISTER = 0x4F;
moel@56
    71
    private const byte TEMPERATURE_SOURCE_SELECT_REG = 0x49;
moel@56
    72
moel@195
    73
    private readonly byte[] TEMPERATURE_REG = new byte[] { 0x50, 0x50, 0x27 };
moel@195
    74
    private readonly byte[] TEMPERATURE_BANK = new byte[] { 1, 2, 0 };
moel@34
    75
moel@195
    76
    private readonly byte[] FAN_TACHO_REG = 
moel@195
    77
      new byte[] { 0x28, 0x29, 0x2A, 0x3F, 0x53 };
moel@195
    78
    private readonly byte[] FAN_TACHO_BANK = 
moel@195
    79
      new byte[] { 0, 0, 0, 0, 5 };       
moel@195
    80
    private readonly byte[] FAN_BIT_REG =
moel@195
    81
      new byte[] { 0x47, 0x4B, 0x4C, 0x59, 0x5D };
moel@195
    82
    private readonly byte[] FAN_DIV_BIT0 = new byte[] { 36, 38, 30, 8, 10 };
moel@195
    83
    private readonly byte[] FAN_DIV_BIT1 = new byte[] { 37, 39, 31, 9, 11 };
moel@195
    84
    private readonly byte[] FAN_DIV_BIT2 = new byte[] { 5, 6, 7, 23, 15 };
moel@34
    85
moel@34
    86
    private byte ReadByte(byte bank, byte register) {
moel@34
    87
      WinRing0.WriteIoPortByte(
moel@34
    88
         (ushort)(address + ADDRESS_REGISTER_OFFSET), BANK_SELECT_REGISTER);
moel@34
    89
      WinRing0.WriteIoPortByte(
moel@34
    90
         (ushort)(address + DATA_REGISTER_OFFSET), bank);
moel@34
    91
      WinRing0.WriteIoPortByte(
moel@34
    92
         (ushort)(address + ADDRESS_REGISTER_OFFSET), register);
moel@34
    93
      return WinRing0.ReadIoPortByte(
moel@34
    94
        (ushort)(address + DATA_REGISTER_OFFSET));
moel@130
    95
    } 
moel@34
    96
moel@56
    97
    private void WriteByte(byte bank, byte register, byte value) {
moel@56
    98
      WinRing0.WriteIoPortByte(
moel@56
    99
         (ushort)(address + ADDRESS_REGISTER_OFFSET), BANK_SELECT_REGISTER);
moel@56
   100
      WinRing0.WriteIoPortByte(
moel@56
   101
         (ushort)(address + DATA_REGISTER_OFFSET), bank);
moel@56
   102
      WinRing0.WriteIoPortByte(
moel@56
   103
         (ushort)(address + ADDRESS_REGISTER_OFFSET), register);
moel@56
   104
      WinRing0.WriteIoPortByte(
moel@56
   105
         (ushort)(address + DATA_REGISTER_OFFSET), value); 
moel@56
   106
    }
moel@56
   107
   
moel@130
   108
    public W836XX(Chip chip, byte revision, ushort address) {
moel@34
   109
      this.address = address;
moel@34
   110
      this.revision = revision;
moel@130
   111
      this.chip = chip;
moel@34
   112
moel@130
   113
      if (!IsWinbondVendor())
moel@130
   114
        return;
moel@130
   115
      
moel@130
   116
      temperatures = new float?[3];
moel@130
   117
      peciTemperature = new bool[3];
moel@56
   118
      switch (chip) {
moel@63
   119
        case Chip.W83667HG:
moel@63
   120
        case Chip.W83667HGB:
moel@130
   121
          // note temperature sensor registers that read PECI
moel@63
   122
          byte flag = ReadByte(0, TEMPERATURE_SOURCE_SELECT_REG);
moel@130
   123
          peciTemperature[0] = (flag & 0x04) != 0;
moel@130
   124
          peciTemperature[1] = (flag & 0x40) != 0;
moel@130
   125
          peciTemperature[2] = false;
moel@63
   126
          break;
moel@63
   127
        case Chip.W83627DHG:        
moel@63
   128
        case Chip.W83627DHGP:
moel@152
   129
          // note temperature sensor registers that read PECI
moel@56
   130
          byte sel = ReadByte(0, TEMPERATURE_SOURCE_SELECT_REG);
moel@130
   131
          peciTemperature[0] = (sel & 0x07) != 0;
moel@130
   132
          peciTemperature[1] = (sel & 0x70) != 0;
moel@130
   133
          peciTemperature[2] = false;
moel@56
   134
          break;
moel@56
   135
        default:
moel@130
   136
          // no PECI support
moel@130
   137
          peciTemperature[0] = false;
moel@130
   138
          peciTemperature[1] = false;
moel@130
   139
          peciTemperature[2] = false;
moel@56
   140
          break;
moel@56
   141
      }
moel@34
   142
moel@34
   143
      switch (chip) {
moel@130
   144
        case Chip.W83627EHF:
moel@130
   145
          voltages = new float?[10];
moel@130
   146
          voltageRegister = new byte[] { 
moel@130
   147
            0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x50, 0x51, 0x52 };
moel@130
   148
          voltageBank = new byte[] { 0, 0, 0, 0, 0, 0, 0, 5, 5, 5 };
moel@130
   149
          voltageGain = 0.008f;
moel@130
   150
          fans = new float?[5];
moel@130
   151
          break;
moel@34
   152
        case Chip.W83627DHG:
moel@130
   153
        case Chip.W83627DHGP:        
moel@34
   154
        case Chip.W83667HG:
moel@130
   155
        case Chip.W83667HGB:
moel@130
   156
          voltages = new float?[9];
moel@130
   157
          voltageRegister = new byte[] { 
moel@130
   158
            0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x50, 0x51 };
moel@130
   159
          voltageBank = new byte[] { 0, 0, 0, 0, 0, 0, 0, 5, 5 };
moel@130
   160
          voltageGain = 0.008f;
moel@130
   161
          fans = new float?[5];
moel@34
   162
          break;
moel@54
   163
        case Chip.W83627HF:
moel@54
   164
        case Chip.W83627THF:
moel@67
   165
        case Chip.W83687THF:
moel@130
   166
          voltages = new float?[7];
moel@130
   167
          voltageRegister = new byte[] { 
moel@130
   168
            0x20, 0x21, 0x22, 0x23, 0x24, 0x50, 0x51 };
moel@130
   169
          voltageBank = new byte[] { 0, 0, 0, 0, 0, 5, 5 };
moel@130
   170
          voltageGain = 0.016f;
moel@130
   171
          fans = new float?[3];         
moel@34
   172
          break;
moel@34
   173
      }
moel@130
   174
    }    
moel@34
   175
moel@34
   176
    private bool IsWinbondVendor() {
moel@34
   177
      ushort vendorId =
moel@34
   178
        (ushort)((ReadByte(HIGH_BYTE, VENDOR_ID_REGISTER) << 8) |
moel@34
   179
           ReadByte(0, VENDOR_ID_REGISTER));
moel@34
   180
      return vendorId == WINBOND_VENDOR_ID;
moel@34
   181
    }
moel@34
   182
moel@167
   183
    private static ulong SetBit(ulong target, int bit, int value) {
moel@85
   184
      if ((value & 1) != value)
moel@85
   185
        throw new ArgumentException("Value must be one bit only.");
moel@85
   186
moel@85
   187
      if (bit < 0 || bit > 63)
moel@85
   188
        throw new ArgumentException("Bit out of range.");
moel@85
   189
moel@85
   190
      ulong mask = (((ulong)1) << bit);
moel@85
   191
      return value > 0 ? target | mask : target & ~mask;
moel@85
   192
    }
moel@85
   193
moel@130
   194
    public Chip Chip { get { return chip; } }
moel@130
   195
    public float?[] Voltages { get { return voltages; } }
moel@130
   196
    public float?[] Temperatures { get { return temperatures; } }
moel@130
   197
    public float?[] Fans { get { return fans; } }
moel@56
   198
moel@130
   199
    public void Update() {
moel@163
   200
      if (!WinRing0.WaitIsaBusMutex(10))
moel@162
   201
        return;
moel@130
   202
moel@130
   203
      for (int i = 0; i < voltages.Length; i++) {
moel@130
   204
        if (voltageRegister[i] != VOLTAGE_VBAT_REG) {
moel@58
   205
          // two special VCore measurement modes for W83627THF
moel@130
   206
          float fvalue;
moel@67
   207
          if ((chip == Chip.W83627HF || chip == Chip.W83627THF || 
moel@130
   208
            chip == Chip.W83687THF) && i == 0) 
moel@67
   209
          {
moel@58
   210
            byte vrmConfiguration = ReadByte(0, 0x18);
moel@130
   211
            int value = ReadByte(voltageBank[i], voltageRegister[i]);
moel@58
   212
            if ((vrmConfiguration & 0x01) == 0)
moel@130
   213
              fvalue = 0.016f * value; // VRM8 formula
moel@58
   214
            else
moel@130
   215
              fvalue = 0.00488f * value + 0.69f; // VRM9 formula
moel@58
   216
          } else {
moel@130
   217
            int value = ReadByte(voltageBank[i], voltageRegister[i]);
moel@130
   218
            fvalue = voltageGain * value;
moel@58
   219
          }
moel@130
   220
          if (fvalue > 0)
moel@130
   221
            voltages[i] = fvalue;
moel@130
   222
          else
moel@130
   223
            voltages[i] = null;
moel@34
   224
        } else {
moel@34
   225
          // Battery voltage
moel@34
   226
          bool valid = (ReadByte(0, 0x5D) & 0x01) > 0;
moel@34
   227
          if (valid) {
moel@130
   228
            voltages[i] = voltageGain * ReadByte(5, VOLTAGE_VBAT_REG);
moel@84
   229
          } else {
moel@130
   230
            voltages[i] = null;
moel@84
   231
          }
moel@34
   232
        }
moel@34
   233
      }
moel@34
   234
moel@130
   235
      for (int i = 0; i < temperatures.Length; i++) {
moel@130
   236
        int value = ((sbyte)ReadByte(TEMPERATURE_BANK[i], 
moel@130
   237
          TEMPERATURE_REG[i])) << 1;
moel@130
   238
        if (TEMPERATURE_BANK[i] > 0) 
moel@130
   239
          value |= ReadByte(TEMPERATURE_BANK[i],
moel@130
   240
            (byte)(TEMPERATURE_REG[i] + 1)) >> 7;
moel@63
   241
moel@56
   242
        float temperature = value / 2.0f;
moel@130
   243
        if (temperature <= 125 && temperature >= -55 && !peciTemperature[i]) {
moel@130
   244
          temperatures[i] = temperature;
moel@34
   245
        } else {
moel@130
   246
          temperatures[i] = null;
moel@34
   247
        }
moel@34
   248
      }
moel@34
   249
moel@85
   250
      ulong bits = 0;
moel@34
   251
      for (int i = 0; i < FAN_BIT_REG.Length; i++)
moel@34
   252
        bits = (bits << 8) | ReadByte(0, FAN_BIT_REG[i]);
moel@85
   253
      ulong newBits = bits;
moel@130
   254
      for (int i = 0; i < fans.Length; i++) {
moel@130
   255
        int count = ReadByte(FAN_TACHO_BANK[i], FAN_TACHO_REG[i]);
moel@85
   256
        
moel@85
   257
        // assemble fan divisor
moel@34
   258
        int divisorBits = (int)(
moel@130
   259
          (((bits >> FAN_DIV_BIT2[i]) & 1) << 2) |
moel@130
   260
          (((bits >> FAN_DIV_BIT1[i]) & 1) << 1) |
moel@130
   261
           ((bits >> FAN_DIV_BIT0[i]) & 1));
moel@34
   262
        int divisor = 1 << divisorBits;
moel@85
   263
       
moel@34
   264
        float value = (count < 0xff) ? 1.35e6f / (count * divisor) : 0;
moel@130
   265
        fans[i] = value;
moel@85
   266
moel@85
   267
        // update fan divisor
moel@85
   268
        if (count > 192 && divisorBits < 7) 
moel@85
   269
          divisorBits++;
moel@85
   270
        if (count < 96 && divisorBits > 0)
moel@85
   271
          divisorBits--;
moel@85
   272
moel@130
   273
        newBits = SetBit(newBits, FAN_DIV_BIT2[i], (divisorBits >> 2) & 1);
moel@130
   274
        newBits = SetBit(newBits, FAN_DIV_BIT1[i], (divisorBits >> 1) & 1);
moel@130
   275
        newBits = SetBit(newBits, FAN_DIV_BIT0[i], divisorBits & 1);
moel@85
   276
      }
moel@85
   277
     
moel@85
   278
      // write new fan divisors 
moel@85
   279
      for (int i = FAN_BIT_REG.Length - 1; i >= 0; i--) {
moel@85
   280
        byte oldByte = (byte)(bits & 0xFF);
moel@85
   281
        byte newByte = (byte)(newBits & 0xFF);
moel@85
   282
        bits = bits >> 8;
moel@85
   283
        newBits = newBits >> 8;
moel@85
   284
        if (oldByte != newByte) 
moel@85
   285
          WriteByte(0, FAN_BIT_REG[i], newByte);        
moel@85
   286
      }
moel@162
   287
moel@162
   288
      WinRing0.ReleaseIsaBusMutex();
moel@34
   289
    }
moel@34
   290
moel@130
   291
    public string GetReport() {
moel@34
   292
      StringBuilder r = new StringBuilder();
moel@34
   293
moel@34
   294
      r.AppendLine("LPC " + this.GetType().Name);
moel@34
   295
      r.AppendLine();
moel@34
   296
      r.Append("Chip ID: 0x"); r.AppendLine(chip.ToString("X"));
moel@166
   297
      r.Append("Chip revision: 0x");
moel@166
   298
      r.AppendLine(revision.ToString("X", CultureInfo.InvariantCulture));
moel@166
   299
      r.Append("Base Adress: 0x");
moel@166
   300
      r.AppendLine(address.ToString("X4", CultureInfo.InvariantCulture));
moel@34
   301
      r.AppendLine();
moel@162
   302
moel@163
   303
      if (!WinRing0.WaitIsaBusMutex(100))
moel@162
   304
        return r.ToString();
moel@162
   305
moel@34
   306
      r.AppendLine("Hardware Monitor Registers");
moel@34
   307
      r.AppendLine();
moel@34
   308
      r.AppendLine("      00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F");
moel@34
   309
      r.AppendLine();
moel@56
   310
      for (int i = 0; i <= 0x7; i++) {
moel@166
   311
        r.Append(" ");
moel@166
   312
        r.Append((i << 4).ToString("X2", CultureInfo.InvariantCulture)); 
moel@166
   313
        r.Append("  ");
moel@34
   314
        for (int j = 0; j <= 0xF; j++) {
moel@34
   315
          r.Append(" ");
moel@166
   316
          r.Append(ReadByte(0, (byte)((i << 4) | j)).ToString(
moel@166
   317
            "X2", CultureInfo.InvariantCulture));
moel@34
   318
        }
moel@34
   319
        r.AppendLine();
moel@34
   320
      }
moel@53
   321
      for (int k = 1; k <= 15; k++) {
moel@34
   322
        r.AppendLine("Bank " + k);
moel@34
   323
        for (int i = 0x5; i < 0x6; i++) {
moel@166
   324
          r.Append(" "); 
moel@166
   325
          r.Append((i << 4).ToString("X2", CultureInfo.InvariantCulture)); 
moel@166
   326
          r.Append("  ");
moel@34
   327
          for (int j = 0; j <= 0xF; j++) {
moel@34
   328
            r.Append(" ");
moel@166
   329
            r.Append(ReadByte((byte)(k), (byte)((i << 4) | j)).ToString(
moel@166
   330
              "X2", CultureInfo.InvariantCulture));
moel@34
   331
          }
moel@34
   332
          r.AppendLine();
moel@34
   333
        }
moel@34
   334
      }
moel@34
   335
      r.AppendLine();
moel@34
   336
moel@162
   337
      WinRing0.ReleaseIsaBusMutex();
moel@162
   338
moel@34
   339
      return r.ToString();
moel@34
   340
    }
moel@130
   341
  } 
moel@34
   342
}