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.Core.Logging;
|
||||
using Aaru.Decoders.MMC;
|
||||
using Aaru.Decoders.SecureDigital;
|
||||
using Schemas;
|
||||
using CSD = Aaru.Decoders.MMC.CSD;
|
||||
using DeviceType = Aaru.CommonTypes.Enums.DeviceType;
|
||||
using MediaType = Aaru.CommonTypes.MediaType;
|
||||
using Version = Aaru.CommonTypes.Interop.Version;
|
||||
@@ -85,6 +87,7 @@ namespace Aaru.Core.Devices.Dumping
|
||||
uint physicalBlockSize = 0;
|
||||
bool byteAddressed = true;
|
||||
uint[] response;
|
||||
bool supportsCmd23 = false;
|
||||
|
||||
Dictionary<MediaTagType, byte[]> mediaTags = new Dictionary<MediaTagType, byte[]>();
|
||||
|
||||
@@ -104,6 +107,9 @@ namespace Aaru.Core.Devices.Dumping
|
||||
|
||||
mediaTags.Add(MediaTagType.MMC_CSD, null);
|
||||
|
||||
// Found at least since MMC System Specification 3.31
|
||||
supportsCmd23 = csdDecoded.Version >= 3;
|
||||
|
||||
if(csdDecoded.Size == 0xFFF)
|
||||
{
|
||||
UpdateStatus?.Invoke("Reading Extended CSD");
|
||||
@@ -215,7 +221,12 @@ namespace Aaru.Core.Devices.Dumping
|
||||
scr = null;
|
||||
}
|
||||
else
|
||||
{
|
||||
supportsCmd23 = Decoders.SecureDigital.Decoders.DecodeSCR(scr)?.CommandSupport.
|
||||
HasFlag(CommandSupport.SetBlockCount) ?? false;
|
||||
|
||||
mediaTags.Add(MediaTagType.SD_SCR, null);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
@@ -254,9 +265,39 @@ namespace Aaru.Core.Devices.Dumping
|
||||
byte[] cmdBuf;
|
||||
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)
|
||||
{
|
||||
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)
|
||||
blocksToRead /= 2;
|
||||
@@ -269,13 +310,24 @@ namespace Aaru.Core.Devices.Dumping
|
||||
if(error)
|
||||
{
|
||||
_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;
|
||||
}
|
||||
}
|
||||
|
||||
if(supportsCmd23 || blocksToRead == 1)
|
||||
{
|
||||
UpdateStatus?.Invoke($"Device can read {blocksToRead} blocks at a time.");
|
||||
_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)
|
||||
_skip = blocksToRead;
|
||||
@@ -491,8 +543,15 @@ namespace Aaru.Core.Devices.Dumping
|
||||
UpdateProgress?.Invoke($"Reading sector {i} of {blocks} ({currentSpeed:F3} MiB/sec.)", (long)i,
|
||||
(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);
|
||||
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)
|
||||
{
|
||||
@@ -588,8 +647,8 @@ namespace Aaru.Core.Devices.Dumping
|
||||
|
||||
PulseProgress?.Invoke($"Trimming sector {badSector}");
|
||||
|
||||
error = _dev.Read(out cmdBuf, out response, (uint)badSector, blockSize, 1, byteAddressed, timeout,
|
||||
out duration);
|
||||
error = _dev.ReadSingleBlock(out cmdBuf, out response, (uint)badSector, blockSize, byteAddressed,
|
||||
timeout, out duration);
|
||||
|
||||
totalDuration += duration;
|
||||
|
||||
@@ -640,8 +699,8 @@ namespace Aaru.Core.Devices.Dumping
|
||||
forward ? "forward" : "reverse",
|
||||
runningPersistent ? "recovering partial data, " : ""));
|
||||
|
||||
error = _dev.Read(out cmdBuf, out response, (uint)badSector, blockSize, 1, byteAddressed, timeout,
|
||||
out duration);
|
||||
error = _dev.ReadSingleBlock(out cmdBuf, out response, (uint)badSector, blockSize, byteAddressed,
|
||||
timeout, out duration);
|
||||
|
||||
totalDuration += duration;
|
||||
|
||||
|
||||
@@ -34,6 +34,8 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using Aaru.Core.Logging;
|
||||
using Aaru.Decoders.MMC;
|
||||
using Aaru.Decoders.SecureDigital;
|
||||
using CSD = Aaru.Decoders.MMC.CSD;
|
||||
using DeviceType = Aaru.CommonTypes.Enums.DeviceType;
|
||||
|
||||
// ReSharper disable JoinDeclarationAndInitializer
|
||||
@@ -55,6 +57,7 @@ namespace Aaru.Core.Devices.Scanning
|
||||
ushort blocksToRead = 128;
|
||||
uint blockSize = 512;
|
||||
bool byteAddressed = true;
|
||||
bool supportsCmd23 = false;
|
||||
|
||||
switch(_dev.Type)
|
||||
{
|
||||
@@ -68,6 +71,9 @@ namespace Aaru.Core.Devices.Scanning
|
||||
results.Blocks = (ulong)((csd.Size + 1) * Math.Pow(2, csd.SizeMultiplier + 2));
|
||||
blockSize = (uint)Math.Pow(2, csd.ReadBlockLength);
|
||||
|
||||
// Found at least since MMC System Specification 3.31
|
||||
supportsCmd23 = csd.Version >= 3;
|
||||
|
||||
if(csd.Size == 0xFFF)
|
||||
{
|
||||
sense = _dev.ReadExtendedCsd(out cmdBuf, out _, timeout, out _);
|
||||
@@ -115,6 +121,12 @@ namespace Aaru.Core.Devices.Scanning
|
||||
results.Blocks *= ratio;
|
||||
blockSize = 512;
|
||||
}
|
||||
|
||||
sense = _dev.ReadScr(out cmdBuf, out _, timeout, out _);
|
||||
|
||||
if(!sense)
|
||||
supportsCmd23 = Decoders.SecureDigital.Decoders.DecodeSCR(cmdBuf)?.CommandSupport.
|
||||
HasFlag(CommandSupport.SetBlockCount) ?? false;
|
||||
}
|
||||
|
||||
break;
|
||||
@@ -128,9 +140,36 @@ namespace Aaru.Core.Devices.Scanning
|
||||
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)
|
||||
{
|
||||
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)
|
||||
blocksToRead /= 2;
|
||||
@@ -142,10 +181,12 @@ namespace Aaru.Core.Devices.Scanning
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
results.A = 0; // <3ms
|
||||
results.B = 0; // >=3ms, <10ms
|
||||
@@ -164,11 +205,14 @@ namespace Aaru.Core.Devices.Scanning
|
||||
results.SeekMax = double.MinValue;
|
||||
results.SeekMin = double.MaxValue;
|
||||
results.SeekTotal = 0;
|
||||
const int SEEK_TIMES = 100;
|
||||
const int seekTimes = 100;
|
||||
|
||||
var rnd = new Random();
|
||||
|
||||
if(supportsCmd23 || blocksToRead == 1)
|
||||
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);
|
||||
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,
|
||||
(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);
|
||||
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)
|
||||
{
|
||||
@@ -256,7 +309,7 @@ namespace Aaru.Core.Devices.Scanning
|
||||
|
||||
InitProgress?.Invoke();
|
||||
|
||||
for(int i = 0; i < SEEK_TIMES; i++)
|
||||
for(int i = 0; i < seekTimes; i++)
|
||||
{
|
||||
if(_aborted || !_seekTest)
|
||||
break;
|
||||
@@ -285,7 +338,7 @@ namespace Aaru.Core.Devices.Scanning
|
||||
results.ProcessingTime /= 1000;
|
||||
results.TotalTime = (end - start).TotalSeconds;
|
||||
results.AvgSpeed = blockSize * (double)(results.Blocks + 1) / 1048576 / results.ProcessingTime;
|
||||
results.SeekTimes = SEEK_TIMES;
|
||||
results.SeekTimes = seekTimes;
|
||||
|
||||
return results;
|
||||
}
|
||||
|
||||
@@ -243,5 +243,63 @@ namespace Aaru.Devices
|
||||
|
||||
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