Added support for SecureDigital / MultiMediaCard on Windows.

This commit is contained in:
2017-12-06 23:05:59 +00:00
parent d660ec93d1
commit 4cd0ec53e9
6 changed files with 274 additions and 27 deletions

View File

@@ -275,7 +275,7 @@ namespace DiscImageChef.Devices
{
case Interop.PlatformID.Win32NT:
{
throw new NotImplementedException();
return Windows.Command.SendMmcCommand((SafeFileHandle)fd, command, write, isApplication, flags, argument, blockSize, blocks, ref buffer, out response, out duration, out sense, timeout);
}
case Interop.PlatformID.Linux:
{

View File

@@ -203,6 +203,74 @@ namespace DiscImageChef.Devices
ntDevicePath = Windows.Command.GetDevicePath((SafeFileHandle)fd);
DicConsole.DebugWriteLine("Windows devices", "NT device path: {0}", ntDevicePath);
Marshal.FreeHGlobal(descriptorPtr);
if(Windows.Command.IsSdhci((SafeFileHandle)fd))
{
byte[] sdBuffer = new byte[16];
bool sense = false;
lastError = Windows.Command.SendMmcCommand((SafeFileHandle)fd, MmcCommands.SendCSD, false, false, MmcFlags.ResponseSPI_R2 | MmcFlags.Response_R2 | MmcFlags.CommandAC,
0, 16, 1, ref sdBuffer, out uint[] response, out double duration, out sense, 0);
if(!sense)
{
cachedCsd = new byte[16];
Array.Copy(sdBuffer, 0, cachedCsd, 0, 16);
}
sdBuffer = new byte[16];
sense = false;
lastError = Windows.Command.SendMmcCommand((SafeFileHandle)fd, MmcCommands.SendCID, false, false, MmcFlags.ResponseSPI_R2 | MmcFlags.Response_R2 | MmcFlags.CommandAC,
0, 16, 1, ref sdBuffer, out response, out duration, out sense, 0);
if(!sense)
{
cachedCid = new byte[16];
Array.Copy(sdBuffer, 0, cachedCid, 0, 16);
}
sdBuffer = new byte[8];
sense = false;
lastError = Windows.Command.SendMmcCommand((SafeFileHandle)fd, (MmcCommands)SecureDigitalCommands.SendSCR, false, true, MmcFlags.ResponseSPI_R1 | MmcFlags.Response_R1 | MmcFlags.CommandADTC,
0, 8, 1, ref sdBuffer, out response, out duration, out sense, 0);
if(!sense)
{
cachedScr = new byte[8];
Array.Copy(sdBuffer, 0, cachedScr, 0, 8);
}
if(cachedScr != null)
{
sdBuffer = new byte[4];
sense = false;
lastError = Windows.Command.SendMmcCommand((SafeFileHandle)fd, (MmcCommands)SecureDigitalCommands.SendOperatingCondition, false, true, MmcFlags.ResponseSPI_R3 | MmcFlags.Response_R3 | MmcFlags.CommandBCR,
0, 4, 1, ref sdBuffer, out response, out duration, out sense, 0);
if(!sense)
{
cachedScr = new byte[4];
Array.Copy(sdBuffer, 0, cachedScr, 0, 4);
}
}
else
{
sdBuffer = new byte[4];
sense = false;
lastError = Windows.Command.SendMmcCommand((SafeFileHandle)fd, MmcCommands.SendOpCond, false, true, MmcFlags.ResponseSPI_R3 | MmcFlags.Response_R3 | MmcFlags.CommandBCR,
0, 4, 1, ref sdBuffer, out response, out duration, out sense, 0);
if(!sense)
{
cachedScr = new byte[4];
Array.Copy(sdBuffer, 0, cachedScr, 0, 4);
}
}
}
}
else
{
@@ -236,7 +304,10 @@ namespace DiscImageChef.Devices
if(len == 0)
cachedOcr = null;
}
}
}
#region SecureDigital / MultiMediaCard
if(cachedCid != null)
{
scsiType = Decoders.SCSI.PeripheralDeviceTypes.DirectAccess;
@@ -261,8 +332,7 @@ namespace DiscImageChef.Devices
serial = string.Format("{0}", decoded.ProductSerialNumber);
}
}
}
}
#endregion SecureDigital / MultiMediaCard
#region USB

View File

