Hardware/LPC/LPCIO.cs
author moel.mich
Sat, 31 Dec 2011 17:31:04 +0000
changeset 324 c6ee430d6995
parent 296 414783d1cda9
child 341 5172a92c5c20
permissions -rw-r--r--
Modified and extended version of the patch v4 by Roland Reinl (see Issue 256). Main differences to the original patch: DeviceIoControl refactorings removed, SmartAttribute is now descriptive only and does not hold any state, report is written as one 80 columns table, sensors are created only for meaningful values and without duplicates (remaining life, temperatures, host writes and reads). Also the current implementation should really preserve all the functionality of the old system. Additionally there is now a simple SMART devices emulation class (DebugSmart) that can be used in place of WindowsSmart for testing with reported data.
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@265
    19
  Portions created by the Initial Developer are Copyright (C) 2009-2011
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@245
    91
    #region Winbond, Nuvoton, 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@245
    96
    private const byte WINBOND_NUVOTON_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@245
   101
    private void WinbondNuvotonFintekEnter() {
moel@236
   102
      Ring0.WriteIoPort(registerPort, 0x87);
moel@236
   103
      Ring0.WriteIoPort(registerPort, 0x87);
moel@110
   104
    }
moel@110
   105
moel@245
   106
    private void WinbondNuvotonFintekExit() {
moel@236
   107
      Ring0.WriteIoPort(registerPort, 0xAA);
moel@110
   108
    }
moel@110
   109
moel@167
   110
    private bool DetectWinbondFintek() {
moel@245
   111
      WinbondNuvotonFintekEnter();
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@296
   157
        case 0x10:
moel@296
   158
          switch (revision) {
moel@296
   159
            case 0x05:
moel@296
   160
              chip = Chip.F71889AD;
moel@296
   161
              logicalDeviceNumber = FINTEK_HARDWARE_MONITOR_LDN;
moel@296
   162
              break;
moel@296
   163
          } break;
moel@167
   164
        case 0x52:
moel@167
   165
          switch (revision) {
moel@167
   166
            case 0x17:
moel@167
   167
            case 0x3A:
moel@167
   168
            case 0x41:
moel@167
   169
              chip = Chip.W83627HF;
moel@245
   170
              logicalDeviceNumber = WINBOND_NUVOTON_HARDWARE_MONITOR_LDN;
moel@167
   171
              break;
moel@167
   172
          } break;
moel@167
   173
        case 0x82:
moel@167
   174
          switch (revision & 0xF0) {
moel@167
   175
            case 0x80:
moel@167
   176
              chip = Chip.W83627THF;
moel@245
   177
              logicalDeviceNumber = WINBOND_NUVOTON_HARDWARE_MONITOR_LDN;
moel@167
   178
              break;
moel@167
   179
          } break;
moel@167
   180
        case 0x85:
moel@167
   181
          switch (revision) {
moel@167
   182
            case 0x41:
moel@167
   183
              chip = Chip.W83687THF;
moel@245
   184
              logicalDeviceNumber = WINBOND_NUVOTON_HARDWARE_MONITOR_LDN;
moel@167
   185
              break;
moel@167
   186
          } break;
moel@167
   187
        case 0x88:
moel@167
   188
          switch (revision & 0xF0) {
moel@167
   189
            case 0x50:
moel@167
   190
            case 0x60:
moel@167
   191
              chip = Chip.W83627EHF;
moel@245
   192
              logicalDeviceNumber = WINBOND_NUVOTON_HARDWARE_MONITOR_LDN;
moel@167
   193
              break;
moel@167
   194
          } break;
moel@167
   195
        case 0xA0:
moel@167
   196
          switch (revision & 0xF0) {
moel@167
   197
            case 0x20:
moel@167
   198
              chip = Chip.W83627DHG;
moel@245
   199
              logicalDeviceNumber = WINBOND_NUVOTON_HARDWARE_MONITOR_LDN;
moel@167
   200
              break;
moel@167
   201
          } break;
moel@167
   202
        case 0xA5:
moel@167
   203
          switch (revision & 0xF0) {
moel@167
   204
            case 0x10:
moel@167
   205
              chip = Chip.W83667HG;
moel@245
   206
              logicalDeviceNumber = WINBOND_NUVOTON_HARDWARE_MONITOR_LDN;
moel@167
   207
              break;
moel@167
   208
          } break;
moel@167
   209
        case 0xB0:
moel@167
   210
          switch (revision & 0xF0) {
moel@167
   211
            case 0x70:
moel@167
   212
              chip = Chip.W83627DHGP;
moel@245
   213
              logicalDeviceNumber = WINBOND_NUVOTON_HARDWARE_MONITOR_LDN;
moel@167
   214
              break;
moel@167
   215
          } break;
moel@167
   216
        case 0xB3:
moel@167
   217
          switch (revision & 0xF0) {
moel@167
   218
            case 0x50:
moel@167
   219
              chip = Chip.W83667HGB;
moel@245
   220
              logicalDeviceNumber = WINBOND_NUVOTON_HARDWARE_MONITOR_LDN;
moel@245
   221
              break;
moel@245
   222
          } break;
moel@245
   223
        case 0xB4:
moel@245
   224
          switch (revision & 0xF0) {
moel@245
   225
            case 0x70:
moel@245
   226
              chip = Chip.NCT6771F;
moel@245
   227
              logicalDeviceNumber = WINBOND_NUVOTON_HARDWARE_MONITOR_LDN;
moel@167
   228
              break;
moel@167
   229
          } break;
moel@265
   230
        case 0xC3:
moel@265
   231
          switch (revision & 0xF0) {
moel@265
   232
            case 0x30:
moel@265
   233
              chip = Chip.NCT6776F;
moel@265
   234
              logicalDeviceNumber = WINBOND_NUVOTON_HARDWARE_MONITOR_LDN;
moel@265
   235
              break;
moel@265
   236
          } break;
moel@167
   237
      }
