mirror of
https://github.com/aaru-dps/Aaru.git
synced 2026-07-08 18:16:24 +00:00
Add Omnidrive BD raw support
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
// /***************************************************************************
|
||||
// /***************************************************************************
|
||||
// Aaru Data Preservation Suite
|
||||
// ----------------------------------------------------------------------------
|
||||
//
|
||||
@@ -80,6 +80,7 @@ partial class Dump
|
||||
var containsFloppyPage = false;
|
||||
const ushort sbcProfile = 0x0001;
|
||||
const uint DvdLeadinSectors = 4096; // Usable Lead-in before LBA 0 per DVD spec (PSN 0x02F000–0x02FFFF)
|
||||
const uint BdFallbackNegativeSectors = 4832 * 32; // Usable lead-in clusters before LBA 0 per BD spec
|
||||
double totalDuration = 0;
|
||||
double currentSpeed = 0;
|
||||
double maxSpeed = double.MinValue;
|
||||
@@ -237,7 +238,7 @@ partial class Dump
|
||||
break;
|
||||
}
|
||||
|
||||
if(scsiReader.FindReadCommand())
|
||||
if(scsiReader.FindReadCommand(dskType))
|
||||
{
|
||||
AaruLogging.WriteLine(Localization.Core.ERROR_Cannot_find_correct_read_command_0, scsiReader.ErrorMessage);
|
||||
StoppingErrorMessage?.Invoke(Localization.Core.Unable_to_read_medium);
|
||||
@@ -327,7 +328,7 @@ partial class Dump
|
||||
scsiReader.otp = decodedPfi?.TrackPath ?? false;
|
||||
|
||||
if(scsiReader.HldtstReadRaw) blocksToRead = 1;
|
||||
if(scsiReader.OmniDriveReadRaw) blocksToRead = 31;
|
||||
if(scsiReader.OmniDriveReadRaw) blocksToRead = scsiReader.OmniDriveReadRawBluray ? 7u : 31u;
|
||||
|
||||
UpdateStatus?.Invoke(string.Format(Localization.Core.Reading_0_raw_bytes_1_cooked_bytes_per_sector,
|
||||
longBlockSize,
|
||||
@@ -442,7 +443,8 @@ partial class Dump
|
||||
mediaTags.TryGetValue(MediaTagType.BD_DI, out byte[] di);
|
||||
DI.DiscInformation? decodedDi = DI.Decode(di);
|
||||
|
||||
if(decodedDi.HasValue) nominalNegativeSectors = decodedDi.Value.Units[0].FirstAun;
|
||||
if(scsiReader.OmniDriveReadRawBluray)
|
||||
nominalNegativeSectors = BdFallbackNegativeSectors;
|
||||
|
||||
sense = _dev.ReadDiscInformation(out byte[] readBuffer,
|
||||
out _,
|
||||
@@ -871,35 +873,53 @@ partial class Dump
|
||||
|
||||
if(scsiReader.HldtstReadRaw || scsiReader.ReadBuffer3CReadRaw || scsiReader.OmniDriveReadRaw)
|
||||
{
|
||||
uint nominalForRawDvd = 0;
|
||||
uint overflowForRawDvd = 0;
|
||||
uint nominalForRaw = 0;
|
||||
uint overflowForRaw = 0;
|
||||
|
||||
if(scsiReader.OmniDriveReadRaw && outputFormat is IWritableOpticalImage optImg)
|
||||
{
|
||||
if(optImg.OpticalCapabilities.HasFlag(OpticalImageCapabilities.CanStoreNegativeSectors))
|
||||
nominalForRawDvd = nominalNegativeSectors;
|
||||
nominalForRaw = nominalNegativeSectors;
|
||||
|
||||
if(optImg.OpticalCapabilities.HasFlag(OpticalImageCapabilities.CanStoreOverflowSectors))
|
||||
overflowForRawDvd = 100u;
|
||||
overflowForRaw = scsiReader.OmniDriveReadRawBluray ? 0x432u : 100u;
|
||||
}
|
||||
|
||||
ReadRawDvdData(blocks,
|
||||
blocksToRead,
|
||||
blockSize,
|
||||
currentTry,
|
||||
extents,
|
||||
ref currentSpeed,
|
||||
ref minSpeed,
|
||||
ref maxSpeed,
|
||||
ref totalDuration,
|
||||
scsiReader,
|
||||
mhddLog,
|
||||
ibgLog,
|
||||
ref imageWriteDuration,
|
||||
ref newTrim,
|
||||
discKey ?? null,
|
||||
nominalForRawDvd,
|
||||
overflowForRawDvd);
|
||||
if(scsiReader.OmniDriveReadRawBluray)
|
||||
ReadRawBdData(blocks,
|
||||
blocksToRead,
|
||||
blockSize,
|
||||
currentTry,
|
||||
extents,
|
||||
ref currentSpeed,
|
||||
ref minSpeed,
|
||||
ref maxSpeed,
|
||||
ref totalDuration,
|
||||
scsiReader,
|
||||
mhddLog,
|
||||
ibgLog,
|
||||
ref imageWriteDuration,
|
||||
ref newTrim,
|
||||
nominalForRaw,
|
||||
overflowForRaw);
|
||||
else
|
||||
ReadRawDvdData(blocks,
|
||||
blocksToRead,
|
||||
blockSize,
|
||||
currentTry,
|
||||
extents,
|
||||
ref currentSpeed,
|
||||
ref minSpeed,
|
||||
ref maxSpeed,
|
||||
ref totalDuration,
|
||||
scsiReader,
|
||||
mhddLog,
|
||||
ibgLog,
|
||||
ref imageWriteDuration,
|
||||
ref newTrim,
|
||||
discKey ?? null,
|
||||
nominalForRaw,
|
||||
overflowForRaw);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -342,6 +342,14 @@ partial class Dump
|
||||
}
|
||||
else
|
||||
{
|
||||
if(scsiReader.OmniDriveReadRawBluray)
|
||||
{
|
||||
_resume.BadBlocks.Remove(badSector);
|
||||
outputFormat.WriteSectorLong(buffer, badSector, false, SectorStatus.Dumped);
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
var cmi = new byte[1];
|
||||
|
||||
byte[] key = buffer.Skip(7).Take(5).ToArray();
|
||||
|
||||
320
Aaru.Core/Devices/Dumping/Sbc/RawBd.cs
Normal file
320
Aaru.Core/Devices/Dumping/Sbc/RawBd.cs
Normal file
@@ -0,0 +1,320 @@
|
||||
// /***************************************************************************
|
||||
// Aaru Data Preservation Suite
|
||||
// ----------------------------------------------------------------------------
|
||||
//
|
||||
// Filename : RawBd.cs
|
||||
// Author(s) : Rebecca Wallander <sakcheen@gmail.com>
|
||||
//
|
||||
// --[ License ] --------------------------------------------------------------
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as
|
||||
// published by the Free Software Foundation, either version 3 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This program 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 General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
// ----------------------------------------------------------------------------
|
||||
// Copyright © 2011-2026 Natalia Portillo
|
||||
// Copyright © 2020-2026 Rebecca Wallander
|
||||
// ****************************************************************************/
|
||||
|
||||
using System;
|
||||
using System.Linq;
|
||||
using Aaru.CommonTypes.AaruMetadata;
|
||||
using Aaru.CommonTypes.Enums;
|
||||
using Aaru.CommonTypes.Extents;
|
||||
using Aaru.CommonTypes.Interfaces;
|
||||
using Aaru.Core.Logging;
|
||||
using Aaru.Logging;
|
||||
using Humanizer;
|
||||
|
||||
// ReSharper disable JoinDeclarationAndInitializer
|
||||
// ReSharper disable InlineOutVariableDeclaration
|
||||
// ReSharper disable TooWideLocalVariableScope
|
||||
|
||||
namespace Aaru.Core.Devices.Dumping;
|
||||
|
||||
partial class Dump
|
||||
{
|
||||
/// <summary>
|
||||
/// Dumps raw Blu-ray sectors (2052-byte DataFrames) when dumping from a SCSI Block Commands compliant device.
|
||||
/// Supports OmniDrive raw reading.
|
||||
/// </summary>
|
||||
/// <param name="blocks">Media blocks</param>
|
||||
/// <param name="maxBlocksToRead">Maximum number of blocks to read in a single command</param>
|
||||
/// <param name="blockSize">Block size in bytes</param>
|
||||
/// <param name="currentTry">Resume information</param>
|
||||
/// <param name="extents">Correctly dump extents</param>
|
||||
/// <param name="currentSpeed">Current speed</param>
|
||||
/// <param name="minSpeed">Minimum speed</param>
|
||||
/// <param name="maxSpeed">Maximum speed</param>
|
||||
/// <param name="totalDuration">Total time spent in commands</param>
|
||||
/// <param name="scsiReader">SCSI reader</param>
|
||||
/// <param name="mhddLog">MHDD log</param>
|
||||
/// <param name="ibgLog">ImgBurn log</param>
|
||||
/// <param name="imageWriteDuration">Total time spent writing to image</param>
|
||||
/// <param name="newTrim">Set if we need to start a trim</param>
|
||||
/// <param name="nominalNegativeSectors">Lead-in sectors to read when drive and format supports negative sectors</param>
|
||||
/// <param name="overflowSectors">Leadout sectors to read when drive and format supports overflow sectors</param>
|
||||
void ReadRawBdData(in ulong blocks, in uint maxBlocksToRead, in uint blockSize, DumpHardware currentTry,
|
||||
ExtentsULong extents, ref double currentSpeed, ref double minSpeed, ref double maxSpeed,
|
||||
ref double totalDuration, Reader scsiReader, MhddLog mhddLog, IbgLog ibgLog,
|
||||
ref double imageWriteDuration, ref bool newTrim, uint nominalNegativeSectors,
|
||||
uint overflowSectors)
|
||||
{
|
||||
ulong sectorSpeedStart = 0;
|
||||
bool sense;
|
||||
byte[] buffer;
|
||||
uint blocksToRead = maxBlocksToRead;
|
||||
var outputFormat = _outputPlugin as IWritableImage;
|
||||
|
||||
if(outputFormat is null)
|
||||
{
|
||||
ErrorMessage?.Invoke(Localization.Core.Output_format_not_initialized);
|
||||
return;
|
||||
}
|
||||
|
||||
InitProgress?.Invoke();
|
||||
|
||||
// Phase 1: Lead-in (negative LBA) — OmniDrive only. Read from nominalNegativeSectors up to -1.
|
||||
if(nominalNegativeSectors > 0)
|
||||
{
|
||||
UpdateStatus?.Invoke(Localization.Core.Reading_lead_in_sectors);
|
||||
|
||||
for(ulong sectorAddress = nominalNegativeSectors; sectorAddress >= 1;)
|
||||
{
|
||||
if(_aborted)
|
||||
{
|
||||
currentTry.Extents = ExtentsConverter.ToMetadata(extents);
|
||||
UpdateStatus?.Invoke(Localization.Core.Aborted);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
uint toRead = (uint)Math.Min(sectorAddress, blocksToRead);
|
||||
|
||||
if(currentSpeed > maxSpeed && currentSpeed > 0) maxSpeed = currentSpeed;
|
||||
if(currentSpeed < minSpeed && currentSpeed > 0) minSpeed = currentSpeed;
|
||||
|
||||
UpdateProgress?.Invoke(string.Format(Localization.Core.Reading_sector_0_of_1_2,
|
||||
sectorAddress,
|
||||
nominalNegativeSectors,
|
||||
ByteSize.FromMegabytes(currentSpeed).Per(_oneSecond).Humanize()),
|
||||
(long)(nominalNegativeSectors - sectorAddress + toRead),
|
||||
(long)nominalNegativeSectors);
|
||||
|
||||
sense = scsiReader.ReadBlocks(out buffer, sectorAddress, toRead, out double cmdDuration, out _, out _, true);
|
||||
totalDuration += cmdDuration;
|
||||
|
||||
if(!sense && !_dev.Error)
|
||||
{
|
||||
mhddLog.Write((ulong)-(long)sectorAddress, cmdDuration, toRead);
|
||||
ibgLog.Write((ulong)-(long)sectorAddress, currentSpeed * 1024);
|
||||
|
||||
// ReadBlocks returns sectors in logical order (-N..-1); WriteSectorsLong expects ascending order.
|
||||
byte[] writeBuffer = new byte[buffer.Length];
|
||||
for(uint i = 0; i < toRead; i++)
|
||||
Array.Copy(buffer, (int)(i * blockSize), writeBuffer, (int)((toRead - 1 - i) * blockSize),
|
||||
(int)blockSize);
|
||||
|
||||
_writeStopwatch.Restart();
|
||||
outputFormat.WriteSectorsLong(writeBuffer,
|
||||
sectorAddress - toRead + 1,
|
||||
true,
|
||||
toRead,
|
||||
Enumerable.Repeat(SectorStatus.Dumped, (int)toRead).ToArray());
|
||||
imageWriteDuration += _writeStopwatch.Elapsed.TotalSeconds;
|
||||
_writeStopwatch.Stop();
|
||||
}
|
||||
else
|
||||
{
|
||||
if(_stopOnError) return;
|
||||
|
||||
_writeStopwatch.Restart();
|
||||
outputFormat.WriteSectorsLong(new byte[blockSize * toRead],
|
||||
sectorAddress,
|
||||
true,
|
||||
toRead,
|
||||
Enumerable.Repeat(SectorStatus.NotDumped, (int)toRead).ToArray());
|
||||
imageWriteDuration += _writeStopwatch.Elapsed.TotalSeconds;
|
||||
_writeStopwatch.Stop();
|
||||
}
|
||||
|
||||
if(sectorAddress <= 1) break;
|
||||
sectorAddress -= toRead;
|
||||
sectorSpeedStart += toRead;
|
||||
double elapsed = _speedStopwatch.Elapsed.TotalSeconds;
|
||||
if(elapsed > 0)
|
||||
{
|
||||
currentSpeed = (double)sectorSpeedStart * blockSize / (1048576d * elapsed);
|
||||
sectorSpeedStart = 0;
|
||||
_speedStopwatch.Restart();
|
||||
}
|
||||
}
|
||||
|
||||
UpdateStatus?.Invoke(Localization.Core.Reading_data_sectors);
|
||||
}
|
||||
|
||||
// Phase 2: Data zone
|
||||
for(ulong i = _resume.NextBlock; i < blocks; i += blocksToRead)
|
||||
{
|
||||
if(_aborted)
|
||||
{
|
||||
currentTry.Extents = ExtentsConverter.ToMetadata(extents);
|
||||
UpdateStatus?.Invoke(Localization.Core.Aborted);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
if(blocks - i < blocksToRead) blocksToRead = (uint)(blocks - i);
|
||||
|
||||
if(currentSpeed > maxSpeed && currentSpeed > 0) maxSpeed = currentSpeed;
|
||||
|
||||
if(currentSpeed < minSpeed && currentSpeed > 0) minSpeed = currentSpeed;
|
||||
|
||||
UpdateProgress?.Invoke(string.Format(Localization.Core.Reading_sector_0_of_1_2,
|
||||
i,
|
||||
blocks,
|
||||
ByteSize.FromMegabytes(currentSpeed).Per(_oneSecond).Humanize()),
|
||||
(long)i,
|
||||
(long)blocks);
|
||||
|
||||
sense = scsiReader.ReadBlocks(out buffer, i, blocksToRead, out double cmdDuration, out _, out _);
|
||||
totalDuration += cmdDuration;
|
||||
|
||||
if(!sense && !_dev.Error)
|
||||
{
|
||||
mhddLog.Write(i, cmdDuration, blocksToRead);
|
||||
ibgLog.Write(i, currentSpeed * 1024);
|
||||
|
||||
_writeStopwatch.Restart();
|
||||
outputFormat.WriteSectorsLong(buffer,
|
||||
i,
|
||||
false,
|
||||
blocksToRead,
|
||||
Enumerable.Repeat(SectorStatus.Dumped, (int)blocksToRead).ToArray());
|
||||
|
||||
imageWriteDuration += _writeStopwatch.Elapsed.TotalSeconds;
|
||||
extents.Add(i, blocksToRead, true);
|
||||
_mediaGraph?.PaintSectorsGood(i, blocksToRead);
|
||||
}
|
||||
else
|
||||
{
|
||||
if(_stopOnError) return;
|
||||
|
||||
if(i + _skip > blocks) _skip = (uint)(blocks - i);
|
||||
|
||||
_writeStopwatch.Restart();
|
||||
outputFormat.WriteSectorsLong(new byte[blockSize * _skip],
|
||||
i,
|
||||
false,
|
||||
_skip,
|
||||
Enumerable.Repeat(SectorStatus.NotDumped, (int)_skip).ToArray());
|
||||
|
||||
imageWriteDuration += _writeStopwatch.Elapsed.TotalSeconds;
|
||||
|
||||
for(ulong b = i; b < i + _skip; b++) _resume.BadBlocks.Add(b);
|
||||
|
||||
mhddLog.Write(i, cmdDuration < 500 ? 65535 : cmdDuration, _skip);
|
||||
ibgLog.Write(i, 0);
|
||||
AaruLogging.WriteLine(Localization.Core.Skipping_0_blocks_from_errored_block_1, _skip, i);
|
||||
i += _skip - blocksToRead;
|
||||
newTrim = true;
|
||||
}
|
||||
|
||||
_writeStopwatch.Stop();
|
||||
sectorSpeedStart += blocksToRead;
|
||||
_resume.NextBlock = i + blocksToRead;
|
||||
|
||||
double elapsed = _speedStopwatch.Elapsed.TotalSeconds;
|
||||
|
||||
if(elapsed <= 0) continue;
|
||||
|
||||
currentSpeed = sectorSpeedStart * blockSize / (1048576 * elapsed);
|
||||
sectorSpeedStart = 0;
|
||||
_speedStopwatch.Restart();
|
||||
}
|
||||
|
||||
// Phase 3: Leadout (overflow sectors) — OmniDrive only
|
||||
if(overflowSectors > 0)
|
||||
{
|
||||
UpdateStatus?.Invoke(Localization.Core.Reading_lead_out_sectors);
|
||||
|
||||
blocksToRead = maxBlocksToRead;
|
||||
for(ulong lba = blocks; lba < blocks + overflowSectors; lba += blocksToRead)
|
||||
{
|
||||
if(_aborted)
|
||||
{
|
||||
currentTry.Extents = ExtentsConverter.ToMetadata(extents);
|
||||
UpdateStatus?.Invoke(Localization.Core.Aborted);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
uint toRead = (uint)(blocks + overflowSectors - lba);
|
||||
if(toRead > blocksToRead) toRead = blocksToRead;
|
||||
|
||||
if(currentSpeed > maxSpeed && currentSpeed > 0) maxSpeed = currentSpeed;
|
||||
if(currentSpeed < minSpeed && currentSpeed > 0) minSpeed = currentSpeed;
|
||||
|
||||
UpdateProgress?.Invoke(string.Format(Localization.Core.Reading_sector_0_of_1_2,
|
||||
lba,
|
||||
blocks + overflowSectors,
|
||||
ByteSize.FromMegabytes(currentSpeed).Per(_oneSecond).Humanize()),
|
||||
(long)lba,
|
||||
(long)(blocks + overflowSectors));
|
||||
|
||||
sense = scsiReader.ReadBlocks(out buffer, lba, toRead, out double cmdDuration, out _, out _);
|
||||
totalDuration += cmdDuration;
|
||||
|
||||
if(!sense && !_dev.Error)
|
||||
{
|
||||
mhddLog.Write(lba, cmdDuration, toRead);
|
||||
ibgLog.Write(lba, currentSpeed * 1024);
|
||||
|
||||
_writeStopwatch.Restart();
|
||||
outputFormat.WriteSectorsLong(buffer,
|
||||
lba,
|
||||
false,
|
||||
toRead,
|
||||
Enumerable.Repeat(SectorStatus.Dumped, (int)toRead).ToArray());
|
||||
imageWriteDuration += _writeStopwatch.Elapsed.TotalSeconds;
|
||||
}
|
||||
else
|
||||
{
|
||||
if(_stopOnError) return;
|
||||
|
||||
_writeStopwatch.Restart();
|
||||
outputFormat.WriteSectorsLong(new byte[blockSize * toRead],
|
||||
lba,
|
||||
false,
|
||||
toRead,
|
||||
Enumerable.Repeat(SectorStatus.NotDumped, (int)toRead).ToArray());
|
||||
imageWriteDuration += _writeStopwatch.Elapsed.TotalSeconds;
|
||||
}
|
||||
|
||||
_writeStopwatch.Stop();
|
||||
sectorSpeedStart += toRead;
|
||||
double elapsed = _speedStopwatch.Elapsed.TotalSeconds;
|
||||
if(elapsed > 0)
|
||||
{
|
||||
currentSpeed = (double)sectorSpeedStart * blockSize / (1048576d * elapsed);
|
||||
sectorSpeedStart = 0;
|
||||
_speedStopwatch.Restart();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_speedStopwatch.Stop();
|
||||
_resume.BadBlocks = _resume.BadBlocks.Distinct().ToList();
|
||||
|
||||
EndProgress?.Invoke();
|
||||
}
|
||||
}
|
||||
@@ -110,6 +110,14 @@ partial class Dump
|
||||
}
|
||||
else
|
||||
{
|
||||
if(scsiReader.OmniDriveReadRawBluray)
|
||||
{
|
||||
_resume.BadBlocks.Remove(badSector);
|
||||
outputFormat.WriteSectorLong(buffer, badSector, false, SectorStatus.Dumped);
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
var cmi = new byte[1];
|
||||
|
||||
byte[] key = buffer.Skip(7).Take(5).ToArray();
|
||||
|
||||
@@ -36,6 +36,7 @@ using Aaru.CommonTypes.Enums;
|
||||
using Aaru.CommonTypes.Structs.Devices.ATA;
|
||||
using Aaru.Core.Logging;
|
||||
using Aaru.Devices;
|
||||
using Aaru.CommonTypes;
|
||||
|
||||
namespace Aaru.Core.Devices;
|
||||
|
||||
@@ -104,7 +105,7 @@ sealed partial class Reader
|
||||
}
|
||||
}
|
||||
|
||||
internal bool FindReadCommand()
|
||||
internal bool FindReadCommand(MediaType mediaType = MediaType.Unknown)
|
||||
{
|
||||
switch(_dev.Type)
|
||||
{
|
||||
@@ -112,7 +113,7 @@ sealed partial class Reader
|
||||
return AtaFindReadCommand();
|
||||
case DeviceType.ATAPI:
|
||||
case DeviceType.SCSI:
|
||||
return ScsiFindReadCommand();
|
||||
return ScsiFindReadCommand(mediaType);
|
||||
default:
|
||||
ErrorMessage = string.Format(Localization.Core.Unknown_device_type_0, _dev.Type);
|
||||
|
||||
|
||||
@@ -31,9 +31,11 @@
|
||||
// ****************************************************************************/
|
||||
|
||||
using System;
|
||||
using Aaru.CommonTypes.Enums;
|
||||
using Aaru.CommonTypes.Structs.Devices.SCSI;
|
||||
using Aaru.Decoders.SCSI;
|
||||
using Aaru.Logging;
|
||||
using Aaru.CommonTypes;
|
||||
|
||||
namespace Aaru.Core.Devices;
|
||||
|
||||
@@ -56,12 +58,24 @@ sealed partial class Reader
|
||||
public bool HldtstReadRaw;
|
||||
public uint layerbreak;
|
||||
public bool OmniDriveReadRaw;
|
||||
public bool OmniDriveReadRawBluray;
|
||||
public bool ReadBuffer3CReadRaw;
|
||||
public bool otp;
|
||||
|
||||
ulong ScsiGetBlocks() => ScsiGetBlockSize() ? 0 : Blocks;
|
||||
|
||||
bool ScsiFindReadCommand()
|
||||
static bool IsBlurayMedia(MediaType mediaType) =>
|
||||
mediaType is MediaType.BDROM or
|
||||
MediaType.BDR or
|
||||
MediaType.BDRE or
|
||||
MediaType.BDRXL or
|
||||
MediaType.BDREXL or
|
||||
MediaType.UHDBD or
|
||||
MediaType.PS3BD or
|
||||
MediaType.PS4BD or
|
||||
MediaType.PS5BD;
|
||||
|
||||
bool ScsiFindReadCommand(MediaType mediaType = MediaType.Unknown)
|
||||
{
|
||||
if(Blocks == 0) GetDeviceBlocks();
|
||||
|
||||
@@ -591,6 +605,22 @@ sealed partial class Reader
|
||||
// Try OmniDrive on drives with OmniDrive firmware (standard descramble=1 and Nintendo descramble=0)
|
||||
if(_dev.IsOmniDriveFirmware())
|
||||
{
|
||||
OmniDriveReadRawBluray = false;
|
||||
|
||||
if(IsBlurayMedia(mediaType))
|
||||
{
|
||||
OmniDriveReadRawBluray = !_dev.OmniDriveReadRawBd(out _,
|
||||
out senseBuf,
|
||||
0,
|
||||
1,
|
||||
_timeout,
|
||||
out _,
|
||||
true,
|
||||
true);
|
||||
OmniDriveReadRaw = OmniDriveReadRawBluray;
|
||||
}
|
||||
else
|
||||
{
|
||||
bool omniStandardOk = !_dev.OmniDriveReadRawDvd(out _, out senseBuf, 0, 1, _timeout, out _, true, true);
|
||||
|
||||
OmniDriveReadRaw = omniStandardOk
|
||||
@@ -606,12 +636,13 @@ sealed partial class Reader
|
||||
null,
|
||||
false,
|
||||
0);
|
||||
}
|
||||
}
|
||||
|
||||
if(HldtstReadRaw || _plextorReadRaw || ReadBuffer3CReadRaw || OmniDriveReadRaw)
|
||||
{
|
||||
CanReadRaw = true;
|
||||
LongBlockSize = 2064;
|
||||
LongBlockSize = OmniDriveReadRawBluray ? 2052u : 2064u;
|
||||
}
|
||||
|
||||
// READ LONG (10) for some DVD drives
|
||||
@@ -644,7 +675,8 @@ sealed partial class Reader
|
||||
else if(_plextorReadRaw)
|
||||
AaruLogging.WriteLine($"[slateblue1]{Localization.Core.Using_Plextor_raw_DVD_reading}[/]");
|
||||
else if(OmniDriveReadRaw)
|
||||
AaruLogging.WriteLine($"[slateblue1]{Localization.Core.Using_OmniDrive_raw_DVD_reading}[/]");
|
||||
AaruLogging.WriteLine(
|
||||
$"[slateblue1]{(OmniDriveReadRawBluray ? Localization.Core.Using_OmniDrive_raw_BD_reading : Localization.Core.Using_OmniDrive_raw_DVD_reading)}[/]");
|
||||
else if(ReadBuffer3CReadRaw)
|
||||
AaruLogging.WriteLine($"[slateblue1]{Localization.Core.Using_ReadBuffer_3C_raw_DVD_reading}[/]");
|
||||
}
|
||||
@@ -712,7 +744,7 @@ sealed partial class Reader
|
||||
BlocksToRead = 1;
|
||||
else if(OmniDriveReadRaw)
|
||||
{
|
||||
BlocksToRead = (uint)Math.Min(31, startWithBlocks);
|
||||
BlocksToRead = (uint)Math.Min(OmniDriveReadRawBluray ? 7 : 31, startWithBlocks);
|
||||
return false;
|
||||
}
|
||||
else if(_read6)
|
||||
@@ -865,7 +897,14 @@ sealed partial class Reader
|
||||
{
|
||||
uint lba = negative ? (uint)(-(long)block) : (uint)block;
|
||||
|
||||
if(OmniDriveNintendoMode)
|
||||
if(OmniDriveReadRawBluray)
|
||||
sense = _dev.OmniDriveReadRawBd(out buffer,
|
||||
out senseBuf,
|
||||
lba,
|
||||
count,
|
||||
_timeout,
|
||||
out duration);
|
||||
else if(OmniDriveNintendoMode)
|
||||
{
|
||||
ulong regularDataEndExclusive = Blocks + 1;
|
||||
|
||||
|
||||
@@ -118,6 +118,14 @@ public static class DI
|
||||
{
|
||||
if(DIResponse == null) return null;
|
||||
|
||||
// Handle if the size has been stripped from the DI
|
||||
if(DIResponse.Length == 4096)
|
||||
{
|
||||
byte[] tmp2 = new byte[4100];
|
||||
Array.Copy(DIResponse, 0, tmp2, 4, 4096);
|
||||
DIResponse = tmp2;
|
||||
}
|
||||
|
||||
if(DIResponse.Length != 4100)
|
||||
{
|
||||
AaruLogging.Debug(MODULE_NAME,
|
||||
|
||||
@@ -28,11 +28,12 @@ using Aaru.Decoders.Bluray;
|
||||
|
||||
namespace Aaru.Decoders.Bluray;
|
||||
|
||||
/// <summary>Blu-ray DataFrame: 2048 bytes main_data + 4 bytes EDC (redumper raw .sbram).</summary>
|
||||
/// <summary>Blu-ray DataFrame: 2048 bytes main_data + 4 bytes EDC.</summary>
|
||||
public static class DataFrame
|
||||
{
|
||||
/// <summary>Total size of one BD DataFrame in a Redumper .sbram file.</summary>
|
||||
/// <summary>Total size of one BD DataFrame.</summary>
|
||||
public const int Size = 2048 + 4;
|
||||
public const int UserControlDataSize = 18;
|
||||
|
||||
/// <summary>Descrambles a 2052-byte frame in place (ISO/IEC 30190 LFSR XOR).</summary>
|
||||
public static void Descramble(Span<byte> frame, int lba, bool nintendo)
|
||||
|
||||
@@ -37,12 +37,16 @@ using Aaru.CommonTypes.Enums;
|
||||
using Aaru.CommonTypes.Structs.Devices.SCSI;
|
||||
using Aaru.Logging;
|
||||
using Aaru.Decoders.DVD;
|
||||
using BlurayDataFrame = Aaru.Decoders.Bluray.DataFrame;
|
||||
using NintendoSector = Aaru.Decoders.Nintendo.Sector;
|
||||
|
||||
namespace Aaru.Devices;
|
||||
|
||||
public partial class Device
|
||||
{
|
||||
const int OMNIDRIVE_BD_DATA_FRAME_SIZE = BlurayDataFrame.Size;
|
||||
const int OMNIDRIVE_BD_TRANSFER_PER_LBA = OMNIDRIVE_BD_DATA_FRAME_SIZE + BlurayDataFrame.UserControlDataSize;
|
||||
|
||||
readonly NintendoSector _nintendoSectorDecoder = new NintendoSector();
|
||||
readonly Sector _dvdSectorDecoder = new Sector();
|
||||
enum OmniDriveDiscType
|
||||
@@ -67,7 +71,7 @@ public partial class Device
|
||||
return (byte)(d | (r << 2) | (f << 3) | (s << 4));
|
||||
}
|
||||
|
||||
static void FillOmniDriveReadDvdCdb(Span<byte> cdb, uint lba, uint transferLength, byte cdbByte1)
|
||||
static void FillOmniDriveReadCdb(Span<byte> cdb, uint lba, uint transferLength, byte cdbByte1)
|
||||
{
|
||||
cdb.Clear();
|
||||
cdb[0] = (byte)ScsiCommands.ReadOmniDrive;
|
||||
@@ -129,7 +133,7 @@ public partial class Device
|
||||
Span<byte> cdb = CdbBuffer[..12];
|
||||
buffer = new byte[2064 * transferLength];
|
||||
|
||||
FillOmniDriveReadDvdCdb(cdb,
|
||||
FillOmniDriveReadCdb(cdb,
|
||||
lba,
|
||||
transferLength,
|
||||
EncodeOmniDriveReadCdb1(OmniDriveDiscType.DVD, false, fua, descramble));
|
||||
@@ -147,6 +151,54 @@ public partial class Device
|
||||
return sense;
|
||||
}
|
||||
|
||||
/// <summary>Reads raw Blu-ray sectors (2052-byte DataFrame) directly by LBA on OmniDrive firmware.</summary>
|
||||
/// <returns><c>true</c> if the command failed and <paramref name="senseBuffer" /> contains the sense buffer.</returns>
|
||||
/// <param name="buffer">Buffer where the raw Blu-ray DataFrame response will be stored.</param>
|
||||
/// <param name="senseBuffer">Sense buffer.</param>
|
||||
/// <param name="lba">Start block address (LBA).</param>
|
||||
/// <param name="transferLength">Number of 2052-byte sectors to read.</param>
|
||||
/// <param name="timeout">Timeout in seconds.</param>
|
||||
/// <param name="duration">Duration in milliseconds it took for the device to execute the command.</param>
|
||||
/// <param name="fua">Set to <c>true</c> if the command should use FUA.</param>
|
||||
/// <param name="descramble">Set to <c>true</c> if the data should be descrambled by the device.</param>
|
||||
public bool OmniDriveReadRawBd(out byte[] buffer, out ReadOnlySpan<byte> senseBuffer, uint lba, uint transferLength,
|
||||
uint timeout, out double duration, bool fua = false, bool descramble = true)
|
||||
{
|
||||
senseBuffer = SenseBuffer;
|
||||
Span<byte> cdb = CdbBuffer[..12];
|
||||
byte[] deviceBuffer = new byte[OMNIDRIVE_BD_TRANSFER_PER_LBA * transferLength];
|
||||
buffer = new byte[OMNIDRIVE_BD_DATA_FRAME_SIZE * transferLength];
|
||||
|
||||
FillOmniDriveReadCdb(cdb,
|
||||
lba,
|
||||
transferLength,
|
||||
EncodeOmniDriveReadCdb1(OmniDriveDiscType.BD, false, fua, descramble));
|
||||
|
||||
LastError = SendScsiCommand(cdb, ref deviceBuffer, timeout, ScsiDirection.In, out duration, out bool sense);
|
||||
|
||||
if(sense)
|
||||
{
|
||||
Error = LastError != 0;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
for(uint i = 0; i < transferLength; i++)
|
||||
{
|
||||
int deviceOffset = (int)(i * OMNIDRIVE_BD_TRANSFER_PER_LBA);
|
||||
int dataOffset = (int)(i * OMNIDRIVE_BD_DATA_FRAME_SIZE);
|
||||
Array.Copy(deviceBuffer, deviceOffset, buffer, dataOffset, OMNIDRIVE_BD_DATA_FRAME_SIZE);
|
||||
|
||||
if(descramble && !Decoders.Bluray.Sector.CheckEdc(buffer.AsSpan(dataOffset, OMNIDRIVE_BD_DATA_FRAME_SIZE).ToArray())) return true;
|
||||
}
|
||||
|
||||
Error = LastError != 0;
|
||||
|
||||
AaruLogging.Debug(SCSI_MODULE_NAME, "OmniDrive READ RAW BD took {0} ms", duration);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reads Nintendo GameCube/Wii DVD sectors (2064 bytes) on OmniDrive. The drive returns DVD-layer data with
|
||||
/// drive-side DVD descramble off; this method applies per-sector Nintendo XOR descramble and returns the result.
|
||||
@@ -171,10 +223,10 @@ public partial class Device
|
||||
Span<byte> cdb = CdbBuffer[..12];
|
||||
buffer = new byte[2064 * transferLength];
|
||||
|
||||
FillOmniDriveReadDvdCdb(cdb,
|
||||
lba,
|
||||
transferLength,
|
||||
EncodeOmniDriveReadCdb1(OmniDriveDiscType.DVD, false, fua, false));
|
||||
FillOmniDriveReadCdb(cdb,
|
||||
lba,
|
||||
transferLength,
|
||||
EncodeOmniDriveReadCdb1(OmniDriveDiscType.DVD, false, fua, false));
|
||||
|
||||
LastError = SendScsiCommand(cdb, ref buffer, timeout, ScsiDirection.In, out duration, out bool sense);
|
||||
|
||||
|
||||
6
Aaru.Localization/Core.Designer.cs
generated
6
Aaru.Localization/Core.Designer.cs
generated
@@ -6857,6 +6857,12 @@ namespace Aaru.Localization {
|
||||
}
|
||||
}
|
||||
|
||||
public static string Using_OmniDrive_raw_BD_reading {
|
||||
get {
|
||||
return ResourceManager.GetString("Using_OmniDrive_raw_BD_reading", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
public static string Using_ReadBuffer_3C_raw_DVD_reading {
|
||||
get {
|
||||
return ResourceManager.GetString("Using_ReadBuffer_3C_raw_DVD_reading", resourceCulture);
|
||||
|
||||
@@ -3286,6 +3286,9 @@ No tiene sentido hacerlo y supondría demasiado esfuerzo para la cinta.</value>
|
||||
<data name="Using_OmniDrive_raw_DVD_reading" xml:space="preserve">
|
||||
<value>[slateblue1]Usando lectura de [fuchsia]DVD sin procesar de OmniDrive[/].[/]</value>
|
||||
</data>
|
||||
<data name="Using_OmniDrive_raw_BD_reading" xml:space="preserve">
|
||||
<value>[slateblue1]Usando lectura de [fuchsia]Blu-ray sin procesar de OmniDrive[/].[/]</value>
|
||||
</data>
|
||||
<data name="Using_Plextor_raw_DVD_reading" xml:space="preserve">
|
||||
<value>[slateblue1]Usando lectura de [fuchsia]DVD sin procesar de Plextor[/].[/]</value>
|
||||
</data>
|
||||
|
||||
@@ -3511,6 +3511,9 @@ It has no sense to do it, and it will put too much strain on the tape.</value>
|
||||
<data name="Using_OmniDrive_raw_DVD_reading" xml:space="preserve">
|
||||
<value>[slateblue1]Using [fuchsia]OmniDrive[/] raw DVD reading[/]</value>
|
||||
</data>
|
||||
<data name="Using_OmniDrive_raw_BD_reading" xml:space="preserve">
|
||||
<value>[slateblue1]Using [fuchsia]OmniDrive[/] raw Blu-ray reading[/]</value>
|
||||
</data>
|
||||
<data name="Using_ReadBuffer_3C_raw_DVD_reading" xml:space="preserve">
|
||||
<value>[slateblue1]Using [fuchsia]ReadBuffer 3C raw DVD[/] reading[/]</value>
|
||||
</data>
|
||||
|
||||
Reference in New Issue
Block a user