@@ -570,6 +570,91 @@ namespace DiscImageChef.Devices.Windows
Extern.SetupDiDestroyDeviceInfoList(hDevInfo);
return null;
}
internal static bool IsSdhci(SafeFileHandle fd)
{
SffdiskQueryDeviceProtocolData queryData1 = new SffdiskQueryDeviceProtocolData();
queryData1.size = (ushort)Marshal.SizeOf(queryData1);
uint bytesReturned;
Extern.DeviceIoControl(fd, WindowsIoctl.IOCTL_SFFDISK_QUERY_DEVICE_PROTOCOL, IntPtr.Zero, 0,
ref queryData1, queryData1.size, out bytesReturned, IntPtr.Zero);
return queryData1.protocolGuid.Equals(Consts.GUID_SFF_PROTOCOL_SD);
}
/// <summary>
/// Sends a MMC/SD command
/// </summary>
/// <returns>The result of the command.</returns>
/// <param name="fd">File handle</param>
/// <param name="command">MMC/SD opcode</param>
/// <param name="buffer">Buffer for MMC/SD command response</param>
/// <param name="timeout">Timeout in seconds</param>
/// <param name="duration">Time it took to execute the command in milliseconds</param>
/// <param name="sense"><c>True</c> if MMC/SD returned non-OK status</param>
/// <param name="write"><c>True</c> if data is sent from host to card</param>
/// <param name="isApplication"><c>True</c> if command should be preceded with CMD55</param>
/// <param name="flags">Flags indicating kind and place of response</param>
/// <param name="blocks">How many blocks to transfer</param>
/// <param name="argument">Command argument</param>
/// <param name="response">Response registers</param>
/// <param name="blockSize">Size of block in bytes</param>
internal static int SendMmcCommand(SafeFileHandle fd, MmcCommands command, bool write, bool isApplication,
MmcFlags flags, uint argument, uint blockSize, uint blocks, ref byte[] buffer, out uint[] response,
out double duration, out bool sense, uint timeout = 0)
{
SffdiskDeviceCommandData commandData = new SffdiskDeviceCommandData();
SdCmdDescriptor commandDescriptor = new SdCmdDescriptor();
commandData.size = (ushort)Marshal.SizeOf(commandData);
commandData.command = SffdiskDcmd.DeviceCommand;
commandData.protocolArgumentSize = (ushort)Marshal.SizeOf(commandDescriptor);
commandData.deviceDataBufferSize = blockSize * blocks;
commandDescriptor.commandCode = (byte)command;
commandDescriptor.cmdClass = isApplication ? SdCommandClass.AppCmd : SdCommandClass.Standard;
commandDescriptor.transferDirection = write ? SdTransferDirection.Write : SdTransferDirection.Read;
commandDescriptor.transferType = flags.HasFlag(MmcFlags.CommandADTC) ? SdTransferType.SingleBlock : SdTransferType.CmdOnly;
commandDescriptor.responseType = 0;
if(flags.HasFlag(MmcFlags.Response_R1) || flags.HasFlag(MmcFlags.ResponseSPI_R1))
commandDescriptor.responseType = SdResponseType.R1;
if(flags.HasFlag(MmcFlags.Response_R1b) || flags.HasFlag(MmcFlags.ResponseSPI_R1b))
commandDescriptor.responseType = SdResponseType.R1b;
if(flags.HasFlag(MmcFlags.Response_R2) || flags.HasFlag(MmcFlags.ResponseSPI_R2))
commandDescriptor.responseType = SdResponseType.R2;
if(flags.HasFlag(MmcFlags.Response_R3) || flags.HasFlag(MmcFlags.ResponseSPI_R3))
commandDescriptor.responseType = SdResponseType.R3;
if(flags.HasFlag(MmcFlags.Response_R4) || flags.HasFlag(MmcFlags.ResponseSPI_R4))
commandDescriptor.responseType = SdResponseType.R4;
if(flags.HasFlag(MmcFlags.Response_R5) || flags.HasFlag(MmcFlags.ResponseSPI_R5))
commandDescriptor.responseType = SdResponseType.R5;
if(flags.HasFlag(MmcFlags.Response_R6))
commandDescriptor.responseType = SdResponseType.R6;
byte[] command_b = new byte[commandData.size + commandData.protocolArgumentSize + commandData.deviceDataBufferSize];
IntPtr hBuf = Marshal.AllocHGlobal(command_b.Length);
Marshal.StructureToPtr(commandData, hBuf, true);
IntPtr descriptorOffset = new IntPtr(hBuf.ToInt32() + commandData.size);
Marshal.StructureToPtr(commandDescriptor, descriptorOffset, true);
Marshal.Copy(hBuf, command_b, 0, command_b.Length);
Marshal.FreeHGlobal(hBuf);
uint bytesReturned;
int error = 0;
DateTime start = DateTime.Now;
sense = !Extern.DeviceIoControl(fd, WindowsIoctl.IOCTL_SFFDISK_DEVICE_COMMAND, command_b,
(uint)command_b.Length, command_b, (uint)command_b.Length, out bytesReturned, IntPtr.Zero);
DateTime end = DateTime.Now;
if(sense)
error = Marshal.GetLastWin32Error();
buffer = new byte[blockSize * blocks];
Buffer.BlockCopy(command_b, command_b.Length - buffer.Length, buffer, 0, buffer.Length);
response = new uint[4];
duration = (end - start).TotalMilliseconds;
return error;
}
}
}

