Hardware/LPC/LPCIO.cs
author moel.mich
Tue, 25 May 2010 18:57:28 +0000
changeset 127 76aaf45a01c7
parent 110 411b72b73d8f
child 130 80065ab20b84
permissions -rw-r--r--
Added a workaround for the "You must keep the stream open for the lifetime of the Image." problem of the Image.FromStream method. This also reduced the overall memory usage (private working set).
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@110
    40
using System.Text;
moel@110
    41
using System.Threading;
moel@110
    42
moel@110
    43
namespace OpenHardwareMonitor.Hardware.LPC {
moel@110
    44
  public class LPCIO {
moel@110
    45
moel@110
    46
    private List<IHardware> hardware = new List<IHardware>();
moel@110
    47
    private StringBuilder report = new StringBuilder();
moel@110
    48
moel@110
    49
    private Chip chip = Chip.Unknown;
moel@110
    50
moel@110
    51
    // I/O Ports
moel@110
    52
    private ushort[] REGISTER_PORTS = new ushort[] { 0x2e, 0x4e };
moel@110
    53
    private ushort[] VALUE_PORTS = new ushort[] { 0x2f, 0x4f };
moel@110
    54
moel@110
    55
    private ushort registerPort;
moel@110
    56
    private ushort valuePort;
moel@110
    57
moel@110
    58
    // Registers
moel@110
    59
    private const byte CONFIGURATION_CONTROL_REGISTER = 0x02;
moel@110
    60
    private const byte DEVCIE_SELECT_REGISTER = 0x07;
moel@110
    61
    private const byte CHIP_ID_REGISTER = 0x20;
moel@110
    62
    private const byte CHIP_REVISION_REGISTER = 0x21;
moel@110
    63
    private const byte BASE_ADDRESS_REGISTER = 0x60;
moel@110
    64
moel@110
    65
    private byte ReadByte(byte register) {
moel@110
    66
      WinRing0.WriteIoPortByte(registerPort, register);
moel@110
    67
      return WinRing0.ReadIoPortByte(valuePort);
moel@110
    68
    } 
moel@110
    69
moel@110
    70
    private ushort ReadWord(byte register) {
moel@110
    71
      return (ushort)((ReadByte(register) << 8) | 
moel@110
    72
        ReadByte((byte)(register + 1)));
moel@110
    73
    }
moel@110
    74
moel@110
    75
    private void Select(byte logicalDeviceNumber) {
moel@110
    76
      WinRing0.WriteIoPortByte(registerPort, DEVCIE_SELECT_REGISTER);
moel@110
    77
      WinRing0.WriteIoPortByte(valuePort, logicalDeviceNumber);
moel@110
    78
    }
moel@110
    79
moel@110
    80
    // ITE
moel@110
    81
    private const byte IT87_ENVIRONMENT_CONTROLLER_LDN = 0x04;    
moel@110
    82
moel@110
    83
    private void IT87Enter() {
moel@110
    84
      WinRing0.WriteIoPortByte(registerPort, 0x87);
moel@110
    85
      WinRing0.WriteIoPortByte(registerPort, 0x01);
moel@110
    86
      WinRing0.WriteIoPortByte(registerPort, 0x55);
moel@110
    87
      WinRing0.WriteIoPortByte(registerPort, 0x55);
moel@110
    88
    }
moel@110
    89
moel@110
    90
    internal void IT87Exit() {
moel@110
    91
      WinRing0.WriteIoPortByte(registerPort, CONFIGURATION_CONTROL_REGISTER);
moel@110
    92
      WinRing0.WriteIoPortByte(valuePort, 0x02);
moel@110
    93
    }
moel@110
    94
moel@110
    95
    // Winbond, Fintek
moel@110
    96
    private const byte FINTEK_VENDOR_ID_REGISTER = 0x23;
moel@110
    97
    private const ushort FINTEK_VENDOR_ID = 0x1934;
moel@110
    98
moel@110
    99
    private const byte WINBOND_HARDWARE_MONITOR_LDN = 0x0B;
moel@110
   100
moel@110
   101
    private const byte F71858_HARDWARE_MONITOR_LDN = 0x02;
moel@110
   102
    private const byte FINTEK_HARDWARE_MONITOR_LDN = 0x04;
moel@110
   103
moel@110
   104
    private void WinbondFintekEnter() {
moel@110
   105
      WinRing0.WriteIoPortByte(registerPort, 0x87);
moel@110
   106
      WinRing0.WriteIoPortByte(registerPort, 0x87);
moel@110
   107
    }
moel@110
   108
moel@110
   109
    private void WinbondFintekExit() {
moel@110
   110
      WinRing0.WriteIoPortByte(registerPort, 0xAA);      
moel@110
   111
    }
moel@110
   112
moel@110
   113
    // SMSC
moel@110
   114
    private void SMSCEnter() {
moel@110
   115
      WinRing0.WriteIoPortByte(registerPort, 0x55);
moel@110
   116
    }
moel@110
   117
moel@110
   118
    private void SMSCExit() {
moel@110
   119
      WinRing0.WriteIoPortByte(registerPort, 0xAA);
moel@110
   120
    }
moel@110
   121
moel@126
   122
    public LPCIO(Mainboard.Manufacturer mainboardManufacturer, 
moel@126
   123
      Mainboard.Model mainboardModel) 
moel@126
   124
    {
moel@110
   125
      if (!WinRing0.IsAvailable)
moel@110
   126
        return;
moel@110
   127
moel@110
   128
      for (int i = 0; i < REGISTER_PORTS.Length; i++) {
moel@110
   129
        registerPort = REGISTER_PORTS[i];
moel@110
   130
        valuePort = VALUE_PORTS[i];
moel@110
   131
moel@110
   132
        WinbondFintekEnter();
moel@110
   133
moel@110
   134
        byte logicalDeviceNumber;
moel@110
   135
        byte id = ReadByte(CHIP_ID_REGISTER);
moel@110
   136
        byte revision = ReadByte(CHIP_REVISION_REGISTER);
moel@110
   137
        chip = Chip.Unknown;
moel@110
   138
        logicalDeviceNumber = 0;
moel@110
   139
        switch (id) {
moel@110
   140
          case 0x05:
moel@110
   141
            switch (revision) {
moel@110
   142
              case 0x07:
moel@110
   143
                chip = Chip.F71858;
moel@110
   144
                logicalDeviceNumber = F71858_HARDWARE_MONITOR_LDN;
moel@110
   145
                break;
moel@110
   146
              case 0x41:
moel@110
   147
                chip = Chip.F71882;
moel@110
   148
                logicalDeviceNumber = FINTEK_HARDWARE_MONITOR_LDN;
moel@110
   149
                break;              
moel@110
   150
            } break;
moel@110
   151
          case 0x06:
moel@110
   152
            switch (revision) {             
moel@110
   153
              case 0x01:
moel@110
   154
                chip = Chip.F71862;
moel@110
   155
                logicalDeviceNumber = FINTEK_HARDWARE_MONITOR_LDN;
moel@110
   156
                break;              
moel@110
   157
            } break;
moel@110
   158
          case 0x07:
moel@110
   159
            switch (revision) {
moel@110
   160
              case 0x23:
moel@110
   161
                chip = Chip.F71889F;
moel@110
   162
                logicalDeviceNumber = FINTEK_HARDWARE_MONITOR_LDN;
moel@110
   163
                break;              
moel@110
   164
            } break;
moel@110
   165
          case 0x08:
moel@110
   166
            switch (revision) {
moel@110
   167
              case 0x14:
moel@110
   168
                chip = Chip.F71869;
moel@110
   169
                logicalDeviceNumber = FINTEK_HARDWARE_MONITOR_LDN;
moel@110
   170
                break;              
moel@110
   171
            } break;
moel@110
   172
          case 0x09:
moel@110
   173
            switch (revision) {
moel@110
   174
              case 0x09:
moel@110
   175
                chip = Chip.F71889ED;
moel@110
   176
                logicalDeviceNumber = FINTEK_HARDWARE_MONITOR_LDN;
moel@110
   177
                break;              
moel@110
   178
            } break;
moel@110
   179
          case 0x52:
moel@110
   180
            switch (revision) {
moel@110
   181
              case 0x17:
moel@110
   182
              case 0x3A:
moel@110
   183
              case 0x41:
moel@110
   184
                chip = Chip.W83627HF;
moel@110
   185
                logicalDeviceNumber = WINBOND_HARDWARE_MONITOR_LDN;
moel@110
   186
                break;             
moel@110
   187
            } break;
moel@110
   188
          case 0x82:
moel@110
   189
            switch (revision) {
moel@110
   190
              case 0x83:
moel@110
   191
                chip = Chip.W83627THF;
moel@110
   192
                logicalDeviceNumber = WINBOND_HARDWARE_MONITOR_LDN;
moel@110
   193
                break;
moel@110
   194
            } break;
moel@110
   195
          case 0x85:
moel@110
   196
            switch (revision) {
moel@110
   197
              case 0x41:
moel@110
   198
                chip = Chip.W83687THF;
moel@110
   199
                logicalDeviceNumber = WINBOND_HARDWARE_MONITOR_LDN;
moel@110
   200
                break;
moel@110
   201
            } break;
moel@110
   202
          case 0x88:
moel@110
   203
            switch (revision & 0xF0) {
moel@110
   204
              case 0x50:
moel@110
   205
              case 0x60:
moel@110
   206
                chip = Chip.W83627EHF;
moel@110
   207
                logicalDeviceNumber = WINBOND_HARDWARE_MONITOR_LDN;
moel@110
   208
                break;
moel@110
   209
            } break;
moel@110
   210
          case 0xA0:
moel@110
   211
            switch (revision & 0xF0) {
moel@110
   212
              case 0x20: 
moel@110
   213
                chip = Chip.W83627DHG;
moel@110
   214
                logicalDeviceNumber = WINBOND_HARDWARE_MONITOR_LDN;  
moel@110
   215
                break;             
moel@110
   216
            } break;
moel@110
   217
          case 0xA5:
moel@110
   218
            switch (revision & 0xF0) {
moel@110
   219
              case 0x10:
moel@110
   220
                chip = Chip.W83667HG;
moel@110
   221
                logicalDeviceNumber = WINBOND_HARDWARE_MONITOR_LDN;
moel@110
   222
                break;
moel@110
   223
            } break;
moel@110
   224
          case 0xB0:
moel@110
   225
            switch (revision & 0xF0) {
moel@110
   226
              case 0x70:
moel@110
   227
                chip = Chip.W83627DHGP;
moel@110
   228
                logicalDeviceNumber = WINBOND_HARDWARE_MONITOR_LDN;
moel@110
   229
                break;             
moel@110
   230
            } break;
moel@110
   231
          case 0xB3:
moel@110
   232
            switch (revision & 0xF0) {
moel@110
   233
              case 0x50:
moel@110
   234
                chip = Chip.W83667HGB;
moel@110
   235
                logicalDeviceNumber = WINBOND_HARDWARE_MONITOR_LDN;
moel@110
   236
                break;
moel@110
   237
            } break; 
moel@110
   238
        }
moel@110
   239
        if (chip == Chip.Unknown) {
moel@110
   240
          if (id != 0 && id != 0xff) {
moel@110
   241
            WinbondFintekExit();
moel@110
   242
moel@110
   243
            report.Append("Chip ID: Unknown Winbond / Fintek with ID 0x"); 
moel@110
   244
            report.AppendLine(((id << 8) | revision).ToString("X"));
moel@110
   245
            report.AppendLine();
moel@110
   246
          }
moel@110
   247
        } else {
moel@110
   248
moel@110
   249
          Select(logicalDeviceNumber);
moel@110
   250
          ushort address = ReadWord(BASE_ADDRESS_REGISTER);          
moel@110
   251
          Thread.Sleep(1);
moel@110
   252
          ushort verify = ReadWord(BASE_ADDRESS_REGISTER);
moel@110
   253
moel@110
   254
          ushort vendorID = ReadWord(FINTEK_VENDOR_ID_REGISTER);
moel@110
   255
moel@110
   256
          WinbondFintekExit();
moel@110
   257
moel@110
   258
          if (address != verify) {            
moel@110
   259
            report.Append("Chip ID: 0x"); 
moel@110
   260
            report.AppendLine(chip.ToString("X"));
moel@110
   261
            report.Append("Chip revision: 0x"); 
moel@110
   262
            report.AppendLine(revision.ToString("X"));
moel@110
   263
            report.AppendLine("Error: Address verification failed");
moel@110
   264
            report.AppendLine();
moel@110
   265
            return;
moel@110
   266
          }
moel@110
   267
moel@110
   268
          // some Fintek chips have address register offset 0x05 added already
moel@110
   269
          if ((address & 0x07) == 0x05)
moel@110
   270
            address &= 0xFFF8;
moel@110
   271
moel@110
   272
          if (address < 0x100 || (address & 0xF007) != 0) {            
moel@110
   273
            report.Append("Chip ID: 0x");
moel@110
   274
            report.AppendLine(chip.ToString("X"));
moel@110
   275
            report.Append("Chip revision: 0x");
moel@110
   276
            report.AppendLine(revision.ToString("X"));
moel@110
   277
            report.Append("Error: Invalid address 0x");
moel@110
   278
            report.AppendLine(address.ToString("X"));
moel@110
   279
            report.AppendLine();
moel@110
   280
            return;
moel@110
   281
          }
moel@110
   282
moel@110
   283
          switch (chip) {
moel@110
   284
            case Chip.W83627DHG:
moel@110
   285
            case Chip.W83627DHGP:
moel@110
   286
            case Chip.W83627EHF:
moel@110
   287
            case Chip.W83627HF:
moel@110
   288
            case Chip.W83627THF:
moel@110
   289
            case Chip.W83667HG:
moel@110
   290
            case Chip.W83667HGB:
moel@110
   291
            case Chip.W83687THF:
moel@110
   292
              W836XX w836XX = new W836XX(chip, revision, address);
moel@110
   293
              if (w836XX.IsAvailable)
moel@110
   294
                hardware.Add(w836XX);
moel@110
   295
              break;
moel@110
   296
            case Chip.F71858:
moel@110
   297
            case Chip.F71862:
moel@110
   298
            case Chip.F71869:
moel@110
   299
            case Chip.F71882:
moel@110
   300
            case Chip.F71889ED:
moel@110
   301
            case Chip.F71889F:
moel@110
   302
              if (vendorID != FINTEK_VENDOR_ID) {
moel@110
   303
                report.Append("Chip ID: 0x");
moel@110
   304
                report.AppendLine(chip.ToString("X"));
moel@110
   305
                report.Append("Chip revision: 0x");
moel@110
   306
                report.AppendLine(revision.ToString("X"));
moel@110
   307
                report.Append("Error: Invalid vendor ID 0x");
moel@110
   308
                report.AppendLine(vendorID.ToString("X"));
moel@110
   309
                report.AppendLine();
moel@110
   310
                return;
moel@110
   311
              }
moel@110
   312
              hardware.Add(new F718XX(chip, address));
moel@110
   313
              break;
moel@110
   314
            default: break;
moel@110
   315
          }
moel@110
   316
          
moel@110
   317
          return;
moel@110
   318
        }
moel@110
   319
moel@110
   320
        IT87Enter();
moel@110
   321
moel@110
   322
        ushort chipID = ReadWord(CHIP_ID_REGISTER);
moel@110
   323
        switch (chipID) {
moel@110
   324
          case 0x8712: chip = Chip.IT8712F; break;
moel@110
   325
          case 0x8716: chip = Chip.IT8716F; break;
moel@110
   326
          case 0x8718: chip = Chip.IT8718F; break;
moel@110
   327
          case 0x8720: chip = Chip.IT8720F; break;
moel@110
   328
          case 0x8726: chip = Chip.IT8726F; break; 
moel@110
   329
          default: chip = Chip.Unknown; break;
moel@110
   330
        }
moel@110
   331
        if (chip == Chip.Unknown) {
moel@110
   332
          if (chipID != 0 && chipID != 0xffff) {
moel@110
   333
            IT87Exit();
moel@110
   334
moel@110
   335
            report.Append("Chip ID: Unknown ITE with ID 0x");
moel@110
   336
            report.AppendLine(chipID.ToString("X"));
moel@110
   337
            report.AppendLine();
moel@110
   338
          }
moel@110
   339
        } else {
moel@110
   340
          Select(IT87_ENVIRONMENT_CONTROLLER_LDN);
moel@110
   341
          ushort address = ReadWord(BASE_ADDRESS_REGISTER);
moel@110
   342
          Thread.Sleep(1);
moel@110
   343
          ushort verify = ReadWord(BASE_ADDRESS_REGISTER);
moel@110
   344
moel@110
   345
          IT87Exit();
moel@110
   346
moel@110
   347
          if (address != verify || address < 0x100 || (address & 0xF007) != 0) {
moel@110
   348
            report.Append("Chip ID: 0x");
moel@110
   349
            report.AppendLine(chip.ToString("X"));            
moel@110
   350
            report.Append("Error: Invalid address 0x");
moel@110
   351
            report.AppendLine(address.ToString("X"));
moel@110
   352
            report.AppendLine();
moel@110
   353
            return;
moel@110
   354
          }
moel@110
   355
moel@126
   356
          IT87XX it87 = new IT87XX(chip, address, mainboardManufacturer, 
moel@126
   357
            mainboardModel);
moel@110
   358
          if (it87.IsAvailable)
moel@110
   359
            hardware.Add(it87);
moel@110
   360
moel@110
   361
          return;
moel@110
   362
        }
moel@110
   363
moel@110
   364
        SMSCEnter();
moel@110
   365
moel@110
   366
        chipID = ReadWord(CHIP_ID_REGISTER);
moel@110
   367
        switch (chipID) {
moel@110
   368
          default: chip = Chip.Unknown; break;
moel@110
   369
        }
moel@110
   370
        if (chip == Chip.Unknown) {
moel@110
   371
          if (chipID != 0 && chipID != 0xffff) {
moel@110
   372
            SMSCExit();
moel@110
   373
moel@110
   374
            report.Append("Chip ID: Unknown SMSC with ID 0x");
moel@110
   375
            report.AppendLine(chipID.ToString("X"));
moel@110
   376
            report.AppendLine();
moel@110
   377
          }
moel@110
   378
        } else {
moel@110
   379
          SMSCExit();
moel@110
   380
moel@110
   381
          return;
moel@110
   382
        }
moel@110
   383
      }   
moel@110
   384
    }
moel@110
   385
moel@110
   386
    public IHardware[] Hardware {
moel@110
   387
      get {
moel@110
   388
        return hardware.ToArray();
moel@110
   389
      }
moel@110
   390
    }
moel@110
   391
moel@110
   392
    public string GetReport() {
moel@110
   393
      if (report.Length > 0) {
moel@110
   394
        report.Insert(0, "LPCIO" + Environment.NewLine +
moel@110
   395
          Environment.NewLine);        
moel@110
   396
        return report.ToString();
moel@110
   397
      } else
moel@110
   398
        return null;
moel@110
   399
    }
moel@110
   400
  }
moel@110
   401
}