mirror of
https://github.com/aaru-dps/Aaru.git
synced 2025-12-16 19:24:25 +00:00
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:
@@ -1,3 +1,19 @@
|
||||
2016-10-22 Natalia Portillo <claunia@claunia.com>
|
||||
|
||||
* Enums.cs:
|
||||
* Command.cs:
|
||||
* Enums.cs:
|
||||
* Extern.cs:
|
||||
* Command.cs:
|
||||
* Structs.cs:
|
||||
* Commands.cs:
|
||||
* Constructor.cs:
|
||||
* MMC.cs:
|
||||
* DiscImageChef.Devices.csproj:
|
||||
* SecureDigital.cs: Add MMC/SecureDigital device support. Not
|
||||
yet used because of a bad implementation of SEND_CSD and
|
||||
SEND_CID commands (TODO).
|
||||
|
||||
2016-10-17 Natalia Portillo <claunia@claunia.com>
|
||||
|
||||
* Variables.cs:
|
||||
|
||||
@@ -219,6 +219,34 @@ namespace DiscImageChef.Devices
|
||||
throw new InvalidOperationException(string.Format("Platform {0} not yet supported.", ptID));
|
||||
}
|
||||
}
|
||||
|
||||
public 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)
|
||||
{
|
||||
Interop.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 static int SendMmcCommand(Interop.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 Interop.PlatformID.Win32NT:
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
case Interop.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(string.Format("Platform {0} not yet supported.", ptID));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -114,6 +114,30 @@ namespace DiscImageChef.Devices
|
||||
return Command.SendAtaCommand(platformID, fd, registers, out errorRegisters, protocol, transferRegister,
|
||||
ref buffer, timeout, transferBlocks, out duration, out 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)
|
||||
{
|
||||
return Command.SendMmcCommand(platformID, fd, command, write, isApplication, flags, argument, blockSize, blocks,
|
||||
ref buffer, out response, out duration, out sense, timeout);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -90,6 +90,41 @@ namespace DiscImageChef.Devices
|
||||
type = DeviceType.Unknown;
|
||||
scsiType = Decoders.SCSI.PeripheralDeviceTypes.UnknownDevice;
|
||||
|
||||
// TODO: This is getting error -110 in Linux. Apparently I should set device to standby, request CID/CSD, put device to transition. However I can't get it right now.
|
||||
/*
|
||||
try
|
||||
{
|
||||
byte[] csdBuf;
|
||||
byte[] scrBuf;
|
||||
uint[] mmcResponse;
|
||||
double mmcDuration;
|
||||
|
||||
bool mmcSense = ReadCID(out csdBuf, out mmcResponse, 0, out mmcDuration);
|
||||
|
||||
if(!mmcSense)
|
||||
{
|
||||
mmcSense = ReadSCR(out scrBuf, out mmcResponse, 0, out mmcDuration);
|
||||
|
||||
if(!mmcSense)
|
||||
type = DeviceType.SecureDigital;
|
||||
else
|
||||
type = DeviceType.MMC;
|
||||
|
||||
manufacturer = "To be filled manufacturer";
|
||||
model = "To be filled model";
|
||||
revision = "To be filled revision";
|
||||
serial = "To be filled serial";
|
||||
scsiType = Decoders.SCSI.PeripheralDeviceTypes.DirectAccess;
|
||||
removable = false;
|
||||
return;
|
||||
}
|
||||
else
|
||||
System.Console.WriteLine("Error {0}: {1}", error, lastError);
|
||||
}
|
||||
catch(NotImplementedException) { }
|
||||
catch(InvalidOperationException) { }
|
||||
*/
|
||||
|
||||
AtaErrorRegistersCHS errorRegisters;
|
||||
|
||||
byte[] ataBuf;
|
||||
@@ -288,7 +323,6 @@ namespace DiscImageChef.Devices
|
||||
pcmcia = false;
|
||||
#endregion PCMCIA
|
||||
|
||||
|
||||
if(!scsiSense)
|
||||
{
|
||||
Decoders.SCSI.Inquiry.SCSIInquiry? Inquiry = Decoders.SCSI.Inquiry.Decode(inqBuf);
|
||||
|
||||
151
DiscImageChef.Devices/Device/MmcCommands/MMC.cs
Normal file
151
DiscImageChef.Devices/Device/MmcCommands/MMC.cs
Normal file
@@ -0,0 +1,151 @@
|
||||
// /***************************************************************************
|
||||
// The Disc Image Chef
|
||||
// ----------------------------------------------------------------------------
|
||||
//
|
||||
// Filename : MMC.cs
|
||||
// Author(s) : Natalia Portillo <claunia@claunia.com>
|
||||
//
|
||||
// Component : Component
|
||||
//
|
||||
// --[ Description ] ----------------------------------------------------------
|
||||
//
|
||||
// Description
|
||||
//
|
||||
// --[ License ] --------------------------------------------------------------
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as
|
||||
// published by the Free Software Foundation; either version 2.1 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This library is distributed in the hope that it will be useful, but
|
||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
// ----------------------------------------------------------------------------
|
||||
// Copyright © 2011-2016 Natalia Portillo
|
||||
// ****************************************************************************/
|
||||
|
||||
using DiscImageChef.Console;
|
||||
|
||||
namespace DiscImageChef.Devices
|
||||
{
|
||||
public partial class Device
|
||||
{
|
||||
public bool ReadCSD(out byte[] buffer, out uint[] response, uint timeout, out double duration)
|
||||
{
|
||||
buffer = new byte[16];
|
||||
bool sense = false;
|
||||
|
||||
lastError = SendMmcCommand(MmcCommands.SendCSD, false, false, MmcFlags.ResponseSPI_R1 | MmcFlags.Response_R1 | MmcFlags.CommandADTC,
|
||||
0, 16, 1, ref buffer, out response, out duration, out sense, timeout);
|
||||
error = lastError != 0;
|
||||
|
||||
DicConsole.DebugWriteLine("MMC Device", "SEND_CSD took {0} ms.", duration);
|
||||
|
||||
return sense;
|
||||
}
|
||||
|
||||
public bool ReadCID(out byte[] buffer, out uint[] response, uint timeout, out double duration)
|
||||
{
|
||||
buffer = new byte[16];
|
||||
bool sense = false;
|
||||
|
||||
lastError = SendMmcCommand(MmcCommands.SendCID, false, false, MmcFlags.ResponseSPI_R1 | MmcFlags.Response_R1 | MmcFlags.CommandADTC,
|
||||
0, 16, 1, ref buffer, out response, out duration, out sense, timeout);
|
||||
error = lastError != 0;
|
||||
|
||||
DicConsole.DebugWriteLine("MMC Device", "SEND_CID took {0} ms.", duration);
|
||||
|
||||
return sense;
|
||||
}
|
||||
|
||||
public bool ReadOCR(out byte[] buffer, out uint[] response, uint timeout, out double duration)
|
||||
{
|
||||
buffer = new byte[4];
|
||||
bool sense = false;
|
||||
|
||||
lastError = SendMmcCommand(MmcCommands.SendOpCond, false, true, MmcFlags.ResponseSPI_R3 | MmcFlags.Response_R3 | MmcFlags.CommandBCR,
|
||||
0, 4, 1, ref buffer, out response, out duration, out sense, timeout);
|
||||
error = lastError != 0;
|
||||
|
||||
DicConsole.DebugWriteLine("SecureDigital Device", "SEND_OP_COND took {0} ms.", duration);
|
||||
|
||||
return sense;
|
||||
}
|
||||
|
||||
public bool ReadExtendedCSD(out byte[] buffer, out uint[] response, uint timeout, out double duration)
|
||||
{
|
||||
buffer = new byte[512];
|
||||
bool sense = false;
|
||||
|
||||
lastError = SendMmcCommand(MmcCommands.SendExtCSD, false, false, MmcFlags.ResponseSPI_R1 | MmcFlags.Response_R1 | MmcFlags.CommandADTC,
|
||||
0, 512, 1, ref buffer, out response, out duration, out sense, timeout);
|
||||
error = lastError != 0;
|
||||
|
||||
DicConsole.DebugWriteLine("MMC Device", "SEND_EXT_CSD took {0} ms.", duration);
|
||||
|
||||
return sense;
|
||||
}
|
||||
|
||||
public bool SetBlockLength(uint length, out uint[] response, uint timeout, out double duration)
|
||||
{
|
||||
byte[] buffer = new byte[0];
|
||||
bool sense = false;
|
||||
|
||||
lastError = SendMmcCommand(MmcCommands.SetBlocklen, false, false, MmcFlags.ResponseSPI_R1 | MmcFlags.Response_R1 | MmcFlags.CommandAC,
|
||||
length, 0, 0, ref buffer, out response, out duration, out sense, timeout);
|
||||
error = lastError != 0;
|
||||
|
||||
DicConsole.DebugWriteLine("MMC Device", "SET_BLOCKLEN took {0} ms.", duration);
|
||||
|
||||
return sense;
|
||||
}
|
||||
|
||||
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];
|
||||
bool sense = false;
|
||||
uint address;
|
||||
if(byteAddressed)
|
||||
address = lba * blockSize;
|
||||
else
|
||||
address = lba;
|
||||
|
||||
MmcCommands command;
|
||||
if(transferLength > 1)
|
||||
command = MmcCommands.ReadMultipleBlock;
|
||||
else
|
||||
command = MmcCommands.ReadSingleBlock;
|
||||
|
||||
lastError = SendMmcCommand(command, false, false, MmcFlags.ResponseSPI_R1 | MmcFlags.Response_R1 | MmcFlags.CommandADTC,
|
||||
address, blockSize, transferLength, ref buffer, out response, out duration, out sense, timeout);
|
||||
error = lastError != 0;
|
||||
|
||||
if(transferLength > 1)
|
||||
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;
|
||||
}
|
||||
|
||||
public bool ReadStatus(out byte[] buffer, out uint[] response, uint timeout, out double duration)
|
||||
{
|
||||
buffer = new byte[4];
|
||||
bool sense = false;
|
||||
|
||||
lastError = SendMmcCommand(MmcCommands.SendStatus, false, true, MmcFlags.ResponseSPI_R1 | MmcFlags.Response_R1 | MmcFlags.CommandADTC,
|
||||
0, 4, 1, ref buffer, out response, out duration, out sense, timeout);
|
||||
error = lastError != 0;
|
||||
|
||||
DicConsole.DebugWriteLine("SecureDigital Device", "SEND_STATUS took {0} ms.", duration);
|
||||
|
||||
return sense;
|
||||
}
|
||||
}
|
||||
}
|
||||
81
DiscImageChef.Devices/Device/MmcCommands/SecureDigital.cs
Normal file
81
DiscImageChef.Devices/Device/MmcCommands/SecureDigital.cs
Normal file
@@ -0,0 +1,81 @@
|
||||
// /***************************************************************************
|
||||
// The Disc Image Chef
|
||||
// ----------------------------------------------------------------------------
|
||||
//
|
||||
// Filename : SecureDigital.cs
|
||||
// Author(s) : Natalia Portillo <claunia@claunia.com>
|
||||
//
|
||||
// Component : Component
|
||||
//
|
||||
// --[ Description ] ----------------------------------------------------------
|
||||
//
|
||||
// Description
|
||||
//
|
||||
// --[ License ] --------------------------------------------------------------
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as
|
||||
// published by the Free Software Foundation; either version 2.1 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This library is distributed in the hope that it will be useful, but
|
||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
// ----------------------------------------------------------------------------
|
||||
// Copyright © 2011-2016 Natalia Portillo
|
||||
// ****************************************************************************/
|
||||
|
||||
using DiscImageChef.Console;
|
||||
|
||||
namespace DiscImageChef.Devices
|
||||
{
|
||||
public partial class Device
|
||||
{
|
||||
public bool ReadSDStatus(out byte[] buffer, out uint[] response, uint timeout, out double duration)
|
||||
{
|
||||
buffer = new byte[64];
|
||||
bool sense = false;
|
||||
|
||||
lastError = SendMmcCommand((MmcCommands)SecureDigitalCommands.SendStatus, false, true, MmcFlags.ResponseSPI_R1 | MmcFlags.Response_R1 | MmcFlags.CommandADTC,
|
||||
0, 64, 1, ref buffer, out response, out duration, out sense, timeout);
|
||||
error = lastError != 0;
|
||||
|
||||
DicConsole.DebugWriteLine("SecureDigital Device", "SD_STATUS took {0} ms.", duration);
|
||||
|
||||
return sense;
|
||||
}
|
||||
|
||||
public bool ReadSDOCR(out byte[] buffer, out uint[] response, uint timeout, out double duration)
|
||||
{
|
||||
buffer = new byte[4];
|
||||
bool sense = false;
|
||||
|
||||
lastError = SendMmcCommand((MmcCommands)SecureDigitalCommands.SendOperatingCondition, false, true, MmcFlags.ResponseSPI_R3 | MmcFlags.Response_R3 | MmcFlags.CommandBCR,
|
||||
0, 4, 1, ref buffer, out response, out duration, out sense, timeout);
|
||||
error = lastError != 0;
|
||||
|
||||
DicConsole.DebugWriteLine("SecureDigital Device", "SD_SEND_OP_COND took {0} ms.", duration);
|
||||
|
||||
return sense;
|
||||
}
|
||||
|
||||
public bool ReadSCR(out byte[] buffer, out uint[] response, uint timeout, out double duration)
|
||||
{
|
||||
buffer = new byte[8];
|
||||
bool sense = false;
|
||||
|
||||
lastError = SendMmcCommand((MmcCommands)SecureDigitalCommands.SendSCR, false, true, MmcFlags.ResponseSPI_R1 | MmcFlags.Response_R1 | MmcFlags.CommandADTC,
|
||||
0, 8, 1, ref buffer, out response, out duration, out sense, timeout);
|
||||
error = lastError != 0;
|
||||
|
||||
DicConsole.DebugWriteLine("SecureDigital Device", "SEND_SCR took {0} ms.", duration);
|
||||
|
||||
return sense;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -76,6 +76,8 @@
|
||||
<Compile Include="FreeBSD\Enums.cs" />
|
||||
<Compile Include="FreeBSD\Extern.cs" />
|
||||
<Compile Include="FreeBSD\Structs.cs" />
|
||||
<Compile Include="Device\MmcCommands\MMC.cs" />
|
||||
<Compile Include="Device\MmcCommands\SecureDigital.cs" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
|
||||
<ItemGroup>
|
||||
@@ -85,6 +87,7 @@
|
||||
<Folder Include="Device\ScsiCommands\" />
|
||||
<Folder Include="Device\AtaCommands\" />
|
||||
<Folder Include="FreeBSD\" />
|
||||
<Folder Include="Device\MmcCommands\" />
|
||||
</ItemGroup>
|
||||
<ProjectExtensions>
|
||||
<MonoDevelop>
|
||||
@@ -92,8 +95,8 @@
|
||||
<Policies>
|
||||
<DotNetNamingPolicy DirectoryNamespaceAssociation="PrefixedHierarchical" ResourceNamePolicy="MSBuild" />
|
||||
<StandardHeader Text="/***************************************************************************
The Disc Image Chef
----------------------------------------------------------------------------
 
Filename : ${FileName}
Author(s) : ${AuthorName} <${AuthorEmail}>

Component : Component
 
--[ Description ] ----------------------------------------------------------
 
 Description
 
--[ License ] --------------------------------------------------------------
 
 This library is free software; you can redistribute it and/or modify
 it under the terms of the GNU Lesser General Public License as
 published by the Free Software Foundation; either version 2.1 of the
 License, or (at your option) any later version.

 This library is distributed in the hope that it will be useful, but
 WITHOUT ANY WARRANTY; without even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 Lesser General Public License for more details.

 You should have received a copy of the GNU Lesser General Public
 License along with this library; if not, see <http://www.gnu.org/licenses/>.

----------------------------------------------------------------------------
Copyright © 2011-${Year} ${CopyrightHolder}
****************************************************************************/" IncludeInNewFiles="True" />
|
||||
<TextStylePolicy FileWidth="120" inheritsSet="VisualStudio" inheritsScope="text/plain" scope="text/x-csharp" />
|
||||
<CSharpFormattingPolicy IndentSwitchSection="True" NewLinesForBracesInProperties="True" NewLinesForBracesInAccessors="True" NewLinesForBracesInAnonymousMethods="True" NewLinesForBracesInControlBlocks="True" NewLinesForBracesInAnonymousTypes="True" NewLinesForBracesInObjectCollectionArrayInitializers="True" NewLinesForBracesInLambdaExpressionBody="True" NewLineForElse="True" NewLineForCatch="True" NewLineForFinally="True" NewLineForMembersInObjectInit="True" NewLineForMembersInAnonymousTypes="True" NewLineForClausesInQuery="True" SpacingAfterMethodDeclarationName="False" SpaceAfterMethodCallName="False" SpaceAfterControlFlowStatementKeyword="False" SpaceBeforeOpenSquareBracket="False" inheritsSet="Mono" inheritsScope="text/x-csharp" scope="text/x-csharp" />
|
||||
<TextStylePolicy TabWidth="4" TabsToSpaces="True" IndentWidth="4" RemoveTrailingWhitespace="True" NoTabsAfterNonTabs="False" EolMarker="Native" FileWidth="120" inheritsSet="VisualStudio" inheritsScope="text/plain" scope="text/x-csharp" />
|
||||
<CSharpFormattingPolicy IndentBlock="True" IndentBraces="False" IndentSwitchCaseSection="True" LabelPositioning="OneLess" NewLinesForBracesInTypes="True" NewLinesForBracesInMethods="True" SpaceWithinMethodDeclarationParenthesis="False" SpaceBetweenEmptyMethodDeclarationParentheses="False" SpaceWithinMethodCallParentheses="False" SpaceBetweenEmptyMethodCallParentheses="False" SpaceWithinExpressionParentheses="False" SpaceWithinCastParentheses="False" SpaceWithinOtherParentheses="False" SpaceAfterCast="False" SpacesIgnoreAroundVariableDeclaration="False" SpaceBetweenEmptySquareBrackets="False" SpaceWithinSquareBrackets="False" SpaceAfterColonInBaseTypeDeclaration="True" SpaceAfterComma="True" SpaceAfterDot="False" SpaceAfterSemicolonsInForStatement="True" SpaceBeforeColonInBaseTypeDeclaration="True" SpaceBeforeComma="False" SpaceBeforeDot="False" SpaceBeforeSemicolonsInForStatement="False" SpacingAroundBinaryOperator="Single" WrappingPreserveSingleLine="True" WrappingKeepStatementsOnSingleLine="True" PlaceSystemDirectiveFirst="True" IndentSwitchSection="True" NewLinesForBracesInProperties="True" NewLinesForBracesInAccessors="True" NewLinesForBracesInAnonymousMethods="True" NewLinesForBracesInControlBlocks="True" NewLinesForBracesInAnonymousTypes="True" NewLinesForBracesInObjectCollectionArrayInitializers="True" NewLinesForBracesInLambdaExpressionBody="True" NewLineForElse="True" NewLineForCatch="True" NewLineForFinally="True" NewLineForMembersInObjectInit="True" NewLineForMembersInAnonymousTypes="True" NewLineForClausesInQuery="True" SpacingAfterMethodDeclarationName="False" SpaceAfterMethodCallName="False" SpaceAfterControlFlowStatementKeyword="False" SpaceBeforeOpenSquareBracket="False" inheritsSet="Mono" inheritsScope="text/x-csharp" scope="text/x-csharp" />
|
||||
</Policies>
|
||||
</Properties>
|
||||
</MonoDevelop>
|
||||
|
||||
@@ -3455,5 +3455,355 @@ namespace DiscImageChef.Devices
|
||||
Obsolete1 = 4,
|
||||
Obsolete2 = 5
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// MMC / SecureDigital commands
|
||||
/// </summary>
|
||||
public enum MmcCommands : byte
|
||||
{
|
||||
#region Class 1 MMC Commands (Basic and read-stream)
|
||||
/// <summary>
|
||||
/// Resets device to idle (BC)
|
||||
/// </summary>
|
||||
GoIdle = 0,
|
||||
/// <summary>
|
||||
/// Resets the device to pre-idle (BC)
|
||||
/// </summary>
|
||||
GoPreIdleState = 0,
|
||||
/// <summary>
|
||||
/// Initiate alternative boot operation
|
||||
/// </summary>
|
||||
BootInitiation = 0,
|
||||
/// <summary>
|
||||
/// Asks device in idle state to send their operation conditions in response (BCR, R3)
|
||||
/// </summary>
|
||||
SendOpCond = 1,
|
||||
/// <summary>
|
||||
/// Asks device to send their CID numbers (BCR, R2)
|
||||
/// </summary>
|
||||
AllSendCID = 2,
|
||||
/// <summary>
|
||||
/// Assigns a relative address to the device (AC, R1)
|
||||
/// </summary>
|
||||
SetRelativeAddress = 3,
|
||||
/// <summary>
|
||||
/// Programs the DSR of the device (BC)
|
||||
/// </summary>
|
||||
SetDSR = 4,
|
||||
/// <summary>
|
||||
/// Toggles the device between sleep and standby (AC, R1b)
|
||||
/// </summary>
|
||||
SleepAwake = 5,
|
||||
/// <summary>
|
||||
/// Switches device mode of operation (AC, R1b)
|
||||
/// </summary>
|
||||
Switch = 6,
|
||||
/// <summary>
|
||||
/// Toggles a device between the stand-by and transfer stats or between the programming and disconnect states (AC, R1b)
|
||||
/// </summary>
|
||||
SelectCard = 7,
|
||||
/// <summary>
|
||||
/// Asks device to send its extended card-specific data (ExtCSD) (ADTC, R1)
|
||||
/// </summary>
|
||||
SendExtCSD = 8,
|
||||
/// <summary>
|
||||
/// Asks device to send its card-specific data (CSD) (AC, R2)
|
||||
/// </summary>
|
||||
SendCSD = 9,
|
||||
/// <summary>
|
||||
/// Asks device to send its card identification (CID) (AC, R2)
|
||||
/// </summary>
|
||||
SendCID = 10,
|
||||
/// <summary>
|
||||
/// Reads data stream from device, starting at given address, until a <see cref="StopTransmission"/> follows (ADTC, R1)
|
||||
/// </summary>
|
||||
[Obsolete]
|
||||
ReadDatUntilStop = 11,
|
||||
/// <summary>
|
||||
/// Terminates a read/write stream/multiple block operation (AC, R1 / R1b)
|
||||
/// </summary>
|
||||
StopTransmission = 12,
|
||||
/// <summary>
|
||||
/// Asks device to send its status register (AC, R1)
|
||||
/// </summary>
|
||||
SendStatus = 13,
|
||||
/// <summary>
|
||||
/// The host reads the reversed bus testing data pattern from a device (ADTC, R1)
|
||||
/// </summary>
|
||||
BusTestRead = 14,
|
||||
/// <summary>
|
||||
/// Sets the card to inactive state (AC)
|
||||
/// </summary>
|
||||
GoInactiveState = 15,
|
||||
/// <summary>
|
||||
/// The host sends the bus testing data pattern to a device (ADTC, R1)
|
||||
/// </summary>
|
||||
BusTestWrite = 19,
|
||||
SPIReadOCR = 58,
|
||||
SPICRCOnOff = 59,
|
||||
#endregion Class 1 MMC Commands (Basic and read-stream)
|
||||
|
||||
#region Class 2 MMC Commands (Block-oriented read)
|
||||
/// <summary>
|
||||
/// Sets the block length in bytes (AC, R1)
|
||||
/// </summary>
|
||||
SetBlocklen = 16,
|
||||
/// <summary>
|
||||
/// Reads a block (ADTC, R1)
|
||||
/// </summary>
|
||||
ReadSingleBlock = 17,
|
||||
/// <summary>
|
||||
/// Transfers data blocks from card to host until interrupted (ADTC, R1)
|
||||
/// </summary>
|
||||
ReadMultipleBlock = 18,
|
||||
/// <summary>
|
||||
/// 128 blocks of tuning pattern is sent for HS200 optimal sampling point detection (ADTC, R1)
|
||||
/// </summary>
|
||||
SendTuningBlockHS200 = 21,
|
||||
#endregion Class 2 MMC Commands (Block-oriented read)
|
||||
|
||||
#region Class 3 MMC Commands (Stream write)
|
||||
/// <summary>
|
||||
/// Writes data stream from host until a <see cref="StopTransmission"/> follows (ADTC, R1)
|
||||
/// </summary>
|
||||
[Obsolete]
|
||||
WriteDatUntilStop = 20,
|
||||
#endregion Class 3 MMC Commands (Stream write)
|
||||
|
||||
#region Class 4 MMC Commands (Block-oriented write)
|
||||
/// <summary>
|
||||
/// Defines the number of blocks which are going to be transferred in the immediately succeeding multiple block command (AC, R1)
|
||||
/// </summary>
|
||||
SetBlockCount = 23,
|
||||
/// <summary>
|
||||
/// Writes a block (ADTC, R1)
|
||||
/// </summary>
|
||||
WriteBlock = 24,
|
||||
/// <summary>
|
||||
/// Continuosly writes blocks until interrupted (ADTC, R1)
|
||||
/// </summary>
|
||||
WriteMultipleBlock = 25,
|
||||
/// <summary>
|
||||
/// Programs the Card Information register (ADTC, R1)
|
||||
/// </summary>
|
||||
ProgramCID = 26,
|
||||
/// <summary>
|
||||
/// Programs the programmable bits of the CSD (ADTC, R1)
|
||||
/// </summary>
|
||||
ProgramCSD = 27,
|
||||
/// <summary>
|
||||
/// Sets the real time clock according to information in block (ADTC, R1)
|
||||
/// </summary>
|
||||
SetTime = 49,
|
||||
#endregion Class 4 MMC Commands (Block-oriented write)
|
||||
|
||||
#region Class 5 MMC Commands (Erase)
|
||||
/// <summary>
|
||||
/// Sets the address of the first erase group (AC, R1)
|
||||
/// </summary>
|
||||
EraseGroupStart = 35,
|
||||
/// <summary>
|
||||
/// Sets the address of the last erase group (AC, R1)
|
||||
/// </summary>
|
||||
EraseGroupEnd = 36,
|
||||
/// <summary>
|
||||
/// Erases previously selected write blocks (AC, R1b)
|
||||
/// </summary>
|
||||
Erase = 38,
|
||||
#endregion Class 5 MMC Commands (Erase)
|
||||
|
||||
#region Class 6 MMC Commands (Block-oriented write protection)
|
||||
/// <summary>
|
||||
/// Sets the write protection bit (AC, R1b)
|
||||
/// </summary>
|
||||
SetWriteProtect = 28,
|
||||
/// <summary>
|
||||
/// Clears the write protection bit (AC, R1b)
|
||||
/// </summary>
|
||||
ClearWriteProtect = 29,
|
||||
/// <summary>
|
||||
/// Asks the device to send the status of the write protection bit (ADTC, R1)
|
||||
/// </summary>
|
||||
SendWriteProtect = 30,
|
||||
/// <summary>
|
||||
/// Sends the type of write protection that is set for the different write protection groups (ADTC, R1)
|
||||
/// </summary>
|
||||
SentWriteProtectType = 31,
|
||||
#endregion Class 6 MMC Commands (Block-oriented write protection)
|
||||
|
||||
#region Class 7 MMC Commands (Lock)
|
||||
/// <summary>
|
||||
/// Used to set/reset the password or lock/unlock the card (ADTC, R1b)
|
||||
/// </summary>
|
||||
LockUnlock = 42,
|
||||
#endregion Class 7 MMC Commands (Lock)
|
||||
|
||||
#region Class 8 MMC Commands (Application-specific)
|
||||
/// <summary>
|
||||
/// Indicates the card that the next command is an application specific command (AC, R1)
|
||||
/// </summary>
|
||||
ApplicationCommand = 55,
|
||||
/// <summary>
|
||||
/// Transfers a data block to/from the card for general purpose / application specific commands (ADTC, R1b)
|
||||
/// </summary>
|
||||
GenericCommand = 56,
|
||||
#endregion Class 8 MMC Commands (Application-specific)
|
||||
|
||||
#region Class 9 MMC Commands (I/O mode)
|
||||
/// <summary>
|
||||
/// Used to write and read 8 bit data field, used to access application dependent registers not defined in MMC standard (AC, R4)
|
||||
/// </summary>
|
||||
FastIO = 39,
|
||||
/// <summary>
|
||||
/// Sets the system into interrupt mode (BCR, R5)
|
||||
/// </summary>
|
||||
GoIRQState = 40,
|
||||
#endregion Class 9 MMC Commands (I/O mode)
|
||||
|
||||
#region Class 10 MMC Commands (Security Protocols)
|
||||
/// <summary>
|
||||
/// Reads data blocks (ADTC, R1)
|
||||
/// </summary>
|
||||
ProtocolRead = 53,
|
||||
/// <summary>
|
||||
/// Writes data blocks (ADTC, R1)
|
||||
/// </summary>
|
||||
ProtocolWrite = 54,
|
||||
#endregion Class 10 MMC Commands (Security Protocols)
|
||||
|
||||
#region Class 11 MMC Commands (Command Queue)
|
||||
/// <summary>
|
||||
/// Defines data direction, priority, task ID and block count of queued task (AC, R1)
|
||||
/// </summary>
|
||||
QueuedTaskParameters = 44,
|
||||
/// <summary>
|
||||
/// Defines the block address of queued task (AC, R1)
|
||||
/// </summary>
|
||||
QueuedTaskAddress = 45,
|
||||
/// <summary>
|
||||
/// Executes the task queue for reading (ADTC, R1)
|
||||
/// </summary>
|
||||
ExecuteTaskRead = 46,
|
||||
/// <summary>
|
||||
/// Executes the task queue for writing (ADTC, R1)
|
||||
/// </summary>
|
||||
ExecuteTaskWrite = 47,
|
||||
/// <summary>
|
||||
/// Manages queues and tasks (AC, R1b)
|
||||
/// </summary>
|
||||
CmdQTaskManagement = 48,
|
||||
#endregion Class 11 MMC Commands (Command Queue)
|
||||
|
||||
#region Class 1 SecureDigital Commands (Basic)
|
||||
/// <summary>
|
||||
/// Sends SD interface condition (BCR, R7)
|
||||
/// </summary>
|
||||
SendInterfaceCondition = 8,
|
||||
/// <summary>
|
||||
/// Switch to 1.8V bus signaling level (AC, R1)
|
||||
/// </summary>
|
||||
VoltageSwitch = 11,
|
||||
#endregion Class 1 SecureDigital Commands (Basic)
|
||||
|
||||
#region Class 2 SecureDigital Commands (Block-oriented read)
|
||||
/// <summary>
|
||||
/// 64 bytes of tuning pattern is sent for SDR50 and SDR104 optinal sampling point detection (ADTC, R1)
|
||||
/// </summary>
|
||||
SendTuningBlock = 19,
|
||||
/// <summary>
|
||||
/// Speed class control command (AC, R1b)
|
||||
/// </summary>
|
||||
SpeedClassControl = 20,
|
||||
#endregion Class 2 SecureDigital Commands (Block-oriented read)
|
||||
|
||||
#region Class 11 SecureDigital Commands (Function Extension)
|
||||
/// <summary>
|
||||
/// Single block read type (ADTC, R1)
|
||||
/// </summary>
|
||||
ReadExtraSingle = 48,
|
||||
/// <summary>
|
||||
/// Single block write type (ADTC, R1)
|
||||
/// </summary>
|
||||
WriteExtraSingle = 49,
|
||||
/// <summary>
|
||||
/// Multiple block read type (ADTC, R1)
|
||||
/// </summary>
|
||||
ReadExtraMulti = 58,
|
||||
/// <summary>
|
||||
/// Multiple block write type (ADTC, R1)
|
||||
/// </summary>
|
||||
WriteExtraMulti = 59,
|
||||
#endregion Class 11 SecureDigital Commands (Function Extension)
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// SecureDigital application-specific commands
|
||||
/// </summary>
|
||||
public enum SecureDigitalCommands : byte
|
||||
{
|
||||
/// <summary>
|
||||
/// Defines the data bus width to be used for data transfer (AC, R1)
|
||||
/// </summary>
|
||||
SetBusWidth = 6,
|
||||
/// <summary>
|
||||
/// Sends the SD status register (ADTC, R1)
|
||||
/// </summary>
|
||||
SendStatus = 13,
|
||||
/// <summary>
|
||||
/// Send the number of the written write blocks (ADTC, R1)
|
||||
/// </summary>
|
||||
SendNumWriteBlocks = 22,
|
||||
/// <summary>
|
||||
/// Set the number of write blocks to be pre-erased before writing (AC, R1)
|
||||
/// </summary>
|
||||
SetWriteBlockEraseCount = 23,
|
||||
/// <summary>
|
||||
/// Sends host capacity support information and asks the card to send its operating condition register (BCR, R3)
|
||||
/// </summary>
|
||||
SendOperatingCondition = 41,
|
||||
/// <summary>
|
||||
/// Connects/Disconnects the 50 kOhm pull-up resistor on CD/DAT3 pin of card (AC, R1)
|
||||
/// </summary>
|
||||
SetClearCardDetect = 42,
|
||||
/// <summary>
|
||||
/// Reads the SD Configuration Register SCR (ADTC, R1)
|
||||
/// </summary>
|
||||
SendSCR = 51,
|
||||
}
|
||||
|
||||
[Flags]
|
||||
public enum MmcFlags : uint
|
||||
{
|
||||
ResponsePresent = 1 << 0,
|
||||
Response136 = 1 << 1,
|
||||
ResponseCrc = 1 << 2,
|
||||
ResponseBusy = 1 << 3,
|
||||
ResponseOpcode = 1 << 4,
|
||||
CommandMask = 3 << 5,
|
||||
CommandAC = 0 << 5,
|
||||
CommandADTC = 1 << 5,
|
||||
CommandBC = 2 << 5,
|
||||
CommandBCR = 3 << 5,
|
||||
ResponseSPI_S1 = 1 << 7,
|
||||
ResponseSPI_S2 = 1 << 8,
|
||||
ResponseSPI_B4 = 1 << 9,
|
||||
ResponseSPI_Busy = 1 << 10,
|
||||
ResponseNone = 0,
|
||||
Response_R1 = ResponsePresent | ResponseCrc | ResponseOpcode,
|
||||
Response_R1b = ResponsePresent | ResponseCrc | ResponseOpcode | ResponseBusy,
|
||||
Response_R2 = ResponsePresent | Response136 | ResponseCrc,
|
||||
Response_R3 = ResponsePresent,
|
||||
Response_R4 = ResponsePresent,
|
||||
Response_R5 = ResponsePresent | ResponseCrc | ResponseOpcode,
|
||||
Response_R6 = ResponsePresent | ResponseCrc | ResponseOpcode,
|
||||
Response_R7 = ResponsePresent | ResponseCrc | ResponseOpcode,
|
||||
ResponseSPI_R1 = ResponseSPI_S1,
|
||||
ResponseSPI_R1b = ResponseSPI_S1 | ResponseSPI_Busy,
|
||||
ResponseSPI_R2 = ResponseSPI_S1 | ResponseSPI_S2,
|
||||
ResponseSPI_R3 = ResponseSPI_S1 | ResponseSPI_B4,
|
||||
ResponseSPI_R4 = ResponseSPI_S1 | ResponseSPI_B4,
|
||||
ResponseSPI_R5 = ResponseSPI_S1 | ResponseSPI_S2,
|
||||
ResponseSPI_R7 = ResponseSPI_S1 | ResponseSPI_B4
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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]
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user