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