View File

@@ -343,6 +343,8 @@ namespace DiscImageChef.Devices.Windows
IOCTL_STORAGE_QUERY_PROPERTY = 0x2D1400,
IOCTL_IDE_PASS_THROUGH = 0x4D028,
IOCTL_STORAGE_GET_DEVICE_NUMBER = 0x2D1080,
IOCTL_SFFDISK_QUERY_DEVICE_PROTOCOL = 0x71E80,
IOCTL_SFFDISK_DEVICE_COMMAND = 0x79E84,
}
[Flags]
@@ -447,8 +449,53 @@ namespace DiscImageChef.Devices.Windows
DeviceInterface = 0x10,
}
public enum SdCommandClass : uint
{
Standard,
AppCmd
}
public enum SdTransferDirection : uint
{
Unspecified,
Read,
Write
}
public enum SdTransferType : uint
{
Unspecified,
CmdOnly,
SingleBlock,
MultiBlock,
MultiBlockNoCmd12
}
public enum SdResponseType : uint
{
Unspecified,
None,
R1,
R1b,
R2,
R3,
R4,
R5,
R5b,
R6
}
public enum SffdiskDcmd : uint
{
GetVersion,
LockChannel,
UnlockChannel,
DeviceCommand
};
static class Consts
{
public static Guid GUID_SFF_PROTOCOL_SD = new Guid("AD7536A8-D055-4C40-AA4D-96312DDB6B38");
public static Guid GUID_DEVINTERFACE_DISK = new Guid(0x53F56307, 0xB6BF, 0x11D0, 0x94, 0xF2, 0x00, 0xA0, 0xC9, 0x1E, 0xFB, 0x8B);
}
}

View File

@@ -98,7 +98,6 @@ namespace DiscImageChef.Devices.Windows
IntPtr Overlapped
);
[DllImport("Kernel32.dll", SetLastError = true, EntryPoint = "DeviceIoControl", CharSet = CharSet.Auto)]
internal static extern bool DeviceIoControlGetDeviceNumber(
SafeFileHandle hDevice,
@@ -111,6 +110,22 @@ namespace DiscImageChef.Devices.Windows
IntPtr Overlapped
);
[DllImport("Kernel32.dll", SetLastError = true, EntryPoint = "DeviceIoControl", CharSet = CharSet.Auto)]
internal static extern bool DeviceIoControl(
SafeFileHandle hDevice,
WindowsIoctl IoControlCode,
IntPtr InBuffer,
uint nInBufferSize,
ref SffdiskQueryDeviceProtocolData OutBuffer,
uint nOutBufferSize,
out uint pBytesReturned,
IntPtr Overlapped
);
[DllImport("Kernel32.dll", SetLastError = true, EntryPoint = "DeviceIoControl", CharSet = CharSet.Auto)]
internal static extern bool DeviceIoControl(SafeFileHandle hDevice, WindowsIoctl IoControlCode, byte[] InBuffer,
uint nInBufferSize, byte[] OutBuffer, uint nOutBufferSize, out uint pBytesReturned, IntPtr Overlapped);
[DllImport("setupapi.dll", CharSet = CharSet.Auto)]
internal static extern SafeFileHandle SetupDiGetClassDevs(
ref Guid ClassGuid,

View File

@@ -248,6 +248,7 @@ namespace DiscImageChef.Devices.Windows
public short wIndex;
public short wLength;
}
[StructLayout(LayoutKind.Sequential)]
struct USB_DESCRIPTOR_REQUEST
{
@@ -255,5 +256,34 @@ namespace DiscImageChef.Devices.Windows
public USB_SETUP_PACKET SetupPacket;
//public byte[] Data;
}
[StructLayout(LayoutKind.Sequential)]
struct SffdiskQueryDeviceProtocolData
{
public ushort size;
public ushort reserved;
public Guid protocolGuid;
}
[StructLayout(LayoutKind.Sequential)]
struct SffdiskDeviceCommandData
{
public ushort size;
public ushort reserved;
public SffdiskDcmd command;
public ushort protocolArgumentSize;
public uint deviceDataBufferSize;
public uint information;
}
[StructLayout(LayoutKind.Sequential)]
struct SdCmdDescriptor
{
public byte commandCode;
public SdCommandClass cmdClass;
public SdTransferDirection transferDirection;
public SdTransferType transferType;
public SdResponseType responseType;
}
}