Hardware/LPC/W836XX.cs
author moel.mich
Tue, 25 May 2010 18:57:28 +0000
changeset 127 76aaf45a01c7
parent 110 411b72b73d8f
child 130 80065ab20b84
permissions -rw-r--r--
Added a workaround for the "You must keep the stream open for the lifetime of the Image." problem of the Image.FromStream method. This also reduced the overall memory usage (private working set).
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@34
    39
using System.Collections.Generic;
moel@34
    40
using System.Drawing;
moel@34
    41
using System.Text;
moel@34
    42
moel@34
    43
namespace OpenHardwareMonitor.Hardware.LPC {
moel@34
    44
  public class W836XX : LPCHardware, IHardware {
moel@34
    45
moel@34
    46
    private ushort address;
moel@34
    47
    private byte revision;
moel@34
    48
moel@34
    49
    private bool available;
moel@34
    50
moel@34
    51
    private Sensor[] temperatures;
moel@34
    52
    private Sensor[] fans;
moel@34
    53
    private Sensor[] voltages;
moel@34
    54
moel@34
    55
    private float[] voltageGains;
moel@34
    56
    private string[] fanNames;
moel@34
    57
moel@34
    58
    // Consts 
moel@34
    59
    private const ushort WINBOND_VENDOR_ID = 0x5CA3;
moel@34
    60
    private const byte HIGH_BYTE = 0x80;
moel@34
    61
moel@34
    62
    // Hardware Monitor
moel@34
    63
    private const byte ADDRESS_REGISTER_OFFSET = 0x05;
moel@34
    64
    private const byte DATA_REGISTER_OFFSET = 0x06;
moel@34
    65
moel@34
    66
    // Hardware Monitor Registers
moel@34
    67
    private const byte VOLTAGE_BASE_REG = 0x20;
moel@54
    68
    private const byte BANK_SELECT_REGISTER = 0x4E;
moel@34
    69
    private const byte VENDOR_ID_REGISTER = 0x4F;
moel@56
    70
    private const byte TEMPERATURE_SOURCE_SELECT_REG = 0x49;
moel@56
    71
moel@56
    72
    private string[] TEMPERATURE_NAME = 
moel@56
    73
      new string[] {"CPU", "Auxiliary", "System"};
moel@56
    74
    private byte[] TEMPERATURE_REG = new byte[] { 0x50, 0x50, 0x27 };
moel@56
    75
    private byte[] TEMPERATURE_BANK = new byte[] { 1, 2, 0 };
moel@34
    76
moel@34
    77
    private byte[] FAN_TACHO_REG = new byte[] { 0x28, 0x29, 0x2A, 0x3F, 0x53 };
moel@34
    78
    private byte[] FAN_TACHO_BANK = new byte[] { 0, 0, 0, 0, 5 };       
moel@34
    79
    private byte[] FAN_BIT_REG = new byte[] { 0x47, 0x4B, 0x4C, 0x59, 0x5D };
moel@34
    80
    private byte[] FAN_DIV_BIT0 = new byte[] { 36, 38, 30, 8, 10 };
moel@34
    81
    private byte[] FAN_DIV_BIT1 = new byte[] { 37, 39, 31, 9, 11 };
moel@34
    82
    private byte[] FAN_DIV_BIT2 = new byte[] { 5, 6, 7, 23, 15 };
moel@34
    83
moel@34
    84
    private byte ReadByte(byte bank, byte register) {
moel@34
    85
      WinRing0.WriteIoPortByte(
moel@34
    86
         (ushort)(address + ADDRESS_REGISTER_OFFSET), BANK_SELECT_REGISTER);
moel@34
    87
      WinRing0.WriteIoPortByte(
moel@34
    88
         (ushort)(address + DATA_REGISTER_OFFSET), bank);
moel@34
    89
      WinRing0.WriteIoPortByte(
moel@34
    90
         (ushort)(address + ADDRESS_REGISTER_OFFSET), register);
moel@34
    91
      return WinRing0.ReadIoPortByte(
moel@34
    92
        (ushort)(address + DATA_REGISTER_OFFSET));
moel@85
    93
    }
moel@34
    94
moel@56
    95
    private void WriteByte(byte bank, byte register, byte value) {
moel@56
    96
      WinRing0.WriteIoPortByte(
moel@56
    97
         (ushort)(address + ADDRESS_REGISTER_OFFSET), BANK_SELECT_REGISTER);
moel@56
    98
      WinRing0.WriteIoPortByte(
moel@56
    99
         (ushort)(address + DATA_REGISTER_OFFSET), bank);
moel@56
   100
      WinRing0.WriteIoPortByte(
moel@56
   101
         (ushort)(address + ADDRESS_REGISTER_OFFSET), register);
moel@56
   102
      WinRing0.WriteIoPortByte(
moel@56
   103
         (ushort)(address + DATA_REGISTER_OFFSET), value); 
moel@56
   104
    }
moel@56
   105
   
moel@34
   106
    public W836XX(Chip chip, byte revision, ushort address) 
moel@34
   107
      : base(chip)
moel@34
   108
    {
moel@34
   109
      this.address = address;
moel@34
   110
      this.revision = revision;
moel@34
   111
moel@34
   112
      available = IsWinbondVendor();
moel@34
   113
moel@63
   114
      ParameterDescription[] parameter = new ParameterDescription[] {
moel@122
   115
        new ParameterDescription("Offset [°C]", "Temperature offset.", 0)
moel@63
   116
      };
moel@56
   117
      List<Sensor> list = new List<Sensor>();
moel@56
   118
      switch (chip) {
moel@63
   119
        case Chip.W83667HG:
moel@63
   120
        case Chip.W83667HGB:
moel@63
   121
          // do not add temperature sensor registers that read PECI
moel@63
   122
          byte flag = ReadByte(0, TEMPERATURE_SOURCE_SELECT_REG);
moel@63
   123
          if ((flag & 0x04) == 0)
moel@63
   124
            list.Add(new Sensor(TEMPERATURE_NAME[0], 0, null,
moel@63
   125
              SensorType.Temperature, this, parameter));
moel@63
   126
          if ((flag & 0x40) == 0)
moel@63
   127
            list.Add(new Sensor(TEMPERATURE_NAME[1], 1, null,
moel@63
   128
              SensorType.Temperature, this, parameter));
moel@63
   129
          list.Add(new Sensor(TEMPERATURE_NAME[2], 2, null,
moel@63
   130
            SensorType.Temperature, this, parameter));
moel@63
   131
          break;
moel@63
   132
        case Chip.W83627DHG:        
moel@63
   133
        case Chip.W83627DHGP:
moel@63
   134
          // do not add temperature sensor registers that read PECI
moel@56
   135
          byte sel = ReadByte(0, TEMPERATURE_SOURCE_SELECT_REG);
moel@56
   136
          if ((sel & 0x07) == 0)
moel@63
   137
            list.Add(new Sensor(TEMPERATURE_NAME[0], 0, null,
moel@63
   138
              SensorType.Temperature, this, parameter));
moel@56
   139
          if ((sel & 0x70) == 0)
moel@63
   140
            list.Add(new Sensor(TEMPERATURE_NAME[1], 1, null,
moel@63
   141
              SensorType.Temperature, this, parameter));
moel@63
   142
          list.Add(new Sensor(TEMPERATURE_NAME[2], 2, null,
moel@63
   143
            SensorType.Temperature, this, parameter));
moel@56
   144
          break;
moel@56
   145
        default:
moel@63
   146
          // no PECI support, add all sensors
moel@63
   147
          for (int i = 0; i < TEMPERATURE_NAME.Length; i++)
moel@63
   148
            list.Add(new Sensor(TEMPERATURE_NAME[i], i, null,
moel@63
   149
              SensorType.Temperature, this, parameter));
moel@56
   150
          break;
moel@56
   151
      }
moel@56
   152
      temperatures = list.ToArray();
moel@34
   153
moel@34
   154
      switch (chip) {
moel@34
   155
        case Chip.W83627DHG:
moel@34
   156
        case Chip.W83627DHGP:
moel@34
   157
        case Chip.W83627EHF:
moel@34
   158
        case Chip.W83667HG:
moel@34
   159
        case Chip.W83667HGB: 
moel@34
   160
          fanNames = new string[] { "System", "CPU", "Auxiliary", 
moel@34
   161
            "CPU #2", "Auxiliary #2" };
moel@34
   162
          voltageGains = new float[] { 1, 1, 1, 2, 1, 1, 1, 2 };
moel@34
   163
          voltages = new Sensor[3];
moel@34
   164
          voltages[0] = new Sensor("CPU VCore", 0, SensorType.Voltage, this);
moel@34
   165
          voltages[1] = new Sensor("+3.3V", 3, SensorType.Voltage, this);
moel@34
   166
          voltages[2] = new Sensor("Battery", 7, SensorType.Voltage, this);
moel@34
   167
          break;
moel@54
   168
        case Chip.W83627HF:
moel@54
   169
        case Chip.W83627THF:
moel@67
   170
        case Chip.W83687THF:
moel@54
   171
          fanNames = new string[] { "System", "CPU", "Auxiliary" };
moel@34
   172
          voltageGains = new float[] { 2, 1, 2, 1, 1, 1, 1, 2 };
moel@34
   173
          voltages = new Sensor[3];
moel@34
   174
          voltages[0] = new Sensor("CPU VCore", 0, SensorType.Voltage, this);
moel@34
   175
          voltages[1] = new Sensor("+3.3V", 2, SensorType.Voltage, this);
moel@34
   176
          voltages[2] = new Sensor("Battery", 7, SensorType.Voltage, this);
moel@34
   177
          break;
moel@34
   178
        default: fanNames = new string[0];
moel@34
   179
          break;
moel@34
   180
      }
moel@34
   181
      
moel@34
   182
      fans = new Sensor[fanNames.Length];
moel@34
   183
      for (int i = 0; i < fanNames.Length; i++)
moel@34
   184
        fans[i] = new Sensor(fanNames[i], i, SensorType.Fan, this);
moel@34
   185
    }
moel@34
   186
moel@34
   187
    public bool IsAvailable {
moel@34
   188
      get { return available; }
moel@34
   189
    }        
moel@34
   190
moel@34
   191
    private bool IsWinbondVendor() {
moel@34
   192
      ushort vendorId =
moel@34
   193
        (ushort)((ReadByte(HIGH_BYTE, VENDOR_ID_REGISTER) << 8) |
moel@34
   194
           ReadByte(0, VENDOR_ID_REGISTER));
moel@34
   195
      return vendorId == WINBOND_VENDOR_ID;
moel@34
   196
    }
moel@34
   197
moel@85
   198
    private ulong SetBit(ulong target, int bit, int value) {
moel@85
   199
      if ((value & 1) != value)
moel@85
   200
        throw new ArgumentException("Value must be one bit only.");
moel@85
   201
moel@85
   202
      if (bit < 0 || bit > 63)
moel@85
   203
        throw new ArgumentException("Bit out of range.");
moel@85
   204
moel@85
   205
      ulong mask = (((ulong)1) << bit);
moel@85
   206
      return value > 0 ? target | mask : target & ~mask;
moel@85
   207
    }
moel@85
   208
moel@110
   209
    public override void Update() {
moel@56
   210
moel@34
   211
      foreach (Sensor sensor in voltages) {
moel@34
   212
        if (sensor.Index < 7) {
moel@58
   213
          // two special VCore measurement modes for W83627THF
moel@67
   214
          if ((chip == Chip.W83627HF || chip == Chip.W83627THF || 
moel@67
   215
            chip == Chip.W83687THF) && sensor.Index == 0) 
moel@67
   216
          {
moel@58
   217
            byte vrmConfiguration = ReadByte(0, 0x18);
moel@58
   218
            int value = ReadByte(0, VOLTAGE_BASE_REG);
moel@58
   219
            if ((vrmConfiguration & 0x01) == 0)
moel@58
   220
              sensor.Value = 0.016f * value; // VRM8 formula
moel@58
   221
            else
moel@58
   222
              sensor.Value = 0.00488f * value + 0.69f; // VRM9 formula
moel@58
   223
          } else {
moel@58
   224
            int value = ReadByte(0, (byte)(VOLTAGE_BASE_REG + sensor.Index));
moel@58
   225
            sensor.Value = 0.008f * voltageGains[sensor.Index] * value;
moel@58
   226
          }
moel@34
   227
          if (sensor.Value > 0)
moel@34
   228
            ActivateSensor(sensor);
moel@34
   229
        } else {
moel@34
   230
          // Battery voltage
moel@34
   231
          bool valid = (ReadByte(0, 0x5D) & 0x01) > 0;
moel@34
   232
          if (valid) {
moel@56
   233
            sensor.Value =
moel@34
   234
              0.008f * voltageGains[sensor.Index] * ReadByte(5, 0x51);
moel@34
   235
            ActivateSensor(sensor);
moel@84
   236
          } else {
moel@84
   237
            sensor.Value = null;
moel@84
   238
          }
moel@34
   239
        }
moel@34
   240
      }
moel@34
   241
moel@34
   242
      foreach (Sensor sensor in temperatures) {
moel@63
   243
        int value = ((sbyte)ReadByte(TEMPERATURE_BANK[sensor.Index],
moel@63
   244
          TEMPERATURE_REG[sensor.Index])) << 1;
moel@63
   245
        if (TEMPERATURE_BANK[sensor.Index] > 0) 
moel@63
   246
          value |= ReadByte(TEMPERATURE_BANK[sensor.Index],
moel@63
   247
            (byte)(TEMPERATURE_REG[sensor.Index] + 1)) >> 7;
moel@63
   248
moel@56
   249
        float temperature = value / 2.0f;
moel@56
   250
        if (temperature <= 125 && temperature >= -55) {
moel@63
   251
          sensor.Value = temperature + sensor.Parameters[0].Value;
moel@56
   252
          ActivateSensor(sensor);
moel@34
   253
        } else {
moel@84
   254
          sensor.Value = null;
moel@34
   255
        }
moel@34
   256
      }
moel@34
   257
moel@85
   258
      ulong bits = 0;
moel@34
   259
      for (int i = 0; i < FAN_BIT_REG.Length; i++)
moel@34
   260
        bits = (bits << 8) | ReadByte(0, FAN_BIT_REG[i]);
moel@85
   261
      ulong newBits = bits;
moel@34
   262
      foreach (Sensor sensor in fans) {
moel@34
   263
        int count = ReadByte(FAN_TACHO_BANK[sensor.Index], 
moel@34
   264
          FAN_TACHO_REG[sensor.Index]);
moel@85
   265
        
moel@85
   266
        // assemble fan divisor
moel@34
   267
        int divisorBits = (int)(
moel@34
   268
          (((bits >> FAN_DIV_BIT2[sensor.Index]) & 1) << 2) |
moel@34
   269
          (((bits >> FAN_DIV_BIT1[sensor.Index]) & 1) << 1) |
moel@34
   270
           ((bits >> FAN_DIV_BIT0[sensor.Index]) & 1));
moel@34
   271
        int divisor = 1 << divisorBits;
moel@85
   272
       
moel@34
   273
        float value = (count < 0xff) ? 1.35e6f / (count * divisor) : 0;
moel@34
   274
        sensor.Value = value;
moel@34
   275
        if (value > 0)
moel@85
   276
          ActivateSensor(sensor);
moel@85
   277
moel@85
   278
        // update fan divisor
moel@85
   279
        if (count > 192 && divisorBits < 7) 
moel@85
   280
          divisorBits++;
moel@85
   281
        if (count < 96 && divisorBits > 0)
moel@85
   282
          divisorBits--;
moel@85
   283
moel@85
   284
        newBits = SetBit(newBits, FAN_DIV_BIT2[sensor.Index], 
moel@85
   285
          (divisorBits >> 2) & 1);
moel@85
   286
        newBits = SetBit(newBits, FAN_DIV_BIT1[sensor.Index], 
moel@85
   287
          (divisorBits >> 1) & 1);
moel@85
   288
        newBits = SetBit(newBits, FAN_DIV_BIT0[sensor.Index], 
moel@85
   289
          divisorBits & 1);
moel@85
   290
      }
moel@85
   291
     
moel@85
   292
      // write new fan divisors 
moel@85
   293
      for (int i = FAN_BIT_REG.Length - 1; i >= 0; i--) {
moel@85
   294
        byte oldByte = (byte)(bits & 0xFF);
moel@85
   295
        byte newByte = (byte)(newBits & 0xFF);
moel@85
   296
        bits = bits >> 8;
moel@85
   297
        newBits = newBits >> 8;
moel@85
   298
        if (oldByte != newByte) 
moel@85
   299
          WriteByte(0, FAN_BIT_REG[i], newByte);        
moel@85
   300
      }
moel@34
   301
    }
moel@34
   302
moel@110
   303
    public override string GetReport() {
moel@34
   304
      StringBuilder r = new StringBuilder();
moel@34
   305
moel@34
   306
      r.AppendLine("LPC " + this.GetType().Name);
moel@34
   307
      r.AppendLine();
moel@34
   308
      r.Append("Chip ID: 0x"); r.AppendLine(chip.ToString("X"));
moel@34
   309
      r.Append("Chip revision: 0x"); r.AppendLine(revision.ToString("X"));
moel@34
   310
      r.Append("Base Adress: 0x"); r.AppendLine(address.ToString("X4"));
moel@34
   311
      r.AppendLine();
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@34
   317
        r.Append(" "); r.Append((i << 4).ToString("X2")); r.Append("  ");
moel@34
   318
        for (int j = 0; j <= 0xF; j++) {
moel@34
   319
          r.Append(" ");
moel@34
   320
          r.Append(ReadByte(0, (byte)((i << 4) | j)).ToString("X2"));
moel@34
   321
        }
moel@34
   322
        r.AppendLine();
moel@34
   323
      }
moel@53
   324
      for (int k = 1; k <= 15; k++) {
moel@34
   325
        r.AppendLine("Bank " + k);
moel@34
   326
        for (int i = 0x5; i < 0x6; i++) {
moel@34
   327
          r.Append(" "); r.Append((i << 4).ToString("X2")); r.Append("  ");
moel@34
   328
          for (int j = 0; j <= 0xF; j++) {
moel@34
   329
            r.Append(" ");
moel@34
   330
            r.Append(ReadByte((byte)(k),
moel@34
   331
              (byte)((i << 4) | j)).ToString("X2"));
moel@34
   332
          }
moel@34
   333
          r.AppendLine();
moel@34
   334
        }
moel@34
   335
      }
moel@34
   336
      r.AppendLine();
moel@34
   337
moel@34
   338
      return r.ToString();
moel@34
   339
    }
moel@34
   340
  }
moel@34
   341
}