/// <summary> /// Sends a MMC/SD command /// </summary> /// <returns>The result of the command.</returns> /// <param name="ptId">Platform ID for executing the command</param> /// <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> /// <exception cref="InvalidOperationException">If the specified platform is not supported</exception> internal static int SendMmcCommand(PlatformID ptId, object 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) { switch (ptId) { case PlatformID.Win32NT: { return(Windows.Command.SendMmcCommand((SafeFileHandle)fd, command, write, isApplication, flags, argument, blockSize, blocks, ref buffer, out response, out duration, out sense, timeout)); } case PlatformID.Linux: { return(Linux.Command.SendMmcCommand((int)fd, command, write, isApplication, flags, argument, blockSize, blocks, ref buffer, out response, out duration, out sense, timeout)); } default: throw new InvalidOperationException($"Platform {ptId} not yet supported."); } }
/// <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); } MmcIocCmd ioCmd = new MmcIocCmd(); IntPtr bufPtr = Marshal.AllocHGlobal(buffer.Length); ioCmd.write_flag = write; ioCmd.is_ascmd = isApplication; ioCmd.opcode = (uint)command; ioCmd.arg = argument; ioCmd.flags = flags; ioCmd.blksz = blockSize; ioCmd.blocks = blocks; if (timeout > 0) { ioCmd.data_timeout_ns = timeout * 1000000000; ioCmd.cmd_timeout_ms = timeout * 1000; } ioCmd.data_ptr = (ulong)bufPtr; Marshal.Copy(buffer, 0, bufPtr, buffer.Length); DateTime start = DateTime.UtcNow; int error = Extern.ioctlMmc(fd, LinuxIoctl.MmcIocCmd, ref ioCmd); DateTime end = DateTime.UtcNow; sense |= error < 0; if (error < 0) { error = Marshal.GetLastWin32Error(); } Marshal.Copy(bufPtr, buffer, 0, buffer.Length); response = ioCmd.response; duration = (end - start).TotalMilliseconds; Marshal.FreeHGlobal(bufPtr); 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> /// <exception cref="InvalidOperationException">If the specified platform is not supported</exception> internal static int SendMmcCommand(object 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) { PlatformID ptId = DetectOS.GetRealPlatformID(); return(SendMmcCommand(ptId, (int)fd, command, write, isApplication, flags, argument, blockSize, blocks, ref buffer, out response, out duration, out sense, timeout)); }
public bool Read(out byte[] buffer, out uint[] response, uint lba, uint blockSize, uint transferLength, bool byteAddressed, uint timeout, out double duration) { buffer = new byte[transferLength * blockSize]; uint address; if (byteAddressed) { address = lba * blockSize; } else { address = lba; } MmcCommands command = transferLength > 1 ? MmcCommands.ReadMultipleBlock : MmcCommands.ReadSingleBlock; LastError = SendMmcCommand(command, false, false, MmcFlags.ResponseSpiR1 | MmcFlags.ResponseR1 | MmcFlags.CommandAdtc, address, blockSize, transferLength, ref buffer, out response, out duration, out bool sense, timeout); Error = LastError != 0; if (transferLength > 1) { byte[] foo = new byte[0]; SendMmcCommand(MmcCommands.StopTransmission, false, false, MmcFlags.ResponseR1B | MmcFlags.ResponseSpiR1B | MmcFlags.CommandAc, 0, 0, 0, ref foo, out _, out double stopDuration, out bool _, timeout); duration += stopDuration; DicConsole.DebugWriteLine("MMC Device", "READ_MULTIPLE_BLOCK took {0} ms.", duration); } else { DicConsole.DebugWriteLine("MMC Device", "READ_SINGLE_BLOCK took {0} ms.", duration); } return(sense); }
/// <summary>Sends a MMC/SD command to this device</summary> /// <returns>The result of the command.</returns> /// <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> public int SendMmcCommand(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) { switch (command) { case MmcCommands.SendCid when _cachedCid != null: { DateTime start = DateTime.Now; buffer = new byte[_cachedCid.Length]; Array.Copy(_cachedCid, buffer, buffer.Length); response = new uint[4]; sense = false; DateTime end = DateTime.Now; duration = (end - start).TotalMilliseconds; return(0); } case MmcCommands.SendCsd when _cachedCid != null: { DateTime start = DateTime.Now; buffer = new byte[_cachedCsd.Length]; Array.Copy(_cachedCsd, buffer, buffer.Length); response = new uint[4]; sense = false; DateTime end = DateTime.Now; duration = (end - start).TotalMilliseconds; return(0); } case (MmcCommands)SecureDigitalCommands.SendScr when _cachedScr != null: { DateTime start = DateTime.Now; buffer = new byte[_cachedScr.Length]; Array.Copy(_cachedScr, buffer, buffer.Length); response = new uint[4]; sense = false; DateTime end = DateTime.Now; duration = (end - start).TotalMilliseconds; return(0); } case (MmcCommands)SecureDigitalCommands.SendOperatingCondition when _cachedOcr != null: case MmcCommands.SendOpCond when _cachedOcr != null: { DateTime start = DateTime.Now; buffer = new byte[_cachedOcr.Length]; Array.Copy(_cachedOcr, buffer, buffer.Length); response = new uint[4]; sense = false; DateTime end = DateTime.Now; duration = (end - start).TotalMilliseconds; return(0); } } return(_remote is null ? Command.SendMmcCommand(PlatformId, FileHandle, command, write, isApplication, flags, argument, blockSize, blocks, ref buffer, out response, out duration, out sense, timeout) : _remote.SendMmcCommand(command, write, isApplication, flags, argument, blockSize, blocks, ref buffer, out response, out duration, out sense, timeout)); }
/// <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.ResponseR1) || flags.HasFlag(MmcFlags.ResponseSpiR1)) { commandDescriptor.responseType = SdResponseType.R1; } if (flags.HasFlag(MmcFlags.ResponseR1B) || flags.HasFlag(MmcFlags.ResponseSpiR1B)) { commandDescriptor.responseType = SdResponseType.R1b; } if (flags.HasFlag(MmcFlags.ResponseR2) || flags.HasFlag(MmcFlags.ResponseSpiR2)) { commandDescriptor.responseType = SdResponseType.R2; } if (flags.HasFlag(MmcFlags.ResponseR3) || flags.HasFlag(MmcFlags.ResponseSpiR3)) { commandDescriptor.responseType = SdResponseType.R3; } if (flags.HasFlag(MmcFlags.ResponseR4) || flags.HasFlag(MmcFlags.ResponseSpiR4)) { commandDescriptor.responseType = SdResponseType.R4; } if (flags.HasFlag(MmcFlags.ResponseR5) || flags.HasFlag(MmcFlags.ResponseSpiR5)) { commandDescriptor.responseType = SdResponseType.R5; } if (flags.HasFlag(MmcFlags.ResponseR6)) { commandDescriptor.responseType = SdResponseType.R6; } byte[] commandB = new byte[commandData.size + commandData.protocolArgumentSize + commandData.deviceDataBufferSize]; IntPtr hBuf = Marshal.AllocHGlobal(commandB.Length); Marshal.StructureToPtr(commandData, hBuf, true); IntPtr descriptorOffset = IntPtr.Add(hBuf, commandData.size); Marshal.StructureToPtr(commandDescriptor, descriptorOffset, true); Marshal.Copy(hBuf, commandB, 0, commandB.Length); Marshal.FreeHGlobal(hBuf); int error = 0; DateTime start = DateTime.Now; sense = !Extern.DeviceIoControl(fd, WindowsIoctl.IoctlSffdiskDeviceCommand, commandB, (uint)commandB.Length, commandB, (uint)commandB.Length, out _, IntPtr.Zero); DateTime end = DateTime.Now; if (sense) { error = Marshal.GetLastWin32Error(); } buffer = new byte[blockSize * blocks]; Buffer.BlockCopy(commandB, commandB.Length - buffer.Length, buffer, 0, buffer.Length); response = new uint[4]; duration = (end - start).TotalMilliseconds; return(error); }
public int SendMmcCommand(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) { duration = 0; sense = true; response = null; var cmdPkt = new AaruPacketCmdSdhci { hdr = new AaruPacketHeader { remote_id = Consts.RemoteId, packet_id = Consts.PacketId, version = Consts.PacketVersion, packetType = AaruPacketType.CommandAtaLba48 }, command = command, write = write, application = isApplication, flags = flags, argument = argument, block_size = blockSize, blocks = blocks, timeout = timeout * 1000 }; if (buffer != null) { cmdPkt.buf_len = (uint)buffer.Length; } cmdPkt.hdr.len = (uint)(Marshal.SizeOf <AaruPacketCmdSdhci>() + cmdPkt.buf_len); byte[] pktBuf = Marshal.StructureToByteArrayLittleEndian(cmdPkt); byte[] buf = new byte[cmdPkt.hdr.len]; Array.Copy(pktBuf, 0, buf, 0, Marshal.SizeOf <AaruPacketCmdSdhci>()); if (buffer != null) { Array.Copy(buffer, 0, buf, Marshal.SizeOf <AaruPacketCmdSdhci>(), cmdPkt.buf_len); } int len = _socket.Send(buf, SocketFlags.None); if (len != buf.Length) { AaruConsole.ErrorWriteLine("Could not write to the network..."); return(-1); } byte[] hdrBuf = new byte[Marshal.SizeOf <AaruPacketHeader>()]; len = Receive(_socket, hdrBuf, hdrBuf.Length, SocketFlags.Peek); if (len < hdrBuf.Length) { AaruConsole.ErrorWriteLine("Could not read from the network..."); return(-1); } AaruPacketHeader hdr = Marshal.ByteArrayToStructureLittleEndian <AaruPacketHeader>(hdrBuf); if (hdr.remote_id != Consts.RemoteId || hdr.packet_id != Consts.PacketId) { AaruConsole.ErrorWriteLine("Received data is not an Aaru Remote Packet..."); return(-1); } if (hdr.packetType != AaruPacketType.ResponseSdhci) { AaruConsole.ErrorWriteLine("Expected SDHCI Response Packet, got packet type {0}...", hdr.packetType); return(-1); } buf = new byte[hdr.len]; len = Receive(_socket, buf, buf.Length, SocketFlags.None); if (len < buf.Length) { AaruConsole.ErrorWriteLine("Could not read from the network..."); return(-1); } AaruPacketResSdhci res = Marshal.ByteArrayToStructureLittleEndian <AaruPacketResSdhci>(buf); buffer = new byte[res.buf_len]; Array.Copy(buf, Marshal.SizeOf <AaruPacketResSdhci>(), buffer, 0, res.buf_len); duration = res.duration; sense = res.sense != 0; response = new uint[4]; response[0] = res.response[0]; response[1] = res.response[1]; response[2] = res.response[2]; response[3] = res.response[3]; return((int)res.error_no); }