Hardware/HDD/AbstractHarddrive.cs
author moel.mich
Sun, 23 Sep 2012 18:37:43 +0000
changeset 380 573f1fff48b2
parent 369 5077ed7ddca8
child 385 8f16f03797f5
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@324
     1
/*
moel@324
     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@324
     6
 
moel@344
     7
  Copyright (C) 2009-2012 Michael Möller <mmoeller@openhardwaremonitor.org>
moel@344
     8
	Copyright (C) 2010 Paul Werelds
moel@344
     9
  Copyright (C) 2011 Roland Reinl <roland-reinl@gmx.de>
moel@344
    10
	
moel@324
    11
*/
moel@324
    12
moel@324
    13
using System;
moel@324
    14
using System.Collections.Generic;
moel@324
    15
using System.Globalization;
moel@369
    16
using System.IO;
moel@324
    17
using System.Text;
moel@324
    18
using OpenHardwareMonitor.Collections;
moel@324
    19
moel@324
    20
namespace OpenHardwareMonitor.Hardware.HDD {
moel@324
    21
  internal abstract class AbstractHarddrive : Hardware {
moel@324
    22
moel@324
    23
    private const int UPDATE_DIVIDER = 30; // update only every 30s
moel@324
    24
moel@324
    25
    // array of all harddrive types, matching type is searched in this order
moel@324
    26
    private static Type[] hddTypes = {       
moel@324
    27
      typeof(SSDPlextor),
moel@324
    28
      typeof(SSDIntel),
moel@324
    29
      typeof(SSDSandforce),
moel@324
    30
      typeof(SSDIndilinx),
moel@328
    31
      typeof(SSDSamsung),
moel@358
    32
      typeof(SSDMicron),
moel@324
    33
      typeof(GenericHarddisk)
moel@324
    34
    };
moel@324
    35
moel@325
    36
    private string firmwareRevision;
moel@324
    37
    private readonly ISmart smart;
moel@324
    38
moel@324
    39
    private readonly IntPtr handle;
moel@324
    40
    private readonly int index;
moel@324
    41
    private int count;
moel@324
    42
moel@324
    43
    private IList<SmartAttribute> smartAttributes;
moel@324
    44
    private IDictionary<SmartAttribute, Sensor> sensors;
moel@324
    45
moel@369
    46
    private DriveInfo[] driveInfos;
moel@369
    47
    private Sensor usageSensor;
moel@369
    48
moel@325
    49
    protected AbstractHarddrive(ISmart smart, string name, 
moel@325
    50
      string firmwareRevision, int index, 
moel@324
    51
      IEnumerable<SmartAttribute> smartAttributes, ISettings settings) 
moel@324
    52
      : base(name, new Identifier("hdd",
moel@324
    53
        index.ToString(CultureInfo.InvariantCulture)), settings)
moel@324
    54
    {
moel@325
    55
      this.firmwareRevision = firmwareRevision;
moel@324
    56
      this.smart = smart;
moel@324
    57
      handle = smart.OpenDrive(index);
moel@324
    58
moel@324
    59
      smart.EnableSmart(handle, index);
moel@324
    60
moel@324
    61
      this.index = index;
moel@324
    62
      this.count = 0;
moel@324
    63
moel@324
    64
      this.smartAttributes = new List<SmartAttribute>(smartAttributes);
moel@324
    65
moel@369
    66
      string[] logicalDrives = smart.GetLogicalDrives(index);
moel@369
    67
      List<DriveInfo> driveInfoList = new List<DriveInfo>(logicalDrives.Length);
moel@369
    68
      foreach (string logicalDrive in logicalDrives) {
moel@369
    69
        try {
moel@369
    70
          DriveInfo di = new DriveInfo(logicalDrive);
moel@369
    71
          if (di.TotalSize > 0) 
moel@369
    72
            driveInfoList.Add(new DriveInfo(logicalDrive));
moel@369
    73
        } catch (ArgumentException) { } catch (IOException) { }
moel@369
    74
      }
moel@369
    75
      driveInfos = driveInfoList.ToArray();
moel@369
    76
moel@324
    77
      CreateSensors();
moel@324
    78
    }
moel@324
    79
moel@324
    80
    public static AbstractHarddrive CreateInstance(ISmart smart, 
moel@324
    81
      int driveIndex, ISettings settings) 
moel@324
    82
    {
moel@324
    83
      IntPtr deviceHandle = smart.OpenDrive(driveIndex);
moel@324
    84
moel@324
    85
      if (deviceHandle == smart.InvalidHandle) 
moel@324
    86
        return null;
moel@324
    87
moel@325
    88
      string name;
moel@325
    89
      string firmwareRevision;
moel@325
    90
      bool nameValid = smart.ReadNameAndFirmwareRevision(deviceHandle, 
moel@325
    91
        driveIndex, out name, out firmwareRevision);
moel@324
    92
      bool smartEnabled = smart.EnableSmart(deviceHandle, driveIndex);
moel@324
    93
moel@324
    94
      DriveAttributeValue[] values = {};
moel@324
    95
      if (smartEnabled)
moel@324
    96
        values = smart.ReadSmartData(deviceHandle, driveIndex);
moel@324
    97
moel@324
    98
      smart.CloseHandle(deviceHandle);
moel@324
    99
moel@325
   100
      if (!nameValid || string.IsNullOrEmpty(name)) 
moel@369
   101
        return null;      
moel@324
   102
moel@324
   103
      foreach (Type type in hddTypes) {
moel@324
   104
        // get the array of name prefixes for the current type
moel@324
   105
        NamePrefixAttribute[] namePrefixes = type.GetCustomAttributes(
moel@324
   106
          typeof(NamePrefixAttribute), true) as NamePrefixAttribute[];
moel@324
   107
moel@324
   108
        // get the array of the required SMART attributes for the current type
moel@324
   109
        RequireSmartAttribute[] requiredAttributes = type.GetCustomAttributes(
moel@324
   110
          typeof(RequireSmartAttribute), true) as RequireSmartAttribute[];
moel@324
   111
moel@324
   112
        // check if all required attributes are present
moel@324
   113
        bool allRequiredAttributesFound = true;
moel@324
   114
        foreach (var requireAttribute in requiredAttributes) {
moel@324
   115
          bool adttributeFound = false;
moel@324
   116
          foreach (DriveAttributeValue value in values) {
moel@324
   117
            if (value.Identifier == requireAttribute.AttributeId) {
moel@324
   118
              adttributeFound = true;
moel@324
   119
              break;
moel@324
   120
            }
moel@324
   121
          }
moel@324
   122
          if (!adttributeFound) {
moel@324
   123
            allRequiredAttributesFound = false;
moel@324
   124
            break;
moel@324
   125
          }
moel@324
   126
        }
moel@324
   127
moel@324
   128
        // if an attribute is missing, then try the next type
moel@324
   129
        if (!allRequiredAttributesFound)
moel@324
   130
          continue;        
moel@324
   131
moel@324
   132
        // check if there is a matching name prefix for this type
moel@324
   133
        foreach (NamePrefixAttribute prefix in namePrefixes) {
moel@324
   134
          if (name.StartsWith(prefix.Prefix, StringComparison.InvariantCulture)) 
moel@325
   135
            return Activator.CreateInstance(type, smart, name, firmwareRevision,
moel@325
   136
              driveIndex, settings) as AbstractHarddrive;
moel@324
   137
        }
moel@324
   138
      }
moel@324
   139
moel@324
   140
      // no matching type has been found
moel@324
   141
      return null;
moel@324
   142
    }
moel@324
   143
moel@324
   144
    private void CreateSensors() {
moel@324
   145
      sensors = new Dictionary<SmartAttribute, Sensor>();
moel@324
   146
moel@324
   147
      IList<Pair<SensorType, int>> sensorTypeAndChannels = 
moel@324
   148
        new List<Pair<SensorType, int>>();
moel@324
   149
moel@324
   150
      DriveAttributeValue[] values = smart.ReadSmartData(handle, index);
moel@324
   151
moel@324
   152
      foreach (SmartAttribute attribute in smartAttributes) {
moel@324
   153
        if (!attribute.SensorType.HasValue) 
moel@324
   154
          continue;
moel@324
   155
moel@324
   156
        bool found = false;
moel@324
   157
        foreach (DriveAttributeValue value in values) {
moel@324
   158
          if (value.Identifier == attribute.Identifier) {
moel@324
   159
            found = true;
moel@324
   160
            break;
moel@324
   161
          }
moel@324
   162
        }
moel@324
   163
        if (!found)
moel@324
   164
          continue;
moel@324
   165
moel@324
   166
        Pair<SensorType, int> pair = new Pair<SensorType, int>(
moel@324
   167
          attribute.SensorType.Value, attribute.SensorChannel);
moel@324
   168
moel@324
   169
        if (!sensorTypeAndChannels.Contains(pair)) {
moel@324
   170
          Sensor sensor = new Sensor(attribute.Name, 
moel@340
   171
            attribute.SensorChannel, attribute.DefaultHiddenSensor, 
moel@374
   172
            attribute.SensorType.Value, this, attribute.ParameterDescriptions, 
moel@374
   173
            settings);
moel@324
   174
moel@324
   175
          sensors.Add(attribute, sensor);
moel@339
   176
          ActivateSensor(sensor);
moel@324
   177
          sensorTypeAndChannels.Add(pair);
moel@324
   178
        }     
moel@324
   179
      }
moel@369
   180
moel@369
   181
      if (driveInfos.Length > 0) {
moel@369
   182
        usageSensor = 
moel@369
   183
          new Sensor("Used Space", 0, SensorType.Load, this, settings);
moel@369
   184
        ActivateSensor(usageSensor);
moel@369
   185
      }
moel@324
   186
    }
moel@324
   187
moel@324
   188
    public override HardwareType HardwareType {
moel@324
   189
      get { return HardwareType.HDD; }
moel@324
   190
    }
moel@324
   191
moel@339
   192
    public virtual void UpdateAdditionalSensors(DriveAttributeValue[] values) {}
moel@324
   193
moel@324
   194
    public override void Update() {
moel@324
   195
      if (count == 0) {
moel@324
   196
        DriveAttributeValue[] values = smart.ReadSmartData(handle, index);
moel@324
   197
moel@324
   198
        foreach (KeyValuePair<SmartAttribute, Sensor> keyValuePair in sensors) {
moel@324
   199
          SmartAttribute attribute = keyValuePair.Key;          
moel@324
   200
          foreach (DriveAttributeValue value in values) {
moel@324
   201
            if (value.Identifier == attribute.Identifier) {
moel@324
   202
              Sensor sensor = keyValuePair.Value;
moel@374
   203
              sensor.Value = attribute.ConvertValue(value, sensor.Parameters);
moel@324
   204
            }
moel@324
   205
          }
moel@339
   206
        }
moel@339
   207
moel@339
   208
        UpdateAdditionalSensors(values);
moel@369
   209
moel@369
   210
        if (usageSensor != null) {
moel@369
   211
          long totalSize = 0;
moel@369
   212
          long totalFreeSpace = 0;
moel@369
   213
          for (int i = 0; i < driveInfos.Length; i++) {
moel@369
   214
            totalSize += driveInfos[i].TotalSize;
moel@369
   215
            totalFreeSpace += driveInfos[i].TotalFreeSpace;
moel@369
   216
          }
moel@369
   217
          usageSensor.Value = 100.0f - (100.0f * totalFreeSpace) / totalSize;
moel@369
   218
        }
moel@324
   219
      }
moel@324
   220
moel@324
   221
      count++; 
moel@324
   222
      count %= UPDATE_DIVIDER; 
moel@324
   223
    }
moel@324
   224
moel@324
   225
    public override string GetReport() {
moel@324
   226
      StringBuilder r = new StringBuilder();
moel@324
   227
      DriveAttributeValue[] values = smart.ReadSmartData(handle, index);
moel@324
   228
      DriveThresholdValue[] thresholds = 
moel@324
   229
        smart.ReadSmartThresholds(handle, index);
moel@324
   230
moel@324
   231
      if (values.Length > 0) {
moel@324
   232
        r.AppendLine(this.GetType().Name);
moel@324
   233
        r.AppendLine();
moel@324
   234
        r.AppendLine("Drive name: " + name);
moel@325
   235
        r.AppendLine("Firmware version: " + firmwareRevision);
moel@369
   236
        r.AppendLine();    
moel@324
   237
        r.AppendFormat(CultureInfo.InvariantCulture, 
moel@324
   238
          " {0}{1}{2}{3}{4}{5}{6}{7}",
moel@324
   239
          ("ID").PadRight(3),
moel@328
   240
          ("Description").PadRight(35),
moel@324
   241
          ("Raw Value").PadRight(13),
moel@324
   242
          ("Worst").PadRight(6),
moel@324
   243
          ("Value").PadRight(6),
moel@324
   244
          ("Thres").PadRight(6),
moel@324
   245
          ("Physical").PadRight(8),
moel@324
   246
          Environment.NewLine);
moel@324
   247
moel@324
   248
        foreach (DriveAttributeValue value in values) {
moel@324
   249
          if (value.Identifier == 0x00) 
moel@324
   250
            break;
moel@324
   251
moel@324
   252
          byte? threshold = null;
moel@324
   253
          foreach (DriveThresholdValue t in thresholds) {
moel@324
   254
            if (t.Identifier == value.Identifier) {
moel@324
   255
              threshold = t.Threshold;
moel@324
   256
            }
moel@324
   257
          }
moel@324
   258
moel@324
   259
          string description = "Unknown";
moel@324
   260
          float? physical = null;
moel@324
   261
          foreach (SmartAttribute a in smartAttributes) {
moel@324
   262
            if (a.Identifier == value.Identifier) {
moel@324
   263
              description = a.Name;
moel@324
   264
              if (a.HasRawValueConversion | a.SensorType.HasValue)
moel@374
   265
                physical = a.ConvertValue(value, null);
moel@324
   266
              else
moel@324
   267
                physical = null;
moel@324
   268
            }
moel@324
   269
          }
moel@324
   270
moel@324
   271
          string raw = BitConverter.ToString(value.RawValue);
moel@324
   272
          r.AppendFormat(CultureInfo.InvariantCulture, 
moel@324
   273
            " {0}{1}{2}{3}{4}{5}{6}{7}",
moel@324
   274
            value.Identifier.ToString("X2").PadRight(3),
moel@328
   275
            description.PadRight(35),
moel@324
   276
            raw.Replace("-", "").PadRight(13),
moel@324
   277
            value.WorstValue.ToString(CultureInfo.InvariantCulture).PadRight(6),
moel@324
   278
            value.AttrValue.ToString(CultureInfo.InvariantCulture).PadRight(6),
moel@324
   279
            (threshold.HasValue ? threshold.Value.ToString(
moel@324
   280
              CultureInfo.InvariantCulture) : "-").PadRight(6),
moel@324
   281
            (physical.HasValue ? physical.Value.ToString(
moel@324
   282
              CultureInfo.InvariantCulture) : "-").PadRight(8),
moel@324
   283
            Environment.NewLine);
moel@324
   284
        }
moel@324
   285
        r.AppendLine();
moel@324
   286
      }
moel@324
   287
moel@369
   288
      foreach (DriveInfo di in driveInfos) {
moel@369
   289
        r.AppendLine("Logical drive name: " + di.Name);
moel@369
   290
        r.AppendLine("Format: " + di.DriveFormat);
moel@369
   291
        r.AppendLine("Total size: " + di.TotalSize);
moel@369
   292
        r.AppendLine("Total free space: " + di.TotalFreeSpace);
moel@369
   293
        r.AppendLine();
moel@369
   294
      }
moel@369
   295
moel@324
   296
      return r.ToString();
moel@324
   297
    }
moel@324
   298
moel@374
   299
    protected static float RawToInt(byte[] raw, byte value,
moel@374
   300
      IReadOnlyArray<IParameter> parameters) 
moel@374
   301
    {
moel@324
   302
      return (raw[3] << 24) | (raw[2] << 16) | (raw[1] << 8) | raw[0];
moel@324
   303
    }
moel@324
   304
moel@324
   305
    public override void Close() {
moel@324
   306
      smart.CloseHandle(handle);
moel@324
   307
      base.Close();
moel@324
   308
    }
moel@324
   309
moel@324
   310
    public override void Traverse(IVisitor visitor) {
moel@324
   311
      foreach (ISensor sensor in Sensors)
moel@324
   312
        sensor.Accept(visitor);
moel@324
   313
    }
moel@324
   314
  }
moel@324
   315
}