Added initial SSD support for Intel, Indilinx, SandForce and Samsung drives. Experimental feature for now!
This commit is contained in:
+56
-14
@@ -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 @@ namespace OpenHardwareMonitor.Hardware.HDD {
|
||||
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 @@ namespace OpenHardwareMonitor.Hardware.HDD {
|
||||
|
||||
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 @@ namespace OpenHardwareMonitor.Hardware.HDD {
|
||||
|
||||
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<SMART.DriveAttribute> 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;
|
||||
|
||||
+76
-29
@@ -68,46 +68,93 @@ namespace OpenHardwareMonitor.Hardware.HDD {
|
||||
continue;
|
||||
}
|
||||
|
||||
SMART.DriveAttribute[] attributes = SMART.ReadSmart(handle, drive);
|
||||
if (attributes == null) {
|
||||
List<SMART.DriveAttribute> attributes =
|
||||
new List<SMART.DriveAttribute>(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<SMART.DriveAttribute> 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<SMART.DriveAttribute> 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 @@ namespace OpenHardwareMonitor.Hardware.HDD {
|
||||
continue;
|
||||
}
|
||||
|
||||
SMART.DriveAttribute[] attributes = SMART.ReadSmart(handle, drive);
|
||||
List<SMART.DriveAttribute> attributes = SMART.ReadSmart(handle, drive);
|
||||
|
||||
if (attributes != null) {
|
||||
r.AppendLine("Drive name: " + name);
|
||||
|
||||
+17
-7
@@ -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 @@ namespace OpenHardwareMonitor.Hardware.HDD {
|
||||
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 @@ namespace OpenHardwareMonitor.Hardware.HDD {
|
||||
IntPtr.Zero);
|
||||
}
|
||||
|
||||
public static DriveAttribute[] ReadSmart(IntPtr handle, int driveNumber) {
|
||||
public static List<DriveAttribute> ReadSmart(IntPtr handle,
|
||||
int driveNumber)
|
||||
{
|
||||
DriveCommandParameter parameter = new DriveCommandParameter();
|
||||
DriveSmartReadResult result;
|
||||
uint bytesReturned;
|
||||
@@ -268,15 +279,14 @@ namespace OpenHardwareMonitor.Hardware.HDD {
|
||||
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<DriveAttribute>(result.Attributes)
|
||||
: new List<DriveAttribute>();
|
||||
}
|
||||
|
||||
public static string ReadName(IntPtr handle, int driveNumber) {
|
||||
|
||||
Reference in New Issue
Block a user