Hardware/LPC/LPCGroup.cs
author moel.mich
Tue, 09 Mar 2010 22:27:10 +0000
changeset 79 9cdbe1d8d12a
parent 67 bb5696abab23
child 92 8a5ff8bdf3ca
permissions -rw-r--r--
Changed the CPU clock calculation. If no invariant TSC is available, then the max CPU clock is estimated at startup under load, otherwise an average over one second is used.
moel@1
     1
/*
moel@1
     2
  
moel@1
     3
  Version: MPL 1.1/GPL 2.0/LGPL 2.1
moel@1
     4
moel@1
     5
  The contents of this file are subject to the Mozilla Public License Version
moel@1
     6
  1.1 (the "License"); you may not use this file except in compliance with
moel@1
     7
  the License. You may obtain a copy of the License at
moel@1
     8
 
moel@1
     9
  http://www.mozilla.org/MPL/
moel@1
    10
moel@1
    11
  Software distributed under the License is distributed on an "AS IS" basis,
moel@1
    12
  WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
moel@1
    13
  for the specific language governing rights and limitations under the License.
moel@1
    14
moel@1
    15
  The Original Code is the Open Hardware Monitor code.
moel@1
    16
moel@1
    17
  The Initial Developer of the Original Code is 
moel@1
    18
  Michael Möller <m.moeller@gmx.ch>.
moel@1
    19
  Portions created by the Initial Developer are Copyright (C) 2009-2010
moel@1
    20
  the Initial Developer. All Rights Reserved.
moel@1
    21
moel@1
    22
  Contributor(s):
moel@1
    23
moel@1
    24
  Alternatively, the contents of this file may be used under the terms of
moel@1
    25
  either the GNU General Public License Version 2 or later (the "GPL"), or
moel@1
    26
  the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
moel@1
    27
  in which case the provisions of the GPL or the LGPL are applicable instead
moel@1
    28
  of those above. If you wish to allow use of your version of this file only
moel@1
    29
  under the terms of either the GPL or the LGPL, and not to allow others to
moel@1
    30
  use your version of this file under the terms of the MPL, indicate your
moel@1
    31
  decision by deleting the provisions above and replace them with the notice
moel@1
    32
  and other provisions required by the GPL or the LGPL. If you do not delete
moel@1
    33
  the provisions above, a recipient may use your version of this file under
moel@1
    34
  the terms of any one of the MPL, the GPL or the LGPL.
moel@1
    35
 
moel@1
    36
*/
moel@1
    37
moel@1
    38
using System;
moel@1
    39
using System.Collections.Generic;
moel@1
    40
using System.Text;
moel@1
    41
using System.Threading;
moel@1
    42
moel@1
    43
