Hardware/LPC/W836XX.cs
author moel.mich
Sat, 25 Jun 2011 14:46:28 +0000
changeset 304 16a86362c2ca
parent 228 458a6c3de579
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@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@236
    87
      Ring0.WriteIoPort(
moel@34
    88
         (ushort)(address + ADDRESS_REGISTER_OFFSET), BANK_SELECT_REGISTER);
moel@236
    89
      Ring0.WriteIoPort(
moel@34
    90
         (ushort)(address + DATA_REGISTER_OFFSET), bank);
moel@236
    91
      Ring0.WriteIoPort(
moel@34
    92
         (ushort)(address + ADDRESS_REGISTER_OFFSET), register);
moel@236
    93
      return Ring0.ReadIoPort(
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@236
    98
      Ring0.WriteIoPort(
moel@56
    99
         (ushort)(address + ADDRESS_REGISTER_OFFSET), BANK_SELECT_REGISTER);
moel@236
   100
      Ring0.WriteIoPort(
moel@56
   101
         (ushort)(address + DATA_REGISTER_OFFSET), bank);
moel@236
   102
      Ring0.WriteIoPort(
moel@56
   103
         (ushort)(address + ADDRESS_REGISTER_OFFSET), register);
moel@236
   104
      Ring0.WriteIoPort(
moel@56
   105
         (ushort)(address + DATA_REGISTER_OFFSET), value); 
moel@56
   106
    }
moel@228
   107
moel@228
   108
    public byte? ReadGPIO(int index) {
moel@228
   109
      return null;
moel@228
   110
    }
moel@228
   111
moel@228
   112
    public void WriteGPIO(int index, byte value) { }
moel@56
   113
   
moel@130
   114
    public W836XX(Chip chip, byte revision, ushort address) {
moel@34
   115
      this.address = address;
moel@34
   116
      this.revision = revision;
moel@130
   117
      this.chip = chip;
moel@34
   118
moel@130
   119
      if (!IsWinbondVendor())
moel@130
   120
        return;
moel@130
   121
      
moel@130
   122
      temperatures = new float?[3];
moel@130
   123
      peciTemperature = new bool[3];
moel@56
   124
      switch (chip) {
moel@63
   125
        case Chip.W83667HG:
moel@63
   126
        case Chip.W83667HGB:
moel@130
   127
          // note temperature sensor registers that read PECI
moel@63
   128
          byte flag = ReadByte(0, TEMPERATURE_SOURCE_SELECT_REG);
moel@130
   129
          peciTemperature[0] = (flag & 0x04) != 0;
moel@130
   130
          peciTemperature[1] = (flag & 0x40) != 0;
moel@130
   131
          peciTemperature[2] = false;
moel@63
   132
          break;
moel@63
   133
        case Chip.W83627DHG:        
moel@63
   134
        case Chip.W83627DHGP:
moel@152
   135
          // note temperature sensor registers that read PECI
moel@56
   136
          byte sel = ReadByte(0, TEMPERATURE_SOURCE_SELECT_REG);
moel@130
   137
          peciTemperature[0] = (sel & 0x07) != 0;
moel@130
   138
          peciTemperature[1] = (sel & 0x70) != 0;
moel@130
   139
          peciTemperature[2] = false;
moel@56
   140
          break;
moel@56
   141
        default:
moel@130
   142
          // no PECI support
moel@130
   143
          peciTemperature[0] = false;
moel@130
   144
          peciTemperature[1] = false;
moel@130
   145
          peciTemperature[2] = false;
moel@56
   146
          break;
moel@56
   147
      }
moel@34
   148
moel@34
   149
      switch (chip) {
moel@130
   150
        case Chip.W83627EHF:
moel@130
   151
          voltages = new float?[10];
moel@130
   152
          voltageRegister = new byte[] { 
moel@130
   153
            0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x50, 0x51, 0x52 };
moel@130
   154
          voltageBank = new byte[] { 0, 0, 0, 0, 0, 0, 0, 5, 5, 5 };
moel@130
   155
          voltageGain = 0.008f;
moel@130
   156
          fans = new float?[5];
moel@130
   157
          break;
moel@34
   158
        case Chip.W83627DHG:
moel@130
   159
        case Chip.W83627DHGP:        
moel@34
   160
        case Chip.W83667HG:
moel@130
   161
        case Chip.W83667HGB:
moel@130
   162
          voltages = new float?[9];
moel@130
   163
          voltageRegister = new byte[] { 
moel@130
   164
            0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x50, 0x51 };
moel@130
   165
          voltageBank = new byte[] { 0, 0, 0, 0, 0, 0, 0, 5, 5 };
moel@130
   166
          voltageGain = 0.008f;
moel@130
   167
          fans = new float?[5];
moel@34
   168
          break;
moel@54
   169
        case Chip.W83627HF:
moel@54
   170
        case Chip.W83627THF:
moel@67
   171
        case Chip.W83687THF:
moel@130
   172
          voltages = new float?[7];
moel@130
   173
          voltageRegister = new byte[] { 
moel@130
   174
            0x20, 0x21, 0x22, 0x23, 0x24, 0x50, 0x51 };
moel@130
   175
          voltageBank = new byte[] { 0, 0, 0, 0, 0, 5, 5 };
moel@130
   176
          voltageGain = 0.016f;
moel@130
   177
          fans = new float?[3];         
moel@34
   178
          break;
moel@34
   179
      }
moel@130
   180
    }    
