Hardware/LPC/LPCIO.cs
author moel.mich
Thu, 11 Nov 2010 21:22:24 +0000
changeset 241 52007c404f32
parent 228 458a6c3de579
child 245 f8e72b2efcc0
permissions -rw-r--r--
Fixed a problem, where the MainForm location and size was lost when the application is started minimized and exited without ever showing the form. This caused MainForm_Load to be never called (location and size was not loaded), but the default size and location were still saved. The new implementation only saves the location and size when one of the two is changed.
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@236
    65
      Ring0.WriteIoPort(registerPort, register);
moel@236
    66
      return Ring0.ReadIoPort(valuePort);
moel@228
    67
    }
moel@110
    68
moel@110
    69
    private ushort ReadWord(byte register) {
moel@228
    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@236
    75
      Ring0.WriteIoPort(registerPort, DEVCIE_SELECT_REGISTER);
moel@236
    76
      Ring0.WriteIoPort(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@236
   102
      Ring0.WriteIoPort(registerPort, 0x87);
moel@236
   103
      Ring0.WriteIoPort(registerPort, 0x87);
moel@110
   104
    }
moel@110
   105
moel@110
   106
    private void WinbondFintekExit() {
moel@236
   107
      Ring0.WriteIoPort(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@228
   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@228
   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@228
   253
          report.AppendLine(revision.ToString("X",
moel@167
   254
            CultureInfo.InvariantCulture));
moel@167
   255
          report.Append("Error: Invalid address 0x");
moel@228
   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@228
   283
              report.AppendLine(revision.ToString("X",
moel@167
   284
                CultureInfo.InvariantCulture));
moel@167
   285
              report.Append("Error: Invalid vendor ID 0x");
moel@228
   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@228
   307
    private const byte IT87_GPIO_LDN = 0x07;
moel@169
   308
    private const byte IT87_CHIP_VERSION_REGISTER = 0x22;
moel@169
   309
moel@169
   310
    private void IT87Enter() {
moel@236
   311
      Ring0.WriteIoPort(registerPort, 0x87);
moel@236
   312
      Ring0.WriteIoPort(registerPort, 0x01);
moel@236
   313
      Ring0.WriteIoPort(registerPort, 0x55);
moel@236
   314
      Ring0.WriteIoPort(registerPort, 0x55);
moel@169
   315
    }
moel@169
   316
moel@169
   317
    private void IT87Exit() {
moel@236
   318
      Ring0.WriteIoPort(registerPort, CONFIGURATION_CONTROL_REGISTER);
moel@236
   319
      Ring0.WriteIoPort(valuePort, 0x02);
moel@169
   320
    }
moel@169
   321
moel@167
   322
    private bool DetectIT87() {
moel@169
   323
moel@169
   324
      // IT87XX can enter only on port 0x2E
moel@169
   325
      if (registerPort != 0x2E)
moel@169
   326
        return false;
moel@169
   327
moel@167
   328
      IT87Enter();
moel@167
   329
moel@167
   330
      ushort chipID = ReadWord(CHIP_ID_REGISTER);
moel@167
   331
      Chip chip;
moel@167
   332
      switch (chipID) {
moel@167
   333
        case 0x8712: chip = Chip.IT8712F; break;
moel@167
   334
        case 0x8716: chip = Chip.IT8716F; break;
moel@167
   335
        case 0x8718: chip = Chip.IT8718F; break;
moel@167
   336
        case 0x8720: chip = Chip.IT8720F; break;
moel@170
   337
        case 0x8721: chip = Chip.IT8721F; break;
moel@167
   338
        case 0x8726: chip = Chip.IT8726F; break;
moel@167
   339
        default: chip = Chip.Unknown; break;
moel@167
   340
      }
moel@167
   341
      if (chip == Chip.Unknown) {
moel@167
   342
        if (chipID != 0 && chipID != 0xffff) {
moel@167
   343
          IT87Exit();
moel@167
   344
moel@167
   345
          ReportUnknownChip("ITE", chipID);
moel@167
   346
        }
moel@167
   347
      } else {
moel@167
   348
        Select(IT87_ENVIRONMENT_CONTROLLER_LDN);
moel@167
   349
        ushort address = ReadWord(BASE_ADDRESS_REGISTER);
moel@167
   350
        Thread.Sleep(1);
moel@167
   351
        ushort verify = ReadWord(BASE_ADDRESS_REGISTER);
moel@167
   352
moel@167
   353
        byte version = (byte)(ReadByte(IT87_CHIP_VERSION_REGISTER) & 0x0F);
moel@167
   354
moel@228
   355
        Select(IT87_GPIO_LDN);
moel@228
   356
        ushort gpioAddress = ReadWord(BASE_ADDRESS_REGISTER + 2);
moel@228
   357
        Thread.Sleep(1);
moel@228
   358
        ushort gpioVerify = ReadWord(BASE_ADDRESS_REGISTER + 2);
moel@228
   359
moel@167
   360
        IT87Exit();
moel@167
   361
moel@167
   362
        if (address != verify || address < 0x100 || (address & 0xF007) != 0) {
moel@167
   363
          report.Append("Chip ID: 0x");
moel@167
   364
          report.AppendLine(chip.ToString("X"));
moel@167
   365
          report.Append("Error: Invalid address 0x");
moel@167
   366
          report.AppendLine(address.ToString("X",
moel@167
   367
            CultureInfo.InvariantCulture));
moel@167
   368
          report.AppendLine();
moel@167
   369
          return false;
moel@167
   370
        }
moel@167
   371
moel@228
   372
        if (gpioAddress != gpioVerify || gpioAddress < 0x100 ||
moel@228
   373
          (gpioAddress & 0xF007) != 0) {
moel@228
   374
          report.Append("Chip ID: 0x");
moel@228
   375
          report.AppendLine(chip.ToString("X"));
moel@228
   376
          report.Append("Error: Invalid GPIO address 0x");
moel@228
   377
          report.AppendLine(gpioAddress.ToString("X",
moel@228
   378
            CultureInfo.InvariantCulture));
moel@228
   379
          report.AppendLine();
moel@228
   380
          return false;
moel@228
   381
        }
moel@228
   382
moel@228
   383
        superIOs.Add(new IT87XX(chip, address, gpioAddress, version));
moel@167
   384
        return true;
moel@167
   385
      }
moel@167
   386
moel@167
   387
      return false;
moel@167
   388
    }
moel@167
   389
moel@169
   390
    #endregion
moel@169
   391
moel@169
   392
    #region SMSC
moel@169
   393
moel@169
   394
    private void SMSCEnter() {
moel@236
   395
      Ring0.WriteIoPort(registerPort, 0x55);
moel@169
   396
    }
moel@169
   397
moel@169
   398
    private void SMSCExit() {
moel@236
   399
      Ring0.WriteIoPort(registerPort, 0xAA);
moel@169
   400
    }
moel@169
   401
moel@167
   402
    private bool DetectSMSC() {
moel@167
   403
      SMSCEnter();
moel@167
   404
moel@167
   405
      ushort chipID = ReadWord(CHIP_ID_REGISTER);
moel@167
   406
      Chip chip;
moel@167
   407
      switch (chipID) {
moel@167
   408
        default: chip = Chip.Unknown; break;
moel@167
   409
      }
moel@167
   410
      if (chip == Chip.Unknown) {
moel@167
   411
        if (chipID != 0 && chipID != 0xffff) {
moel@167
   412
          SMSCExit();
moel@167
   413
moel@167
   414
          ReportUnknownChip("SMSC", chipID);
moel@167
   415
        }
moel@167
   416
      } else {
moel@167
   417
        SMSCExit();
moel@167
   418
        return true;
moel@167
   419
      }
moel@167
   420
moel@167
   421
      return false;
moel@167
   422
    }
moel@167
   423
moel@169
   424
    #endregion
moel@169
   425
moel@163
   426
    private void Detect() {
moel@110
   427
moel@110
   428
      for (int i = 0; i < REGISTER_PORTS.Length; i++) {
moel@110
   429
        registerPort = REGISTER_PORTS[i];
moel@110
   430
        valuePort = VALUE_PORTS[i];
moel@110
   431
moel@167
   432
        if (DetectWinbondFintek()) continue;
moel@110
   433
moel@167
   434
        if (DetectIT87()) continue;
moel@110
   435
moel@167
   436
        if (DetectSMSC()) continue;
moel@228
   437
      }
moel@163
   438
    }
moel@163
   439
moel@163
   440
    public LPCIO() {
moel@236
   441
      if (!Ring0.IsOpen)
moel@163
   442
        return;
moel@163
   443
moel@236
   444
      if (!Ring0.WaitIsaBusMutex(100))
moel@163
   445
        return;
moel@163
   446
moel@163
   447
      Detect();
moel@163
   448
moel@236
   449
      Ring0.ReleaseIsaBusMutex();
moel@110
   450
    }
moel@110
   451
moel@130
   452
    public ISuperIO[] SuperIO {
moel@110
   453
      get {
moel@130
   454
        return superIOs.ToArray();
moel@110
   455
      }
moel@110
   456
    }
moel@110
   457
moel@110
   458
    public string GetReport() {
moel@110
   459
      if (report.Length > 0) {
moel@195
   460
        return "LPCIO" + Environment.NewLine + Environment.NewLine + report;
moel@110
   461
      } else
moel@110
   462
        return null;
moel@110
   463
    }
moel@110
   464
  }
moel@110
   465
}