Added a new sensor type "Level" for wear or charge level (or any other percentage based sensors that don't fit into Load or Control).
3 Version: MPL 1.1/GPL 2.0/LGPL 2.1
5 The contents of this file are subject to the Mozilla Public License Version
6 1.1 (the "License"); you may not use this file except in compliance with
7 the License. You may obtain a copy of the License at
9 http://www.mozilla.org/MPL/
11 Software distributed under the License is distributed on an "AS IS" basis,
12 WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
13 for the specific language governing rights and limitations under the License.
15 The Original Code is the Open Hardware Monitor code.
17 The Initial Developer of the Original Code is
18 Michael Möller <m.moeller@gmx.ch>.
19 Portions created by the Initial Developer are Copyright (C) 2009-2010
20 the Initial Developer. All Rights Reserved.
24 Alternatively, the contents of this file may be used under the terms of
25 either the GNU General Public License Version 2 or later (the "GPL"), or
26 the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
27 in which case the provisions of the GPL or the LGPL are applicable instead
28 of those above. If you wish to allow use of your version of this file only
29 under the terms of either the GPL or the LGPL, and not to allow others to
30 use your version of this file under the terms of the MPL, indicate your
31 decision by deleting the provisions above and replace them with the notice
32 and other provisions required by the GPL or the LGPL. If you do not delete
33 the provisions above, a recipient may use your version of this file under
34 the terms of any one of the MPL, the GPL or the LGPL.
39 using System.Runtime.InteropServices;
41 namespace OpenHardwareMonitor.Hardware.HDD {
43 internal class SMART {
46 public enum Status : ushort {
47 PreFailureWarranty = 0x01,
48 OnLineCollection = 0x02,
55 public enum AttributeID : byte {
57 ThroughputPerformance = 0x02,
59 StartStopCount = 0x04,
60 ReallocatedSectorsCount = 0x05,
61 ReadChannelMargin = 0x06,
63 SeekTimePerformance = 0x08,
65 SpinRetryCount = 0x0A,
66 RecalibrationRetries = 0x0B,
67 PowerCycleCount = 0x0C,
68 SoftReadErrorRate = 0x0D,
69 AirflowTemperature = 0xBE,
71 HardwareECCRecovered = 0xC3,
72 ReallocationEventCount = 0xC4,
73 CurrentPendingSectorCount = 0xC5,
74 UncorrectableSectorCount = 0xC6,
75 UltraDMACRCErrorCount = 0xC7,
76 WriteErrorRate = 0xC8,
77 DriveTemperature = 0xE7
80 [StructLayout(LayoutKind.Sequential, Pack = 1)]
81 public struct DriveAttribute {
82 public AttributeID ID;
83 public Status StatusFlags;
84 public byte AttrValue;
85 public byte WorstValue;
86 [MarshalAs(UnmanagedType.ByValArray, SizeConst = 6)]
87 public byte[] RawValue;
92 protected enum AccessMode : uint {
100 protected enum ShareMode : uint {
107 protected enum CreationMode : uint {
116 protected enum FileAttribute : uint {
117 Readonly = 0x00000001,
120 Directory = 0x00000010,
121 Archive = 0x00000020,
124 Temporary = 0x00000100,
125 SparseFile = 0x00000200,
126 ReparsePoint = 0x00000400,
127 Compressed = 0x00000800,
128 Offline = 0x00001000,
129 NotContentIndexed = 0x00002000,
130 Encrypted = 0x00004000,
133 protected enum DriveCommand : uint {
134 GetVersion = 0x00074080,
135 SendDriveCommand = 0x0007c084,
136 ReceiveDriveData = 0x0007c088
139 [StructLayout(LayoutKind.Sequential, Pack = 1)]
140 protected struct CommandBlockRegisters {
141 public byte Features;
142 public byte SectorCount;
148 public byte Reserved;
151 [StructLayout(LayoutKind.Sequential, Pack = 1)]
152 protected struct DriveCommandParameter {
153 public uint BufferSize;
154 public CommandBlockRegisters Registers;
155 public byte DriveNumber;
156 [MarshalAs(UnmanagedType.ByValArray, SizeConst = 20)]
157 public byte[] Reserved;
160 [StructLayout(LayoutKind.Sequential, Pack = 1)]
161 protected struct DriverStatus {
162 public byte DriverError;
163 public byte IDEError;
164 [MarshalAs(UnmanagedType.ByValArray, SizeConst = 10)]
165 public byte[] Reserved;
168 [StructLayout(LayoutKind.Sequential, Pack = 1)]
169 protected struct DriveCommandResult {
170 public uint BufferSize;
171 public DriverStatus DriverStatus;
174 [StructLayout(LayoutKind.Sequential, Pack = 1)]
175 protected struct DriveSmartReadResult {
176 public uint BufferSize;
177 public DriverStatus DriverStatus;
179 public byte Reserved;
180 [MarshalAs(UnmanagedType.ByValArray, SizeConst = MAX_DRIVE_ATTRIBUTES)]
181 public DriveAttribute[] Attributes;
184 [StructLayout(LayoutKind.Sequential, Pack = 1)]
185 protected struct Identify {
186 public ushort GeneralConfiguration;
187 public ushort NumberOfCylinders;
188 public ushort Reserved;
189 public ushort NumberOfHeads;
190 public ushort UnformattedBytesPerTrack;
191 public ushort UnformattedBytesPerSector;
192 public ushort SectorsPerTrack;
193 [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)]
194 public ushort[] VendorUnique;
195 [MarshalAs(UnmanagedType.ByValArray, SizeConst = 20)]
196 public byte[] SerialNumber;
197 public ushort BufferType;
198 public ushort BufferSectorSize;
199 public ushort NumberOfEccBytes;
200 [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)]
201 public byte[] FirmwareRevision;
202 [MarshalAs(UnmanagedType.ByValArray, SizeConst = 40)]
203 public byte[] ModelNumber;
204 public ushort MoreVendorUnique;
205 public ushort DoubleWordIo;
206 public ushort Capabilities;
207 public ushort MoreReserved;
208 public ushort PioCycleTimingMode;
209 public ushort DmaCycleTimingMode;
210 [MarshalAs(UnmanagedType.ByValArray, SizeConst = 406)]
214 [StructLayout(LayoutKind.Sequential, Pack = 1)]
215 protected struct DriveIdentifyResult {
216 public uint BufferSize;
217 public DriverStatus DriverStatus;
218 public Identify Identify;
221 public static readonly IntPtr INVALID_HANDLE_VALUE = (IntPtr)(-1);
223 private const byte SMART_CMD = 0xB0;
224 private const byte ID_CMD = 0xEC;
226 private const byte SMART_READ_DATA = 0xD0;
227 private const byte SMART_ENABLE_OPERATIONS = 0xD8;
229 private const byte SMART_LBA_MID = 0x4F;
230 private const byte SMART_LBA_HI = 0xC2;
232 private const int MAX_DRIVE_ATTRIBUTES = 512;
236 public static IntPtr OpenPhysicalDrive(int driveNumber) {
237 return NativeMethods.CreateFile(@"\\.\PhysicalDrive" + driveNumber,
238 AccessMode.Read | AccessMode.Write, ShareMode.Read | ShareMode.Write,
239 IntPtr.Zero, CreationMode.OpenExisting, FileAttribute.Device,
243 public static bool EnableSmart(IntPtr handle, int driveNumber) {
244 DriveCommandParameter parameter = new DriveCommandParameter();
245 DriveCommandResult result;
248 parameter.DriveNumber = (byte)driveNumber;
249 parameter.Registers.Features = SMART_ENABLE_OPERATIONS;
250 parameter.Registers.LBAMid = SMART_LBA_MID;
251 parameter.Registers.LBAHigh = SMART_LBA_HI;
252 parameter.Registers.Command = SMART_CMD;
254 return NativeMethods.DeviceIoControl(handle, DriveCommand.SendDriveCommand,
255 ref parameter, Marshal.SizeOf(typeof(DriveCommandParameter)), out result,
256 Marshal.SizeOf(typeof(DriveCommandResult)), out bytesReturned,
260 public static DriveAttribute[] ReadSmart(IntPtr handle, int driveNumber) {
261 DriveCommandParameter parameter = new DriveCommandParameter();
262 DriveSmartReadResult result;
265 parameter.DriveNumber = (byte)driveNumber;
266 parameter.Registers.Features = SMART_READ_DATA;
267 parameter.Registers.LBAMid = SMART_LBA_MID;
268 parameter.Registers.LBAHigh = SMART_LBA_HI;
269 parameter.Registers.Command = SMART_CMD;
271 bool valid = NativeMethods.DeviceIoControl(handle,
272 DriveCommand.ReceiveDriveData, ref parameter, Marshal.SizeOf(parameter),
273 out result, Marshal.SizeOf(typeof(DriveSmartReadResult)),
274 out bytesReturned, IntPtr.Zero);
279 return result.Attributes;
282 public static string ReadName(IntPtr handle, int driveNumber) {
283 DriveCommandParameter parameter = new DriveCommandParameter();
284 DriveIdentifyResult result;
287 parameter.DriveNumber = (byte)driveNumber;
288 parameter.Registers.Command = ID_CMD;
290 bool valid = NativeMethods.DeviceIoControl(handle,
291 DriveCommand.ReceiveDriveData, ref parameter, Marshal.SizeOf(parameter),
292 out result, Marshal.SizeOf(typeof(DriveIdentifyResult)),
293 out bytesReturned, IntPtr.Zero);
299 byte[] bytes = result.Identify.ModelNumber;
300 char[] chars = new char[bytes.Length];
301 for (int i = 0; i < bytes.Length; i += 2) {
302 chars[i] = (char)bytes[i + 1];
303 chars[i + 1] = (char)bytes[i];
306 return new string(chars).Trim();
310 public static int CloseHandle(IntPtr handle) {
311 return NativeMethods.CloseHandle(handle);
314 protected static class NativeMethods {
315 private const string KERNEL = "kernel32.dll";
317 [DllImport(KERNEL, CallingConvention = CallingConvention.Winapi,
318 CharSet = CharSet.Unicode)]
319 public static extern IntPtr CreateFile(string fileName,
320 AccessMode desiredAccess, ShareMode shareMode, IntPtr securityAttributes,
321 CreationMode creationDisposition, FileAttribute flagsAndAttributes,
322 IntPtr templateFilehandle);
324 [DllImport(KERNEL, CallingConvention = CallingConvention.Winapi)]
325 public static extern int CloseHandle(IntPtr handle);
327 [DllImport(KERNEL, CallingConvention = CallingConvention.Winapi)]
328 [return: MarshalAsAttribute(UnmanagedType.Bool)]
329 public static extern bool DeviceIoControl(IntPtr handle,
330 DriveCommand command, ref DriveCommandParameter parameter,
331 int parameterSize, out DriveSmartReadResult result, int resultSize,
332 out uint bytesReturned, IntPtr overlapped);
334 [DllImport(KERNEL, CallingConvention = CallingConvention.Winapi)]
335 [return: MarshalAsAttribute(UnmanagedType.Bool)]
336 public static extern bool DeviceIoControl(IntPtr handle,
337 DriveCommand command, ref DriveCommandParameter parameter,
338 int parameterSize, out DriveCommandResult result, int resultSize,
339 out uint bytesReturned, IntPtr overlapped);
341 [DllImport(KERNEL, CallingConvention = CallingConvention.Winapi)]
342 [return: MarshalAsAttribute(UnmanagedType.Bool)]
343 public static extern bool DeviceIoControl(IntPtr handle,
344 DriveCommand command, ref DriveCommandParameter parameter,
345 int parameterSize, out DriveIdentifyResult result, int resultSize,
346 out uint bytesReturned, IntPtr overlapped);