moel@167
   238
      if (chip == Chip.Unknown) {
moel@167
   239
        if (id != 0 && id != 0xff) {
moel@245
   240
          WinbondNuvotonFintekExit();
moel@167
   241
moel@245
   242
          ReportUnknownChip("Winbond / Nuvoton / Fintek", 
moel@245
   243
            ((id << 8) | revision));
moel@167
   244
        }
moel@167
   245
      } else {
moel@167
   246
moel@167
   247
        Select(logicalDeviceNumber);
moel@167
   248
        ushort address = ReadWord(BASE_ADDRESS_REGISTER);
moel@167
   249
        Thread.Sleep(1);
moel@167
   250
        ushort verify = ReadWord(BASE_ADDRESS_REGISTER);
moel@167
   251
moel@167
   252
        ushort vendorID = ReadWord(FINTEK_VENDOR_ID_REGISTER);
moel@167
   253
moel@245
   254
        WinbondNuvotonFintekExit();
moel@167
   255
moel@167
   256
        if (address != verify) {
moel@167
   257
          report.Append("Chip ID: 0x");
moel@167
   258
          report.AppendLine(chip.ToString("X"));
moel@167
   259
          report.Append("Chip revision: 0x");
moel@228
   260
          report.AppendLine(revision.ToString("X",
moel@167
   261
            CultureInfo.InvariantCulture));
moel@167
   262
          report.AppendLine("Error: Address verification failed");
moel@167
   263
          report.AppendLine();
moel@167
   264
          return false;
moel@167
   265
        }
moel@167
   266
moel@167
   267
        // some Fintek chips have address register offset 0x05 added already
moel@167
   268
        if ((address & 0x07) == 0x05)
moel@167
   269
          address &= 0xFFF8;
moel@167
   270
moel@167
   271
        if (address < 0x100 || (address & 0xF007) != 0) {
moel@167
   272
          report.Append("Chip ID: 0x");
moel@167
   273
          report.AppendLine(chip.ToString("X"));
moel@167
   274
          report.Append("Chip revision: 0x");
moel@228
   275
          report.AppendLine(revision.ToString("X",
moel@167
   276
            CultureInfo.InvariantCulture));
moel@167
   277
          report.Append("Error: Invalid address 0x");
moel@228
   278
          report.AppendLine(address.ToString("X",
moel@167
   279
            CultureInfo.InvariantCulture));
moel@167
   280
          report.AppendLine();
moel@167
   281
          return false;
moel@167
   282
        }
moel@167
   283
moel@167
   284
        switch (chip) {
moel@167
   285
          case Chip.W83627DHG:
moel@167
   286
          case Chip.W83627DHGP:
moel@167
   287
          case Chip.W83627EHF:
moel@167
   288
          case Chip.W83627HF:
moel@167
   289
          case Chip.W83627THF:
moel@167
   290
          case Chip.W83667HG:
moel@167
   291
          case Chip.W83667HGB:
moel@167
   292
          case Chip.W83687THF:
moel@167
   293
            superIOs.Add(new W836XX(chip, revision, address));
moel@167
   294
            break;
moel@245
   295
          case Chip.NCT6771F:
moel@265
   296
          case Chip.NCT6776F:
moel@245
   297
            superIOs.Add(new NCT677X(chip, revision, address));
moel@245
   298
            break;
moel@167
   299
          case Chip.F71858:
moel@167
   300
          case Chip.F71862:
moel@167
   301
          case Chip.F71869:
moel@167
   302
          case Chip.F71882:
moel@296
   303
          case Chip.F71889AD:
moel@167
   304
          case Chip.F71889ED:
moel@167
   305
          case Chip.F71889F:
moel@167
   306
            if (vendorID != FINTEK_VENDOR_ID) {
moel@167
   307
              report.Append("Chip ID: 0x");
moel@167
   308
              report.AppendLine(chip.ToString("X"));
moel@167
   309
              report.Append("Chip revision: 0x");
moel@228
   310
              report.AppendLine(revision.ToString("X",
moel@167
   311
                CultureInfo.InvariantCulture));
moel@167
   312
              report.Append("Error: Invalid vendor ID 0x");
moel@228
   313
              report.AppendLine(vendorID.ToString("X",
moel@167
   314
                CultureInfo.InvariantCulture));
moel@167
   315
              report.AppendLine();
moel@167
   316
              return false;
moel@167
   317
            }
moel@167
   318
            superIOs.Add(new F718XX(chip, address));
moel@167
   319
            break;
moel@167
   320
          default: break;
moel@167
   321
        }
moel@167
   322
moel@167
   323
        return true;
moel@167
   324
      }
