Use APTD to communicate with ATA devices in Windows.

This commit is contained in:
2021-09-15 23:55:06 +01:00
parent aba2e7fb9f
commit 0847dafd7d
3 changed files with 115 additions and 137 deletions

View File

@@ -136,15 +136,11 @@ namespace Aaru.Devices.Windows
if(buffer == null) if(buffer == null)
return -1; return -1;
uint offsetForBuffer = (uint)(Marshal.SizeOf(typeof(AtaPassThroughEx)) + Marshal.SizeOf(typeof(uint))); var aptd = new AtaPassThroughDirect
var aptdBuf = new AtaPassThroughExBuffer
{
aptd = new AtaPassThroughEx
{ {
TimeOutValue = timeout, TimeOutValue = timeout,
DataBufferOffset = (IntPtr)offsetForBuffer, DataBuffer = Marshal.AllocHGlobal(buffer.Length),
Length = (ushort)Marshal.SizeOf(typeof(AtaPassThroughEx)), Length = (ushort)Marshal.SizeOf(typeof(AtaPassThroughDirect)),
DataTransferLength = (uint)buffer.Length, DataTransferLength = (uint)buffer.Length,
PreviousTaskFile = new AtaTaskFile(), PreviousTaskFile = new AtaTaskFile(),
CurrentTaskFile = new AtaTaskFile CurrentTaskFile = new AtaTaskFile
@@ -157,8 +153,6 @@ namespace Aaru.Devices.Windows
SectorCount = registers.SectorCount, SectorCount = registers.SectorCount,
SectorNumber = registers.Sector SectorNumber = registers.Sector
} }
},
dataBuffer = new byte[64 * 512]
}; };
switch(protocol) switch(protocol)
@@ -166,12 +160,12 @@ namespace Aaru.Devices.Windows
case AtaProtocol.PioIn: case AtaProtocol.PioIn:
case AtaProtocol.UDmaIn: case AtaProtocol.UDmaIn:
case AtaProtocol.Dma: case AtaProtocol.Dma:
aptdBuf.aptd.AtaFlags = AtaFlags.DataIn; aptd.AtaFlags = AtaFlags.DataIn;
break; break;
case AtaProtocol.PioOut: case AtaProtocol.PioOut:
case AtaProtocol.UDmaOut: case AtaProtocol.UDmaOut:
aptdBuf.aptd.AtaFlags = AtaFlags.DataOut; aptd.AtaFlags = AtaFlags.DataOut;
break; break;
} }
@@ -183,44 +177,46 @@ namespace Aaru.Devices.Windows
case AtaProtocol.FpDma: case AtaProtocol.FpDma:
case AtaProtocol.UDmaIn: case AtaProtocol.UDmaIn:
case AtaProtocol.UDmaOut: case AtaProtocol.UDmaOut:
aptdBuf.aptd.AtaFlags |= AtaFlags.Dma; aptd.AtaFlags |= AtaFlags.Dma;
break; break;
} }
// Unknown if needed // Unknown if needed
aptdBuf.aptd.AtaFlags |= AtaFlags.DrdyRequired; aptd.AtaFlags |= AtaFlags.DrdyRequired;
uint k = 0; uint k = 0;
int error = 0; int error = 0;
Array.Copy(buffer, 0, aptdBuf.dataBuffer, 0, buffer.Length); Marshal.Copy(buffer, 0, aptd.DataBuffer, buffer.Length);
DateTime start = DateTime.Now; DateTime start = DateTime.Now;
sense = !Extern.DeviceIoControlAta(fd, WindowsIoctl.IoctlAtaPassThrough, ref aptdBuf, sense = !Extern.DeviceIoControlAta(fd, WindowsIoctl.IoctlAtaPassThroughDirect, ref aptd,
(uint)Marshal.SizeOf(aptdBuf), ref aptdBuf, (uint)Marshal.SizeOf(aptd), ref aptd, (uint)Marshal.SizeOf(aptd), ref k,
(uint)Marshal.SizeOf(aptdBuf), ref k, IntPtr.Zero); IntPtr.Zero);
DateTime end = DateTime.Now; DateTime end = DateTime.Now;
if(sense) if(sense)
error = Marshal.GetLastWin32Error(); error = Marshal.GetLastWin32Error();
Array.Copy(aptdBuf.dataBuffer, 0, buffer, 0, buffer.Length); Marshal.Copy(aptd.DataBuffer, buffer, 0, buffer.Length);
duration = (end - start).TotalMilliseconds; duration = (end - start).TotalMilliseconds;
errorRegisters.CylinderHigh = aptdBuf.aptd.CurrentTaskFile.CylinderHigh; errorRegisters.CylinderHigh = aptd.CurrentTaskFile.CylinderHigh;
errorRegisters.CylinderLow = aptdBuf.aptd.CurrentTaskFile.CylinderLow; errorRegisters.CylinderLow = aptd.CurrentTaskFile.CylinderLow;
errorRegisters.DeviceHead = aptdBuf.aptd.CurrentTaskFile.DeviceHead; errorRegisters.DeviceHead = aptd.CurrentTaskFile.DeviceHead;
errorRegisters.Error = aptdBuf.aptd.CurrentTaskFile.Error; errorRegisters.Error = aptd.CurrentTaskFile.Error;
errorRegisters.Sector = aptdBuf.aptd.CurrentTaskFile.SectorNumber; errorRegisters.Sector = aptd.CurrentTaskFile.SectorNumber;
errorRegisters.SectorCount = aptdBuf.aptd.CurrentTaskFile.SectorCount; errorRegisters.SectorCount = aptd.CurrentTaskFile.SectorCount;
errorRegisters.Status = aptdBuf.aptd.CurrentTaskFile.Status; errorRegisters.Status = aptd.CurrentTaskFile.Status;
sense = errorRegisters.Error != 0 || (errorRegisters.Status & 0xA5) != 0; sense = errorRegisters.Error != 0 || (errorRegisters.Status & 0xA5) != 0;
Marshal.FreeHGlobal(aptd.DataBuffer);
return error; return error;
} }
@@ -245,15 +241,11 @@ namespace Aaru.Devices.Windows
if(buffer == null) if(buffer == null)
return -1; return -1;
uint offsetForBuffer = (uint)(Marshal.SizeOf(typeof(AtaPassThroughEx)) + Marshal.SizeOf(typeof(uint))); var aptd = new AtaPassThroughDirect
var aptdBuf = new AtaPassThroughExBuffer
{
aptd = new AtaPassThroughEx
{ {
TimeOutValue = timeout, TimeOutValue = timeout,
DataBufferOffset = (IntPtr)offsetForBuffer, DataBuffer = Marshal.AllocHGlobal(buffer.Length),
Length = (ushort)Marshal.SizeOf(typeof(AtaPassThroughEx)), Length = (ushort)Marshal.SizeOf(typeof(AtaPassThroughDirect)),
DataTransferLength = (uint)buffer.Length, DataTransferLength = (uint)buffer.Length,
PreviousTaskFile = new AtaTaskFile(), PreviousTaskFile = new AtaTaskFile(),
CurrentTaskFile = new AtaTaskFile CurrentTaskFile = new AtaTaskFile
@@ -266,8 +258,6 @@ namespace Aaru.Devices.Windows
SectorCount = registers.SectorCount, SectorCount = registers.SectorCount,
SectorNumber = registers.LbaLow SectorNumber = registers.LbaLow
} }
},
dataBuffer = new byte[64 * 512]
}; };
switch(protocol) switch(protocol)
@@ -275,12 +265,12 @@ namespace Aaru.Devices.Windows
case AtaProtocol.PioIn: case AtaProtocol.PioIn:
case AtaProtocol.UDmaIn: case AtaProtocol.UDmaIn:
case AtaProtocol.Dma: case AtaProtocol.Dma:
aptdBuf.aptd.AtaFlags = AtaFlags.DataIn; aptd.AtaFlags = AtaFlags.DataIn;
break; break;
case AtaProtocol.PioOut: case AtaProtocol.PioOut:
case AtaProtocol.UDmaOut: case AtaProtocol.UDmaOut:
aptdBuf.aptd.AtaFlags = AtaFlags.DataOut; aptd.AtaFlags = AtaFlags.DataOut;
break; break;
} }
@@ -292,44 +282,46 @@ namespace Aaru.Devices.Windows
case AtaProtocol.FpDma: case AtaProtocol.FpDma:
case AtaProtocol.UDmaIn: case AtaProtocol.UDmaIn:
case AtaProtocol.UDmaOut: case AtaProtocol.UDmaOut:
aptdBuf.aptd.AtaFlags |= AtaFlags.Dma; aptd.AtaFlags |= AtaFlags.Dma;
break; break;
} }
// Unknown if needed // Unknown if needed
aptdBuf.aptd.AtaFlags |= AtaFlags.DrdyRequired; aptd.AtaFlags |= AtaFlags.DrdyRequired;
uint k = 0; uint k = 0;
int error = 0; int error = 0;
Array.Copy(buffer, 0, aptdBuf.dataBuffer, 0, buffer.Length); Marshal.Copy(buffer, 0, aptd.DataBuffer, buffer.Length);
DateTime start = DateTime.Now; DateTime start = DateTime.Now;
sense = !Extern.DeviceIoControlAta(fd, WindowsIoctl.IoctlAtaPassThrough, ref aptdBuf, sense = !Extern.DeviceIoControlAta(fd, WindowsIoctl.IoctlAtaPassThroughDirect, ref aptd,
(uint)Marshal.SizeOf(aptdBuf), ref aptdBuf, (uint)Marshal.SizeOf(aptd), ref aptd, (uint)Marshal.SizeOf(aptd), ref k,
(uint)Marshal.SizeOf(aptdBuf), ref k, IntPtr.Zero); IntPtr.Zero);
DateTime end = DateTime.Now; DateTime end = DateTime.Now;
if(sense) if(sense)
error = Marshal.GetLastWin32Error(); error = Marshal.GetLastWin32Error();
Array.Copy(aptdBuf.dataBuffer, 0, buffer, 0, buffer.Length); Marshal.Copy(aptd.DataBuffer, buffer, 0, buffer.Length);
duration = (end - start).TotalMilliseconds; duration = (end - start).TotalMilliseconds;
errorRegisters.LbaHigh = aptdBuf.aptd.CurrentTaskFile.CylinderHigh; errorRegisters.LbaHigh = aptd.CurrentTaskFile.CylinderHigh;
errorRegisters.LbaMid = aptdBuf.aptd.CurrentTaskFile.CylinderLow; errorRegisters.LbaMid = aptd.CurrentTaskFile.CylinderLow;
errorRegisters.DeviceHead = aptdBuf.aptd.CurrentTaskFile.DeviceHead; errorRegisters.DeviceHead = aptd.CurrentTaskFile.DeviceHead;
errorRegisters.Error = aptdBuf.aptd.CurrentTaskFile.Error; errorRegisters.Error = aptd.CurrentTaskFile.Error;
errorRegisters.LbaLow = aptdBuf.aptd.CurrentTaskFile.SectorNumber; errorRegisters.LbaLow = aptd.CurrentTaskFile.SectorNumber;
errorRegisters.SectorCount = aptdBuf.aptd.CurrentTaskFile.SectorCount; errorRegisters.SectorCount = aptd.CurrentTaskFile.SectorCount;
errorRegisters.Status = aptdBuf.aptd.CurrentTaskFile.Status; errorRegisters.Status = aptd.CurrentTaskFile.Status;
sense = errorRegisters.Error != 0 || (errorRegisters.Status & 0xA5) != 0; sense = errorRegisters.Error != 0 || (errorRegisters.Status & 0xA5) != 0;
Marshal.FreeHGlobal(aptd.DataBuffer);
return error; return error;
} }
@@ -354,15 +346,11 @@ namespace Aaru.Devices.Windows
if(buffer == null) if(buffer == null)
return -1; return -1;
uint offsetForBuffer = (uint)(Marshal.SizeOf(typeof(AtaPassThroughEx)) + Marshal.SizeOf(typeof(uint))); var aptd = new AtaPassThroughDirect
var aptdBuf = new AtaPassThroughExBuffer
{
aptd = new AtaPassThroughEx
{ {
TimeOutValue = timeout, TimeOutValue = timeout,
DataBufferOffset = (IntPtr)offsetForBuffer, DataBuffer = Marshal.AllocHGlobal(buffer.Length),
Length = (ushort)Marshal.SizeOf(typeof(AtaPassThroughEx)), Length = (ushort)Marshal.SizeOf(typeof(AtaPassThroughDirect)),
DataTransferLength = (uint)buffer.Length, DataTransferLength = (uint)buffer.Length,
PreviousTaskFile = new AtaTaskFile PreviousTaskFile = new AtaTaskFile
{ {
@@ -382,8 +370,6 @@ namespace Aaru.Devices.Windows
SectorCount = (byte)(registers.SectorCount & 0xFF), SectorCount = (byte)(registers.SectorCount & 0xFF),
SectorNumber = registers.LbaLowCurrent SectorNumber = registers.LbaLowCurrent
} }
},
dataBuffer = new byte[64 * 512]
}; };
switch(protocol) switch(protocol)
@@ -391,12 +377,12 @@ namespace Aaru.Devices.Windows
case AtaProtocol.PioIn: case AtaProtocol.PioIn:
case AtaProtocol.UDmaIn: case AtaProtocol.UDmaIn:
case AtaProtocol.Dma: case AtaProtocol.Dma:
aptdBuf.aptd.AtaFlags = AtaFlags.DataIn; aptd.AtaFlags = AtaFlags.DataIn;
break; break;
case AtaProtocol.PioOut: case AtaProtocol.PioOut:
case AtaProtocol.UDmaOut: case AtaProtocol.UDmaOut:
aptdBuf.aptd.AtaFlags = AtaFlags.DataOut; aptd.AtaFlags = AtaFlags.DataOut;
break; break;
} }
@@ -408,51 +394,53 @@ namespace Aaru.Devices.Windows
case AtaProtocol.FpDma: case AtaProtocol.FpDma:
case AtaProtocol.UDmaIn: case AtaProtocol.UDmaIn:
case AtaProtocol.UDmaOut: case AtaProtocol.UDmaOut:
aptdBuf.aptd.AtaFlags |= AtaFlags.Dma; aptd.AtaFlags |= AtaFlags.Dma;
break; break;
} }
aptdBuf.aptd.AtaFlags |= AtaFlags.ExtendedCommand; aptd.AtaFlags |= AtaFlags.ExtendedCommand;
// Unknown if needed // Unknown if needed
aptdBuf.aptd.AtaFlags |= AtaFlags.DrdyRequired; aptd.AtaFlags |= AtaFlags.DrdyRequired;
uint k = 0; uint k = 0;
int error = 0; int error = 0;
Array.Copy(buffer, 0, aptdBuf.dataBuffer, 0, buffer.Length); Marshal.Copy(buffer, 0, aptd.DataBuffer, buffer.Length);
DateTime start = DateTime.Now; DateTime start = DateTime.Now;
sense = !Extern.DeviceIoControlAta(fd, WindowsIoctl.IoctlAtaPassThrough, ref aptdBuf, sense = !Extern.DeviceIoControlAta(fd, WindowsIoctl.IoctlAtaPassThroughDirect, ref aptd,
(uint)Marshal.SizeOf(aptdBuf), ref aptdBuf, (uint)Marshal.SizeOf(aptd), ref aptd, (uint)Marshal.SizeOf(aptd), ref k,
(uint)Marshal.SizeOf(aptdBuf), ref k, IntPtr.Zero); IntPtr.Zero);
DateTime end = DateTime.Now; DateTime end = DateTime.Now;
if(sense) if(sense)
error = Marshal.GetLastWin32Error(); error = Marshal.GetLastWin32Error();
Array.Copy(aptdBuf.dataBuffer, 0, buffer, 0, buffer.Length); Marshal.Copy(aptd.DataBuffer, buffer, 0, buffer.Length);
duration = (end - start).TotalMilliseconds; duration = (end - start).TotalMilliseconds;
errorRegisters.SectorCount = (ushort)((aptdBuf.aptd.PreviousTaskFile.SectorCount << 8) + errorRegisters.SectorCount = (ushort)((aptd.PreviousTaskFile.SectorCount << 8) +
aptdBuf.aptd.CurrentTaskFile.SectorCount); aptd.CurrentTaskFile.SectorCount);
errorRegisters.LbaLowPrevious = aptdBuf.aptd.PreviousTaskFile.SectorNumber; errorRegisters.LbaLowPrevious = aptd.PreviousTaskFile.SectorNumber;
errorRegisters.LbaMidPrevious = aptdBuf.aptd.PreviousTaskFile.CylinderLow; errorRegisters.LbaMidPrevious = aptd.PreviousTaskFile.CylinderLow;
errorRegisters.LbaHighPrevious = aptdBuf.aptd.PreviousTaskFile.CylinderHigh; errorRegisters.LbaHighPrevious = aptd.PreviousTaskFile.CylinderHigh;
errorRegisters.LbaLowCurrent = aptdBuf.aptd.CurrentTaskFile.SectorNumber; errorRegisters.LbaLowCurrent = aptd.CurrentTaskFile.SectorNumber;
errorRegisters.LbaMidCurrent = aptdBuf.aptd.CurrentTaskFile.CylinderLow; errorRegisters.LbaMidCurrent = aptd.CurrentTaskFile.CylinderLow;
errorRegisters.LbaHighCurrent = aptdBuf.aptd.CurrentTaskFile.CylinderHigh; errorRegisters.LbaHighCurrent = aptd.CurrentTaskFile.CylinderHigh;
errorRegisters.DeviceHead = aptdBuf.aptd.CurrentTaskFile.DeviceHead; errorRegisters.DeviceHead = aptd.CurrentTaskFile.DeviceHead;
errorRegisters.Error = aptdBuf.aptd.CurrentTaskFile.Error; errorRegisters.Error = aptd.CurrentTaskFile.Error;
errorRegisters.Status = aptdBuf.aptd.CurrentTaskFile.Status; errorRegisters.Status = aptd.CurrentTaskFile.Status;
sense = errorRegisters.Error != 0 || (errorRegisters.Status & 0xA5) != 0; sense = errorRegisters.Error != 0 || (errorRegisters.Status & 0xA5) != 0;
Marshal.FreeHGlobal(aptd.DataBuffer);
return error; return error;
} }

