# HG changeset patch # User paulwerelds # Date 1286540312 0 # Node ID 194186efdde979668bb9bc7258e7f66b7d6fca8c # Parent d93ddd6ca0af53b0816cf0188ab39610879d0886 Added initial SSD support for Intel, Indilinx, SandForce and Samsung drives. Experimental feature for now! diff -r d93ddd6ca0af -r 194186efdde9 Hardware/HDD/HDD.cs --- a/Hardware/HDD/HDD.cs Thu Oct 07 19:34:36 2010 +0000 +++ b/Hardware/HDD/HDD.cs Fri Oct 08 12:18:32 2010 +0000 @@ -19,7 +19,7 @@ Portions created by the Initial Developer are Copyright (C) 2009-2010 the Initial Developer. All Rights Reserved. - Contributor(s): + Contributor(s): Paul Werelds Alternatively, the contents of this file may be used under the terms of either the GNU General Public License Version 2 or later (the "GPL"), or @@ -36,6 +36,7 @@ */ using System; +using System.Collections.Generic; using System.Globalization; namespace OpenHardwareMonitor.Hardware.HDD { @@ -46,24 +47,40 @@ private readonly string name; private readonly IntPtr handle; private readonly int drive; - private readonly int attribute; - private readonly Sensor temperature; private int count; - - public HDD(string name, IntPtr handle, int drive, int attribute, - ISettings settings) + private readonly SMART.AttributeID temperatureID = 0x00; + private readonly SMART.SSDLifeID lifeID = 0x00; + + private readonly Sensor temperatureSensor; + private readonly Sensor lifeSensor; + + public HDD(string name, IntPtr handle, int drive, + SMART.AttributeID temperatureID, ISettings settings) { this.name = name; this.handle = handle; this.drive = drive; - this.attribute = attribute; this.count = 0; - this.temperature = new Sensor("HDD", 0, SensorType.Temperature, this, - settings); + this.temperatureID = temperatureID; + this.temperatureSensor = new Sensor("HDD", 0, SensorType.Temperature, + this, settings); + Update(); } + public HDD(string name, IntPtr handle, int drive, SMART.SSDLifeID lifeID, + ISettings settings) + { + this.name = name; + this.handle = handle; + this.drive = drive; + this.count = 0; + this.lifeID = lifeID; + this.lifeSensor = new Sensor("HDD", 0, SensorType.Level, this, settings); + + Update(); + } public string Name { get { return name; } @@ -90,7 +107,13 @@ public ISensor[] Sensors { get { - return new ISensor[] { temperature }; + if (lifeID != SMART.SSDLifeID.None) + return new ISensor[] { lifeSensor }; + + if (temperatureID != 0x00) + return new ISensor[] { temperatureSensor }; + + return new ISensor[] {}; } } @@ -100,11 +123,30 @@ public void Update() { if (count == 0) { - SMART.DriveAttribute[] attributes = SMART.ReadSmart(handle, drive); - if (attributes != null && attribute < attributes.Length) - temperature.Value = attributes[attribute].RawValue[0]; + List attributes = SMART.ReadSmart(handle, drive); + if (temperatureID != 0x00 && + attributes.Exists(attr => (int)attr.ID == (int)temperatureID)) + { + temperatureSensor.Value = attributes + .Find(attr => (int)attr.ID == (int)temperatureID) + .RawValue[0]; + } + + if (lifeID != 0x00 && + attributes.Exists(attr => (int)attr.ID == (int)lifeID)) + { + lifeSensor.Value = attributes + .Find(attr => (int)attr.ID == (int)temperatureID) + .AttrValue; + } } else { - temperature.Value = temperature.Value; + if (temperatureID != 0x00) { + temperatureSensor.Value = temperatureSensor.Value; + } + + if (lifeID != 0x00) { + lifeSensor.Value = lifeSensor.Value; + } } count++; count %= UPDATE_DIVIDER; diff -r d93ddd6ca0af -r 194186efdde9 Hardware/HDD/HDDGroup.cs --- a/Hardware/HDD/HDDGroup.cs Thu Oct 07 19:34:36 2010 +0000 +++ b/Hardware/HDD/HDDGroup.cs Fri Oct 08 12:18:32 2010 +0000 @@ -68,46 +68,93 @@ continue; } - SMART.DriveAttribute[] attributes = SMART.ReadSmart(handle, drive); - if (attributes == null) { + List attributes = + new List(SMART.ReadSmart(handle, drive)); + + if (!(attributes.Count > 0)) { SMART.CloseHandle(handle); continue; } - int attribute = -1; + SMART.SSDLifeID ssdLifeID = GetSSDLifeID(attributes); + if (ssdLifeID == SMART.SSDLifeID.None) { + SMART.AttributeID temperatureID = GetTemperatureIndex(attributes); - // search for the Temperature attribute - for (int i = 0; i < attributes.Length; i++) - if (attributes[i].ID == SMART.AttributeID.Temperature) { - attribute = i; - break; + if (temperatureID != 0x00) { + hardware.Add(new HDD(name, handle, drive, temperatureID, settings)); + continue; } - - // if no temperature attribute is found, search for DriveTemperature - if (attribute == -1) - for (int i = 0; i < attributes.Length; i++) - if (attributes[i].ID == SMART.AttributeID.DriveTemperature) { - attribute = i; - break; - } - - // if no temperature attribute is found, search for AirflowTemperature - if (attribute == -1) - for (int i = 0; i < attributes.Length; i++) - if (attributes[i].ID == SMART.AttributeID.AirflowTemperature) { - attribute = i; - break; - } - - if (attribute >= 0) { - hardware.Add(new HDD(name, handle, drive, attribute, settings)); + } else { + hardware.Add(new HDD(name, handle, drive, ssdLifeID, settings)); continue; } - + SMART.CloseHandle(handle); } } + private SMART.SSDLifeID GetSSDLifeID(List attributes) { + // ID E9 is present on Intel, JM, SF and Samsung + // ID D2 is present on Indilinx + // Neither ID has been found on a mechanical hard drive (yet), + // So this seems like a good way to check if it's an SSD. + bool isKnownSSD = (attributes.Exists(attr => (int)attr.ID == 0xE9) || + attributes.Exists(attr => (int)attr.ID == 0xD2) + ); + + if (!isKnownSSD) return SMART.SSDLifeID.None; + + // We start with a traditional loop, because there are 4 unique ID's + // that potentially identify one of the vendors + for (int i = 0; i < attributes.Count; i++) { + + switch ((int)attributes[i].ID) { + case 0xB4: + return SMART.SSDLifeID.Samsung; + case 0xAB: + return SMART.SSDLifeID.SandForce; + case 0xD2: + return SMART.SSDLifeID.Indilinx; + } + } + + // TODO: Find out JMicron's Life attribute ID; their unique ID = 0xE4 + + // For Intel, we make sure we have their 3 most important ID's + // We do a traditional loop again, because we all we need to know + // is whether we can find all 3; pointless to use Exists() + int intelRegisterCount = 0; + foreach (SMART.DriveAttribute attribute in attributes) { + if ((int)attribute.ID == 0xE1 || + (int)attribute.ID == 0xE8 || + (int)attribute.ID == 0xE9 + ) + intelRegisterCount++; + } + + return (intelRegisterCount == 3) + ? SMART.SSDLifeID.Intel + : SMART.SSDLifeID.None; + } + + private SMART.AttributeID GetTemperatureIndex( + List attributes) + { + SMART.AttributeID[] validIds = new[] { + SMART.AttributeID.Temperature, + SMART.AttributeID.DriveTemperature, + SMART.AttributeID.AirflowTemperature + }; + + foreach (SMART.AttributeID validId in validIds) { + SMART.AttributeID id = validId; + if (attributes.Exists(attr => attr.ID == id)) + return validId; + } + + return 0x00; + } + public IHardware[] Hardware { get { return hardware.ToArray(); @@ -140,7 +187,7 @@ continue; } - SMART.DriveAttribute[] attributes = SMART.ReadSmart(handle, drive); + List attributes = SMART.ReadSmart(handle, drive); if (attributes != null) { r.AppendLine("Drive name: " + name); diff -r d93ddd6ca0af -r 194186efdde9 Hardware/HDD/SMART.cs --- a/Hardware/HDD/SMART.cs Thu Oct 07 19:34:36 2010 +0000 +++ b/Hardware/HDD/SMART.cs Fri Oct 08 12:18:32 2010 +0000 @@ -19,7 +19,7 @@ Portions created by the Initial Developer are Copyright (C) 2009-2010 the Initial Developer. All Rights Reserved. - Contributor(s): + Contributor(s): Paul Werelds Alternatively, the contents of this file may be used under the terms of either the GNU General Public License Version 2 or later (the "GPL"), or @@ -36,6 +36,7 @@ */ using System; +using System.Collections.Generic; using System.Runtime.InteropServices; namespace OpenHardwareMonitor.Hardware.HDD { @@ -77,6 +78,14 @@ DriveTemperature = 0xE7 } + public enum SSDLifeID { + None = 0x00, + Indilinx = 0xD1, + Intel = 0xE8, + Samsung = 0xB4, + SandForce = 0xE7 + } + [StructLayout(LayoutKind.Sequential, Pack = 1)] public struct DriveAttribute { public AttributeID ID; @@ -257,7 +266,9 @@ IntPtr.Zero); } - public static DriveAttribute[] ReadSmart(IntPtr handle, int driveNumber) { + public static List ReadSmart(IntPtr handle, + int driveNumber) + { DriveCommandParameter parameter = new DriveCommandParameter(); DriveSmartReadResult result; uint bytesReturned; @@ -268,15 +279,14 @@ parameter.Registers.LBAHigh = SMART_LBA_HI; parameter.Registers.Command = SMART_CMD; - bool valid = NativeMethods.DeviceIoControl(handle, + bool isValid = NativeMethods.DeviceIoControl(handle, DriveCommand.ReceiveDriveData, ref parameter, Marshal.SizeOf(parameter), out result, Marshal.SizeOf(typeof(DriveSmartReadResult)), out bytesReturned, IntPtr.Zero); - if (!valid) - return null; - else - return result.Attributes; + return (isValid) + ? new List(result.Attributes) + : new List(); } public static string ReadName(IntPtr handle, int driveNumber) {