Added initial SSD support for Intel, Indilinx, SandForce and Samsung drives. Experimental feature for now!
authorpaulwerelds
Fri, 08 Oct 2010 12:18:32 +0000
changeset 218194186efdde9
parent 217 d93ddd6ca0af
child 219 ce04404774d6
Added initial SSD support for Intel, Indilinx, SandForce and Samsung drives. Experimental feature for now!
Hardware/HDD/HDD.cs
Hardware/HDD/HDDGroup.cs
Hardware/HDD/SMART.cs
     1.1 --- a/Hardware/HDD/HDD.cs	Thu Oct 07 19:34:36 2010 +0000
     1.2 +++ b/Hardware/HDD/HDD.cs	Fri Oct 08 12:18:32 2010 +0000
     1.3 @@ -19,7 +19,7 @@
     1.4    Portions created by the Initial Developer are Copyright (C) 2009-2010
     1.5    the Initial Developer. All Rights Reserved.
     1.6  
     1.7 -  Contributor(s):
     1.8 +  Contributor(s): Paul Werelds
     1.9  
    1.10    Alternatively, the contents of this file may be used under the terms of
    1.11    either the GNU General Public License Version 2 or later (the "GPL"), or
    1.12 @@ -36,6 +36,7 @@
    1.13  */
    1.14  
    1.15  using System;
    1.16 +using System.Collections.Generic;
    1.17  using System.Globalization;
    1.18  
    1.19  namespace OpenHardwareMonitor.Hardware.HDD {
    1.20 @@ -46,24 +47,40 @@
    1.21      private readonly string name;
    1.22      private readonly IntPtr handle;
    1.23      private readonly int drive;
    1.24 -    private readonly int attribute;    
    1.25 -    private readonly Sensor temperature;
    1.26      private int count;
    1.27 -    
    1.28  
    1.29 -    public HDD(string name, IntPtr handle, int drive, int attribute, 
    1.30 -      ISettings settings) 
    1.31 +    private readonly SMART.AttributeID temperatureID = 0x00;    
    1.32 +    private readonly SMART.SSDLifeID lifeID = 0x00;
    1.33 +
    1.34 +    private readonly Sensor temperatureSensor;
    1.35 +    private readonly Sensor lifeSensor;
    1.36 +
    1.37 +    public HDD(string name, IntPtr handle, int drive,
    1.38 +      SMART.AttributeID temperatureID, ISettings settings)
    1.39      {
    1.40        this.name = name;
    1.41        this.handle = handle;
    1.42        this.drive = drive;
    1.43 -      this.attribute = attribute;
    1.44        this.count = 0;
    1.45 -      this.temperature = new Sensor("HDD", 0, SensorType.Temperature, this, 
    1.46 -        settings);
    1.47 +      this.temperatureID = temperatureID;
    1.48 +      this.temperatureSensor = new Sensor("HDD", 0, SensorType.Temperature,
    1.49 +        this, settings);
    1.50 +
    1.51        Update();
    1.52      }
    1.53  
    1.54 +    public HDD(string name, IntPtr handle, int drive, SMART.SSDLifeID lifeID,
    1.55 +      ISettings settings)
    1.56 +    {
    1.57 +      this.name = name;
    1.58 +      this.handle = handle;
    1.59 +      this.drive = drive;
    1.60 +      this.count = 0;
    1.61 +      this.lifeID = lifeID;
    1.62 +      this.lifeSensor = new Sensor("HDD", 0, SensorType.Level, this, settings);
    1.63 +
    1.64 +      Update();
    1.65 +    }
    1.66  
    1.67      public string Name {
    1.68        get { return name; }
    1.69 @@ -90,7 +107,13 @@
    1.70  
    1.71      public ISensor[] Sensors {
    1.72        get {
    1.73 -        return new ISensor[] { temperature };
    1.74 +        if (lifeID != SMART.SSDLifeID.None)
    1.75 +          return new ISensor[] { lifeSensor };
    1.76 +
    1.77 +        if (temperatureID != 0x00)
    1.78 +          return new ISensor[] { temperatureSensor };
    1.79 +
    1.80 +        return new ISensor[] {};
    1.81        }
    1.82      }
    1.83  
    1.84 @@ -100,11 +123,30 @@
    1.85  
    1.86      public void Update() {
    1.87        if (count == 0) {
    1.88 -        SMART.DriveAttribute[] attributes = SMART.ReadSmart(handle, drive);
    1.89 -        if (attributes != null && attribute < attributes.Length) 
    1.90 -          temperature.Value = attributes[attribute].RawValue[0];
    1.91 +        List<SMART.DriveAttribute> attributes = SMART.ReadSmart(handle, drive);
    1.92 +        if (temperatureID != 0x00 &&
    1.93 +          attributes.Exists(attr => (int)attr.ID == (int)temperatureID))
    1.94 +        {
    1.95 +          temperatureSensor.Value = attributes
    1.96 +            .Find(attr => (int)attr.ID == (int)temperatureID)
    1.97 +            .RawValue[0];
    1.98 +        }
    1.99 +
   1.100 +        if (lifeID != 0x00 &&
   1.101 +          attributes.Exists(attr => (int)attr.ID == (int)lifeID))
   1.102 +        {
   1.103 +          lifeSensor.Value = attributes
   1.104 +            .Find(attr => (int)attr.ID == (int)temperatureID)
   1.105 +            .AttrValue;
   1.106 +        }
   1.107        } else {
   1.108 -        temperature.Value = temperature.Value;
   1.109 +        if (temperatureID != 0x00) {
   1.110 +          temperatureSensor.Value = temperatureSensor.Value;
   1.111 +        }
   1.112 +
   1.113 +        if (lifeID != 0x00) {
   1.114 +          lifeSensor.Value = lifeSensor.Value;
   1.115 +        }
   1.116        }
   1.117  
   1.118        count++; count %= UPDATE_DIVIDER; 
     2.1 --- a/Hardware/HDD/HDDGroup.cs	Thu Oct 07 19:34:36 2010 +0000
     2.2 +++ b/Hardware/HDD/HDDGroup.cs	Fri Oct 08 12:18:32 2010 +0000
     2.3 @@ -68,46 +68,93 @@
     2.4            continue;
     2.5          }
     2.6  
     2.7 -        SMART.DriveAttribute[] attributes = SMART.ReadSmart(handle, drive);
     2.8 -        if (attributes == null) {
     2.9 +        List<SMART.DriveAttribute> attributes =
    2.10 +          new List<SMART.DriveAttribute>(SMART.ReadSmart(handle, drive));
    2.11 +        
    2.12 +        if (!(attributes.Count > 0)) {
    2.13            SMART.CloseHandle(handle);
    2.14            continue;
    2.15          }
    2.16  
    2.17 -        int attribute = -1;
    2.18 +        SMART.SSDLifeID ssdLifeID = GetSSDLifeID(attributes);
    2.19 +        if (ssdLifeID == SMART.SSDLifeID.None) {
    2.20 +          SMART.AttributeID temperatureID = GetTemperatureIndex(attributes);
    2.21  
    2.22 -        // search for the Temperature attribute
    2.23 -        for (int i = 0; i < attributes.Length; i++)
    2.24 -          if (attributes[i].ID == SMART.AttributeID.Temperature) {
    2.25 -            attribute = i;
    2.26 -            break;
    2.27 +          if (temperatureID != 0x00) {
    2.28 +            hardware.Add(new HDD(name, handle, drive, temperatureID, settings));
    2.29 +            continue;
    2.30            }
    2.31 -
    2.32 -        // if no temperature attribute is found, search for DriveTemperature
    2.33 -        if (attribute == -1)
    2.34 -          for (int i = 0; i < attributes.Length; i++)
    2.35 -            if (attributes[i].ID == SMART.AttributeID.DriveTemperature) {
    2.36 -              attribute = i;
    2.37 -              break;
    2.38 -            }
    2.39 -
    2.40 -        // if no temperature attribute is found, search for AirflowTemperature
    2.41 -        if (attribute == -1)
    2.42 -          for (int i = 0; i < attributes.Length; i++)
    2.43 -            if (attributes[i].ID == SMART.AttributeID.AirflowTemperature) {
    2.44 -              attribute = i;
    2.45 -              break;
    2.46 -            }
    2.47 -
    2.48 -        if (attribute >= 0) {
    2.49 -          hardware.Add(new HDD(name, handle, drive, attribute, settings));
    2.50 +        } else {
    2.51 +          hardware.Add(new HDD(name, handle, drive, ssdLifeID, settings));
    2.52            continue;
    2.53          }
    2.54 -
    2.55 +        
    2.56          SMART.CloseHandle(handle);
    2.57        }
    2.58      }
    2.59  
    2.60 +    private SMART.SSDLifeID GetSSDLifeID(List<SMART.DriveAttribute> attributes) {
    2.61 +      // ID E9 is present on Intel, JM, SF and Samsung
    2.62 +      // ID D2 is present on Indilinx
    2.63 +      // Neither ID has been found on a mechanical hard drive (yet),
    2.64 +      // So this seems like a good way to check if it's an SSD.
    2.65 +      bool isKnownSSD = (attributes.Exists(attr => (int)attr.ID == 0xE9) ||
    2.66 +              attributes.Exists(attr => (int)attr.ID == 0xD2)
    2.67 +      );
    2.68 +
    2.69 +      if (!isKnownSSD) return SMART.SSDLifeID.None;
    2.70 +
    2.71 +      // We start with a traditional loop, because there are 4 unique ID's
    2.72 +      // that potentially identify one of the vendors
    2.73 +      for (int i = 0; i < attributes.Count; i++) {
    2.74 +
    2.75 +        switch ((int)attributes[i].ID) {
    2.76 +          case 0xB4:
    2.77 +            return SMART.SSDLifeID.Samsung;
    2.78 +          case 0xAB:
    2.79 +            return SMART.SSDLifeID.SandForce;
    2.80 +          case 0xD2:
    2.81 +            return SMART.SSDLifeID.Indilinx;
    2.82 +        }
    2.83 +      }
    2.84 +
    2.85 +      // TODO: Find out JMicron's Life attribute ID; their unique ID = 0xE4
    2.86 +
    2.87 +      // For Intel, we make sure we have their 3 most important ID's
    2.88 +      // We do a traditional loop again, because we all we need to know
    2.89 +      // is whether we can find all 3; pointless to use Exists()
    2.90 +      int intelRegisterCount = 0;
    2.91 +      foreach (SMART.DriveAttribute attribute in attributes) {
    2.92 +        if ((int)attribute.ID == 0xE1 ||
    2.93 +          (int)attribute.ID == 0xE8 ||
    2.94 +          (int)attribute.ID == 0xE9
    2.95 +        )
    2.96 +          intelRegisterCount++;
    2.97 +      }
    2.98 +
    2.99 +      return (intelRegisterCount == 3)
   2.100 +        ? SMART.SSDLifeID.Intel
   2.101 +        : SMART.SSDLifeID.None;
   2.102 +    }
   2.103 +
   2.104 +    private SMART.AttributeID GetTemperatureIndex(
   2.105 +      List<SMART.DriveAttribute> attributes)
   2.106 +    {
   2.107 +      SMART.AttributeID[] validIds = new[] {
   2.108 +        SMART.AttributeID.Temperature,
   2.109 +        SMART.AttributeID.DriveTemperature,
   2.110 +        SMART.AttributeID.AirflowTemperature
   2.111 +      };
   2.112 +
   2.113 +      foreach (SMART.AttributeID validId in validIds) {
   2.114 +        SMART.AttributeID id = validId;
   2.115 +        if (attributes.Exists(attr => attr.ID == id))
   2.116 +          return validId;
   2.117 +      }
   2.118 +
   2.119 +      return 0x00;
   2.120 +    }
   2.121 +
   2.122      public IHardware[] Hardware {
   2.123        get {
   2.124          return hardware.ToArray();
   2.125 @@ -140,7 +187,7 @@
   2.126            continue;
   2.127          }
   2.128  
   2.129 -        SMART.DriveAttribute[] attributes = SMART.ReadSmart(handle, drive);
   2.130 +        List<SMART.DriveAttribute> attributes = SMART.ReadSmart(handle, drive);
   2.131  
   2.132          if (attributes != null) {
   2.133            r.AppendLine("Drive name: " + name);
     3.1 --- a/Hardware/HDD/SMART.cs	Thu Oct 07 19:34:36 2010 +0000
     3.2 +++ b/Hardware/HDD/SMART.cs	Fri Oct 08 12:18:32 2010 +0000
     3.3 @@ -19,7 +19,7 @@
     3.4    Portions created by the Initial Developer are Copyright (C) 2009-2010
     3.5    the Initial Developer. All Rights Reserved.
     3.6  
     3.7 -  Contributor(s):
     3.8 +  Contributor(s): Paul Werelds
     3.9  
    3.10    Alternatively, the contents of this file may be used under the terms of
    3.11    either the GNU General Public License Version 2 or later (the "GPL"), or
    3.12 @@ -36,6 +36,7 @@
    3.13  */
    3.14  
    3.15  using System;
    3.16 +using System.Collections.Generic;
    3.17  using System.Runtime.InteropServices;
    3.18  
    3.19  namespace OpenHardwareMonitor.Hardware.HDD {
    3.20 @@ -77,6 +78,14 @@
    3.21        DriveTemperature = 0xE7
    3.22      }
    3.23  
    3.24 +    public enum SSDLifeID {
    3.25 +      None = 0x00,
    3.26 +      Indilinx = 0xD1,
    3.27 +      Intel = 0xE8,
    3.28 +      Samsung = 0xB4,
    3.29 +      SandForce = 0xE7
    3.30 +    }
    3.31 +
    3.32      [StructLayout(LayoutKind.Sequential, Pack = 1)]
    3.33      public struct DriveAttribute {
    3.34        public AttributeID ID;
    3.35 @@ -257,7 +266,9 @@
    3.36          IntPtr.Zero);
    3.37      }
    3.38  
    3.39 -    public static DriveAttribute[] ReadSmart(IntPtr handle, int driveNumber) {
    3.40 +    public static List<DriveAttribute> ReadSmart(IntPtr handle,
    3.41 +      int driveNumber)
    3.42 +    {
    3.43        DriveCommandParameter parameter = new DriveCommandParameter();
    3.44        DriveSmartReadResult result;
    3.45        uint bytesReturned;
    3.46 @@ -268,15 +279,14 @@
    3.47        parameter.Registers.LBAHigh = SMART_LBA_HI;
    3.48        parameter.Registers.Command = SMART_CMD;
    3.49  
    3.50 -      bool valid = NativeMethods.DeviceIoControl(handle, 
    3.51 +      bool isValid = NativeMethods.DeviceIoControl(handle, 
    3.52          DriveCommand.ReceiveDriveData, ref parameter, Marshal.SizeOf(parameter), 
    3.53          out result, Marshal.SizeOf(typeof(DriveSmartReadResult)), 
    3.54          out bytesReturned, IntPtr.Zero);
    3.55  
    3.56 -      if (!valid)
    3.57 -        return null;
    3.58 -      else
    3.59 -        return result.Attributes;
    3.60 +      return (isValid)
    3.61 +        ? new List<DriveAttribute>(result.Attributes)
    3.62 +        : new List<DriveAttribute>();
    3.63      }
    3.64  
    3.65      public static string ReadName(IntPtr handle, int driveNumber) {