View File

@@ -58,8 +58,8 @@ namespace Aaru.Devices.Windows
[DllImport("Kernel32.dll", SetLastError = true, EntryPoint = "DeviceIoControl", CharSet = CharSet.Auto)] [DllImport("Kernel32.dll", SetLastError = true, EntryPoint = "DeviceIoControl", CharSet = CharSet.Auto)]
internal static extern bool DeviceIoControlAta(SafeFileHandle hDevice, WindowsIoctl ioControlCode, internal static extern bool DeviceIoControlAta(SafeFileHandle hDevice, WindowsIoctl ioControlCode,
ref AtaPassThroughExBuffer inBuffer, uint nInBufferSize, ref AtaPassThroughDirect inBuffer, uint nInBufferSize,
ref AtaPassThroughExBuffer outBuffer, uint nOutBufferSize, ref AtaPassThroughDirect outBuffer, uint nOutBufferSize,
ref uint pBytesReturned, IntPtr overlapped); ref uint pBytesReturned, IntPtr overlapped);
[DllImport("Kernel32.dll", SetLastError = true, EntryPoint = "DeviceIoControl", CharSet = CharSet.Auto)] [DllImport("Kernel32.dll", SetLastError = true, EntryPoint = "DeviceIoControl", CharSet = CharSet.Auto)]

