| 
moel@1
 | 
     1  | 
/*
  | 
| 
moel@1
 | 
     2  | 
  
  | 
| 
moel@1
 | 
     3  | 
  Version: MPL 1.1/GPL 2.0/LGPL 2.1
  | 
| 
moel@1
 | 
     4  | 
  | 
| 
moel@1
 | 
     5  | 
  The contents of this file are subject to the Mozilla Public License Version
  | 
| 
moel@1
 | 
     6  | 
  1.1 (the "License"); you may not use this file except in compliance with
  | 
| 
moel@1
 | 
     7  | 
  the License. You may obtain a copy of the License at
  | 
| 
moel@1
 | 
     8  | 
 
  | 
| 
moel@1
 | 
     9  | 
  http://www.mozilla.org/MPL/
  | 
| 
moel@1
 | 
    10  | 
  | 
| 
moel@1
 | 
    11  | 
  Software distributed under the License is distributed on an "AS IS" basis,
  | 
| 
moel@1
 | 
    12  | 
  WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
  | 
| 
moel@1
 | 
    13  | 
  for the specific language governing rights and limitations under the License.
  | 
| 
moel@1
 | 
    14  | 
  | 
| 
moel@1
 | 
    15  | 
  The Original Code is the Open Hardware Monitor code.
  | 
| 
moel@1
 | 
    16  | 
  | 
| 
moel@1
 | 
    17  | 
  The Initial Developer of the Original Code is 
  | 
| 
moel@1
 | 
    18  | 
  Michael Möller <m.moeller@gmx.ch>.
  | 
| 
moel@1
 | 
    19  | 
  Portions created by the Initial Developer are Copyright (C) 2009-2010
  | 
| 
moel@1
 | 
    20  | 
  the Initial Developer. All Rights Reserved.
  | 
| 
moel@1
 | 
    21  | 
  | 
| 
moel@1
 | 
    22  | 
  Contributor(s):
  | 
| 
moel@1
 | 
    23  | 
  | 
| 
moel@1
 | 
    24  | 
  Alternatively, the contents of this file may be used under the terms of
  | 
| 
moel@1
 | 
    25  | 
  either the GNU General Public License Version 2 or later (the "GPL"), or
  | 
| 
moel@1
 | 
    26  | 
  the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
  | 
| 
moel@1
 | 
    27  | 
  in which case the provisions of the GPL or the LGPL are applicable instead
  | 
| 
moel@1
 | 
    28  | 
  of those above. If you wish to allow use of your version of this file only
  | 
| 
moel@1
 | 
    29  | 
  under the terms of either the GPL or the LGPL, and not to allow others to
  | 
| 
moel@1
 | 
    30  | 
  use your version of this file under the terms of the MPL, indicate your
  | 
| 
moel@1
 | 
    31  | 
  decision by deleting the provisions above and replace them with the notice
  | 
| 
moel@1
 | 
    32  | 
  and other provisions required by the GPL or the LGPL. If you do not delete
  | 
| 
moel@1
 | 
    33  | 
  the provisions above, a recipient may use your version of this file under
  | 
| 
moel@1
 | 
    34  | 
  the terms of any one of the MPL, the GPL or the LGPL.
  | 
| 
moel@1
 | 
    35  | 
 
  | 
| 
moel@1
 | 
    36  | 
*/
  | 
| 
moel@1
 | 
    37  | 
  | 
| 
moel@1
 | 
    38  | 
using System;
  | 
| 
moel@1
 | 
    39  | 
using System.Collections.Generic;
  | 
| 
moel@1
 | 
    40  | 
using System.Text;
  | 
| 
moel@1
 | 
    41  | 
using System.Threading;
  | 
| 
moel@1
 | 
    42  | 
  | 
| 
moel@1
 | 
    43  | 