moel@34
   181
moel@34
   182
    private bool IsWinbondVendor() {
moel@34
   183
      ushort vendorId =
moel@34
   184
        (ushort)((ReadByte(HIGH_BYTE, VENDOR_ID_REGISTER) << 8) |
moel@34
   185
           ReadByte(0, VENDOR_ID_REGISTER));
moel@34
   186
      return vendorId == WINBOND_VENDOR_ID;
moel@34
   187
    }
moel@34
   188
moel@167
   189
    private static ulong SetBit(ulong target, int bit, int value) {
moel@85
   190
      if ((value & 1) != value)
moel@85
   191
        throw new ArgumentException("Value must be one bit only.");
moel@85
   192
moel@85
   193
      if (bit < 0 || bit > 63)
moel@85
   194
        throw new ArgumentException("Bit out of range.");
moel@85
   195
moel@85
   196
      ulong mask = (((ulong)1) << bit);
moel@85
   197
      return value > 0 ? target | mask : target & ~mask;
moel@85
   198
    }
moel@85
   199
moel@130
   200
    public Chip Chip { get { return chip; } }
moel@130
   201
    public float?[] Voltages { get { return voltages; } }
moel@130
   202
    public float?[] Temperatures { get { return temperatures; } }
moel@130
   203
    public float?[] Fans { get { return fans; } }
moel@56
   204
moel@130
   205
    public void Update() {
moel@236
   206
      if (!Ring0.WaitIsaBusMutex(10))
moel@162
   207
        return;
moel@130
   208
moel@130
   209
      for (int i = 0; i < voltages.Length; i++) {
moel@130
   210
        if (voltageRegister[i] != VOLTAGE_VBAT_REG) {
moel@58
   211
          // two special VCore measurement modes for W83627THF
moel@130
   212
          float fvalue;
moel@67
   213
          if ((chip == Chip.W83627HF || chip == Chip.W83627THF || 
moel@130
   214
            chip == Chip.W83687THF) && i == 0) 
moel@67
   215
          {
moel@58
   216
            byte vrmConfiguration = ReadByte(0, 0x18);
moel@130
   217
            int value = ReadByte(voltageBank[i], voltageRegister[i]);
moel@58
   218
            if ((vrmConfiguration & 0x01) == 0)
moel@130
   219
              fvalue = 0.016f * value; // VRM8 formula
moel@58
   220
            else
moel@130
   221
              fvalue = 0.00488f * value + 0.69f; // VRM9 formula
moel@58
   222
          } else {
moel@130
   223
            int value = ReadByte(voltageBank[i], voltageRegister[i]);
moel@130
   224
            fvalue = voltageGain * value;
moel@58
   225
          }
moel@130
   226
          if (fvalue > 0)
moel@130
   227
            voltages[i] = fvalue;
moel@130
   228
          else
moel@130
   229
            voltages[i] = null;
moel@34
   230
        } else {
moel@34
   231
          // Battery voltage
moel@34
   232
          bool valid = (ReadByte(0, 0x5D) & 0x01) > 0;
moel@34
   233
          if (valid) {
moel@130
   234
            voltages[i] = voltageGain * ReadByte(5, VOLTAGE_VBAT_REG);
moel@84
   235
          } else {
moel@130
   236
            voltages[i] = null;
moel@84
   237
          }
moel@34
   238
        }
moel@34
   239
      }
moel@34
   240
moel@130
   241
      for (int i = 0; i < temperatures.Length; i++) {
moel@130
   242
        int value = ((sbyte)ReadByte(TEMPERATURE_BANK[i], 
moel@130
   243
          TEMPERATURE_REG[i])) << 1;
moel@130
   244
        if (TEMPERATURE_BANK[i] > 0) 
moel@130
   245
          value |= ReadByte(TEMPERATURE_BANK[i],
moel@130
   246
            (byte)(TEMPERATURE_REG[i] + 1)) >> 7;
moel@63
   247
moel@56
   248
        float temperature = value / 2.0f;
moel@130
   249
        if (temperature <= 125 && temperature >= -55 && !peciTemperature[i]) {
moel@130
   250
          temperatures[i] = temperature;
moel@34
   251
        } else {
moel@130
   252
          temperatures[i] = null;
moel@34
   253
        }
moel@34
   254
      }
moel@34
   255
moel@85
   256
      ulong bits = 0;
moel@34
   257
      for (int i = 0; i < FAN_BIT_REG.Length; i++)
moel@34
   258
        bits = (bits << 8) | ReadByte(0, FAN_BIT_REG[i]);
moel@85
   259
      ulong newBits = bits;
moel@130
   260
      for (int i = 0; i < fans.Length; i++) {
moel@130
   261
        int count = ReadByte(FAN_TACHO_BANK[i], FAN_TACHO_REG[i]);
moel@85
   262
        
moel@85
   263
        // assemble fan divisor
moel@34
   264
        int divisorBits = (int)(
moel@130
   265
          (((bits >> FAN_DIV_BIT2[i]) & 1) << 2) |
moel@130
   266
          (((bits >> FAN_DIV_BIT1[i]) & 1) << 1) |
moel@130
   267
           ((bits >> FAN_DIV_BIT0[i]) & 1));
moel@34
   268
        int divisor = 1 << divisorBits;
moel@85
   269
       
moel@34
   270
        float value = (count < 0xff) ? 1.35e6f / (count * divisor) : 0;
moel@130
   271
        fans[i] = value;
moel@85
   272
moel@85
   273
        // update fan divisor
moel@85
   274
        if (count > 192 && divisorBits < 7) 
moel@85
   275
          divisorBits++;
moel@85
   276
        if (count < 96 && divisorBits > 0)
moel@85
   277
          divisorBits--;
moel@85
   278
moel@130
   279
        newBits = SetBit(newBits, FAN_DIV_BIT2[i], (divisorBits >> 2) & 1);
moel@130
   280
        newBits = SetBit(newBits, FAN_DIV_BIT1[i], (divisorBits >> 1) & 1);
moel@130
   281
        newBits = SetBit(newBits, FAN_DIV_BIT0[i], divisorBits & 1);
moel@85
   282
      }
moel@85
   283
     
moel@85
   284
      // write new fan divisors 
moel@85
   285
      for (int i = FAN_BIT_REG.Length - 1; i >= 0; i--) {
moel@85
   286
        byte oldByte = (byte)(bits & 0xFF);
moel@85
   287
        byte newByte = (byte)(newBits & 0xFF);
moel@85
   288
        bits = bits >> 8;
moel@85
   289
        newBits = newBits >> 8;
moel@85
   290
        if (oldByte != newByte) 
moel@85
   291
          WriteByte(0, FAN_BIT_REG[i], newByte);        
moel@85
   292
      }
moel@162
   293
moel@236
   294
      Ring0.ReleaseIsaBusMutex();
moel@34
   295
    }
