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