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