moel@167
   325
moel@167
   326
      return false;
moel@167
   327
    }
moel@167
   328
moel@169
   329
    #endregion
moel@169
   330
moel@169
   331
    #region ITE
moel@169
   332
moel@169
   333
    private const byte IT87_ENVIRONMENT_CONTROLLER_LDN = 0x04;
moel@228
   334
    private const byte IT87_GPIO_LDN = 0x07;
moel@169
   335
    private const byte IT87_CHIP_VERSION_REGISTER = 0x22;
moel@169
   336
moel@169
   337
    private void IT87Enter() {
moel@236
   338
      Ring0.WriteIoPort(registerPort, 0x87);
moel@236
   339
      Ring0.WriteIoPort(registerPort, 0x01);
moel@236
   340
      Ring0.WriteIoPort(registerPort, 0x55);
moel@236
   341
      Ring0.WriteIoPort(registerPort, 0x55);
moel@169
   342
    }
moel@169
   343
moel@169
   344
    private void IT87Exit() {
moel@236
   345
      Ring0.WriteIoPort(registerPort, CONFIGURATION_CONTROL_REGISTER);
moel@236
   346
      Ring0.WriteIoPort(valuePort, 0x02);
moel@169
   347
    }
moel@169
   348
moel@167
   349
    private bool DetectIT87() {
moel@169
   350
moel@169
   351
      // IT87XX can enter only on port 0x2E
moel@169
   352
      if (registerPort != 0x2E)
moel@169
   353
        return false;
moel@169
   354
moel@167
   355
      IT87Enter();
moel@167
   356
moel@167
   357
      ushort chipID = ReadWord(CHIP_ID_REGISTER);
moel@167
   358
      Chip chip;
moel@167
   359
      switch (chipID) {
moel@167
   360
        case 0x8712: chip = Chip.IT8712F; break;
moel@167
   361
        case 0x8716: chip = Chip.IT8716F; break;
moel@167
   362
        case 0x8718: chip = Chip.IT8718F; break;
moel@167
   363
        case 0x8720: chip = Chip.IT8720F; break;
moel@170
   364
        case 0x8721: chip = Chip.IT8721F; break;
moel@167
   365
        case 0x8726: chip = Chip.IT8726F; break;
moel@277
   366
        case 0x8728: chip = Chip.IT8728F; break;
moel@319
   367
        case 0x8772: chip = Chip.IT8772E; break;
moel@167
   368
        default: chip = Chip.Unknown; break;
moel@167
   369
      }
moel@167
   370
      if (chip == Chip.Unknown) {
moel@167
   371
        if (chipID != 0 && chipID != 0xffff) {
moel@167
   372
          IT87Exit();
moel@167
   373
moel@167
   374
          ReportUnknownChip("ITE", chipID);
moel@167
   375
        }
moel@167
   376
      } else {
moel@167
   377
        Select(IT87_ENVIRONMENT_CONTROLLER_LDN);
moel@167
   378
        ushort address = ReadWord(BASE_ADDRESS_REGISTER);
moel@167
   379
        Thread.Sleep(1);
moel@167
   380
        ushort verify = ReadWord(BASE_ADDRESS_REGISTER);
moel@167
   381
moel@167
   382
        byte version = (byte)(ReadByte(IT87_CHIP_VERSION_REGISTER) & 0x0F);
moel@167
   383
moel@228
   384
        Select(IT87_GPIO_LDN);
moel@228
   385
        ushort gpioAddress = ReadWord(BASE_ADDRESS_REGISTER + 2);
moel@228
   386
        Thread.Sleep(1);
moel@228
   387
        ushort gpioVerify = ReadWord(BASE_ADDRESS_REGISTER + 2);
moel@228
   388
moel@167
   389
        IT87Exit();
moel@167
   390
moel@167
   391
        if (address != verify || address < 0x100 || (address & 0xF007) != 0) {
moel@167
   392
          report.Append("Chip ID: 0x");
moel@167
   393
          report.AppendLine(chip.ToString("X"));
moel@167
   394
          report.Append("Error: Invalid address 0x");
moel@167
   395
          report.AppendLine(address.ToString("X",
moel@167
   396
            CultureInfo.InvariantCulture));
moel@167
   397
          report.AppendLine();
moel@167
   398
          return false;
moel@167
   399
        }
moel@167
   400
moel@228
   401
        if (gpioAddress != gpioVerify || gpioAddress < 0x100 ||
moel@228
   402
          (gpioAddress & 0xF007) != 0) {
moel@228
   403
          report.Append("Chip ID: 0x");
moel@228
   404
          report.AppendLine(chip.ToString("X"));
moel@228
   405
          report.Append("Error: Invalid GPIO address 0x");
moel@228
   406
          report.AppendLine(gpioAddress.ToString("X",
moel@228
   407
            CultureInfo.InvariantCulture));
moel@228
   408
          report.AppendLine();
moel@228
   409
          return false;
moel@228
   410
        }
moel@228
   411
moel@228
   412
        superIOs.Add(new IT87XX(chip, address, gpioAddress, version));
moel@167
   413
        return true;
moel@167
   414
      }
moel@167
   415
moel@167
   416
      return false;
moel@167
   417
    }
