Hardware/LPC/IT87XX.cs
author moel.mich
Sun, 23 Sep 2012 18:37:43 +0000
changeset 380 573f1fff48b2
parent 344 3145aadca3d2
child 382 ba6abd47a80c
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-2012 Michael Möller <mmoeller@openhardwaremonitor.org>
     8 	
     9 */
    10 
    11 using System.Globalization;
    12 using System.Text;
    13 
    14 namespace OpenHardwareMonitor.Hardware.LPC {
    15   internal class IT87XX : ISuperIO {
    16        
    17     private readonly ushort address;
    18     private readonly Chip chip;
    19     private readonly byte version;
    20 
    21     private readonly ushort gpioAddress;
    22     private readonly int gpioCount;
    23 
    24     private readonly ushort addressReg;
    25     private readonly ushort dataReg;
    26 
    27     private readonly float?[] voltages = new float?[0];
    28     private readonly float?[] temperatures = new float?[0];
    29     private readonly float?[] fans = new float?[0];
    30     private readonly float?[] controls = new float?[0];
    31 
    32     private readonly float voltageGain;
    33     private readonly bool has16bitFanCounter;
    34    
    35     // Consts
    36     private const byte ITE_VENDOR_ID = 0x90;
    37        
    38     // Environment Controller
    39     private const byte ADDRESS_REGISTER_OFFSET = 0x05;
    40     private const byte DATA_REGISTER_OFFSET = 0x06;
    41 
    42     // Environment Controller Registers    
    43     private const byte CONFIGURATION_REGISTER = 0x00;
    44     private const byte TEMPERATURE_BASE_REG = 0x29;
    45     private const byte VENDOR_ID_REGISTER = 0x58;
    46     private const byte FAN_TACHOMETER_DIVISOR_REGISTER = 0x0B;
    47     private readonly byte[] FAN_TACHOMETER_REG = 
    48       new byte[] { 0x0d, 0x0e, 0x0f, 0x80, 0x82 };
    49     private readonly byte[] FAN_TACHOMETER_EXT_REG =
    50       new byte[] { 0x18, 0x19, 0x1a, 0x81, 0x83 };
    51     private const byte VOLTAGE_BASE_REG = 0x20;
    52 
    53     private byte ReadByte(byte register, out bool valid) {
    54       Ring0.WriteIoPort(addressReg, register);
    55       byte value = Ring0.ReadIoPort(dataReg);
    56       valid = register == Ring0.ReadIoPort(addressReg);
    57       return value;
    58     }
    59 
    60     private bool WriteByte(byte register, byte value) {
    61       Ring0.WriteIoPort(addressReg, register);
    62       Ring0.WriteIoPort(dataReg, value);
    63       return register == Ring0.ReadIoPort(addressReg); 
    64     }
    65 
    66     public byte? ReadGPIO(int index) {
    67       if (index >= gpioCount)
    68         return null;
    69 
    70       return Ring0.ReadIoPort((ushort)(gpioAddress + index));
    71     }
    72 
    73     public void WriteGPIO(int index, byte value) {
    74       if (index >= gpioCount)
    75         return;
    76 
    77       Ring0.WriteIoPort((ushort)(gpioAddress + index), value);
    78     } 
    79 
    80     public void SetControl(int index, byte? value) { }   
    81 
    82     public IT87XX(Chip chip, ushort address, ushort gpioAddress, byte version) {
    83 
    84       this.address = address;
    85       this.chip = chip;
    86       this.version = version;
    87       this.addressReg = (ushort)(address + ADDRESS_REGISTER_OFFSET);
    88       this.dataReg = (ushort)(address + DATA_REGISTER_OFFSET);
    89       this.gpioAddress = gpioAddress;
    90 
    91       // Check vendor id
    92       bool valid;
    93       byte vendorId = ReadByte(VENDOR_ID_REGISTER, out valid);       
    94       if (!valid || vendorId != ITE_VENDOR_ID)
    95         return;
    96 
    97       // Bit 0x10 of the configuration register should always be 1
    98       if ((ReadByte(CONFIGURATION_REGISTER, out valid) & 0x10) == 0)
    99         return;
   100       if (!valid)
   101         return;
   102 
   103       voltages = new float?[9];
   104       temperatures = new float?[3];
   105       fans = new float?[chip == Chip.IT8705F ? 3 : 5];
   106 
   107       // IT8721F, IT8728F and IT8772E use a 12mV resultion ADC, all others 16mV
   108       if (chip == Chip.IT8721F || chip == Chip.IT8728F || chip == Chip.IT8771E 
   109         || chip == Chip.IT8772E) 
   110       {
   111         voltageGain = 0.012f;
   112       } else {
   113         voltageGain = 0.016f;        
   114       }
   115 
   116       // older IT8705F and IT8721F revisions do not have 16-bit fan counters
   117       if ((chip == Chip.IT8705F && version < 3) || 
   118           (chip == Chip.IT8712F && version < 8)) 
   119       {
   120         has16bitFanCounter = false;
   121       } else {
   122         has16bitFanCounter = true;
   123       }
   124 
   125       // Set the number of GPIO sets
   126       switch (chip) {
   127         case Chip.IT8712F:
   128         case Chip.IT8716F:
   129         case Chip.IT8718F:
   130         case Chip.IT8726F:
   131           gpioCount = 5;
   132           break;
   133         case Chip.IT8720F:
   134         case Chip.IT8721F:
   135           gpioCount = 8;
   136           break;
   137         case Chip.IT8705F: 
   138         case Chip.IT8728F:
   139         case Chip.IT8771E:
   140         case Chip.IT8772E:
   141           gpioCount = 0;
   142           break;
   143       }
   144     }
   145 
   146     public Chip Chip { get { return chip; } }
   147     public float?[] Voltages { get { return voltages; } }
   148     public float?[] Temperatures { get { return temperatures; } }
   149     public float?[] Fans { get { return fans; } }
   150     public float?[] Controls { get { return controls; } }
   151 
   152     public string GetReport() {
   153       StringBuilder r = new StringBuilder();
   154 
   155       r.AppendLine("LPC " + this.GetType().Name);
   156       r.AppendLine();
   157       r.Append("Chip ID: 0x"); r.AppendLine(chip.ToString("X"));
   158       r.Append("Chip Version: 0x"); r.AppendLine(
   159         version.ToString("X", CultureInfo.InvariantCulture));
   160       r.Append("Base Address: 0x"); r.AppendLine(
   161         address.ToString("X4", CultureInfo.InvariantCulture));
   162       r.Append("GPIO Address: 0x"); r.AppendLine(
   163         gpioAddress.ToString("X4", CultureInfo.InvariantCulture));
   164       r.AppendLine();
   165 
   166       if (!Ring0.WaitIsaBusMutex(100))
   167         return r.ToString();
   168 
   169       r.AppendLine("Environment Controller Registers");
   170       r.AppendLine();
   171       r.AppendLine("      00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F");
   172       r.AppendLine();
   173       for (int i = 0; i <= 0xA; i++) {
   174         r.Append(" "); 
   175         r.Append((i << 4).ToString("X2", CultureInfo.InvariantCulture)); 
   176         r.Append("  ");
   177         for (int j = 0; j <= 0xF; j++) {
   178           r.Append(" ");
   179           bool valid;
   180           byte value = ReadByte((byte)((i << 4) | j), out valid);
   181           r.Append(
   182             valid ? value.ToString("X2", CultureInfo.InvariantCulture) : "??");
   183         }
   184         r.AppendLine();
   185       }
   186       r.AppendLine();
   187 
   188       r.AppendLine("GPIO Registers");
   189       r.AppendLine();
   190       for (int i = 0; i < gpioCount; i++) {
   191         r.Append(" ");
   192         r.Append(ReadGPIO(i).Value.ToString("X2",
   193           CultureInfo.InvariantCulture));
   194       }
   195       r.AppendLine();
   196       r.AppendLine();
   197 
   198       Ring0.ReleaseIsaBusMutex();
   199 
   200       return r.ToString();
   201     }
   202 
   203     public void Update() {
   204       if (!Ring0.WaitIsaBusMutex(10))
   205         return;
   206 
   207       for (int i = 0; i < voltages.Length; i++) {
   208         bool valid;
   209         
   210         float value = 
   211           voltageGain * ReadByte((byte)(VOLTAGE_BASE_REG + i), out valid);   
   212 
   213         if (!valid)
   214           continue;
   215         if (value > 0)
   216           voltages[i] = value;  
   217         else
   218           voltages[i] = null;
   219       }
   220 
   221       for (int i = 0; i < temperatures.Length; i++) {
   222         bool valid;
   223         sbyte value = (sbyte)ReadByte(
   224           (byte)(TEMPERATURE_BASE_REG + i), out valid);
   225         if (!valid)
   226           continue;
   227 
   228         if (value < sbyte.MaxValue && value > 0)
   229           temperatures[i] = value;
   230         else
   231           temperatures[i] = null;       
   232       }
   233 
   234       if (has16bitFanCounter) {
   235         for (int i = 0; i < fans.Length; i++) {
   236           bool valid;
   237           int value = ReadByte(FAN_TACHOMETER_REG[i], out valid);
   238           if (!valid)
   239             continue;
   240           value |= ReadByte(FAN_TACHOMETER_EXT_REG[i], out valid) << 8;
   241           if (!valid)
   242             continue;
   243 
   244           if (value > 0x3f) {
   245             fans[i] = (value < 0xffff) ? 1.35e6f / (value * 2) : 0;
   246           } else {
   247             fans[i] = null;
   248           }
   249         }
   250       } else {
   251         for (int i = 0; i < fans.Length; i++) {
   252           bool valid;
   253           int value = ReadByte(FAN_TACHOMETER_REG[i], out valid);
   254           if (!valid)
   255             continue;
   256 
   257           int divisor = 2;
   258           if (i < 2) {
   259             int divisors = ReadByte(FAN_TACHOMETER_DIVISOR_REGISTER, out valid);
   260             if (!valid)
   261               continue;
   262             divisor = 1 << ((divisors >> (3 * i)) & 0x7);
   263           }
   264 
   265           if (value > 0) {
   266             fans[i] = (value < 0xff) ? 1.35e6f / (value * divisor) : 0;
   267           } else {
   268             fans[i] = null;
   269           }
   270         }
   271       }
   272 
   273       Ring0.ReleaseIsaBusMutex();
   274     }
   275   } 
   276 }