moel@34
   296
moel@130
   297
    public string GetReport() {
moel@34
   298
      StringBuilder r = new StringBuilder();
moel@34
   299
moel@34
   300
      r.AppendLine("LPC " + this.GetType().Name);
moel@34
   301
      r.AppendLine();
moel@34
   302
      r.Append("Chip ID: 0x"); r.AppendLine(chip.ToString("X"));
moel@166
   303
      r.Append("Chip revision: 0x");
moel@166
   304
      r.AppendLine(revision.ToString("X", CultureInfo.InvariantCulture));
moel@166
   305
      r.Append("Base Adress: 0x");
moel@166
   306
      r.AppendLine(address.ToString("X4", CultureInfo.InvariantCulture));
moel@34
   307
      r.AppendLine();
moel@162
   308
moel@236
   309
      if (!Ring0.WaitIsaBusMutex(100))
moel@162
   310
        return r.ToString();
moel@162
   311
moel@34
   312
      r.AppendLine("Hardware Monitor Registers");
moel@34
   313
      r.AppendLine();
moel@34
   314
      r.AppendLine("      00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F");
moel@34
   315
      r.AppendLine();
moel@56
   316
      for (int i = 0; i <= 0x7; i++) {
moel@166
   317
        r.Append(" ");
moel@166
   318
        r.Append((i << 4).ToString("X2", CultureInfo.InvariantCulture)); 
moel@166
   319
        r.Append("  ");
moel@34
   320
        for (int j = 0; j <= 0xF; j++) {
moel@34
   321
          r.Append(" ");
moel@166
   322
          r.Append(ReadByte(0, (byte)((i << 4) | j)).ToString(
moel@166
   323
            "X2", CultureInfo.InvariantCulture));
moel@34
   324
        }
moel@34
   325
        r.AppendLine();
moel@34
   326
      }
moel@53
   327
      for (int k = 1; k <= 15; k++) {
moel@34
   328
        r.AppendLine("Bank " + k);
moel@34
   329
        for (int i = 0x5; i < 0x6; i++) {
moel@166
   330
          r.Append(" "); 
moel@166
   331
          r.Append((i << 4).ToString("X2", CultureInfo.InvariantCulture)); 
moel@166
   332
          r.Append("  ");
moel@34
   333
          for (int j = 0; j <= 0xF; j++) {
moel@34
   334
            r.Append(" ");
moel@166
   335
            r.Append(ReadByte((byte)(k), (byte)((i << 4) | j)).ToString(
moel@166
   336
              "X2", CultureInfo.InvariantCulture));
moel@34
   337
          }
moel@34
   338
          r.AppendLine();
moel@34
   339
        }
moel@34
   340
      }
moel@34
   341
      r.AppendLine();
moel@34
   342
moel@236
   343
      Ring0.ReleaseIsaBusMutex();
moel@162
   344
moel@34
   345
      return r.ToString();
moel@34
   346
    }
moel@130
   347
  } 
moel@34
   348
}