View File

@@ -68,7 +68,7 @@ namespace Aaru.Devices.Windows
} }
[StructLayout(LayoutKind.Sequential), SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] [StructLayout(LayoutKind.Sequential), SuppressMessage("ReSharper", "MemberCanBePrivate.Global")]
internal struct AtaPassThroughEx internal struct AtaPassThroughDirect
{ {
/// <summary>Length in bytes of this structure</summary> /// <summary>Length in bytes of this structure</summary>
public ushort Length; public ushort Length;
@@ -98,8 +98,8 @@ namespace Aaru.Devices.Windows
/// <summary>Reserved</summary> /// <summary>Reserved</summary>
public uint ReservedAsUlong; public uint ReservedAsUlong;
/// <summary>Pointer to data buffer relative to start of this structure</summary> /// <summary>Pointer to data buffer</summary>
public IntPtr DataBufferOffset; public IntPtr DataBuffer;
/// <summary>Previous ATA registers, for LBA48</summary> /// <summary>Previous ATA registers, for LBA48</summary>
public AtaTaskFile PreviousTaskFile; public AtaTaskFile PreviousTaskFile;
@@ -108,16 +108,6 @@ namespace Aaru.Devices.Windows
public AtaTaskFile CurrentTaskFile; public AtaTaskFile CurrentTaskFile;
} }
[StructLayout(LayoutKind.Sequential), SuppressMessage("ReSharper", "MemberCanBePrivate.Global")]
internal struct AtaPassThroughExBuffer
{
public AtaPassThroughEx aptd;
public uint filler;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 64 * 512)]
public byte[] dataBuffer;
}
[StructLayout(LayoutKind.Explicit), SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] [StructLayout(LayoutKind.Explicit), SuppressMessage("ReSharper", "MemberCanBePrivate.Global")]
internal struct AtaTaskFile internal struct AtaTaskFile
{ {