Hardware/LPC/LPCIO.cs
author moel.mich
Sun, 23 Sep 2012 18:37:43 +0000
changeset 380 573f1fff48b2
parent 353 b4e37f5b2669
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.
moel@110
     1
/*
moel@110
     2
 
moel@344
     3
  This Source Code Form is subject to the terms of the Mozilla Public
moel@344
     4
  License, v. 2.0. If a copy of the MPL was not distributed with this
moel@344
     5
  file, You can obtain one at http://mozilla.org/MPL/2.0/.
moel@110
     6
 
moel@344
     7
  Copyright (C) 2009-2012 Michael Möller <mmoeller@openhardwaremonitor.org>
moel@344
     8
	
moel@110
     9
*/
moel@110
    10
moel@110
    11
using System;
moel@110
    12
using System.Collections.Generic;
moel@166
    13
using System.Globalization;
moel@110
    14
using System.Text;
moel@110
    15
using System.Threading;
moel@110
    16
moel@110
    17
namespace OpenHardwareMonitor.Hardware.LPC {
moel@165
    18
  internal class LPCIO {
moel@110
    19
moel@195
    20
    private readonly List<ISuperIO> superIOs = new List<ISuperIO>();
moel@195
    21
    private readonly StringBuilder report = new StringBuilder();
moel@110
    22
moel@110
    23
    // I/O Ports
moel@195
    24
    private readonly ushort[] REGISTER_PORTS = new ushort[] { 0x2E, 0x4E };
moel@195
    25
    private readonly ushort[] VALUE_PORTS = new ushort[] { 0x2F, 0x4F };
moel@110
    26
moel@110
    27
    private ushort registerPort;
moel@110
    28
    private ushort valuePort;
moel@110
    29
moel@110
    30
    // Registers
moel@110
    31
    private const byte CONFIGURATION_CONTROL_REGISTER = 0x02;
moel@110
    32
    private const byte DEVCIE_SELECT_REGISTER = 0x07;
moel@110
    33
    private const byte CHIP_ID_REGISTER = 0x20;
moel@110
    34
    private const byte CHIP_REVISION_REGISTER = 0x21;
moel@110
    35
    private const byte BASE_ADDRESS_REGISTER = 0x60;
moel@110
    36
moel@110
    37
    private byte ReadByte(byte register) {
moel@236
    38
      Ring0.WriteIoPort(registerPort, register);
moel@236
    39
      return Ring0.ReadIoPort(valuePort);
moel@228
    40
    }
moel@110
    41
moel@110
    42
    private ushort ReadWord(byte register) {
moel@228
    43
      return (ushort)((ReadByte(register) << 8) |
moel@110
    44
        ReadByte((byte)(register + 1)));
moel@110
    45
    }
moel@110
    46
moel@110
    47
    private void Select(byte logicalDeviceNumber) {
moel@236
    48
      Ring0.WriteIoPort(registerPort, DEVCIE_SELECT_REGISTER);
moel@236
    49
      Ring0.WriteIoPort(valuePort, logicalDeviceNumber);
moel@110
    50
    }
moel@110
    51
moel@169
    52
    private void ReportUnknownChip(string type, int chip) {
moel@169
    53
      report.Append("Chip ID: Unknown ");
moel@169
    54
      report.Append(type);
moel@169
    55
      report.Append(" with ID 0x");
moel@169
    56
      report.Append(chip.ToString("X", CultureInfo.InvariantCulture));
moel@169
    57
      report.Append(" at 0x");
moel@169
    58
      report.Append(registerPort.ToString("X", CultureInfo.InvariantCulture));
moel@169
    59
      report.Append("/0x");
moel@169
    60
      report.AppendLine(valuePort.ToString("X", CultureInfo.InvariantCulture));
moel@169
    61
      report.AppendLine();
moel@110
    62
    }
moel@110
    63
moel@245
    64
    #region Winbond, Nuvoton, Fintek
moel@110
    65
moel@110
    66
    private const byte FINTEK_VENDOR_ID_REGISTER = 0x23;
moel@110
    67
    private const ushort FINTEK_VENDOR_ID = 0x1934;
moel@110
    68
moel@245
    69
    private const byte WINBOND_NUVOTON_HARDWARE_MONITOR_LDN = 0x0B;
moel@110
    70
moel@110
    71
    private const byte F71858_HARDWARE_MONITOR_LDN = 0x02;
moel@110
    72
    private const byte FINTEK_HARDWARE_MONITOR_LDN = 0x04;
moel@110
    73
moel@245
    74
    private void WinbondNuvotonFintekEnter() {
moel@236
    75
      Ring0.WriteIoPort(registerPort, 0x87);
moel@236
    76
      Ring0.WriteIoPort(registerPort, 0x87);
moel@110
    77
    }
moel@110
    78
moel@245
    79
    private void WinbondNuvotonFintekExit() {
moel@236
    80
      Ring0.WriteIoPort(registerPort, 0xAA);
moel@110
    81
    }
moel@110
    82
moel@167
    83
    private bool DetectWinbondFintek() {
moel@245
    84
      WinbondNuvotonFintekEnter();
moel@167
    85
moel@195
    86
      byte logicalDeviceNumber = 0;
moel@167
    87
      byte id = ReadByte(CHIP_ID_REGISTER);
moel@167
    88
      byte revision = ReadByte(CHIP_REVISION_REGISTER);
moel@167
    89
      Chip chip = Chip.Unknown;
moel@167
    90
      switch (id) {
moel@167
    91
        case 0x05:
moel@167
    92
          switch (revision) {
moel@167
    93
            case 0x07:
moel@167
    94
              chip = Chip.F71858;
moel@167
    95
              logicalDeviceNumber = F71858_HARDWARE_MONITOR_LDN;
moel@167
    96
              break;
moel@167
    97
            case 0x41:
moel@167
    98
              chip = Chip.F71882;
moel@167
    99
              logicalDeviceNumber = FINTEK_HARDWARE_MONITOR_LDN;
moel@167
   100
              break;
moel@167
   101
          } break;
moel@167
   102
        case 0x06:
moel@167
   103
          switch (revision) {
moel@167
   104
            case 0x01:
moel@167
   105
              chip = Chip.F71862;
moel@167
   106
              logicalDeviceNumber = FINTEK_HARDWARE_MONITOR_LDN;
moel@167
   107
              break;
moel@167
   108
          } break;
moel@167
   109
        case 0x07:
moel@167
   110
          switch (revision) {
moel@167
   111
            case 0x23:
moel@167
   112
              chip = Chip.F71889F;
moel@167
   113
              logicalDeviceNumber = FINTEK_HARDWARE_MONITOR_LDN;
moel@167
   114
              break;
moel@167
   115
          } break;
moel@167
   116
        case 0x08:
moel@167
   117
          switch (revision) {
moel@167
   118
            case 0x14:
moel@167
   119
              chip = Chip.F71869;
moel@167
   120
              logicalDeviceNumber = FINTEK_HARDWARE_MONITOR_LDN;
moel@167
   121
              break;
moel@167
   122
          } break;
moel@167
   123
        case 0x09:
moel@167
   124
          switch (revision) {
moel@352
   125
            case 0x01:
moel@352
   126
              chip = Chip.F71808E;
moel@352
   127
              logicalDeviceNumber = FINTEK_HARDWARE_MONITOR_LDN;
moel@352
   128
              break;
moel@167
   129
            case 0x09:
moel@167
   130
              chip = Chip.F71889ED;
moel@167
   131
              logicalDeviceNumber = FINTEK_HARDWARE_MONITOR_LDN;
moel@167
   132
              break;
moel@167
   133
          } break;
moel@296
   134
        case 0x10:
moel@296
   135
          switch (revision) {
moel@296
   136
            case 0x05:
moel@296
   137
              chip = Chip.F71889AD;
moel@296
   138
              logicalDeviceNumber = FINTEK_HARDWARE_MONITOR_LDN;
moel@296
   139
              break;
moel@296
   140
          } break;
moel@167
   141
        case 0x52:
moel@167
   142
          switch (revision) {
moel@167
   143
            case 0x17:
moel@167
   144
            case 0x3A:
moel@167
   145
            case 0x41:
moel@167
   146
              chip = Chip.W83627HF;
moel@245
   147
              logicalDeviceNumber = WINBOND_NUVOTON_HARDWARE_MONITOR_LDN;
moel@167
   148
              break;
moel@167
   149
          } break;
moel@167
   150
        case 0x82:
moel@167
   151
          switch (revision & 0xF0) {
moel@167
   152
            case 0x80:
moel@167
   153
              chip = Chip.W83627THF;
moel@245
   154
              logicalDeviceNumber = WINBOND_NUVOTON_HARDWARE_MONITOR_LDN;
moel@167
   155
              break;
moel@167
   156
          } break;
moel@167
   157
        case 0x85:
moel@167
   158
          switch (revision) {
moel@167
   159
            case 0x41:
moel@167
   160
              chip = Chip.W83687THF;
moel@245
   161
              logicalDeviceNumber = WINBOND_NUVOTON_HARDWARE_MONITOR_LDN;
moel@167
   162
              break;
moel@167
   163
          } break;
moel@167
   164
        case 0x88:
moel@167
   165
          switch (revision & 0xF0) {
moel@167
   166
            case 0x50:
moel@167
   167
            case 0x60:
moel@167
   168
              chip = Chip.W83627EHF;
moel@245
   169
              logicalDeviceNumber = WINBOND_NUVOTON_HARDWARE_MONITOR_LDN;
moel@167
   170
              break;
moel@167
   171
          } break;
moel@167
   172
        case 0xA0:
moel@167
   173
          switch (revision & 0xF0) {
moel@167
   174
            case 0x20:
moel@167
   175
              chip = Chip.W83627DHG;
moel@245
   176
              logicalDeviceNumber = WINBOND_NUVOTON_HARDWARE_MONITOR_LDN;
moel@167
   177
              break;
moel@167
   178
          } break;
moel@167
   179
        case 0xA5:
moel@167
   180
          switch (revision & 0xF0) {
moel@167
   181
            case 0x10:
moel@167
   182
              chip = Chip.W83667HG;
moel@245
   183
              logicalDeviceNumber = WINBOND_NUVOTON_HARDWARE_MONITOR_LDN;
moel@167
   184
              break;
moel@167
   185
          } break;
moel@167
   186
        case 0xB0:
moel@167
   187
          switch (revision & 0xF0) {
moel@167
   188
            case 0x70:
moel@167
   189
              chip = Chip.W83627DHGP;
moel@245
   190
              logicalDeviceNumber = WINBOND_NUVOTON_HARDWARE_MONITOR_LDN;
moel@167
   191
              break;
moel@167
   192
          } break;
moel@167
   193
        case 0xB3:
moel@167
   194
          switch (revision & 0xF0) {
moel@167
   195
            case 0x50:
moel@167
   196
              chip = Chip.W83667HGB;
moel@245
   197
              logicalDeviceNumber = WINBOND_NUVOTON_HARDWARE_MONITOR_LDN;
moel@245
   198
              break;
moel@245
   199
          } break;
moel@245
   200
        case 0xB4:
moel@245
   201
          switch (revision & 0xF0) {
moel@245
   202
            case 0x70:
moel@245
   203
              chip = Chip.NCT6771F;
moel@245
   204
              logicalDeviceNumber = WINBOND_NUVOTON_HARDWARE_MONITOR_LDN;
moel@167
   205
              break;
moel@167
   206
          } break;
moel@265
   207
        case 0xC3:
moel@265
   208
          switch (revision & 0xF0) {
moel@265
   209
            case 0x30:
moel@265
   210
              chip = Chip.NCT6776F;
moel@265
   211
              logicalDeviceNumber = WINBOND_NUVOTON_HARDWARE_MONITOR_LDN;
moel@265
   212
              break;
moel@265
   213
          } break;
moel@355
   214
        case 0xC5:
moel@355
   215
          switch (revision & 0xF0) {
moel@355
   216
            case 0x60:
moel@355
   217
              chip = Chip.NCT6779D;
moel@355
   218
              logicalDeviceNumber = WINBOND_NUVOTON_HARDWARE_MONITOR_LDN;
moel@355
   219
              break;
moel@355
   220
          } break;
moel@167
   221
      }
moel@167
   222
      if (chip == Chip.Unknown) {
moel@167
   223
        if (id != 0 && id != 0xff) {
moel@245
   224
          WinbondNuvotonFintekExit();
moel@167
   225
moel@245
   226
          ReportUnknownChip("Winbond / Nuvoton / Fintek", 
moel@245
   227
            ((id << 8) | revision));
moel@167
   228
        }
moel@167
   229
      } else {
moel@167
   230
moel@167
   231
        Select(logicalDeviceNumber);
moel@167
   232
        ushort address = ReadWord(BASE_ADDRESS_REGISTER);
moel@167
   233
        Thread.Sleep(1);
moel@167
   234
        ushort verify = ReadWord(BASE_ADDRESS_REGISTER);
moel@167
   235
moel@167
   236
        ushort vendorID = ReadWord(FINTEK_VENDOR_ID_REGISTER);
moel@167
   237
moel@245
   238
        WinbondNuvotonFintekExit();
moel@167
   239
moel@167
   240
        if (address != verify) {
moel@167
   241
          report.Append("Chip ID: 0x");
moel@167
   242
          report.AppendLine(chip.ToString("X"));
moel@167
   243
          report.Append("Chip revision: 0x");
moel@228
   244
          report.AppendLine(revision.ToString("X",
moel@167
   245
            CultureInfo.InvariantCulture));
moel@167
   246
          report.AppendLine("Error: Address verification failed");
moel@167
   247
          report.AppendLine();
moel@167
   248
          return false;
moel@167
   249
        }
moel@167
   250
moel@167
   251
        // some Fintek chips have address register offset 0x05 added already
moel@167
   252
        if ((address & 0x07) == 0x05)
moel@167
   253
          address &= 0xFFF8;
moel@167
   254
moel@167
   255
        if (address < 0x100 || (address & 0xF007) != 0) {
moel@167
   256
          report.Append("Chip ID: 0x");
moel@167
   257
          report.AppendLine(chip.ToString("X"));
moel@167
   258
          report.Append("Chip revision: 0x");
moel@228
   259
          report.AppendLine(revision.ToString("X",
moel@167
   260
            CultureInfo.InvariantCulture));
moel@167
   261
          report.Append("Error: Invalid address 0x");
moel@228
   262
          report.AppendLine(address.ToString("X",
moel@167
   263
            CultureInfo.InvariantCulture));
moel@167
   264
          report.AppendLine();
moel@167
   265
          return false;
moel@167
   266
        }
moel@167
   267
moel@167
   268
        switch (chip) {
moel@167
   269
          case Chip.W83627DHG:
moel@167
   270
          case Chip.W83627DHGP:
moel@167
   271
          case Chip.W83627EHF:
moel@167
   272
          case Chip.W83627HF:
moel@167
   273
          case Chip.W83627THF:
moel@167
   274
          case Chip.W83667HG:
moel@167
   275
          case Chip.W83667HGB:
moel@167
   276
          case Chip.W83687THF:
moel@167
   277
            superIOs.Add(new W836XX(chip, revision, address));
moel@167
   278
            break;
moel@245
   279
          case Chip.NCT6771F:
moel@265
   280
          case Chip.NCT6776F:
moel@355
   281
          case Chip.NCT6779D:
moel@245
   282
            superIOs.Add(new NCT677X(chip, revision, address));
moel@245
   283
            break;
moel@167
   284
          case Chip.F71858:
moel@167
   285
          case Chip.F71862:
moel@167
   286
          case Chip.F71869:
moel@167
   287
          case Chip.F71882:
moel@296
   288
          case Chip.F71889AD:
moel@167
   289
          case Chip.F71889ED:
moel@167
   290
          case Chip.F71889F:
moel@352
   291
          case Chip.F71808E:
moel@167
   292
            if (vendorID != FINTEK_VENDOR_ID) {
moel@167
   293
              report.Append("Chip ID: 0x");
moel@167
   294
              report.AppendLine(chip.ToString("X"));
moel@167
   295
              report.Append("Chip revision: 0x");
moel@228
   296
              report.AppendLine(revision.ToString("X",
moel@167
   297
                CultureInfo.InvariantCulture));
moel@167
   298
              report.Append("Error: Invalid vendor ID 0x");
moel@228
   299
              report.AppendLine(vendorID.ToString("X",
moel@167
   300
                CultureInfo.InvariantCulture));
moel@167
   301
              report.AppendLine();
moel@167
   302
              return false;
moel@167
   303
            }
moel@167
   304
            superIOs.Add(new F718XX(chip, address));
moel@167
   305
            break;
moel@167
   306
          default: break;
moel@167
   307
        }
moel@167
   308
moel@167
   309
        return true;
moel@167
   310
      }
moel@167
   311
moel@167
   312
      return false;
moel@167
   313
    }
moel@167
   314
moel@169
   315
    #endregion
moel@169
   316
moel@169
   317
    #region ITE
moel@169
   318
moel@169
   319
    private const byte IT87_ENVIRONMENT_CONTROLLER_LDN = 0x04;
moel@353
   320
    private const byte IT8705_GPIO_LDN = 0x05;
moel@353
   321
    private const byte IT87XX_GPIO_LDN = 0x07;
moel@169
   322
    private const byte IT87_CHIP_VERSION_REGISTER = 0x22;
moel@169
   323
moel@169
   324
    private void IT87Enter() {
moel@236
   325
      Ring0.WriteIoPort(registerPort, 0x87);
moel@236
   326
      Ring0.WriteIoPort(registerPort, 0x01);
moel@236
   327
      Ring0.WriteIoPort(registerPort, 0x55);
moel@236
   328
      Ring0.WriteIoPort(registerPort, 0x55);
moel@169
   329
    }
moel@169
   330
moel@169
   331
    private void IT87Exit() {
moel@236
   332
      Ring0.WriteIoPort(registerPort, CONFIGURATION_CONTROL_REGISTER);
moel@236
   333
      Ring0.WriteIoPort(valuePort, 0x02);
moel@169
   334
    }
moel@169
   335
moel@167
   336
    private bool DetectIT87() {
moel@169
   337
moel@169
   338
      // IT87XX can enter only on port 0x2E
moel@169
   339
      if (registerPort != 0x2E)
moel@169
   340
        return false;
moel@169
   341
moel@167
   342
      IT87Enter();
moel@167
   343
moel@167
   344
      ushort chipID = ReadWord(CHIP_ID_REGISTER);
moel@167
   345
      Chip chip;
moel@167
   346
      switch (chipID) {
moel@353
   347
        case 0x8705: chip = Chip.IT8705F; break;
moel@167
   348
        case 0x8712: chip = Chip.IT8712F; break;
moel@167
   349
        case 0x8716: chip = Chip.IT8716F; break;
moel@167
   350
        case 0x8718: chip = Chip.IT8718F; break;
moel@167
   351
        case 0x8720: chip = Chip.IT8720F; break;
moel@170
   352
        case 0x8721: chip = Chip.IT8721F; break;
moel@167
   353
        case 0x8726: chip = Chip.IT8726F; break;
moel@277
   354
        case 0x8728: chip = Chip.IT8728F; break;
moel@341
   355
        case 0x8771: chip = Chip.IT8771E; break;
moel@319
   356
        case 0x8772: chip = Chip.IT8772E; break;
moel@167
   357
        default: chip = Chip.Unknown; break;
moel@167
   358
      }
moel@167
   359
      if (chip == Chip.Unknown) {
moel@167
   360
        if (chipID != 0 && chipID != 0xffff) {
moel@167
   361
          IT87Exit();
moel@167
   362
moel@167
   363
          ReportUnknownChip("ITE", chipID);
moel@167
   364
        }
moel@167
   365
      } else {
moel@167
   366
        Select(IT87_ENVIRONMENT_CONTROLLER_LDN);
moel@167
   367
        ushort address = ReadWord(BASE_ADDRESS_REGISTER);
moel@167
   368
        Thread.Sleep(1);
moel@167
   369
        ushort verify = ReadWord(BASE_ADDRESS_REGISTER);
moel@167
   370
moel@167
   371
        byte version = (byte)(ReadByte(IT87_CHIP_VERSION_REGISTER) & 0x0F);
moel@167
   372
moel@353
   373
        ushort gpioAddress;
moel@353
   374
        ushort gpioVerify;
moel@353
   375
        if (chip == Chip.IT8705F) {
moel@353
   376
          Select(IT8705_GPIO_LDN);
moel@353
   377
          gpioAddress = ReadWord(BASE_ADDRESS_REGISTER);
moel@353
   378
          Thread.Sleep(1);
moel@353
   379
          gpioVerify = ReadWord(BASE_ADDRESS_REGISTER);
moel@353
   380
        } else {
moel@353
   381
          Select(IT87XX_GPIO_LDN);
moel@353
   382
          gpioAddress = ReadWord(BASE_ADDRESS_REGISTER + 2);
moel@353
   383
          Thread.Sleep(1);
moel@353
   384
          gpioVerify = ReadWord(BASE_ADDRESS_REGISTER + 2);
moel@353
   385
        }
moel@353
   386
        
moel@167
   387
        IT87Exit();
moel@167
   388
moel@167
   389
        if (address != verify || address < 0x100 || (address & 0xF007) != 0) {
moel@167
   390
          report.Append("Chip ID: 0x");
moel@167
   391
          report.AppendLine(chip.ToString("X"));
moel@167
   392
          report.Append("Error: Invalid address 0x");
moel@167
   393
          report.AppendLine(address.ToString("X",
moel@167
   394
            CultureInfo.InvariantCulture));
moel@167
   395
          report.AppendLine();
moel@167
   396
          return false;
moel@167
   397
        }
moel@167
   398
moel@228
   399
        if (gpioAddress != gpioVerify || gpioAddress < 0x100 ||
moel@228
   400
          (gpioAddress & 0xF007) != 0) {
moel@228
   401
          report.Append("Chip ID: 0x");
moel@228
   402
          report.AppendLine(chip.ToString("X"));
moel@228
   403
          report.Append("Error: Invalid GPIO address 0x");
moel@228
   404
          report.AppendLine(gpioAddress.ToString("X",
moel@228
   405
            CultureInfo.InvariantCulture));
moel@228
   406
          report.AppendLine();
moel@228
   407
          return false;
moel@228
   408
        }
moel@228
   409
moel@228
   410
        superIOs.Add(new IT87XX(chip, address, gpioAddress, version));
moel@167
   411
        return true;
moel@167
   412
      }
moel@167
   413
moel@167
   414
      return false;
moel@167
   415
    }
moel@167
   416
moel@169
   417
    #endregion
moel@169
   418
moel@169
   419
    #region SMSC
moel@169
   420
moel@169
   421
    private void SMSCEnter() {
moel@236
   422
      Ring0.WriteIoPort(registerPort, 0x55);
moel@169
   423
    }
moel@169
   424
moel@169
   425
    private void SMSCExit() {
moel@236
   426
      Ring0.WriteIoPort(registerPort, 0xAA);
moel@169
   427
    }
moel@169
   428
moel@167
   429
    private bool DetectSMSC() {
moel@167
   430
      SMSCEnter();
moel@167
   431
moel@167
   432
      ushort chipID = ReadWord(CHIP_ID_REGISTER);
moel@167
   433
      Chip chip;
moel@167
   434
      switch (chipID) {
moel@167
   435
        default: chip = Chip.Unknown; break;
moel@167
   436
      }
moel@167
   437
      if (chip == Chip.Unknown) {
moel@167
   438
        if (chipID != 0 && chipID != 0xffff) {
moel@167
   439
          SMSCExit();
moel@167
   440
moel@167
   441
          ReportUnknownChip("SMSC", chipID);
moel@167
   442
        }
moel@167
   443
      } else {
moel@167
   444
        SMSCExit();
moel@167
   445
        return true;
moel@167
   446
      }
moel@167
   447
moel@167
   448
      return false;
moel@167
   449
    }
moel@167
   450
moel@169
   451
    #endregion
moel@169
   452
moel@163
   453
    private void Detect() {
moel@110
   454
moel@110
   455
      for (int i = 0; i < REGISTER_PORTS.Length; i++) {
moel@110
   456
        registerPort = REGISTER_PORTS[i];
moel@110
   457
        valuePort = VALUE_PORTS[i];
moel@110
   458
moel@167
   459
        if (DetectWinbondFintek()) continue;
moel@110
   460
moel@167
   461
        if (DetectIT87()) continue;
moel@110
   462
moel@167
   463
        if (DetectSMSC()) continue;
moel@228
   464
      }
moel@163
   465
    }
moel@163
   466
moel@163
   467
    public LPCIO() {
moel@236
   468
      if (!Ring0.IsOpen)
moel@163
   469
        return;
moel@163
   470
moel@236
   471
      if (!Ring0.WaitIsaBusMutex(100))
moel@163
   472
        return;
moel@163
   473
moel@163
   474
      Detect();
moel@163
   475
moel@236
   476
      Ring0.ReleaseIsaBusMutex();
moel@110
   477
    }
moel@110
   478
moel@130
   479
    public ISuperIO[] SuperIO {
moel@110
   480
      get {
moel@130
   481
        return superIOs.ToArray();
moel@110
   482
      }
moel@110
   483
    }
moel@110
   484
moel@110
   485
    public string GetReport() {
moel@110
   486
      if (report.Length > 0) {
moel@195
   487
        return "LPCIO" + Environment.NewLine + Environment.NewLine + report;
moel@110
   488
      } else
moel@110
   489
        return null;
moel@110
   490
    }
moel@110
   491
  }
moel@110
   492
}