Add MMC/SecureDigital device support. Not yet used because of

a bad implementation of SEND_CSD and SEND_CID commands (TODO).
This commit is contained in:
2016-10-22 22:58:01 +01:00
parent 8b9d678893
commit 0c9dfaa11f
24 changed files with 3607 additions and 3 deletions

View File

@@ -328,6 +328,71 @@ namespace DiscImageChef.Devices.Linux
return error;
}
/// <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(int 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)
{
response = null;
duration = 0;
sense = false;
if(buffer == null)
return -1;
mmc_ioc_cmd io_cmd = new mmc_ioc_cmd();
IntPtr bufPtr = Marshal.AllocHGlobal(buffer.Length);
io_cmd.write_flag = write;
io_cmd.is_ascmd = isApplication;
io_cmd.opcode = (uint)command;
io_cmd.arg = argument;
io_cmd.flags = flags;
io_cmd.blksz = blockSize;
io_cmd.blksz = blocks;
if(timeout > 0)
{
io_cmd.data_timeout_ns = timeout * 1000000000;
io_cmd.cmd_timeout_ms = timeout * 1000;
}
io_cmd.data_ptr = (ulong)bufPtr;
Marshal.Copy(buffer, 0, bufPtr, buffer.Length);
DateTime start = DateTime.UtcNow;
int error = Extern.ioctlMmc(fd, LinuxIoctl.MMC_IOC_CMD, ref io_cmd);
DateTime end = DateTime.UtcNow;
sense |= error < 0;
if(error < 0)
error = Marshal.GetLastWin32Error();
Marshal.Copy(bufPtr, buffer, 0, buffer.Length);
response = io_cmd.response;
duration = (end - start).TotalMilliseconds;
Marshal.FreeHGlobal(bufPtr);
return error;
}
public static string ReadLink(string path)
{
IntPtr buf = Marshal.AllocHGlobal(4096);

View File

@@ -145,6 +145,8 @@ namespace DiscImageChef.Devices.Linux
// SCSI IOCtls
SG_GET_VERSION_NUM = 0x2282,
SG_IO = 0x2285,
// MMC IOCtl
MMC_IOC_CMD = 0xC048B300
}
[Flags]

View File

@@ -52,6 +52,9 @@ namespace DiscImageChef.Devices.Linux
[DllImport("libc", EntryPoint = "ioctl", SetLastError = true)]
internal static extern int ioctlSg(int fd, LinuxIoctl request, ref sg_io_hdr_t value);
[DllImport("libc", EntryPoint = "ioctl", SetLastError = true)]
internal static extern int ioctlMmc(int fd, LinuxIoctl request, ref mmc_ioc_cmd value);
[DllImport("libc", CharSet = CharSet.Ansi, SetLastError = true)]
internal static extern int readlink(string path, System.IntPtr buf, int bufsize);

View File

@@ -65,5 +65,62 @@ namespace DiscImageChef.Devices.Linux
public uint duration; /* [o] */
public SgInfo info; /* [o] */
}
[StructLayout(LayoutKind.Sequential)]
struct mmc_ioc_cmd
{
/// <summary>
/// Implies direction of data. true = write, false = read
/// </summary>
public bool write_flag;
/// <summary>
/// Application-specific command. true = precede with CMD55
/// </summary>
public bool is_ascmd;
public uint opcode;
public uint arg;
/// <summary>
/// CMD response
/// </summary>
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)]
public uint[] response;
public MmcFlags flags;
public uint blksz;
public uint blocks;
/// <summary>
/// Sleep at least <see cref="postsleep_min_us"/> useconds, and at most
/// <see cref="postsleep_max_us"/> useconds *after* issuing command.Needed for
/// some read commands for which cards have no other way of indicating
/// they're ready for the next command (i.e. there is no equivalent of
/// a "busy" indicator for read operations).
/// </summary>
public uint postsleep_min_us;
/// <summary>
/// Sleep at least <see cref="postsleep_min_us"/> useconds, and at most
/// <see cref="postsleep_max_us"/> useconds *after* issuing command.Needed for
/// some read commands for which cards have no other way of indicating
/// they're ready for the next command (i.e. there is no equivalent of
/// a "busy" indicator for read operations).
/// </summary>
public uint postsleep_max_us;
/// <summary>
/// Override driver-computed timeouts.
/// </summary>
public uint data_timeout_ns;
/// <summary>
/// Override driver-computed timeouts.
/// </summary>
public uint cmd_timeout_ms;
/// <summary>
/// For 64-bit machines <see cref="data_ptr"/> , wants to
/// be 8-byte aligned.Make sure this struct is the same size when
/// built for 32-bit.
/// </summary>
public uint __pad;
/// <summary>
/// DAT buffer
/// </summary>
public ulong data_ptr;
}
}