Refactored the hardware monitoring code into a library (Issue 101).
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.Collections.Generic;
40 using System.Runtime.InteropServices;
42 namespace OpenHardwareMonitor.Hardware.HDD {
44 internal class SMART {
47 public enum Status : ushort {
48 PreFailureWarranty = 0x01,
49 OnLineCollection = 0x02,
56 public enum AttributeID : byte {
58 ThroughputPerformance = 0x02,
60 StartStopCount = 0x04,
61 ReallocatedSectorsCount = 0x05,
62 ReadChannelMargin = 0x06,
64 SeekTimePerformance = 0x08,
66 SpinRetryCount = 0x0A,
67 RecalibrationRetries = 0x0B,
68 PowerCycleCount = 0x0C,
69 SoftReadErrorRate = 0x0D,
70 AirflowTemperature = 0xBE,
72 HardwareECCRecovered = 0xC3,
73 ReallocationEventCount = 0xC4,
74 CurrentPendingSectorCount = 0xC5,
75 UncorrectableSectorCount = 0xC6,
76 UltraDMACRCErrorCount = 0xC7,
77 WriteErrorRate = 0xC8,
78 DriveTemperature = 0xE7
81 [StructLayout(LayoutKind.Sequential, Pack = 1)]
82 public struct DriveAttribute {
83 public AttributeID ID;
84 public Status StatusFlags;
85 public byte AttrValue;
86 public byte WorstValue;
87 [MarshalAs(UnmanagedType.ByValArray, SizeConst = 6)]
88 public byte[] RawValue;
93 private enum AccessMode : uint {
101 private enum ShareMode : uint {
108 private enum CreationMode : uint {
117 private enum FileAttribute : uint {
118 Readonly = 0x00000001,
121 Directory = 0x00000010,
122 Archive = 0x00000020,
125 Temporary = 0x00000100,
126 SparseFile = 0x00000200,
127 ReparsePoint = 0x00000400,
128 Compressed = 0x00000800,
129 Offline = 0x00001000,
130 NotContentIndexed = 0x00002000,
131 Encrypted = 0x00004000,
134 private enum DriveCommand : uint {
135 GetVersion = 0x00074080,
136 SendDriveCommand = 0x0007c084,
137 ReceiveDriveData = 0x0007c088
140 [StructLayout(LayoutKind.Sequential, Pack = 1)]
141 private struct CommandBlockRegisters {
142 public byte Features;
143 public byte SectorCount;
149 public byte Reserved;
152 [StructLayout(LayoutKind.Sequential, Pack = 1)]
153 private struct DriveCommandParameter {
154 private uint BufferSize;
155 public CommandBlockRegisters Registers;
156 public byte DriveNumber;
157 [MarshalAs(UnmanagedType.ByValArray, SizeConst = 19)]
158 public byte[] Reserved;
161 [StructLayout(LayoutKind.Sequential, Pack = 1)]
162 private struct DriverStatus {
163 public byte DriverError;
164 public byte IDEError;
165 [MarshalAs(UnmanagedType.ByValArray, SizeConst = 10)]
166 public byte[] Reserved;
169 [StructLayout(LayoutKind.Sequential, Pack = 1)]
170 private struct DriveCommandResult {
171 public uint BufferSize;
172 public DriverStatus DriverStatus;
175 [StructLayout(LayoutKind.Sequential, Pack = 1)]
176 private struct DriveSmartReadResult {
177 public uint BufferSize;
178 public DriverStatus DriverStatus;
180 public byte Reserved;
181 [MarshalAs(UnmanagedType.ByValArray, SizeConst = MAX_DRIVE_ATTRIBUTES)]
182 public DriveAttribute[] Attributes;
185 [StructLayout(LayoutKind.Sequential, Pack = 1)]
186 private struct Identify {
187 public ushort GeneralConfiguration;
188 public ushort NumberOfCylinders;
189 public ushort Reserved;
190 public ushort NumberOfHeads;
191 public ushort UnformattedBytesPerTrack;
192 public ushort UnformattedBytesPerSector;
193 public ushort SectorsPerTrack;
194 [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)]
195 public ushort[] VendorUnique;
196 [MarshalAs(UnmanagedType.ByValArray, SizeConst = 20)]
197 public byte[] SerialNumber;
198 public ushort BufferType;
199 public ushort BufferSectorSize;
200 public ushort NumberOfEccBytes;
201 [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)]
202 public byte[] FirmwareRevision;
203 [MarshalAs(UnmanagedType.ByValArray, SizeConst = 40)]
204 public byte[] ModelNumber;
205 public ushort MoreVendorUnique;
206 public ushort DoubleWordIo;
207 public ushort Capabilities;
208 public ushort MoreReserved;
209 public ushort PioCycleTimingMode;
210 public ushort DmaCycleTimingMode;
211 [MarshalAs(UnmanagedType.ByValArray, SizeConst = 406)]
215 [StructLayout(LayoutKind.Sequential, Pack = 1)]
216 private struct DriveIdentifyResult {
217 public uint BufferSize;
218 public DriverStatus DriverStatus;
219 public Identify Identify;
222 public static readonly IntPtr INVALID_HANDLE_VALUE = (IntPtr)(-1);
224 private const byte SMART_CMD = 0xB0;
225 private const byte ID_CMD = 0xEC;
227 private const byte SMART_READ_DATA = 0xD0;
228 private const byte SMART_ENABLE_OPERATIONS = 0xD8;
230 private const byte SMART_LBA_MID = 0x4F;
231 private const byte SMART_LBA_HI = 0xC2;
233 private const int MAX_DRIVE_ATTRIBUTES = 512;
235 private const string KERNEL = "kernel32.dll";
237 [DllImport(KERNEL, CallingConvention = CallingConvention.Winapi)]
238 private static extern IntPtr CreateFile(string fileName,
239 AccessMode desiredAccess, ShareMode shareMode, IntPtr securityAttributes,
240 CreationMode creationDisposition, FileAttribute flagsAndAttributes,
241 IntPtr templateFilehandle);
243 [DllImport(KERNEL, CallingConvention = CallingConvention.Winapi)]
244 public static extern int CloseHandle(IntPtr handle);
246 [DllImport(KERNEL, CallingConvention = CallingConvention.Winapi)]
247 private static extern bool DeviceIoControl(IntPtr handle,
248 DriveCommand command, ref DriveCommandParameter parameter,
249 int parameterSize, out DriveSmartReadResult result, int resultSize,
250 out uint bytesReturned, IntPtr overlapped);
252 [DllImport(KERNEL, CallingConvention = CallingConvention.Winapi)]
253 private static extern bool DeviceIoControl(IntPtr handle,
254 DriveCommand command, ref DriveCommandParameter parameter,
255 int parameterSize, out DriveCommandResult result, int resultSize,
256 out uint bytesReturned, IntPtr overlapped);
258 [DllImport(KERNEL, CallingConvention = CallingConvention.Winapi)]
259 private static extern bool DeviceIoControl(IntPtr handle,
260 DriveCommand command, ref DriveCommandParameter parameter,
261 int parameterSize, out DriveIdentifyResult result, int resultSize,
262 out uint bytesReturned, IntPtr overlapped);
264 public static IntPtr OpenPhysicalDrive(int driveNumber) {
265 return CreateFile(@"\\.\PhysicalDrive" + driveNumber,
266 AccessMode.Read | AccessMode.Write, ShareMode.Read | ShareMode.Write,
267 IntPtr.Zero, CreationMode.OpenExisting, FileAttribute.Device,
271 public static bool EnableSmart(IntPtr handle, int driveNumber) {
272 DriveCommandParameter parameter = new DriveCommandParameter();
273 DriveCommandResult result;
276 parameter.DriveNumber = (byte)driveNumber;
277 parameter.Registers.Features = SMART_ENABLE_OPERATIONS;
278 parameter.Registers.LBAMid = SMART_LBA_MID;
279 parameter.Registers.LBAHigh = SMART_LBA_HI;
280 parameter.Registers.Command = SMART_CMD;
282 return DeviceIoControl(handle, DriveCommand.SendDriveCommand,
283 ref parameter, Marshal.SizeOf(parameter), out result,
284 Marshal.SizeOf(typeof(DriveCommandResult)), out bytesReturned,
288 public static DriveAttribute[] ReadSmart(IntPtr handle, int driveNumber) {
289 DriveCommandParameter parameter = new DriveCommandParameter();
290 DriveSmartReadResult result;
293 parameter.DriveNumber = (byte)driveNumber;
294 parameter.Registers.Features = SMART_READ_DATA;
295 parameter.Registers.LBAMid = SMART_LBA_MID;
296 parameter.Registers.LBAHigh = SMART_LBA_HI;
297 parameter.Registers.Command = SMART_CMD;
299 bool valid = DeviceIoControl(handle, DriveCommand.ReceiveDriveData,
300 ref parameter, Marshal.SizeOf(parameter), out result,
301 Marshal.SizeOf(typeof(DriveSmartReadResult)), out bytesReturned,
307 return result.Attributes;
310 public static string ReadName(IntPtr handle, int driveNumber) {
311 DriveCommandParameter parameter = new DriveCommandParameter();
312 DriveIdentifyResult result;
315 parameter.DriveNumber = (byte)driveNumber;
316 parameter.Registers.Command = ID_CMD;
318 bool valid = DeviceIoControl(handle, DriveCommand.ReceiveDriveData,
319 ref parameter, Marshal.SizeOf(parameter), out result,
320 Marshal.SizeOf(typeof(DriveIdentifyResult)), out bytesReturned,
327 byte[] bytes = result.Identify.ModelNumber;
328 char[] chars = new char[bytes.Length];
329 for (int i = 0; i < bytes.Length; i += 2) {
330 chars[i] = (char)bytes[i + 1];
331 chars[i + 1] = (char)bytes[i];
334 return new string(chars).Trim();