mirror of
https://github.com/aaru-dps/Aaru.git
synced 2025-12-16 19:24:25 +00:00
Add MMC/SD command to send SET_BLOCK_COUNT, READ_MULTIPLE_BLOCK and STOP_TRANSMISSION in a single call.
This commit is contained in:
@@ -42,7 +42,9 @@ using Aaru.CommonTypes.Interfaces;
|
|||||||
using Aaru.CommonTypes.Metadata;
|
using Aaru.CommonTypes.Metadata;
|
||||||
using Aaru.Core.Logging;
|
using Aaru.Core.Logging;
|
||||||
using Aaru.Decoders.MMC;
|
using Aaru.Decoders.MMC;
|
||||||
|
using Aaru.Decoders.SecureDigital;
|
||||||
using Schemas;
|
using Schemas;
|
||||||
|
using CSD = Aaru.Decoders.MMC.CSD;
|
||||||
using DeviceType = Aaru.CommonTypes.Enums.DeviceType;
|
using DeviceType = Aaru.CommonTypes.Enums.DeviceType;
|
||||||
using MediaType = Aaru.CommonTypes.MediaType;
|
using MediaType = Aaru.CommonTypes.MediaType;
|
||||||
using Version = Aaru.CommonTypes.Interop.Version;
|
using Version = Aaru.CommonTypes.Interop.Version;
|
||||||
@@ -85,6 +87,7 @@ namespace Aaru.Core.Devices.Dumping
|
|||||||
uint physicalBlockSize = 0;
|
uint physicalBlockSize = 0;
|
||||||
bool byteAddressed = true;
|
bool byteAddressed = true;
|
||||||
uint[] response;
|
uint[] response;
|
||||||
|
bool supportsCmd23 = false;
|
||||||
|
|
||||||
Dictionary<MediaTagType, byte[]> mediaTags = new Dictionary<MediaTagType, byte[]>();
|
Dictionary<MediaTagType, byte[]> mediaTags = new Dictionary<MediaTagType, byte[]>();
|
||||||
|
|
||||||
@@ -104,6 +107,9 @@ namespace Aaru.Core.Devices.Dumping
|
|||||||
|
|
||||||
mediaTags.Add(MediaTagType.MMC_CSD, null);
|
mediaTags.Add(MediaTagType.MMC_CSD, null);
|
||||||
|
|
||||||
|
// Found at least since MMC System Specification 3.31
|
||||||
|
supportsCmd23 = csdDecoded.Version >= 3;
|
||||||
|
|
||||||
if(csdDecoded.Size == 0xFFF)
|
if(csdDecoded.Size == 0xFFF)
|
||||||
{
|
{
|
||||||
UpdateStatus?.Invoke("Reading Extended CSD");
|
UpdateStatus?.Invoke("Reading Extended CSD");
|
||||||
@@ -215,7 +221,12 @@ namespace Aaru.Core.Devices.Dumping
|
|||||||
scr = null;
|
scr = null;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
|
supportsCmd23 = Decoders.SecureDigital.Decoders.DecodeSCR(scr)?.CommandSupport.
|
||||||
|
HasFlag(CommandSupport.SetBlockCount) ?? false;
|
||||||
|
|
||||||
mediaTags.Add(MediaTagType.SD_SCR, null);
|
mediaTags.Add(MediaTagType.SD_SCR, null);
|
||||||
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -254,9 +265,39 @@ namespace Aaru.Core.Devices.Dumping
|
|||||||
byte[] cmdBuf;
|
byte[] cmdBuf;
|
||||||
bool error;
|
bool error;
|
||||||
|
|
||||||
|
if(blocksToRead > _maximumReadable)
|
||||||
|
blocksToRead = (ushort)_maximumReadable;
|
||||||
|
|
||||||
|
if(supportsCmd23 && blocksToRead > 1)
|
||||||
|
{
|
||||||
|
sense = _dev.ReadWithBlockCount(out cmdBuf, out _, 0, blockSize, 1, byteAddressed, timeout,
|
||||||
|
out duration);
|
||||||
|
|
||||||
|
if(sense || _dev.Error)
|
||||||
|
{
|
||||||
|
UpdateStatus?.
|
||||||
|
Invoke("Environment does not support setting block count, downgrading to OS reading.");
|
||||||
|
|
||||||
|
supportsCmd23 = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Need to restart device, otherwise is it just busy streaming data with no one listening
|
||||||
|
sense = _dev.ReOpen();
|
||||||
|
|
||||||
|
if(sense)
|
||||||
|
{
|
||||||
|
StoppingErrorMessage?.Invoke($"Error {_dev.LastError} reopening device.");
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(supportsCmd23 && blocksToRead > 1)
|
||||||
|
{
|
||||||
while(true)
|
while(true)
|
||||||
{
|
{
|
||||||
error = _dev.Read(out cmdBuf, out _, 0, blockSize, blocksToRead, byteAddressed, timeout, out duration);
|
error = _dev.ReadWithBlockCount(out cmdBuf, out _, 0, blockSize, blocksToRead, byteAddressed,
|
||||||
|
timeout, out duration);
|
||||||
|
|
||||||
if(error)
|
if(error)
|
||||||
blocksToRead /= 2;
|
blocksToRead /= 2;
|
||||||
@@ -269,13 +310,24 @@ namespace Aaru.Core.Devices.Dumping
|
|||||||
if(error)
|
if(error)
|
||||||
{
|
{
|
||||||
_dumpLog.WriteLine("ERROR: Cannot get blocks to read, device error {0}.", _dev.LastError);
|
_dumpLog.WriteLine("ERROR: Cannot get blocks to read, device error {0}.", _dev.LastError);
|
||||||
StoppingErrorMessage?.Invoke($"Device error {_dev.LastError} trying to guess ideal transfer length.");
|
|
||||||
|
StoppingErrorMessage?.
|
||||||
|
Invoke($"Device error {_dev.LastError} trying to guess ideal transfer length.");
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(supportsCmd23 || blocksToRead == 1)
|
||||||
|
{
|
||||||
UpdateStatus?.Invoke($"Device can read {blocksToRead} blocks at a time.");
|
UpdateStatus?.Invoke($"Device can read {blocksToRead} blocks at a time.");
|
||||||
_dumpLog.WriteLine("Device can read {0} blocks at a time.", blocksToRead);
|
_dumpLog.WriteLine("Device can read {0} blocks at a time.", blocksToRead);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
UpdateStatus?.Invoke($"Device can read {blocksToRead} blocks using sequential commands.");
|
||||||
|
_dumpLog.WriteLine("Device can read {0} blocks using sequential commands.", blocksToRead);
|
||||||
|
}
|
||||||
|
|
||||||
if(_skip < blocksToRead)
|
if(_skip < blocksToRead)
|
||||||
_skip = blocksToRead;
|
_skip = blocksToRead;
|
||||||
@@ -491,8 +543,15 @@ namespace Aaru.Core.Devices.Dumping
|
|||||||
UpdateProgress?.Invoke($"Reading sector {i} of {blocks} ({currentSpeed:F3} MiB/sec.)", (long)i,
|
UpdateProgress?.Invoke($"Reading sector {i} of {blocks} ({currentSpeed:F3} MiB/sec.)", (long)i,
|
||||||
(long)blocks);
|
(long)blocks);
|
||||||
|
|
||||||
error = _dev.Read(out cmdBuf, out response, (uint)i, blockSize, blocksToRead, byteAddressed, timeout,
|
if(blocksToRead == 1)
|
||||||
|
error = _dev.ReadSingleBlock(out cmdBuf, out _, (uint)i, blockSize, byteAddressed, timeout,
|
||||||
out duration);
|
out duration);
|
||||||
|
else if(supportsCmd23)
|
||||||
|
error = _dev.ReadWithBlockCount(out cmdBuf, out _, (uint)i, blockSize, blocksToRead, byteAddressed,
|
||||||
|
timeout, out duration);
|
||||||
|
else
|
||||||
|
error = _dev.ReadMultipleUsingSingle(out cmdBuf, out _, (uint)i, blockSize, blocksToRead,
|
||||||
|
byteAddressed, timeout, out duration);
|
||||||
|
|
||||||
if(!error)
|
if(!error)
|
||||||
{
|
{
|
||||||
@@ -588,8 +647,8 @@ namespace Aaru.Core.Devices.Dumping
|
|||||||
|
|
||||||
PulseProgress?.Invoke($"Trimming sector {badSector}");
|
PulseProgress?.Invoke($"Trimming sector {badSector}");
|
||||||
|
|
||||||
error = _dev.Read(out cmdBuf, out response, (uint)badSector, blockSize, 1, byteAddressed, timeout,
|
error = _dev.ReadSingleBlock(out cmdBuf, out response, (uint)badSector, blockSize, byteAddressed,
|
||||||
out duration);
|
timeout, out duration);
|
||||||
|
|
||||||
totalDuration += duration;
|
totalDuration += duration;
|
||||||
|
|
||||||
@@ -640,8 +699,8 @@ namespace Aaru.Core.Devices.Dumping
|
|||||||
forward ? "forward" : "reverse",
|
forward ? "forward" : "reverse",
|
||||||
runningPersistent ? "recovering partial data, " : ""));
|
runningPersistent ? "recovering partial data, " : ""));
|
||||||
|
|
||||||
error = _dev.Read(out cmdBuf, out response, (uint)badSector, blockSize, 1, byteAddressed, timeout,
|
error = _dev.ReadSingleBlock(out cmdBuf, out response, (uint)badSector, blockSize, byteAddressed,
|
||||||
out duration);
|
timeout, out duration);
|
||||||
|
|
||||||
totalDuration += duration;
|
totalDuration += duration;
|
||||||
|
|
||||||
|
|||||||
@@ -34,6 +34,8 @@ using System;
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using Aaru.Core.Logging;
|
using Aaru.Core.Logging;
|
||||||
using Aaru.Decoders.MMC;
|
using Aaru.Decoders.MMC;
|
||||||
|
using Aaru.Decoders.SecureDigital;
|
||||||
|
using CSD = Aaru.Decoders.MMC.CSD;
|
||||||
using DeviceType = Aaru.CommonTypes.Enums.DeviceType;
|
using DeviceType = Aaru.CommonTypes.Enums.DeviceType;
|
||||||
|
|
||||||
// ReSharper disable JoinDeclarationAndInitializer
|
// ReSharper disable JoinDeclarationAndInitializer
|
||||||
@@ -55,6 +57,7 @@ namespace Aaru.Core.Devices.Scanning
|
|||||||
ushort blocksToRead = 128;
|
ushort blocksToRead = 128;
|
||||||
uint blockSize = 512;
|
uint blockSize = 512;
|
||||||
bool byteAddressed = true;
|
bool byteAddressed = true;
|
||||||
|
bool supportsCmd23 = false;
|
||||||
|
|
||||||
switch(_dev.Type)
|
switch(_dev.Type)
|
||||||
{
|
{
|
||||||
@@ -68,6 +71,9 @@ namespace Aaru.Core.Devices.Scanning
|
|||||||
results.Blocks = (ulong)((csd.Size + 1) * Math.Pow(2, csd.SizeMultiplier + 2));
|
results.Blocks = (ulong)((csd.Size + 1) * Math.Pow(2, csd.SizeMultiplier + 2));
|
||||||
blockSize = (uint)Math.Pow(2, csd.ReadBlockLength);
|
blockSize = (uint)Math.Pow(2, csd.ReadBlockLength);
|
||||||
|
|
||||||
|
// Found at least since MMC System Specification 3.31
|
||||||
|
supportsCmd23 = csd.Version >= 3;
|
||||||
|
|
||||||
if(csd.Size == 0xFFF)
|
if(csd.Size == 0xFFF)
|
||||||
{
|
{
|
||||||
sense = _dev.ReadExtendedCsd(out cmdBuf, out _, timeout, out _);
|
sense = _dev.ReadExtendedCsd(out cmdBuf, out _, timeout, out _);
|
||||||
@@ -115,6 +121,12 @@ namespace Aaru.Core.Devices.Scanning
|
|||||||
results.Blocks *= ratio;
|
results.Blocks *= ratio;
|
||||||
blockSize = 512;
|
blockSize = 512;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sense = _dev.ReadScr(out cmdBuf, out _, timeout, out _);
|
||||||
|
|
||||||
|
if(!sense)
|
||||||
|
supportsCmd23 = Decoders.SecureDigital.Decoders.DecodeSCR(cmdBuf)?.CommandSupport.
|
||||||
|
HasFlag(CommandSupport.SetBlockCount) ?? false;
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
@@ -128,9 +140,36 @@ namespace Aaru.Core.Devices.Scanning
|
|||||||
return results;
|
return results;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(supportsCmd23)
|
||||||
|
{
|
||||||
|
sense = _dev.ReadWithBlockCount(out cmdBuf, out _, 0, blockSize, 1, byteAddressed, timeout,
|
||||||
|
out duration);
|
||||||
|
|
||||||
|
if(sense || _dev.Error)
|
||||||
|
{
|
||||||
|
UpdateStatus?.
|
||||||
|
Invoke("Environment does not support setting block count, downgrading to OS reading.");
|
||||||
|
|
||||||
|
supportsCmd23 = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Need to restart device, otherwise is it just busy streaming data with no one listening
|
||||||
|
sense = _dev.ReOpen();
|
||||||
|
|
||||||
|
if(sense)
|
||||||
|
{
|
||||||
|
StoppingErrorMessage?.Invoke($"Error {_dev.LastError} reopening device.");
|
||||||
|
|
||||||
|
return results;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(supportsCmd23)
|
||||||
|
{
|
||||||
while(true)
|
while(true)
|
||||||
{
|
{
|
||||||
sense = _dev.Read(out cmdBuf, out _, 0, blockSize, blocksToRead, byteAddressed, timeout, out duration);
|
sense = _dev.ReadWithBlockCount(out cmdBuf, out _, 0, blockSize, blocksToRead, byteAddressed,
|
||||||
|
timeout, out duration);
|
||||||
|
|
||||||
if(sense)
|
if(sense)
|
||||||
blocksToRead /= 2;
|
blocksToRead /= 2;
|
||||||
@@ -142,10 +181,12 @@ namespace Aaru.Core.Devices.Scanning
|
|||||||
|
|
||||||
if(sense)
|
if(sense)
|
||||||
{
|
{
|
||||||
StoppingErrorMessage?.Invoke($"Device error {_dev.LastError} trying to guess ideal transfer length.");
|
StoppingErrorMessage?.
|
||||||
|
Invoke($"Device error {_dev.LastError} trying to guess ideal transfer length.");
|
||||||
|
|
||||||
return results;
|
return results;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
results.A = 0; // <3ms
|
results.A = 0; // <3ms
|
||||||
results.B = 0; // >=3ms, <10ms
|
results.B = 0; // >=3ms, <10ms
|
||||||
@@ -164,11 +205,14 @@ namespace Aaru.Core.Devices.Scanning
|
|||||||
results.SeekMax = double.MinValue;
|
results.SeekMax = double.MinValue;
|
||||||
results.SeekMin = double.MaxValue;
|
results.SeekMin = double.MaxValue;
|
||||||
results.SeekTotal = 0;
|
results.SeekTotal = 0;
|
||||||
const int SEEK_TIMES = 100;
|
const int seekTimes = 100;
|
||||||
|
|
||||||
var rnd = new Random();
|
var rnd = new Random();
|
||||||
|
|
||||||
|
if(supportsCmd23 || blocksToRead == 1)
|
||||||
UpdateStatus?.Invoke($"Reading {blocksToRead} sectors at a time.");
|
UpdateStatus?.Invoke($"Reading {blocksToRead} sectors at a time.");
|
||||||
|
else
|
||||||
|
UpdateStatus?.Invoke($"Reading {blocksToRead} sectors using sequential single commands.");
|
||||||
|
|
||||||
InitBlockMap?.Invoke(results.Blocks, blockSize, blocksToRead, sdProfile);
|
InitBlockMap?.Invoke(results.Blocks, blockSize, blocksToRead, sdProfile);
|
||||||
var mhddLog = new MhddLog(_mhddLogPath, _dev, results.Blocks, blockSize, blocksToRead, false);
|
var mhddLog = new MhddLog(_mhddLogPath, _dev, results.Blocks, blockSize, blocksToRead, false);
|
||||||
@@ -198,8 +242,17 @@ namespace Aaru.Core.Devices.Scanning
|
|||||||
UpdateProgress?.Invoke($"Reading sector {i} of {results.Blocks} ({currentSpeed:F3} MiB/sec.)", (long)i,
|
UpdateProgress?.Invoke($"Reading sector {i} of {results.Blocks} ({currentSpeed:F3} MiB/sec.)", (long)i,
|
||||||
(long)results.Blocks);
|
(long)results.Blocks);
|
||||||
|
|
||||||
bool error = _dev.Read(out cmdBuf, out _, (uint)i, blockSize, blocksToRead, byteAddressed, timeout,
|
bool error;
|
||||||
|
|
||||||
|
if(blocksToRead == 1)
|
||||||
|
error = _dev.ReadSingleBlock(out cmdBuf, out _, (uint)i, blockSize, byteAddressed, timeout,
|
||||||
out duration);
|
out duration);
|
||||||
|
else if(supportsCmd23)
|
||||||
|
error = _dev.ReadWithBlockCount(out cmdBuf, out _, (uint)i, blockSize, blocksToRead, byteAddressed,
|
||||||
|
timeout, out duration);
|
||||||
|
else
|
||||||
|
error = _dev.ReadMultipleUsingSingle(out cmdBuf, out _, (uint)i, blockSize, blocksToRead,
|
||||||
|
byteAddressed, timeout, out duration);
|
||||||
|
|
||||||
if(!error)
|
if(!error)
|
||||||
{
|
{
|
||||||
@@ -256,7 +309,7 @@ namespace Aaru.Core.Devices.Scanning
|
|||||||
|
|
||||||
InitProgress?.Invoke();
|
InitProgress?.Invoke();
|
||||||
|
|
||||||
for(int i = 0; i < SEEK_TIMES; i++)
|
for(int i = 0; i < seekTimes; i++)
|
||||||
{
|
{
|
||||||
if(_aborted || !_seekTest)
|
if(_aborted || !_seekTest)
|
||||||
break;
|
break;
|
||||||
@@ -285,7 +338,7 @@ namespace Aaru.Core.Devices.Scanning
|
|||||||
results.ProcessingTime /= 1000;
|
results.ProcessingTime /= 1000;
|
||||||
results.TotalTime = (end - start).TotalSeconds;
|
results.TotalTime = (end - start).TotalSeconds;
|
||||||
results.AvgSpeed = blockSize * (double)(results.Blocks + 1) / 1048576 / results.ProcessingTime;
|
results.AvgSpeed = blockSize * (double)(results.Blocks + 1) / 1048576 / results.ProcessingTime;
|
||||||
results.SeekTimes = SEEK_TIMES;
|
results.SeekTimes = seekTimes;
|
||||||
|
|
||||||
return results;
|
return results;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -243,5 +243,63 @@ namespace Aaru.Devices
|
|||||||
|
|
||||||
return sense;
|
return sense;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public bool ReadWithBlockCount(out byte[] buffer, out uint[] response, uint lba, uint blockSize,
|
||||||
|
ushort transferLength, bool byteAddressed, uint timeout, out double duration)
|
||||||
|
{
|
||||||
|
uint address = byteAddressed ? lba * blockSize : lba;
|
||||||
|
MmcSingleCommand[] commands = new MmcSingleCommand[3];
|
||||||
|
|
||||||
|
// SET_BLOCK_COUNT
|
||||||
|
commands[0] = new MmcSingleCommand
|
||||||
|
{
|
||||||
|
command = MmcCommands.SetBlockCount,
|
||||||
|
write = false,
|
||||||
|
isApplication = false,
|
||||||
|
flags = MmcFlags.ResponseSpiR1 | MmcFlags.ResponseR1 | MmcFlags.CommandAc,
|
||||||
|
argument = transferLength,
|
||||||
|
blockSize = 0,
|
||||||
|
blocks = 0,
|
||||||
|
buffer = new byte[0]
|
||||||
|
};
|
||||||
|
|
||||||
|
// READ_MULTIPLE_BLOCK
|
||||||
|
commands[1] = new MmcSingleCommand
|
||||||
|
{
|
||||||
|
command = MmcCommands.ReadMultipleBlock,
|
||||||
|
write = false,
|
||||||
|
isApplication = false,
|
||||||
|
flags = MmcFlags.ResponseSpiR1 | MmcFlags.ResponseR1 | MmcFlags.CommandAdtc,
|
||||||
|
argument = address,
|
||||||
|
blockSize = blockSize,
|
||||||
|
blocks = transferLength,
|
||||||
|
buffer = new byte[transferLength * blockSize]
|
||||||
|
};
|
||||||
|
|
||||||
|
// STOP_TRANSMISSION
|
||||||
|
// Needed if the previous command fails
|
||||||
|
commands[2] = new MmcSingleCommand
|
||||||
|
{
|
||||||
|
command = MmcCommands.StopTransmission,
|
||||||
|
write = false,
|
||||||
|
isApplication = false,
|
||||||
|
flags = MmcFlags.ResponseSpiR1B | MmcFlags.ResponseR1B | MmcFlags.CommandAc,
|
||||||
|
argument = 0,
|
||||||
|
blockSize = 0,
|
||||||
|
blocks = 0,
|
||||||
|
buffer = new byte[0]
|
||||||
|
};
|
||||||
|
|
||||||
|
LastError = SendMultipleMmcCommands(commands, out duration, out bool sense, timeout);
|
||||||
|
|
||||||
|
Error = LastError != 0;
|
||||||
|
|
||||||
|
AaruConsole.DebugWriteLine("SecureDigital Device", "READ_MULTIPLE_BLOCK took {0} ms.", duration);
|
||||||
|
|
||||||
|
buffer = commands[1].buffer;
|
||||||
|
response = commands[1].response;
|
||||||
|
|
||||||
|
return sense;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user