namespace OpenHardwareMonitor.Hardware.LPC {
 | 
| 
moel@1
 | 
    44  | 
  public class LPCGroup : IGroup {
 | 
| 
moel@1
 | 
    45  | 
    private List<IHardware> hardware = new List<IHardware>();
  | 
| 
moel@1
 | 
    46  | 
  | 
| 
moel@1
 | 
    47  | 
    private Chip chip = Chip.Unknown;
  | 
| 
moel@1
 | 
    48  | 
  | 
| 
moel@1
 | 
    49  | 
    // I/O Ports
  | 
| 
moel@7
 | 
    50  | 
    private ushort[] REGISTER_PORTS = new ushort[] { 0x2e, 0x4e };
 | 
| 
moel@7
 | 
    51  | 
    private ushort[] VALUE_PORTS = new ushort[] { 0x2f, 0x4f };
 | 
| 
moel@7
 | 
    52  | 
  | 
| 
moel@7
 | 
    53  | 
    private ushort registerPort;
  | 
| 
moel@7
 | 
    54  | 
    private ushort valuePort;
  | 
| 
moel@1
 | 
    55  | 
  | 
| 
moel@1
 | 
    56  | 
    // Registers
  | 
| 
moel@1
 | 
    57  | 
    private const byte CONFIGURATION_CONTROL_REGISTER = 0x02;
  | 
| 
moel@1
 | 
    58  | 
    private const byte DEVCIE_SELECT_REGISTER = 0x07;
  | 
| 
moel@1
 | 
    59  | 
    private const byte CHIP_ID_REGISTER = 0x20;
  | 
| 
moel@1
 | 
    60  | 
    private const byte CHIP_REVISION_REGISTER = 0x21;
  | 
| 
moel@7
 | 
    61  | 
    private const byte BASE_ADDRESS_REGISTER = 0x60;
  | 
| 
moel@1
 | 
    62  | 
  | 
| 
moel@7
 | 
    63  | 
    private byte ReadByte(byte register) {
 | 
| 
moel@7
 | 
    64  | 
      WinRing0.WriteIoPortByte(registerPort, register);
  | 
| 
moel@7
 | 
    65  | 
      return WinRing0.ReadIoPortByte(valuePort);
  | 
| 
moel@13
 | 
    66  | 
    } 
  | 
| 
moel@1
 | 
    67  | 
  | 
| 
moel@7
 | 
    68  | 
    private ushort ReadWord(byte register) {
 | 
| 
moel@7
 | 
    69  | 
      return (ushort)((ReadByte(register) << 8) | 
  | 
| 
moel@7
 | 
    70  | 
        ReadByte((byte)(register + 1)));
  | 
| 
moel@1
 | 
    71  | 
    }
  | 
| 
moel@1
 | 
    72  | 
  | 
| 
moel@7
 | 
    73  | 
    private void Select(byte logicalDeviceNumber) {
 | 
| 
moel@7
 | 
    74  | 
      WinRing0.WriteIoPortByte(registerPort, DEVCIE_SELECT_REGISTER);
  | 
| 
moel@7
 | 
    75  | 
      WinRing0.WriteIoPortByte(valuePort, logicalDeviceNumber);
  | 
| 
moel@1
 | 
    76  | 
    }
  | 
| 
moel@1
 | 
    77  | 
  | 
| 
moel@34
 | 
    78  | 
    // ITE
  | 
| 
moel@7
 | 
    79  | 
    private const byte IT87_ENVIRONMENT_CONTROLLER_LDN = 0x04;    
  | 
| 
moel@1
 | 
    80  | 
  | 
| 
moel@7
 | 
    81  | 
    private void IT87Enter() {
 | 
| 
moel@7
 | 
    82  | 
      WinRing0.WriteIoPortByte(registerPort, 0x87);
  | 
| 
moel@7
 | 
    83  | 
      WinRing0.WriteIoPortByte(registerPort, 0x01);
  | 
| 
moel@7
 | 
    84  | 
      WinRing0.WriteIoPortByte(registerPort, 0x55);
  | 
| 
moel@7
 | 
    85  | 
      WinRing0.WriteIoPortByte(registerPort, 0x55);
  | 
| 
moel@1
 | 
    86  | 
    }
  | 
| 
moel@1
 | 
    87  | 
  | 
| 
moel@7
 | 
    88  | 
    internal void IT87Exit() {
 | 
| 
moel@7
 | 
    89  | 
      WinRing0.WriteIoPortByte(registerPort, CONFIGURATION_CONTROL_REGISTER);
  | 
| 
moel@7
 | 
    90  | 
      WinRing0.WriteIoPortByte(valuePort, 0x02);
  | 
| 
moel@1
 | 
    91  | 
    }
  | 
| 
moel@1
 | 
    92  | 
  | 
| 
moel@7
 | 
    93  | 
    // Winbond, Fintek
  | 
| 
moel@7
 | 
    94  | 
    private const byte FINTEK_VENDOR_ID_REGISTER = 0x23;
  | 
| 
moel@7
 | 
    95  | 
    private const ushort FINTEK_VENDOR_ID = 0x1934;
  | 
| 
moel@7
 | 
    96  | 
  | 
| 
moel@34
 | 
    97  | 
    private const byte WINBOND_HARDWARE_MONITOR_LDN = 0x0B;
  | 
| 
moel@16
 | 
    98  | 
  | 
| 
moel@16
 | 
    99  | 
    private const byte F71858_HARDWARE_MONITOR_LDN = 0x02;
  | 
| 
moel@16
 | 
   100  | 
    private const byte FINTEK_HARDWARE_MONITOR_LDN = 0x04;
  | 
| 
moel@7
 | 
   101  | 
  | 
| 
moel@7
 | 
   102  | 
    private void WinbondFintekEnter() {
 | 
| 
moel@7
 | 
   103  | 
      WinRing0.WriteIoPortByte(registerPort, 0x87);
  | 
| 
moel@7
 | 
   104  | 
      WinRing0.WriteIoPortByte(registerPort, 0x87);
  | 
| 
moel@1
 | 
   105  | 
    }
  | 
| 
moel@1
 | 
   106  | 
  | 
| 
moel@7
 | 
   107  | 
    private void WinbondFintekExit() {
 | 
| 
moel@7
 | 
   108  | 
      WinRing0.WriteIoPortByte(registerPort, 0xAA);      
  | 
| 
moel@1
 | 
   109  | 
    }
  | 
| 
moel@1
 | 
   110  | 
  | 
| 
moel@1
 | 
   111  | 
    public LPCGroup() {
 | 
| 
moel@1
 | 
   112  | 
      if (!WinRing0.IsAvailable)
  | 
| 
moel@1
 | 
   113  | 
        return;
  | 
| 
moel@1
 | 
   114  | 
  | 
| 
moel@7
 | 
   115  | 
      for (int i = 0; i < REGISTER_PORTS.Length; i++) {
 | 
| 
moel@7
 | 
   116  | 
        registerPort = REGISTER_PORTS[i];
  | 
| 
moel@7
 | 
   117  | 
        valuePort = VALUE_PORTS[i];
  | 
| 
moel@1
 | 
   118  | 
  | 
| 
moel@7
 | 
   119  | 
        WinbondFintekEnter();
  | 
| 
moel@1
 | 
   120  | 
  | 
| 
moel@16
 | 
   121  | 
        byte logicalDeviceNumber;
  | 
| 
moel@7
 | 
   122  | 
        byte id = ReadByte(CHIP_ID_REGISTER);
  | 
| 
moel@7
 | 
   123  | 
        byte revision = ReadByte(CHIP_REVISION_REGISTER);
  | 
| 
moel@34
 | 
   124  | 
        chip = Chip.Unknown;
  | 
| 
moel@34
 | 
   125  | 
        logicalDeviceNumber = 0;
  | 
| 
moel@7
 | 
   126  | 
        switch (id) {
 | 
| 
moel@16
 | 
   127  | 
          case 0x05:
  | 
| 
moel@16
 | 
   128  | 
            switch (revision) {
 | 
| 
moel@16
 | 
   129  | 
              case 0x41:
  | 
| 
moel@16
 | 
   130  | 
                chip = Chip.F71882;
  | 
| 
moel@16
 | 
   131  | 
                logicalDeviceNumber = FINTEK_HARDWARE_MONITOR_LDN;
  | 
| 
moel@34
 | 
   132  | 
                break;              
  | 
| 
moel@16
 | 
   133  | 
            } break;
  | 
| 
moel@16
 | 
   134  | 
          case 0x06:
  | 
| 
moel@16
 | 
   135  | 
            switch (revision) {             
 | 
| 
moel@16
 | 
   136  | 
              case 0x01:
  | 
| 
moel@16
 | 
   137  | 
                chip = Chip.F71862;
  | 
| 
moel@16
 | 
   138  | 
                logicalDeviceNumber = FINTEK_HARDWARE_MONITOR_LDN;
  | 
| 
moel@34
 | 
   139  | 
                break;              
  | 
| 
moel@16
 | 
   140  | 
            } break;
  | 
| 
moel@16
 | 
   141  | 
          case 0x07:
  | 
| 
moel@16
 | 
   142  | 
            switch (revision) {
 | 
| 
moel@16
 | 
   143  | 
              case 0x23:
  | 
| 
moel@16
 | 
   144  | 
                chip = Chip.F71889;
  | 
| 
moel@16
 | 
   145  | 
                logicalDeviceNumber = FINTEK_HARDWARE_MONITOR_LDN;
  | 
| 
moel@34
 | 
   146  | 
                break;              
  | 
| 
moel@16
 | 
   147  | 
            } break;
  | 
| 
moel@16
 | 
   148  | 
          case 0x08:
  | 
| 
moel@16
 | 
   149  | 
            switch (revision) {
 | 
| 
moel@16
 | 
   150  | 
              case 0x14:
  | 
| 
moel@16
 | 
   151  | 
                chip = Chip.F71869;
  | 
| 
moel@16
 | 
   152  | 
                logicalDeviceNumber = FINTEK_HARDWARE_MONITOR_LDN;
  | 
| 
moel@34
 | 
   153  | 
                break;              
  | 
| 
moel@16
 | 
   154  | 
            } break;
  | 
| 
moel@31
 | 
   155  | 
          case 0x52:
  | 
| 
moel@31
 | 
   156  | 
            switch (revision) {
 | 
| 
moel@31
 | 
   157  | 
              case 0x17:
  | 
| 
moel@31
 | 
   158  | 
              case 0x3A:
  | 
| 
moel@31
 | 
   159  | 
                chip = Chip.W83627HF;
  | 
| 
moel@34
 | 
   160  | 
                logicalDeviceNumber = WINBOND_HARDWARE_MONITOR_LDN;
  | 
| 
moel@34
 | 
   161  | 
                break;             
  | 
| 
moel@34
 | 
   162  | 
            } break;
  | 
| 
moel@54
 | 
   163  | 
          case 0x82:
  | 
| 
moel@54
 | 
   164  | 
            switch (revision) {
 | 
| 
moel@54
 | 
   165  | 
              case 0x83:
  | 
| 
moel@54
 | 
   166  | 
                chip = Chip.W83627THF;
  | 
| 
moel@54
 | 
   167  | 
                logicalDeviceNumber = WINBOND_HARDWARE_MONITOR_LDN;
  | 
| 
moel@54
 | 
   168  | 
                break;
  | 
| 
moel@54
 | 
   169  | 
            } break;
  | 
| 
moel@34
 | 
   170  | 
          case 0x88:
  | 
| 
moel@34
 | 
   171  | 
            switch (revision & 0xF0) {
 | 
| 
moel@34
 | 
   172  | 
              case 0x60:
  | 
| 
moel@34
 | 
   173  | 
                chip = Chip.W83627EHF;
  | 
| 
moel@34
 | 
   174  | 
                logicalDeviceNumber = WINBOND_HARDWARE_MONITOR_LDN;
  | 
| 
moel@31
 | 
   175  | 
                break;
  | 
| 
moel@31
 | 
   176  | 
            } break;
  | 
| 
moel@7
 | 
   177  | 
          case 0xA0:
  | 
| 
moel@7
 | 
   178  | 
            switch (revision & 0xF0) {
 | 
| 
moel@7
 | 
   179  | 
              case 0x20: 
  | 
| 
moel@7
 | 
   180  | 
                chip = Chip.W83627DHG;
  | 
| 
moel@34
 | 
   181  | 
                logicalDeviceNumber = WINBOND_HARDWARE_MONITOR_LDN;  
  | 
| 
moel@34
 | 
   182  | 
                break;             
  | 
| 
moel@34
 | 
   183  | 
            } break;
  | 
| 
moel@34
 | 
   184  | 
          case 0xA5:
  | 
| 
moel@34
 | 
   185  | 
            switch (revision & 0xF0) {
 | 
| 
moel@34
 | 
   186  | 
              case 0x10:
  | 
| 
moel@34
 | 
   187  | 
                chip = Chip.W83667HG;
  | 
| 
moel@34
 | 
   188  | 
                logicalDeviceNumber = WINBOND_HARDWARE_MONITOR_LDN;
  | 
| 
moel@7
 | 
   189  | 
                break;
  | 
| 
moel@19
 | 
   190  | 
            } break;
  | 
| 
moel@19
 | 
   191  | 
          case 0xB0:
  | 
| 
moel@19
 | 
   192  | 
            switch (revision & 0xF0) {
 | 
| 
moel@19
 | 
   193  | 
              case 0x70:
  | 
| 
moel@19
 | 
   194  | 
                chip = Chip.W83627DHGP;
  | 
| 
moel@34
 | 
   195  | 
                logicalDeviceNumber = WINBOND_HARDWARE_MONITOR_LDN;
  | 
| 
moel@34
 | 
   196  | 
                break;             
  | 
| 
moel@34
 | 
   197  | 
            } break;
  | 
| 
moel@34
 | 
   198  | 
          case 0xB3:
  | 
| 
moel@34
 | 
   199  | 
            switch (revision & 0xF0) {
 | 
| 
moel@34
 | 
   200  | 
              case 0x50:
  | 
| 
moel@34
 | 
   201  | 
                chip = Chip.W83667HGB;
  | 
| 
moel@34
 | 
   202  | 
                logicalDeviceNumber = WINBOND_HARDWARE_MONITOR_LDN;
  | 
| 
moel@19
 | 
   203  | 
                break;
  | 
| 
moel@34
 | 
   204  | 
            } break; 
  | 
| 
moel@7
 | 
   205  | 
        }
  | 
| 
moel@7
 | 
   206  | 
        if (chip != Chip.Unknown) {
 | 
| 
moel@1
 | 
   207  | 
  | 
| 
moel@16
 | 
   208  | 
          Select(logicalDeviceNumber);
  | 
| 
moel@60
 | 
   209  | 
          ushort address = ReadWord(BASE_ADDRESS_REGISTER);          
  | 
| 
moel@7
 | 
   210  | 
          Thread.Sleep(1);
  | 
| 
moel@7
 | 
   211  | 
          ushort verify = ReadWord(BASE_ADDRESS_REGISTER);
  | 
| 
moel@60
 | 
   212  | 
          
  | 
| 
moel@7
 | 
   213  | 
          ushort vendorID = 0;
  | 
| 
moel@16
 | 
   214  | 
          if (chip == Chip.F71862 || chip == Chip.F71882 || chip == Chip.F71889)
  | 
| 
moel@7
 | 
   215  | 
            vendorID = ReadWord(FINTEK_VENDOR_ID_REGISTER);
  | 
| 
moel@1
 | 
   216  | 
  | 
| 
moel@7
 | 
   217  | 
          WinbondFintekExit();
  | 
| 
moel@1
 | 
   218  | 
  | 
| 
moel@60
 | 
   219  | 
          if (address != verify)
  | 
| 
moel@60
 | 
   220  | 
            return;
  | 
| 
moel@60
 | 
   221  | 
  | 
| 
moel@60
 | 
   222  | 
          // some Fintek chips have address register offset 0x05 added already
  | 
| 
moel@60
 | 
   223  | 
          if ((address & 0x07) == 0x05)
  | 
| 
moel@60
 | 
   224  | 
            address &= 0xFFF8;
  | 
| 
moel@60
 | 
   225  | 
  | 
| 
moel@60
 | 
   226  | 
          if (address < 0x100 || (address & 0xF007) != 0)
  | 
| 
moel@7
 | 
   227  | 
            return;
  | 
| 
moel@7
 | 
   228  | 
          
  | 
| 
moel@7
 | 
   229  | 
          switch (chip) {
 | 
| 
moel@7
 | 
   230  | 
            case Chip.W83627DHG:
  | 
| 
moel@19
 | 
   231  | 
            case Chip.W83627DHGP:
  | 
| 
moel@34
 | 
   232  | 
            case Chip.W83627EHF:
  | 
| 
moel@31
 | 
   233  | 
            case Chip.W83627HF:
  | 
| 
moel@54
 | 
   234  | 
            case Chip.W83627THF:
  | 
| 
moel@34
 | 
   235  | 
            case Chip.W83667HG:
  | 
| 
moel@34
 | 
   236  | 
            case Chip.W83667HGB:
  | 
| 
moel@34
 | 
   237  | 
              W836XX w836XX = new W836XX(chip, revision, address);
  | 
| 
moel@34
 | 
   238  | 
              if (w836XX.IsAvailable)
  | 
| 
moel@34
 | 
   239  | 
                hardware.Add(w836XX);
  | 
| 
moel@7
 | 
   240  | 
              break;
  | 
| 
moel@16
 | 
   241  | 
            case Chip.F71862:
  | 
| 
moel@16
 | 
   242  | 
            case Chip.F71882:
  | 
| 
moel@16
 | 
   243  | 
            case Chip.F71889: 
  | 
| 
moel@7
 | 
   244  | 
              if (vendorID == FINTEK_VENDOR_ID)
  | 
| 
moel@16
 | 
   245  | 
                hardware.Add(new F718XX(chip, address));
  | 
| 
moel@16
 | 
   246  | 
              break;
  | 
| 
moel@16
 | 
   247  | 
            case Chip.F71869:
  | 
| 
moel@16
 | 
   248  | 
              hardware.Add(new F718XX(chip, address));
  | 
| 
moel@7
 | 
   249  | 
              break;
  | 
| 
moel@7
 | 
   250  | 
            default: break;
  | 
| 
moel@7
 | 
   251  | 
          }
  | 
| 
moel@7
 | 
   252  | 
          
  | 
| 
moel@7
 | 
   253  | 
          return;
  | 
| 
moel@7
 | 
   254  | 
        }
  | 
| 
moel@1
 | 
   255  | 
  | 
| 
moel@7
 | 
   256  | 
        IT87Enter();
  | 
| 
moel@1
 | 
   257  | 
  | 
| 
moel@7
 | 
   258  | 
        switch (ReadWord(CHIP_ID_REGISTER)) {
 | 
| 
moel@21
 | 
   259  | 
          case 0x8716: chip = Chip.IT8716F; break;
  | 
| 
moel@21
 | 
   260  | 
          case 0x8718: chip = Chip.IT8718F; break;
  | 
| 
moel@21
 | 
   261  | 
          case 0x8720: chip = Chip.IT8720F; break;
  | 
| 
moel@21
 | 
   262  | 
          case 0x8726: chip = Chip.IT8726F; break;
  | 
| 
moel@7
 | 
   263  | 
          default: chip = Chip.Unknown; break;
  | 
| 
moel@7
 | 
   264  | 
        }
  | 
| 
moel@7
 | 
   265  | 
  | 
| 
moel@7
 | 
   266  | 
        if (chip != Chip.Unknown) {
 | 
| 
moel@7
 | 
   267  | 
          Select(IT87_ENVIRONMENT_CONTROLLER_LDN);
  | 
| 
moel@7
 | 
   268  | 
          ushort address = ReadWord(BASE_ADDRESS_REGISTER);
  | 
| 
moel@7
 | 
   269  | 
          Thread.Sleep(1);
  | 
| 
moel@7
 | 
   270  | 
          ushort verify = ReadWord(BASE_ADDRESS_REGISTER);
  | 
| 
moel@7
 | 
   271  | 
  | 
| 
moel@7
 | 
   272  | 
          IT87Exit();
  | 
| 
moel@7
 | 
   273  | 
  | 
| 
moel@34
 | 
   274  | 
          if (address != verify || address < 0x100 || (address & 0xF007) != 0)
  | 
| 
moel@7
 | 
   275  | 
            return;
  | 
| 
moel@7
 | 
   276  | 
  | 
| 
moel@16
 | 
   277  | 
          IT87XX it87 = new IT87XX(chip, address);
  | 
| 
moel@7
 | 
   278  | 
          if (it87.IsAvailable)
  | 
| 
moel@7
 | 
   279  | 
            hardware.Add(it87);
  | 
| 
moel@7
 | 
   280  | 
  | 
| 
moel@1
 | 
   281  | 
          return;
  | 
| 
moel@7
 | 
   282  | 
        }
  | 
| 
moel@7
 | 
   283  | 
      }   
  | 
| 
moel@1
 | 
   284  | 
    }
  | 
| 
moel@1
 | 
   285  | 
  | 
| 
moel@1
 | 
   286  | 
    public IHardware[] Hardware {
 | 
| 
moel@1
 | 
   287  | 
      get {
 | 
| 
moel@1
 | 
   288  | 
        return hardware.ToArray();
  | 
| 
moel@1
 | 
   289  | 
      }
  | 
| 
moel@1
 | 
   290  | 
    }
  | 
| 
moel@1
 | 
   291  | 
  | 
| 
moel@1
 | 
   292  | 
    public string GetReport() {
 | 
| 
moel@1
 | 
   293  | 
      return null;
  | 
| 
moel@1
 | 
   294  | 
    }
  | 
| 
moel@1
 | 
   295  | 
  | 
| 
moel@1
 | 
   296  | 
    public void Close() { }
 | 
| 
moel@1
 | 
   297  | 
  }
  | 
| 
moel@1
 | 
   298  | 
}
  |