Added initial SSD support for Intel, Indilinx, SandForce and Samsung drives. Experimental feature for now!
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) {