moel@167
   418
moel@169
   419
    #endregion
moel@169
   420
moel@169
   421
    #region SMSC
moel@169
   422
moel@169
   423
    private void SMSCEnter() {
moel@236
   424
      Ring0.WriteIoPort(registerPort, 0x55);
moel@169
   425
    }
moel@169
   426
moel@169
   427
    private void SMSCExit() {
moel@236
   428
      Ring0.WriteIoPort(registerPort, 0xAA);
moel@169
   429
    }
moel@169
   430
moel@167
   431
    private bool DetectSMSC() {
moel@167
   432
      SMSCEnter();
moel@167
   433
moel@167
   434
      ushort chipID = ReadWord(CHIP_ID_REGISTER);
moel@167
   435
      Chip chip;
moel@167
   436
      switch (chipID) {
moel@167
   437
        default: chip = Chip.Unknown; break;
moel@167
   438
      }
moel@167
   439
      if (chip == Chip.Unknown) {
moel@167
   440
        if (chipID != 0 && chipID != 0xffff) {
moel@167
   441
          SMSCExit();
moel@167
   442
moel@167
   443
          ReportUnknownChip("SMSC", chipID);
moel@167
   444
        }
moel@167
   445
      } else {
moel@167
   446
        SMSCExit();
moel@167
   447
        return true;
moel@167
   448
      }
moel@167
   449
moel@167
   450
      return false;
moel@167
   451
    }
moel@167
   452
moel@169
   453
    #endregion
moel@169
   454
moel@163
   455
    private void Detect() {
moel@110
   456
moel@110
   457
      for (int i = 0; i < REGISTER_PORTS.Length; i++) {
moel@110
   458
        registerPort = REGISTER_PORTS[i];
moel@110
   459
        valuePort = VALUE_PORTS[i];
moel@110
   460
moel@167
   461
        if (DetectWinbondFintek()) continue;
moel@110
   462
moel@167
   463
        if (DetectIT87()) continue;
moel@110
   464
moel@167
   465
        if (DetectSMSC()) continue;
moel@228
   466
      }
moel@163
   467
    }
moel@163
   468
moel@163
   469
    public LPCIO() {
moel@236
   470
      if (!Ring0.IsOpen)
moel@163
   471
        return;
moel@163
   472
moel@236
   473
      if (!Ring0.WaitIsaBusMutex(100))
moel@163
   474
        return;
moel@163
   475
moel@163
   476
      Detect();
moel@163
   477
moel@236
   478
      Ring0.ReleaseIsaBusMutex();
moel@110
   479
    }
moel@110
   480
moel@130
   481
    public ISuperIO[] SuperIO {
moel@110
   482
      get {
moel@130
   483
        return superIOs.ToArray();
moel@110
   484
      }
moel@110
   485
    }
moel@110
   486
moel@110
   487
    public string GetReport() {
moel@110
   488
      if (report.Length > 0) {
moel@195
   489
        return "LPCIO" + Environment.NewLine + Environment.NewLine + report;
moel@110
   490
      } else
moel@110
   491
        return null;
moel@110
   492
    }
moel@110
   493
  }
moel@110
   494
}