Add Omnidrive BD raw support

This commit is contained in:
Rebecca Wallander
2026-04-15 12:32:01 +02:00
parent b5da187778
commit 9d310890a0
12 changed files with 509 additions and 40 deletions

View File

@@ -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 0x02F0000x02FFFF)
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
{

View File

@@ -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();

View 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();
}
}

View File

@@ -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();

View File

@@ -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);

View File

@@ -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;

View File

@@ -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,

View File

@@ -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)

View File

@@ -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);

View File

@@ -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);

View File

@@ -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>

View File

@@ -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>