From 5c2006d7786e4b5006068aaf10b002ad0197cd44 Mon Sep 17 00:00:00 2001 From: Natalia Portillo Date: Sat, 4 Jul 2026 20:14:28 +0100 Subject: [PATCH] Add OmniDrive READ CD command. --- Aaru.Devices/Device/ScsiCommands/OmniDrive.cs | 115 ++++++++++++------ 1 file changed, 75 insertions(+), 40 deletions(-) diff --git a/Aaru.Devices/Device/ScsiCommands/OmniDrive.cs b/Aaru.Devices/Device/ScsiCommands/OmniDrive.cs index 14c0ecff7..5af6cc3d3 100644 --- a/Aaru.Devices/Device/ScsiCommands/OmniDrive.cs +++ b/Aaru.Devices/Device/ScsiCommands/OmniDrive.cs @@ -4,6 +4,7 @@ // // Filename : OmniDrive.cs // Author(s) : Rebecca Wallander +// Natalia Portillo // // Component : OmniDrive firmware vendor commands. // @@ -30,31 +31,27 @@ // // ---------------------------------------------------------------------------- // Copyright © 2011-2026 Rebecca Wallander +// Copyright © 2011-2026 Natalia Portillo // ****************************************************************************/ using System; using Aaru.CommonTypes.Enums; using Aaru.CommonTypes.Structs.Devices.SCSI; -using Aaru.Logging; using Aaru.Decoders.DVD; +using Aaru.Logging; using NintendoSector = Aaru.Decoders.Nintendo.Sector; namespace Aaru.Devices; public partial class Device { - readonly NintendoSector _nintendoSectorDecoder = new NintendoSector(); - readonly Sector _dvdSectorDecoder = new Sector(); - enum OmniDriveDiscType - { - CD = 0, - DVD = 1, - BD = 2 - } + readonly Sector _dvdSectorDecoder = new(); + readonly NintendoSector _nintendoSectorDecoder = new(); /// /// Encodes byte 1 of the OmniDrive READ CDB to match redumper's CDB12_ReadOmniDrive - /// (scsi/mmc.ixx): disc_type :2 (LSB), raw_addressing :1, fua :1, descramble :1, reserved :3. + /// (scsi/mmc.ixx): disc_type :2 (LSB), raw_addressing :1, fua :1, descramble :1, + /// reserved :3. /// /// 0 = CD, 1 = DVD, 2 = BD (redumper OmniDrive_DiscType). static byte EncodeOmniDriveReadCdb1(OmniDriveDiscType discType, bool rawAddressing, bool fua, bool descramble) @@ -64,22 +61,22 @@ public partial class Device int f = fua ? 1 : 0; int s = descramble ? 1 : 0; - return (byte)(d | (r << 2) | (f << 3) | (s << 4)); + return (byte)(d | r << 2 | f << 3 | s << 4); } static void FillOmniDriveReadDvdCdb(Span cdb, uint lba, uint transferLength, byte cdbByte1) { cdb.Clear(); - cdb[0] = (byte)ScsiCommands.ReadOmniDrive; - cdb[1] = cdbByte1; - cdb[2] = (byte)((lba >> 24) & 0xFF); - cdb[3] = (byte)((lba >> 16) & 0xFF); - cdb[4] = (byte)((lba >> 8) & 0xFF); - cdb[5] = (byte)(lba & 0xFF); - cdb[6] = (byte)((transferLength >> 24) & 0xFF); - cdb[7] = (byte)((transferLength >> 16) & 0xFF); - cdb[8] = (byte)((transferLength >> 8) & 0xFF); - cdb[9] = (byte)(transferLength & 0xFF); + cdb[0] = (byte)ScsiCommands.ReadOmniDrive; + cdb[1] = cdbByte1; + cdb[2] = (byte)(lba >> 24 & 0xFF); + cdb[3] = (byte)(lba >> 16 & 0xFF); + cdb[4] = (byte)(lba >> 8 & 0xFF); + cdb[5] = (byte)(lba & 0xFF); + cdb[6] = (byte)(transferLength >> 24 & 0xFF); + cdb[7] = (byte)(transferLength >> 16 & 0xFF); + cdb[8] = (byte)(transferLength >> 8 & 0xFF); + cdb[9] = (byte)(transferLength & 0xFF); cdb[10] = 0; // subchannels=NONE, c2=0 cdb[11] = 0; // control } @@ -97,21 +94,21 @@ public partial class Device bool sense = ScsiInquiry(out byte[] buffer, out _, Timeout, out _); - if (sense || buffer == null) return false; + if(sense || buffer == null) return false; Inquiry? inquiry = Inquiry.Decode(buffer); - if (!inquiry.HasValue || inquiry.Value.Reserved5 == null || inquiry.Value.Reserved5.Length < 11) - return false; + if(!inquiry.HasValue || inquiry.Value.Reserved5 == null || inquiry.Value.Reserved5.Length < 11) return false; byte[] reserved5 = inquiry.Value.Reserved5; byte[] omnidrive = [0x4F, 0x6D, 0x6E, 0x69, 0x44, 0x72, 0x69, 0x76, 0x65]; // "OmniDrive" - if (reserved5.Length < omnidrive.Length) return false; + if(reserved5.Length < omnidrive.Length) return false; - for (int i = 0; i < omnidrive.Length; i++) - if (reserved5[i] != omnidrive[i]) - return false; + for(var i = 0; i < omnidrive.Length; i++) + { + if(reserved5[i] != omnidrive[i]) return false; + } major = reserved5[9]; minor = reserved5[10]; @@ -130,8 +127,9 @@ public partial class Device /// Duration in milliseconds it took for the device to execute the command. /// Set to true if the command should use FUA. /// Set to true if the data should be descrambled by the device. - public bool OmniDriveReadRawDvd(out byte[] buffer, out ReadOnlySpan senseBuffer, uint lba, uint transferLength, - uint timeout, out double duration, bool fua = false, bool descramble = true) + public bool OmniDriveReadRawDvd(out byte[] buffer, out ReadOnlySpan senseBuffer, uint lba, + uint transferLength, uint timeout, out double duration, bool fua = false, + bool descramble = true) { senseBuffer = SenseBuffer; Span cdb = CdbBuffer[..12]; @@ -144,7 +142,7 @@ public partial class Device LastError = SendScsiCommand(cdb, ref buffer, timeout, ScsiDirection.In, out duration, out bool sense); - if (!Sector.CheckIed(buffer, transferLength)) return true; + if(!Sector.CheckIed(buffer, transferLength)) return true; if(descramble && !Sector.CheckEdc(buffer, transferLength)) return true; @@ -170,10 +168,10 @@ public partial class Device /// descramble. /// /// true if the command failed and contains the sense buffer. - public bool OmniDriveReadNintendoDvd(out byte[] buffer, out ReadOnlySpan senseBuffer, uint lba, uint transferLength, - uint timeout, out double duration, bool fua = false, bool descramble = true, - byte? derivedDiscKey = null, bool negativeAddressing = false, - ulong regularDataEndExclusive = 0) + public bool OmniDriveReadNintendoDvd(out byte[] buffer, out ReadOnlySpan senseBuffer, uint lba, + uint transferLength, uint timeout, out double duration, bool fua = false, + bool descramble = true, byte? derivedDiscKey = null, + bool negativeAddressing = false, ulong regularDataEndExclusive = 0) { senseBuffer = SenseBuffer; Span cdb = CdbBuffer[..12]; @@ -190,13 +188,13 @@ public partial class Device if(descramble) { - const int sectorBytes = 2064; - byte[] outBuf = new byte[sectorBytes * transferLength]; + const int sectorBytes = 2064; + var outBuf = new byte[sectorBytes * transferLength]; const uint maxRegularLba = 0x00FFFFFF; for(uint i = 0; i < transferLength; i++) { - byte[] slice = new byte[sectorBytes]; + var slice = new byte[sectorBytes]; Array.Copy(buffer, i * sectorBytes, slice, 0, sectorBytes); uint absLba = lba + i; @@ -210,7 +208,7 @@ public partial class Device errno = _dvdSectorDecoder.Scramble(slice, out descrambled); else { - byte key = absLba < 16 ? (byte)0 : (derivedDiscKey ?? (byte)0); + byte key = absLba < 16 ? (byte)0 : derivedDiscKey ?? 0; errno = _nintendoSectorDecoder.Scramble(slice, key, out descrambled); } @@ -234,4 +232,41 @@ public partial class Device return sense; } -} + + public bool OmniDriveReadCd(out byte[] buffer, out ReadOnlySpan senseBuffer, uint lba, uint transferLength, + uint timeout, out double duration, bool fua = false, bool rawAddressing = false) + { + senseBuffer = SenseBuffer; + Span cdb = CdbBuffer[..12]; + buffer = new byte[2448 * transferLength]; + + cdb.Clear(); + cdb[0] = (byte)ScsiCommands.ReadOmniDrive; + cdb[1] = EncodeOmniDriveReadCdb1(OmniDriveDiscType.CD, rawAddressing, fua, false); + cdb[2] = (byte)(lba >> 24 & 0xFF); + cdb[3] = (byte)(lba >> 16 & 0xFF); + cdb[4] = (byte)(lba >> 8 & 0xFF); + cdb[5] = (byte)(lba & 0xFF); + cdb[6] = (byte)(transferLength >> 24 & 0xFF); + cdb[7] = (byte)(transferLength >> 16 & 0xFF); + cdb[8] = (byte)(transferLength >> 8 & 0xFF); + cdb[9] = (byte)(transferLength & 0xFF); + cdb[10] = 1; // subchannels=RW + cdb[11] = 0; // control + + LastError = SendScsiCommand(cdb, ref buffer, timeout, ScsiDirection.In, out duration, out bool sense); + + Error = LastError != 0; + + AaruLogging.Debug(SCSI_MODULE_NAME, "OmniDrive READ CD took {0} ms", duration); + + return sense; + } + + enum OmniDriveDiscType + { + CD = 0, + DVD = 1, + BD = 2 + } +} \ No newline at end of file