diff --git a/DiscImageChef.Devices/Command.cs b/DiscImageChef.Devices/Command.cs
index 96f0781fb..239cc3806 100644
--- a/DiscImageChef.Devices/Command.cs
+++ b/DiscImageChef.Devices/Command.cs
@@ -144,6 +144,23 @@ namespace DiscImageChef.Devices
{
case Interop.PlatformID.Win32NT:
{
+ if(
+ ( // Windows XP <= SP1
+ Environment.OSVersion.Version.Major == 5 &&
+ Environment.OSVersion.Version.Minor == 1 &&
+ (Environment.OSVersion.ServicePack == "Service Pack 1" || Environment.OSVersion.ServicePack == "")) ||
+ ( // Windows 2000
+ Environment.OSVersion.Version.Major == 5 &&
+ Environment.OSVersion.Version.Minor == 0)
+ )
+ return Windows.Command.SendIdeCommand((SafeFileHandle)fd, registers, out errorRegisters,
+ protocol, ref buffer, timeout, out duration, out sense);
+ // Windows NT 4 or earlier, requires special ATA pass thru SCSI. But DiscImageChef cannot run there (or can it?)
+ if(
+ Environment.OSVersion.Version.Major <= 4
+ )
+ throw new InvalidOperationException("Windows NT 4.0 or earlier is not supported.");
+
return Windows.Command.SendAtaCommand((SafeFileHandle)fd, registers, out errorRegisters,
protocol, ref buffer, timeout, out duration, out sense);
}
@@ -177,6 +194,23 @@ namespace DiscImageChef.Devices
{
case Interop.PlatformID.Win32NT:
{
+ if(
+ ( // Windows XP <= SP1
+ Environment.OSVersion.Version.Major == 5 &&
+ Environment.OSVersion.Version.Minor == 1 &&
+ (Environment.OSVersion.ServicePack == "Service Pack 1" || Environment.OSVersion.ServicePack == "")) ||
+ ( // Windows 2000
+ Environment.OSVersion.Version.Major == 5 &&
+ Environment.OSVersion.Version.Minor == 0)
+ )
+ return Windows.Command.SendIdeCommand((SafeFileHandle)fd, registers, out errorRegisters,
+ protocol, ref buffer, timeout, out duration, out sense);
+ // Windows NT 4 or earlier, requires special ATA pass thru SCSI. But DiscImageChef cannot run there (or can it?)
+ if(
+ Environment.OSVersion.Version.Major <= 4
+ )
+ throw new InvalidOperationException("Windows NT 4.0 or earlier is not supported.");
+
return Windows.Command.SendAtaCommand((SafeFileHandle)fd, registers, out errorRegisters,
protocol, ref buffer, timeout, out duration, out sense);
}
@@ -210,6 +244,7 @@ namespace DiscImageChef.Devices
{
case Interop.PlatformID.Win32NT:
{
+ // No check for Windows version. A 48-bit ATA disk simply does not work on earlier systems
return Windows.Command.SendAtaCommand((SafeFileHandle)fd, registers, out errorRegisters,
protocol, ref buffer, timeout, out duration, out sense);
}
diff --git a/DiscImageChef.Devices/Windows/Command.cs b/DiscImageChef.Devices/Windows/Command.cs
index 425a7c580..3452f4989 100644
--- a/DiscImageChef.Devices/Windows/Command.cs
+++ b/DiscImageChef.Devices/Windows/Command.cs
@@ -363,6 +363,124 @@ namespace DiscImageChef.Devices.Windows
return error;
}
+
+ internal static int SendIdeCommand(SafeFileHandle fd, AtaRegistersCHS registers, out AtaErrorRegistersCHS errorRegisters,
+ AtaProtocol protocol, ref byte[] buffer, uint timeout, out double duration, out bool sense)
+ {
+ duration = 0;
+ sense = false;
+ errorRegisters = new AtaErrorRegistersCHS();
+
+ if(buffer == null || buffer.Length > 512)
+ return -1;
+
+ IdePassThroughDirect iptd = new IdePassThroughDirect
+ {
+ CurrentTaskFile = new AtaTaskFile
+ {
+ Command = registers.command,
+ CylinderHigh = registers.cylinderHigh,
+ CylinderLow = registers.cylinderLow,
+ DeviceHead = registers.deviceHead,
+ Features = registers.feature,
+ SectorCount = registers.sectorCount,
+ SectorNumber = registers.sector
+ },
+ DataBufferSize = 512,
+ DataBuffer = new byte[512],
+ };
+
+ uint k = 0;
+ int error = 0;
+
+ Array.Copy(buffer, 0, iptd.DataBuffer, 0, buffer.Length);
+
+ DateTime start = DateTime.Now;
+ sense = !Extern.DeviceIoControlIde(fd, WindowsIoctl.IOCTL_IDE_PASS_THROUGH, ref iptd, (uint)Marshal.SizeOf(iptd), ref iptd,
+ (uint)Marshal.SizeOf(iptd), ref k, IntPtr.Zero);
+ DateTime end = DateTime.Now;
+
+ if(sense)
+ error = Marshal.GetLastWin32Error();
+
+ buffer = new byte[k - 12];
+ Array.Copy(iptd.DataBuffer, 0, buffer, 0, buffer.Length);
+
+ duration = (end - start).TotalMilliseconds;
+
+ errorRegisters.command = iptd.CurrentTaskFile.Command;
+ errorRegisters.cylinderHigh = iptd.CurrentTaskFile.CylinderHigh;
+ errorRegisters.cylinderLow = iptd.CurrentTaskFile.CylinderLow;
+ errorRegisters.deviceHead = iptd.CurrentTaskFile.DeviceHead;
+ errorRegisters.error = iptd.CurrentTaskFile.Error;
+ errorRegisters.sector = iptd.CurrentTaskFile.SectorNumber;
+ errorRegisters.sectorCount = iptd.CurrentTaskFile.SectorCount;
+ errorRegisters.status = iptd.CurrentTaskFile.Status;
+
+ sense = errorRegisters.error != 0 || (errorRegisters.status & 0xA5) != 0;
+
+ return error;
+ }
+
+ internal static int SendIdeCommand(SafeFileHandle fd, AtaRegistersLBA28 registers, out AtaErrorRegistersLBA28 errorRegisters,
+ AtaProtocol protocol, ref byte[] buffer, uint timeout, out double duration, out bool sense)
+ {
+ duration = 0;
+ sense = false;
+ errorRegisters = new AtaErrorRegistersLBA28();
+
+ if(buffer == null)
+ return -1;
+
+ uint offsetForBuffer = (uint)(Marshal.SizeOf(typeof(AtaPassThroughDirect)) + Marshal.SizeOf(typeof(uint)));
+
+ IdePassThroughDirect iptd = new IdePassThroughDirect
+ {
+ CurrentTaskFile = new AtaTaskFile
+ {
+ Command = registers.command,
+ CylinderHigh = registers.lbaHigh,
+ CylinderLow = registers.lbaMid,
+ DeviceHead = registers.deviceHead,
+ Features = registers.feature,
+ SectorCount = registers.sectorCount,
+ SectorNumber = registers.lbaLow
+ },
+ DataBufferSize = 512,
+ DataBuffer = new byte[512],
+ };
+
+ uint k = 0;
+ int error = 0;
+
+ Array.Copy(buffer, 0, iptd.DataBuffer, 0, buffer.Length);
+
+ DateTime start = DateTime.Now;
+ sense = !Extern.DeviceIoControlIde(fd, WindowsIoctl.IOCTL_IDE_PASS_THROUGH, ref iptd, (uint)Marshal.SizeOf(iptd), ref iptd,
+ (uint)Marshal.SizeOf(iptd), ref k, IntPtr.Zero);
+ DateTime end = DateTime.Now;
+
+ if(sense)
+ error = Marshal.GetLastWin32Error();
+
+ buffer = new byte[k - 12];
+ Array.Copy(iptd.DataBuffer, 0, buffer, 0, buffer.Length);
+
+ duration = (end - start).TotalMilliseconds;
+
+ errorRegisters.command = iptd.CurrentTaskFile.Command;
+ errorRegisters.lbaHigh = iptd.CurrentTaskFile.CylinderHigh;
+ errorRegisters.lbaMid = iptd.CurrentTaskFile.CylinderLow;
+ errorRegisters.deviceHead = iptd.CurrentTaskFile.DeviceHead;
+ errorRegisters.error = iptd.CurrentTaskFile.Error;
+ errorRegisters.lbaLow = iptd.CurrentTaskFile.SectorNumber;
+ errorRegisters.sectorCount = iptd.CurrentTaskFile.SectorCount;
+ errorRegisters.status = iptd.CurrentTaskFile.Status;
+
+ sense = errorRegisters.error != 0 || (errorRegisters.status & 0xA5) != 0;
+
+ return error;
+ }
}
}
diff --git a/DiscImageChef.Devices/Windows/Enums.cs b/DiscImageChef.Devices/Windows/Enums.cs
index ea39d0c62..5b54fa3bc 100644
--- a/DiscImageChef.Devices/Windows/Enums.cs
+++ b/DiscImageChef.Devices/Windows/Enums.cs
@@ -270,6 +270,7 @@ namespace DiscImageChef.Devices.Windows
///
IOCTL_SCSI_GET_ADDRESS = 0x41018,
IOCTL_STORAGE_QUERY_PROPERTY = 0x2D1400,
+ IOCTL_IDE_PASS_THROUGH = 0x4D028,
}
[Flags]
diff --git a/DiscImageChef.Devices/Windows/Extern.cs b/DiscImageChef.Devices/Windows/Extern.cs
index 4254ea31e..1356d868b 100644
--- a/DiscImageChef.Devices/Windows/Extern.cs
+++ b/DiscImageChef.Devices/Windows/Extern.cs
@@ -84,7 +84,19 @@ namespace DiscImageChef.Devices.Windows
uint nOutBufferSize,
ref uint pBytesReturned,
IntPtr Overlapped
- );
+ );
+
+ [DllImport("Kernel32.dll", SetLastError = true, EntryPoint = "DeviceIoControl", CharSet = CharSet.Auto)]
+ internal static extern bool DeviceIoControlIde(
+ SafeFileHandle hDevice,
+ WindowsIoctl IoControlCode,
+ ref IdePassThroughDirect InBuffer,
+ uint nInBufferSize,
+ ref IdePassThroughDirect OutBuffer,
+ uint nOutBufferSize,
+ ref uint pBytesReturned,
+ IntPtr Overlapped
+ );
[DllImport("Kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)]
internal static extern bool CloseHandle(SafeFileHandle hDevice);
diff --git a/DiscImageChef.Devices/Windows/Structs.cs b/DiscImageChef.Devices/Windows/Structs.cs
index 231bbcf19..c107fd6f8 100644
--- a/DiscImageChef.Devices/Windows/Structs.cs
+++ b/DiscImageChef.Devices/Windows/Structs.cs
@@ -194,5 +194,23 @@ namespace DiscImageChef.Devices.Windows
public uint RawPropertiesLength;
public byte[] RawDeviceProperties;
}
+
+ [StructLayout(LayoutKind.Sequential)]
+ struct IdePassThroughDirect
+ {
+ ///
+ /// ATA registers
+ ///
+ public AtaTaskFile CurrentTaskFile;
+ ///
+ /// Size of data buffer
+ ///
+ public uint DataBufferSize;
+ ///
+ /// Data buffer
+ ///
+ [MarshalAs(UnmanagedType.ByValArray, SizeConst = 512)]
+ public byte[] DataBuffer;
+ }
}