namespace OpenHardwareMonitor.Hardware.LPC {
moel@1
    44
  public class LPCGroup : IGroup {
moel@67
    45
moel@1
    46
    private List<IHardware> hardware = new List<IHardware>();
moel@67
    47
    private StringBuilder report = new StringBuilder();
moel@1
    48
moel@1
    49
    private Chip chip = Chip.Unknown;
moel@1
    50
moel@1
    51
    // I/O Ports
moel@7
    52
    private ushort[] REGISTER_PORTS = new ushort[] { 0x2e, 0x4e };
moel@7
    53
    private ushort[] VALUE_PORTS = new ushort[] { 0x2f, 0x4f };
moel@7
    54
moel@7
    55
    private ushort registerPort;
moel@7
    56
    private ushort valuePort;
moel@1
    57
moel@1
    58
    // Registers
moel@1
    59
    private const byte CONFIGURATION_CONTROL_REGISTER = 0x02;
moel@1
    60
    private const byte DEVCIE_SELECT_REGISTER = 0x07;
moel@1
    61
    private const byte CHIP_ID_REGISTER = 0x20;
moel@1
    62
    private const byte CHIP_REVISION_REGISTER = 0x21;
moel@7
    63
    private const byte BASE_ADDRESS_REGISTER = 0x60;
moel@1
    64
moel@7
    65
    private byte ReadByte(byte register) {
moel@7
    66
      WinRing0.WriteIoPortByte(registerPort, register);
moel@7
    67
      return WinRing0.ReadIoPortByte(valuePort);
moel@13
    68
    } 
moel@1
    69
moel@7
    70
    private ushort ReadWord(byte register) {
moel@7
    71
      return (ushort)((ReadByte(register) << 8) | 
moel@7
    72
        ReadByte((byte)(register + 1)));
moel@1
    73
    }
moel@1
    74
moel@7
    75
    private void Select(byte logicalDeviceNumber) {
moel@7
    76
      WinRing0.WriteIoPortByte(registerPort, DEVCIE_SELECT_REGISTER);
moel@7
    77
      WinRing0.WriteIoPortByte(valuePort, logicalDeviceNumber);
moel@1
    78
    }
moel@1
    79
moel@34
    80
    // ITE
moel@7
    81
    private const byte IT87_ENVIRONMENT_CONTROLLER_LDN = 0x04;    
moel@1
    82
moel@7
    83
    private void IT87Enter() {
moel@7
    84
      WinRing0.WriteIoPortByte(registerPort, 0x87);
moel@7
    85
      WinRing0.WriteIoPortByte(registerPort, 0x01);
moel@7
    86
      WinRing0.WriteIoPortByte(registerPort, 0x55);
moel@7
    87
      WinRing0.WriteIoPortByte(registerPort, 0x55);
moel@1
    88
    }
moel@1
    89
moel@7
    90
    internal void IT87Exit() {
moel@7
    91
      WinRing0.WriteIoPortByte(registerPort, CONFIGURATION_CONTROL_REGISTER);
moel@7
    92
      WinRing0.WriteIoPortByte(valuePort, 0x02);
moel@1
    93
    }
moel@1
    94
moel@7
    95
    // Winbond, Fintek
moel@7
    96
    private const byte FINTEK_VENDOR_ID_REGISTER = 0x23;
moel@7
    97
    private const ushort FINTEK_VENDOR_ID = 0x1934;
moel@7
    98
moel@34
    99
    private const byte WINBOND_HARDWARE_MONITOR_LDN = 0x0B;
moel@16
   100
moel@16
   101
    private const byte F71858_HARDWARE_MONITOR_LDN = 0x02;
moel@16
   102
    private const byte FINTEK_HARDWARE_MONITOR_LDN = 0x04;
moel@7
   103
moel@7
   104
    private void WinbondFintekEnter() {
moel@7
   105
      WinRing0.WriteIoPortByte(registerPort, 0x87);
moel@7
   106
      WinRing0.WriteIoPortByte(registerPort, 0x87);
moel@1
   107
    }
moel@1
   108
moel@7
   109
    private void WinbondFintekExit() {
moel@7
   110
      WinRing0.WriteIoPortByte(registerPort, 0xAA);      
moel@1
   111
    }
moel@1
   112
moel@67
   113
    // SMSC
moel@67
   114
    private void SMSCEnter() {
moel@67
   115
      WinRing0.WriteIoPortByte(registerPort, 0x55);
moel@67
   116
    }
moel@67
   117
moel@67
   118
    private void SMSCExit() {
moel@67
   119
      WinRing0.WriteIoPortByte(registerPort, 0xAA);
moel@67
   120
    }
moel@67
   121
moel@1
   122
    public LPCGroup() {
moel@1
   123
      if (!WinRing0.IsAvailable)
moel@1
   124
        return;
moel@1
   125
moel@7
   126
      for (int i = 0; i < REGISTER_PORTS.Length; i++) {
moel@7
   127
        registerPort = REGISTER_PORTS[i];
moel@7
   128
        valuePort = VALUE_PORTS[i];
moel@1
   129
moel@7
   130
        WinbondFintekEnter();
moel@1
   131
moel@16
   132
        byte logicalDeviceNumber;
moel@7
   133
        byte id = ReadByte(CHIP_ID_REGISTER);
moel@7
   134
        byte revision = ReadByte(CHIP_REVISION_REGISTER);
moel@34
   135
        chip = Chip.Unknown;
moel@34
   136
        logicalDeviceNumber = 0;
moel@7
   137
        switch (id) {
moel@16
   138
          case 0x05:
moel@16
   139
            switch (revision) {
moel@68
   140
              case 0x07:
moel@68
   141
                chip = Chip.F71858;
moel@68
   142
                logicalDeviceNumber = F71858_HARDWARE_MONITOR_LDN;
moel@68
   143
                break;
moel@16
   144
              case 0x41:
moel@16
   145
                chip = Chip.F71882;
moel@16
   146
                logicalDeviceNumber = FINTEK_HARDWARE_MONITOR_LDN;
moel@34
   147
                break;              
moel@16
   148
            } break;
moel@16
   149
          case 0x06:
moel@16
   150
            switch (revision) {             
moel@16
   151
              case 0x01:
moel@16
   152
                chip = Chip.F71862;
moel@16
   153
                logicalDeviceNumber = FINTEK_HARDWARE_MONITOR_LDN;
moel@34
   154
                break;              
moel@16
   155
            } break;
moel@16
   156
          case 0x07:
moel@16
   157
            switch (revision) {
moel@16
   158
              case 0x23:
moel@16
   159
                chip = Chip.F71889;
moel@16
   160
                logicalDeviceNumber = FINTEK_HARDWARE_MONITOR_LDN;
moel@34
   161
                break;              
moel@16
   162
            } break;
moel@16
   163
          case 0x08:
moel@16
   164
            switch (revision) {
moel@16
   165
              case 0x14:
moel@16
   166
                chip = Chip.F71869;
moel@16
   167
                logicalDeviceNumber = FINTEK_HARDWARE_MONITOR_LDN;
moel@34
   168
                break;              
moel@16
   169
            } break;
moel@31
   170
          case 0x52:
moel@31
   171
            switch (revision) {
moel@31
   172
              case 0x17:
moel@31
   173
              case 0x3A:
moel@31
   174
                chip = Chip.W83627HF;
moel@34
   175
                logicalDeviceNumber = WINBOND_HARDWARE_MONITOR_LDN;
moel@34
   176
                break;             
moel@34
   177
            } break;
moel@54
   178
          case 0x82:
moel@54
   179
            switch (revision) {
moel@54
   180
              case 0x83:
moel@54
   181
                chip = Chip.W83627THF;
moel@54
   182
                logicalDeviceNumber = WINBOND_HARDWARE_MONITOR_LDN;
moel@54
   183
                break;
moel@54
   184
            } break;
moel@67
   185
          case 0x85:
moel@67
   186
            switch (revision) {
moel@67
   187
              case 0x41:
moel@67
   188
                chip = Chip.W83687THF;
moel@67
   189
                logicalDeviceNumber = WINBOND_HARDWARE_MONITOR_LDN;
moel@67
   190
                break;
moel@67
   191
            } break;
moel@34
   192
          case 0x88:
moel@34
   193
            switch (revision & 0xF0) {
moel@34
   194
              case 0x60:
moel@34
   195
                chip = Chip.W83627EHF;
moel@34
   196
                logicalDeviceNumber = WINBOND_HARDWARE_MONITOR_LDN;
moel@31
   197
                break;
moel@31
   198
            } break;
moel@7
   199
          case 0xA0:
moel@7
   200
            switch (revision & 0xF0) {
moel@7
   201
              case 0x20: 
moel@7
   202
                chip = Chip.W83627DHG;
moel@34
   203
                logicalDeviceNumber = WINBOND_HARDWARE_MONITOR_LDN;  
moel@34
   204
                break;             
moel@34
   205
            } break;
moel@34
   206
          case 0xA5:
moel@34
   207
            switch (revision & 0xF0) {
moel@34
   208
              case 0x10:
moel@34
   209
                chip = Chip.W83667HG;
moel@34
   210
                logicalDeviceNumber = WINBOND_HARDWARE_MONITOR_LDN;
moel@7
   211
                break;
moel@19
   212
            } break;
moel@19
   213
          case 0xB0:
moel@19
   214
            switch (revision & 0xF0) {
moel@19
   215
              case 0x70:
moel@19
   216
                chip = Chip.W83627DHGP;
moel@34
   217
                logicalDeviceNumber = WINBOND_HARDWARE_MONITOR_LDN;
moel@34
   218
                break;             
moel@34
   219
            } break;
moel@34
   220
          case 0xB3:
moel@34
   221
            switch (revision & 0xF0) {
moel@34
   222
              case 0x50:
moel@34
   223
                chip = Chip.W83667HGB;
moel@34
   224
                logicalDeviceNumber = WINBOND_HARDWARE_MONITOR_LDN;
moel@19
   225
                break;
moel@34
   226
            } break; 
moel@7
   227
        }
moel@67
   228
        if (chip == Chip.Unknown) {
moel@67
   229
          if (id != 0 && id != 0xff) {
moel@67
   230
            WinbondFintekExit();
moel@67
   231
moel@67
   232
            report.Append("Chip ID: Unknown Winbond / Fintek with ID 0x"); 
moel@67
   233
            report.AppendLine(((id << 8) | revision).ToString("X"));
moel@67
   234
            report.AppendLine();
moel@67
   235
          }
moel@67
   236
        } else {
moel@1
   237
moel@16
   238
          Select(logicalDeviceNumber);
moel@60
   239
          ushort address = ReadWord(BASE_ADDRESS_REGISTER);          
moel@7
   240
          Thread.Sleep(1);
moel@7
   241
          ushort verify = ReadWord(BASE_ADDRESS_REGISTER);
moel@68
   242
moel@68
   243
          ushort vendorID = FINTEK_VENDOR_ID;
moel@68
   244
          if (chip == Chip.F71858 || chip == Chip.F71862 || 
moel@68
   245
            chip == Chip.F71882 || chip == Chip.F71889)
moel@7
   246
            vendorID = ReadWord(FINTEK_VENDOR_ID_REGISTER);
moel@1
   247
moel@7
   248
          WinbondFintekExit();
moel@1
   249
moel@67
   250
          if (address != verify) {            
moel@67
   251
            report.Append("Chip ID: 0x"); 
moel@67
   252
            report.AppendLine(chip.ToString("X"));
moel@67
   253
            report.Append("Chip revision: 0x"); 
moel@67
   254
            report.AppendLine(revision.ToString("X"));
moel@67
   255
            report.AppendLine("Error: Address verification failed");
moel@67
   256
            report.AppendLine();
moel@60
   257
            return;
moel@67
   258
          }
moel@60
   259
moel@60
   260
          // some Fintek chips have address register offset 0x05 added already
moel@60
   261
          if ((address & 0x07) == 0x05)
moel@60
   262
            address &= 0xFFF8;
moel@60
   263
moel@67
   264
          if (address < 0x100 || (address & 0xF007) != 0) {            
moel@67
   265
            report.Append("Chip ID: 0x");
moel@67
   266
            report.AppendLine(chip.ToString("X"));
moel@67
   267
            report.Append("Chip revision: 0x");
moel@67
   268
            report.AppendLine(revision.ToString("X"));
moel@67
   269
            report.Append("Error: Invalid address 0x");
moel@67
   270
            report.AppendLine(address.ToString("X"));
moel@67
   271
            report.AppendLine();
moel@7
   272
            return;
moel@67
   273
          }
moel@67
   274
moel@7
   275
          switch (chip) {
moel@7
   276
            case Chip.W83627DHG:
moel@19
   277
            case Chip.W83627DHGP:
moel@34
   278
            case Chip.W83627EHF:
moel@31
   279
            case Chip.W83627HF:
moel@54
   280
            case Chip.W83627THF:
moel@34
   281
            case Chip.W83667HG:
moel@34
   282
            case Chip.W83667HGB:
moel@67
   283
            case Chip.W83687THF:
moel@34
   284
              W836XX w836XX = new W836XX(chip, revision, address);
moel@34
   285
              if (w836XX.IsAvailable)
moel@34
   286
                hardware.Add(w836XX);
moel@7
   287
              break;
moel@68
   288
            case Chip.F71858:
moel@16
   289
            case Chip.F71862:
moel@16
   290
            case Chip.F71882:
moel@16
   291
            case Chip.F71889: 
moel@16
   292
            case Chip.F71869:
moel@16
   293
              hardware.Add(new F718XX(chip, address));
moel@7
   294
              break;
moel@7
   295
            default: break;
moel@7
   296
          }
moel@7
   297
          
moel@7
   298
          return;
moel@7
   299
        }
moel@1
   300
moel@7
   301
        IT87Enter();
moel@1
   302
moel@67
   303
        ushort chipID = ReadWord(CHIP_ID_REGISTER);
moel@67
   304
        switch (chipID) {
moel@21
   305
          case 0x8716: chip = Chip.IT8716F; break;
moel@21
   306
          case 0x8718: chip = Chip.IT8718F; break;
moel@21
   307
          case 0x8720: chip = Chip.IT8720F; break;
moel@67
   308
          case 0x8726: chip = Chip.IT8726F; break; 
moel@7
   309
          default: chip = Chip.Unknown; break;
moel@7
   310
        }
moel@67
   311
        if (chip == Chip.Unknown) {
moel@67
   312
          if (chipID != 0 && chipID != 0xffff) {
moel@67
   313
            IT87Exit();
moel@7
   314
moel@67
   315
            report.Append("Chip ID: Unknown ITE with ID 0x");
moel@67
   316
            report.AppendLine(chipID.ToString("X"));
moel@67
   317
            report.AppendLine();
moel@67
   318
          }
moel@67
   319
        } else {
moel@7
   320
          Select(IT87_ENVIRONMENT_CONTROLLER_LDN);
moel@7
   321
          ushort address = ReadWord(BASE_ADDRESS_REGISTER);
moel@7
   322
          Thread.Sleep(1);
moel@7
   323
          ushort verify = ReadWord(BASE_ADDRESS_REGISTER);
moel@7
   324
moel@7
   325
          IT87Exit();
moel@7
   326
moel@67
   327
          if (address != verify || address < 0x100 || (address & 0xF007) != 0) {
moel@67
   328
            report.Append("Chip ID: 0x");
moel@67
   329
            report.AppendLine(chip.ToString("X"));            
moel@67
   330
            report.Append("Error: Invalid address 0x");
moel@67
   331
            report.AppendLine(address.ToString("X"));
moel@67
   332
            report.AppendLine();
moel@7
   333
            return;
moel@67
   334
          }
moel@7
   335
moel@16
   336
          IT87XX it87 = new IT87XX(chip, address);
moel@7
   337
          if (it87.IsAvailable)
moel@7
   338
            hardware.Add(it87);
moel@7
   339
moel@1
   340
          return;
moel@7
   341
        }
moel@67
   342
moel@67
   343
        SMSCEnter();
moel@67
   344
moel@67
   345
        chipID = ReadWord(CHIP_ID_REGISTER);
moel@67
   346
        switch (chipID) {
moel@67
   347
          default: chip = Chip.Unknown; break;
moel@67
   348
        }
moel@67
   349
        if (chip == Chip.Unknown) {
moel@67
   350
          if (chipID != 0 && chipID != 0xffff) {
moel@67
   351
            SMSCExit();
moel@67
   352
moel@67
   353
            report.Append("Chip ID: Unknown SMSC with ID 0x");
moel@67
   354
            report.AppendLine(chipID.ToString("X"));
moel@67
   355
            report.AppendLine();
moel@67
   356
          }
moel@67
   357
        } else {
moel@67
   358
          SMSCExit();
moel@67
   359
moel@67
   360
          return;
moel@67
   361
        }
moel@7
   362
      }   
moel@1
   363
    }
moel@1
   364
moel@1
   365
    public IHardware[] Hardware {
moel@1
   366
      get {
moel@1
   367
        return hardware.ToArray();
moel@1
   368
      }
moel@1
   369
    }
moel@1
   370
moel@1
   371
    public string GetReport() {
moel@67
   372
      if (report.Length > 0) {
moel@67
   373
        report.Insert(0, "LPCIO" + Environment.NewLine +
moel@67
   374
          Environment.NewLine);        
moel@67
   375
        return report.ToString();
moel@67
   376
      } else
moel@67
   377
        return null;
moel@1
   378
    }
moel@1
   379
moel@1
   380
    public void Close() { }
moel@1
   381
  }
moel@1
   382
}