From 4818765c5d00d4b9f5fac55bbb332a68e51652b1 Mon Sep 17 00:00:00 2001 From: Natalia Portillo Date: Sun, 4 Feb 2018 22:43:37 +0000 Subject: [PATCH] Add support for dumping ISRC and MCN. --- .../Devices/Dumping/CompactDisc.cs | 25 +- .../Device/ScsiCommands/MMC.cs | 266 +++++++++++------- DiscImageChef/Commands/MediaInfo.cs | 142 ++++++---- 3 files changed, 274 insertions(+), 159 deletions(-) diff --git a/DiscImageChef.Core/Devices/Dumping/CompactDisc.cs b/DiscImageChef.Core/Devices/Dumping/CompactDisc.cs index 0b4a2906b..98b8c43d3 100644 --- a/DiscImageChef.Core/Devices/Dumping/CompactDisc.cs +++ b/DiscImageChef.Core/Devices/Dumping/CompactDisc.cs @@ -57,7 +57,7 @@ namespace DiscImageChef.Core.Devices.Dumping /// /// Implement dumping Compact Discs /// - // TODO: ISRC, MCN and pregaps + // TODO: Barcode and pregaps static class CompactDisc { /// @@ -757,6 +757,29 @@ namespace DiscImageChef.Core.Devices.Dumping outputPlugin.WriteSectorTag(new[] {kvp.Value}, track.TrackStartSector, SectorTagType.CdTrackFlags); } + // Set MCN + sense = dev.ReadMcn(out string mcn, out _, out _, dev.Timeout, out _); + if(!sense && mcn != null && mcn != "0000000000000") + if(outputPlugin.WriteMediaTag(Encoding.ASCII.GetBytes(mcn), MediaTagType.CD_MCN)) + { + DicConsole.WriteLine("Setting disc Media Catalogue Number to {0}", mcn); + dumpLog.WriteLine("Setting disc Media Catalogue Number to {0}", mcn); + } + + // Set ISRCs + foreach(Track trk in tracks) + { + sense = dev.ReadIsrc((byte)trk.TrackSequence, out string isrc, out _, out _, dev.Timeout, out _); + if(sense || isrc == null || isrc == "000000000000") continue; + + if(outputPlugin.WriteSectorTag(Encoding.ASCII.GetBytes(isrc), trk.TrackStartSector, + SectorTagType.CdTrackIsrc)) + { + DicConsole.WriteLine("Setting ISRC for track {0} to {1}", trk.TrackSequence, isrc); + dumpLog.WriteLine("Setting ISRC for track {0} to {1}", trk.TrackSequence, isrc); + } + } + if(resume.NextBlock > 0) dumpLog.WriteLine("Resuming from block {0}.", resume.NextBlock); double imageWriteDuration = 0; diff --git a/DiscImageChef.Devices/Device/ScsiCommands/MMC.cs b/DiscImageChef.Devices/Device/ScsiCommands/MMC.cs index 428887ba6..5cb658f7f 100644 --- a/DiscImageChef.Devices/Device/ScsiCommands/MMC.cs +++ b/DiscImageChef.Devices/Device/ScsiCommands/MMC.cs @@ -31,6 +31,7 @@ // ****************************************************************************/ using System; +using System.Text; using DiscImageChef.Console; namespace DiscImageChef.Devices @@ -60,11 +61,11 @@ namespace DiscImageChef.Devices /// Feature number where the feature list should start from /// Timeout in seconds. /// Duration in milliseconds it took for the device to execute the command. - public bool GetConfiguration(out byte[] buffer, out byte[] senseBuffer, ushort startingFeatureNumber, - uint timeout, out double duration) + public bool GetConfiguration(out byte[] buffer, out byte[] senseBuffer, ushort startingFeatureNumber, + uint timeout, out double duration) { return GetConfiguration(out buffer, out senseBuffer, startingFeatureNumber, MmcGetConfigurationRt.All, - timeout, out duration); + timeout, out duration); } /// @@ -77,19 +78,19 @@ namespace DiscImageChef.Devices /// Duration in milliseconds it took for the device to execute the command. /// Starting Feature number. /// Return type, . - public bool GetConfiguration(out byte[] buffer, out byte[] senseBuffer, ushort startingFeatureNumber, - MmcGetConfigurationRt rt, uint timeout, out double duration) + public bool GetConfiguration(out byte[] buffer, out byte[] senseBuffer, ushort startingFeatureNumber, + MmcGetConfigurationRt rt, uint timeout, out double duration) { senseBuffer = new byte[32]; - byte[] cdb = new byte[10]; - buffer = new byte[8]; + byte[] cdb = new byte[10]; + buffer = new byte[8]; cdb[0] = (byte)ScsiCommands.GetConfiguration; - cdb[1] = (byte)((byte)rt & 0x03); + cdb[1] = (byte)((byte)rt & 0x03); cdb[2] = (byte)((startingFeatureNumber & 0xFF00) >> 8); - cdb[3] = (byte)(startingFeatureNumber & 0xFF); - cdb[7] = (byte)((buffer.Length & 0xFF00) >> 8); - cdb[8] = (byte)(buffer.Length & 0xFF); + cdb[3] = (byte)(startingFeatureNumber & 0xFF); + cdb[7] = (byte)((buffer.Length & 0xFF00) >> 8); + cdb[8] = (byte)(buffer.Length & 0xFF); cdb[9] = 0; LastError = SendScsiCommand(cdb, ref buffer, out senseBuffer, timeout, ScsiDirection.In, out duration, @@ -99,10 +100,10 @@ namespace DiscImageChef.Devices if(sense) return true; ushort confLength = (ushort)((buffer[2] << 8) + buffer[3] + 4); - buffer = new byte[confLength]; - cdb[7] = (byte)((buffer.Length & 0xFF00) >> 8); - cdb[8] = (byte)(buffer.Length & 0xFF); - senseBuffer = new byte[32]; + buffer = new byte[confLength]; + cdb[7] = (byte)((buffer.Length & 0xFF00) >> 8); + cdb[8] = (byte)(buffer.Length & 0xFF); + senseBuffer = new byte[32]; LastError = SendScsiCommand(cdb, ref buffer, out senseBuffer, timeout, ScsiDirection.In, out duration, out sense); @@ -127,24 +128,25 @@ namespace DiscImageChef.Devices /// AGID used in medium copy protection /// Duration in milliseconds it took for the device to execute the command. public bool ReadDiscStructure(out byte[] buffer, out byte[] senseBuffer, MmcDiscStructureMediaType mediaType, - uint address, byte layerNumber, MmcDiscStructureFormat format, byte agid, - uint timeout, out double duration) + uint address, byte layerNumber, MmcDiscStructureFormat format, + byte agid, + uint timeout, out double duration) { senseBuffer = new byte[32]; - byte[] cdb = new byte[12]; - buffer = new byte[8]; + byte[] cdb = new byte[12]; + buffer = new byte[8]; - cdb[0] = (byte)ScsiCommands.ReadDiscStructure; - cdb[1] = (byte)((byte)mediaType & 0x0F); - cdb[2] = (byte)((address & 0xFF000000) >> 24); - cdb[3] = (byte)((address & 0xFF0000) >> 16); - cdb[4] = (byte)((address & 0xFF00) >> 8); - cdb[5] = (byte)(address & 0xFF); - cdb[6] = layerNumber; - cdb[7] = (byte)format; - cdb[8] = (byte)((buffer.Length & 0xFF00) >> 8); - cdb[9] = (byte)(buffer.Length & 0xFF); - cdb[10] = (byte)((agid & 0x03) << 6); + cdb[0] = (byte)ScsiCommands.ReadDiscStructure; + cdb[1] = (byte)((byte)mediaType & 0x0F); + cdb[2] = (byte)((address & 0xFF000000) >> 24); + cdb[3] = (byte)((address & 0xFF0000) >> 16); + cdb[4] = (byte)((address & 0xFF00) >> 8); + cdb[5] = (byte)(address & 0xFF); + cdb[6] = layerNumber; + cdb[7] = (byte)format; + cdb[8] = (byte)((buffer.Length & 0xFF00) >> 8); + cdb[9] = (byte)(buffer.Length & 0xFF); + cdb[10] = (byte)((agid & 0x03) << 6); LastError = SendScsiCommand(cdb, ref buffer, out senseBuffer, timeout, ScsiDirection.In, out duration, out bool sense); @@ -153,10 +155,10 @@ namespace DiscImageChef.Devices if(sense) return true; ushort strctLength = (ushort)((buffer[0] << 8) + buffer[1] + 2); - buffer = new byte[strctLength]; - cdb[8] = (byte)((buffer.Length & 0xFF00) >> 8); - cdb[9] = (byte)(buffer.Length & 0xFF); - senseBuffer = new byte[32]; + buffer = new byte[strctLength]; + cdb[8] = (byte)((buffer.Length & 0xFF00) >> 8); + cdb[9] = (byte)(buffer.Length & 0xFF); + senseBuffer = new byte[32]; LastError = SendScsiCommand(cdb, ref buffer, out senseBuffer, timeout, ScsiDirection.In, out duration, out sense); @@ -290,27 +292,27 @@ namespace DiscImageChef.Devices /// Track/Session number /// Timeout in seconds. /// Duration in milliseconds it took for the device to execute the command. - public bool ReadTocPmaAtip(out byte[] buffer, out byte[] senseBuffer, bool msf, byte format, - byte trackSessionNumber, uint timeout, out double duration) + public bool ReadTocPmaAtip(out byte[] buffer, out byte[] senseBuffer, bool msf, byte format, + byte trackSessionNumber, uint timeout, out double duration) { senseBuffer = new byte[32]; - byte[] cdb = new byte[10]; + byte[] cdb = new byte[10]; byte[] tmpBuffer = (format & 0x0F) == 5 ? new byte[32768] : new byte[1024]; - cdb[0] = (byte)ScsiCommands.ReadTocPmaAtip; + cdb[0] = (byte)ScsiCommands.ReadTocPmaAtip; if(msf) cdb[1] = 0x02; - cdb[2] = (byte)(format & 0x0F); - cdb[6] = trackSessionNumber; - cdb[7] = (byte)((tmpBuffer.Length & 0xFF00) >> 8); - cdb[8] = (byte)(tmpBuffer.Length & 0xFF); + cdb[2] = (byte)(format & 0x0F); + cdb[6] = trackSessionNumber; + cdb[7] = (byte)((tmpBuffer.Length & 0xFF00) >> 8); + cdb[8] = (byte)(tmpBuffer.Length & 0xFF); LastError = SendScsiCommand(cdb, ref tmpBuffer, out senseBuffer, timeout, ScsiDirection.In, out duration, out bool sense); Error = LastError != 0; uint strctLength = (uint)((tmpBuffer[0] << 8) + tmpBuffer[1] + 2); - buffer = new byte[strctLength]; + buffer = new byte[strctLength]; if(buffer.Length <= tmpBuffer.Length) { @@ -341,7 +343,7 @@ namespace DiscImageChef.Devices public bool ReadDiscInformation(out byte[] buffer, out byte[] senseBuffer, uint timeout, out double duration) { return ReadDiscInformation(out buffer, out senseBuffer, MmcDiscInformationDataTypes.DiscInformation, - timeout, out duration); + timeout, out duration); } /// @@ -353,24 +355,25 @@ namespace DiscImageChef.Devices /// Which disc information to read /// Timeout in seconds. /// Duration in milliseconds it took for the device to execute the command. - public bool ReadDiscInformation(out byte[] buffer, out byte[] senseBuffer, MmcDiscInformationDataTypes dataType, - uint timeout, out double duration) + public bool ReadDiscInformation(out byte[] buffer, out byte[] senseBuffer, + MmcDiscInformationDataTypes dataType, + uint timeout, out double duration) { - senseBuffer = new byte[32]; - byte[] cdb = new byte[10]; + senseBuffer = new byte[32]; + byte[] cdb = new byte[10]; byte[] tmpBuffer = new byte[804]; cdb[0] = (byte)ScsiCommands.ReadDiscInformation; cdb[1] = (byte)dataType; cdb[7] = (byte)((tmpBuffer.Length & 0xFF00) >> 8); - cdb[8] = (byte)(tmpBuffer.Length & 0xFF); + cdb[8] = (byte)(tmpBuffer.Length & 0xFF); LastError = SendScsiCommand(cdb, ref tmpBuffer, out senseBuffer, timeout, ScsiDirection.In, out duration, out bool sense); Error = LastError != 0; uint strctLength = (uint)((tmpBuffer[0] << 8) + tmpBuffer[1] + 2); - buffer = new byte[strctLength]; + buffer = new byte[strctLength]; Array.Copy(tmpBuffer, 0, buffer, 0, buffer.Length); DicConsole.DebugWriteLine("SCSI Device", "READ DISC INFORMATION took {0} ms.", duration); @@ -398,31 +401,32 @@ namespace DiscImageChef.Devices /// If set to true we request the EDC/ECC fields for data sectors. /// C2 error options. /// Subchannel selection. - public bool ReadCd(out byte[] buffer, out byte[] senseBuffer, uint lba, uint blockSize, uint transferLength, - MmcSectorTypes expectedSectorType, bool dap, bool relAddr, bool sync, - MmcHeaderCodes headerCodes, bool userData, bool edcEcc, MmcErrorField c2Error, - MmcSubchannel subchannel, uint timeout, out double duration) + public bool ReadCd(out byte[] buffer, out byte[] senseBuffer, uint lba, uint blockSize, + uint transferLength, + MmcSectorTypes expectedSectorType, bool dap, bool relAddr, bool sync, + MmcHeaderCodes headerCodes, bool userData, bool edcEcc, MmcErrorField c2Error, + MmcSubchannel subchannel, uint timeout, out double duration) { senseBuffer = new byte[32]; - byte[] cdb = new byte[12]; + byte[] cdb = new byte[12]; - cdb[0] = (byte)ScsiCommands.ReadCd; - cdb[1] = (byte)((byte)expectedSectorType << 2); - if(dap) cdb[1] += 0x02; - if(relAddr) cdb[1] += 0x01; - cdb[2] = (byte)((lba & 0xFF000000) >> 24); - cdb[3] = (byte)((lba & 0xFF0000) >> 16); - cdb[4] = (byte)((lba & 0xFF00) >> 8); - cdb[5] = (byte)(lba & 0xFF); - cdb[6] = (byte)((transferLength & 0xFF0000) >> 16); - cdb[7] = (byte)((transferLength & 0xFF00) >> 8); - cdb[8] = (byte)(transferLength & 0xFF); - cdb[9] = (byte)((byte)c2Error << 1); - cdb[9] += (byte)((byte)headerCodes << 5); - if(sync) cdb[9] += 0x80; + cdb[0] = (byte)ScsiCommands.ReadCd; + cdb[1] = (byte)((byte)expectedSectorType << 2); + if(dap) cdb[1] += 0x02; + if(relAddr) cdb[1] += 0x01; + cdb[2] = (byte)((lba & 0xFF000000) >> 24); + cdb[3] = (byte)((lba & 0xFF0000) >> 16); + cdb[4] = (byte)((lba & 0xFF00) >> 8); + cdb[5] = (byte)(lba & 0xFF); + cdb[6] = (byte)((transferLength & 0xFF0000) >> 16); + cdb[7] = (byte)((transferLength & 0xFF00) >> 8); + cdb[8] = (byte)(transferLength & 0xFF); + cdb[9] = (byte)((byte)c2Error << 1); + cdb[9] += (byte)((byte)headerCodes << 5); + if(sync) cdb[9] += 0x80; if(userData) cdb[9] += 0x10; - if(edcEcc) cdb[9] += 0x08; - cdb[10] = (byte)subchannel; + if(edcEcc) cdb[9] += 0x08; + cdb[10] = (byte)subchannel; buffer = new byte[blockSize * transferLength]; @@ -454,29 +458,32 @@ namespace DiscImageChef.Devices /// If set to true we request the EDC/ECC fields for data sectors. /// C2 error options. /// Subchannel selection. - public bool ReadCdMsf(out byte[] buffer, out byte[] senseBuffer, uint startMsf, uint endMsf, uint blockSize, - MmcSectorTypes expectedSectorType, bool dap, bool sync, MmcHeaderCodes headerCodes, - bool userData, bool edcEcc, MmcErrorField c2Error, MmcSubchannel subchannel, uint timeout, - out double duration) + public bool ReadCdMsf(out byte[] buffer, out byte[] senseBuffer, uint startMsf, + uint endMsf, uint blockSize, + MmcSectorTypes expectedSectorType, bool dap, bool sync, + MmcHeaderCodes headerCodes, + bool userData, bool edcEcc, MmcErrorField c2Error, + MmcSubchannel subchannel, uint timeout, + out double duration) { senseBuffer = new byte[32]; - byte[] cdb = new byte[12]; + byte[] cdb = new byte[12]; - cdb[0] = (byte)ScsiCommands.ReadCdMsf; - cdb[1] = (byte)((byte)expectedSectorType << 2); - if(dap) cdb[1] += 0x02; - cdb[3] = (byte)((startMsf & 0xFF0000) >> 16); - cdb[4] = (byte)((startMsf & 0xFF00) >> 8); - cdb[5] = (byte)(startMsf & 0xFF); - cdb[6] = (byte)((endMsf & 0xFF0000) >> 16); - cdb[7] = (byte)((endMsf & 0xFF00) >> 8); - cdb[8] = (byte)(endMsf & 0xFF); - cdb[9] = (byte)((byte)c2Error << 1); - cdb[9] += (byte)((byte)headerCodes << 5); - if(sync) cdb[9] += 0x80; + cdb[0] = (byte)ScsiCommands.ReadCdMsf; + cdb[1] = (byte)((byte)expectedSectorType << 2); + if(dap) cdb[1] += 0x02; + cdb[3] = (byte)((startMsf & 0xFF0000) >> 16); + cdb[4] = (byte)((startMsf & 0xFF00) >> 8); + cdb[5] = (byte)(startMsf & 0xFF); + cdb[6] = (byte)((endMsf & 0xFF0000) >> 16); + cdb[7] = (byte)((endMsf & 0xFF00) >> 8); + cdb[8] = (byte)(endMsf & 0xFF); + cdb[9] = (byte)((byte)c2Error << 1); + cdb[9] += (byte)((byte)headerCodes << 5); + if(sync) cdb[9] += 0x80; if(userData) cdb[9] += 0x10; - if(edcEcc) cdb[9] += 0x08; - cdb[10] = (byte)subchannel; + if(edcEcc) cdb[9] += 0x08; + cdb[10] = (byte)subchannel; uint transferLength = (uint)((cdb[6] - cdb[3]) * 60 * 75 + (cdb[7] - cdb[4]) * 75 + (cdb[8] - cdb[5])); @@ -504,12 +511,12 @@ namespace DiscImageChef.Devices public bool PreventAllowMediumRemoval(out byte[] senseBuffer, bool persistent, bool prevent, uint timeout, out double duration) { - senseBuffer = new byte[32]; - byte[] cdb = new byte[6]; + senseBuffer = new byte[32]; + byte[] cdb = new byte[6]; byte[] buffer = new byte[0]; - cdb[0] = (byte)ScsiCommands.PreventAllowMediumRemoval; - if(prevent) cdb[4] += 0x01; + cdb[0] = (byte)ScsiCommands.PreventAllowMediumRemoval; + if(prevent) cdb[4] += 0x01; if(persistent) cdb[4] += 0x02; LastError = SendScsiCommand(cdb, ref buffer, out senseBuffer, timeout, ScsiDirection.None, out duration, @@ -541,25 +548,27 @@ namespace DiscImageChef.Devices return StartStopUnit(out senseBuffer, false, 0, 0, false, false, false, timeout, out duration); } - public bool StartStopUnit(out byte[] senseBuffer, bool immediate, byte formatLayer, byte powerConditions, - bool changeFormatLayer, bool loadEject, bool start, uint timeout, out double duration) + public bool StartStopUnit(out byte[] senseBuffer, bool immediate, byte formatLayer, byte powerConditions, + bool changeFormatLayer, bool loadEject, bool start, uint timeout, + out double duration) { - senseBuffer = new byte[32]; - byte[] cdb = new byte[6]; + senseBuffer = new byte[32]; + byte[] cdb = new byte[6]; byte[] buffer = new byte[0]; - cdb[0] = (byte)ScsiCommands.StartStopUnit; + cdb[0] = (byte)ScsiCommands.StartStopUnit; if(immediate) cdb[1] += 0x01; if(changeFormatLayer) { - cdb[3] = (byte)(formatLayer & 0x03); + cdb[3] = (byte)(formatLayer & 0x03); cdb[4] += 0x04; } else { if(loadEject) cdb[4] += 0x02; - if(start) cdb[4] += 0x01; + if(start) cdb[4] += 0x01; } + cdb[4] += (byte)((powerConditions & 0x0F) << 4); LastError = SendScsiCommand(cdb, ref buffer, out senseBuffer, timeout, ScsiDirection.None, out duration, @@ -570,5 +579,60 @@ namespace DiscImageChef.Devices return sense; } + + public bool ReadMcn(out string mcn, out byte[] buffer, out byte[] senseBuffer, uint timeout, + out double duration) + { + senseBuffer = new byte[32]; + byte[] cdb = new byte[10]; + mcn = null; + + cdb[0] = (byte)ScsiCommands.ReadSubChannel; + cdb[1] = 0; + cdb[2] = 0x40; + cdb[3] = 0x02; + cdb[7] = (23 & 0xFF00) >> 8; + cdb[8] = 23 & 0xFF; + + buffer = new byte[23]; + + LastError = SendScsiCommand(cdb, ref buffer, out senseBuffer, timeout, ScsiDirection.In, out duration, + out bool sense); + Error = LastError != 0; + + DicConsole.DebugWriteLine("SCSI Device", "READ READ SUB-CHANNEL (MCN) took {0} ms.", duration); + + if(!sense && (buffer[8] & 0x80) == 0x80) mcn = Encoding.ASCII.GetString(buffer, 9, 13); + + return sense; + } + + public bool ReadIsrc(byte trackNumber, out string isrc, out byte[] buffer, out byte[] senseBuffer, uint timeout, + out double duration) + { + senseBuffer = new byte[32]; + byte[] cdb = new byte[10]; + isrc = null; + + cdb[0] = (byte)ScsiCommands.ReadSubChannel; + cdb[1] = 0; + cdb[2] = 0x40; + cdb[3] = 0x03; + cdb[6] = trackNumber; + cdb[7] = (23 & 0xFF00) >> 8; + cdb[8] = 23 & 0xFF; + + buffer = new byte[23]; + + LastError = SendScsiCommand(cdb, ref buffer, out senseBuffer, timeout, ScsiDirection.In, out duration, + out bool sense); + Error = LastError != 0; + + DicConsole.DebugWriteLine("SCSI Device", "READ READ SUB-CHANNEL (ISRC) took {0} ms.", duration); + + if(!sense && (buffer[8] & 0x80) == 0x80) isrc = Encoding.ASCII.GetString(buffer, 9, 12); + + return sense; + } } } \ No newline at end of file diff --git a/DiscImageChef/Commands/MediaInfo.cs b/DiscImageChef/Commands/MediaInfo.cs index 7fac21a66..fa09f5660 100644 --- a/DiscImageChef/Commands/MediaInfo.cs +++ b/DiscImageChef/Commands/MediaInfo.cs @@ -56,9 +56,9 @@ namespace DiscImageChef.Commands { internal static void DoMediaInfo(MediaInfoOptions options) { - DicConsole.DebugWriteLine("Media-Info command", "--debug={0}", options.Debug); - DicConsole.DebugWriteLine("Media-Info command", "--verbose={0}", options.Verbose); - DicConsole.DebugWriteLine("Media-Info command", "--device={0}", options.DevicePath); + DicConsole.DebugWriteLine("Media-Info command", "--debug={0}", options.Debug); + DicConsole.DebugWriteLine("Media-Info command", "--verbose={0}", options.Verbose); + DicConsole.DebugWriteLine("Media-Info command", "--device={0}", options.DevicePath); DicConsole.DebugWriteLine("Media-Info command", "--output-prefix={0}", options.OutputPrefix); if(options.DevicePath.Length == 2 && options.DevicePath[1] == ':' && options.DevicePath[0] != '/' && @@ -114,13 +114,13 @@ namespace DiscImageChef.Commands static void DoScsiMediaInfo(string outputPrefix, Device dev) { - byte[] cmdBuf; - byte[] senseBuf; - bool sense; - MediaType dskType = MediaType.Unknown; - ulong blocks = 0; - uint blockSize = 0; - int resets = 0; + byte[] cmdBuf; + byte[] senseBuf; + bool sense; + MediaType dskType = MediaType.Unknown; + ulong blocks = 0; + uint blockSize = 0; + int resets = 0; if(dev.IsRemovable) { @@ -192,7 +192,7 @@ namespace DiscImageChef.Commands } } - Modes.DecodedMode? decMode = null; + Modes.DecodedMode? decMode = null; PeripheralDeviceTypes devType = dev.ScsiType; sense = dev.ModeSense10(out byte[] modeBuf, out senseBuf, false, true, ScsiModeSensePageControl.Current, @@ -218,8 +218,8 @@ namespace DiscImageChef.Commands if(!sense) DataFile.WriteTo("Media-Info command", outputPrefix, "_scsi_modesense.bin", "SCSI MODE SENSE", modeBuf); - byte scsiMediumType = 0; - byte scsiDensityCode = 0; + byte scsiMediumType = 0; + byte scsiDensityCode = 0; bool containsFloppyPage = false; if(decMode.HasValue) @@ -246,15 +246,15 @@ namespace DiscImageChef.Commands { DataFile.WriteTo("Media-Info command", outputPrefix, "_readcapacity.bin", "SCSI READ CAPACITY", cmdBuf); - blocks = (ulong)((cmdBuf[0] << 24) + (cmdBuf[1] << 16) + (cmdBuf[2] << 8) + cmdBuf[3]); - blockSize = (uint)((cmdBuf[5] << 24) + (cmdBuf[5] << 16) + (cmdBuf[6] << 8) + cmdBuf[7]); + blocks = (ulong)((cmdBuf[0] << 24) + (cmdBuf[1] << 16) + (cmdBuf[2] << 8) + cmdBuf[3]); + blockSize = (uint)((cmdBuf[5] << 24) + (cmdBuf[5] << 16) + (cmdBuf[6] << 8) + cmdBuf[7]); } if(sense || blocks == 0xFFFFFFFF) { sense = dev.ReadCapacity16(out cmdBuf, out senseBuf, dev.Timeout, out _); - if(sense && blocks == 0) + if(sense && blocks == 0) if(dev.ScsiType != PeripheralDeviceTypes.MultiMediaDevice) { DicConsole.ErrorWriteLine("Unable to get media capacity"); @@ -269,7 +269,7 @@ namespace DiscImageChef.Commands Array.Copy(cmdBuf, 0, temp, 0, 8); Array.Reverse(temp); - blocks = BitConverter.ToUInt64(temp, 0); + blocks = BitConverter.ToUInt64(temp, 0); blockSize = (uint)((cmdBuf[5] << 24) + (cmdBuf[5] << 16) + (cmdBuf[6] << 8) + cmdBuf[7]); } } @@ -280,6 +280,7 @@ namespace DiscImageChef.Commands DicConsole.WriteLine("Media has {0} blocks of {1} bytes/each. (for a total of {2} bytes)", blocks, blockSize, blocks * blockSize); } + break; case PeripheralDeviceTypes.SequentialAccess: byte[] medBuf; @@ -318,6 +319,7 @@ namespace DiscImageChef.Commands DicConsole.WriteLine("Medium types currently inserted in device:"); DicConsole.WriteLine(DensitySupport.PrettifyMediumType(meds)); } + DicConsole.WriteLine(DensitySupport.PrettifyMediumType(seqBuf)); } } @@ -472,12 +474,12 @@ namespace DiscImageChef.Commands */ #region All DVD and HD DVD types - if(dskType == MediaType.DVDDownload || dskType == MediaType.DVDPR || dskType == MediaType.DVDPRDL || - dskType == MediaType.DVDPRW || dskType == MediaType.DVDPRWDL || dskType == MediaType.DVDR || - dskType == MediaType.DVDRAM || dskType == MediaType.DVDRDL || dskType == MediaType.DVDROM || - dskType == MediaType.DVDRW || dskType == MediaType.DVDRWDL || dskType == MediaType.HDDVDR || - dskType == MediaType.HDDVDRAM || dskType == MediaType.HDDVDRDL || dskType == MediaType.HDDVDROM || - dskType == MediaType.HDDVDRW || dskType == MediaType.HDDVDRWDL) + if(dskType == MediaType.DVDDownload || dskType == MediaType.DVDPR || dskType == MediaType.DVDPRDL || + dskType == MediaType.DVDPRW || dskType == MediaType.DVDPRWDL || dskType == MediaType.DVDR || + dskType == MediaType.DVDRAM || dskType == MediaType.DVDRDL || dskType == MediaType.DVDROM || + dskType == MediaType.DVDRW || dskType == MediaType.DVDRWDL || dskType == MediaType.HDDVDR || + dskType == MediaType.HDDVDRAM || dskType == MediaType.HDDVDRDL || dskType == MediaType.HDDVDROM || + dskType == MediaType.HDDVDRW || dskType == MediaType.HDDVDRWDL) { sense = dev.ReadDiscStructure(out cmdBuf, out senseBuf, MmcDiscStructureMediaType.Dvd, 0, 0, MmcDiscStructureFormat.PhysicalInformation, 0, dev.Timeout, out _); @@ -566,9 +568,9 @@ namespace DiscImageChef.Commands DicConsole.WriteLine("Xbox 360 DMI:\n{0}", DMI.PrettifyXbox360(cmdBuf)); // All XGD3 all have the same number of blocks - if(blocks == 25063 || // Locked (or non compatible drive) + if(blocks == 25063 || // Locked (or non compatible drive) blocks == 4229664 || // Xtreme unlock - blocks == 4246304) // Wxripper unlock + blocks == 4246304) // Wxripper unlock dskType = MediaType.XGD3; } } @@ -628,6 +630,7 @@ namespace DiscImageChef.Commands "SCSI READ DISC STRUCTURE", cmdBuf); DicConsole.WriteLine("Disc Definition Structure:\n{0}", DDS.Prettify(cmdBuf)); } + sense = dev.ReadDiscStructure(out cmdBuf, out senseBuf, MmcDiscStructureMediaType.Dvd, 0, 0, MmcDiscStructureFormat.DvdramMediumStatus, 0, dev.Timeout, out _); if(sense) @@ -639,6 +642,7 @@ namespace DiscImageChef.Commands "SCSI READ DISC STRUCTURE", cmdBuf); DicConsole.WriteLine("Medium Status:\n{0}", Cartridge.Prettify(cmdBuf)); } + sense = dev.ReadDiscStructure(out cmdBuf, out senseBuf, MmcDiscStructureMediaType.Dvd, 0, 0, MmcDiscStructureFormat.DvdramSpareAreaInformation, 0, dev.Timeout, out _); @@ -651,6 +655,7 @@ namespace DiscImageChef.Commands "SCSI READ DISC STRUCTURE", cmdBuf); DicConsole.WriteLine("Spare Area Information:\n{0}", Spare.Prettify(cmdBuf)); } + break; case MediaType.DVDR: case MediaType.HDDVDR: @@ -914,6 +919,7 @@ namespace DiscImageChef.Commands "SCSI READ DISC STRUCTURE", cmdBuf); DicConsole.WriteLine("Blu-ray Disc Information:\n{0}", DI.Prettify(cmdBuf)); } + sense = dev.ReadDiscStructure(out cmdBuf, out senseBuf, MmcDiscStructureMediaType.Bd, 0, 0, MmcDiscStructureFormat.Pac, 0, dev.Timeout, out _); if(sense) @@ -941,6 +947,7 @@ namespace DiscImageChef.Commands "SCSI READ DISC STRUCTURE", cmdBuf); DicConsole.WriteLine("Blu-ray Burst Cutting Area:\n{0}", BCA.Prettify(cmdBuf)); } + break; #endregion BD-ROM only @@ -961,6 +968,7 @@ namespace DiscImageChef.Commands DicConsole.WriteLine("Blu-ray Disc Definition Structure:\n{0}", Decoders.Bluray.DDS.Prettify(cmdBuf)); } + sense = dev.ReadDiscStructure(out cmdBuf, out senseBuf, MmcDiscStructureMediaType.Bd, 0, 0, MmcDiscStructureFormat.CartridgeStatus, 0, dev.Timeout, out _); if(sense) @@ -973,6 +981,7 @@ namespace DiscImageChef.Commands "SCSI READ DISC STRUCTURE", cmdBuf); DicConsole.WriteLine("Blu-ray Cartridge Status:\n{0}", DI.Prettify(cmdBuf)); } + sense = dev.ReadDiscStructure(out cmdBuf, out senseBuf, MmcDiscStructureMediaType.Bd, 0, 0, MmcDiscStructureFormat.BdSpareAreaInformation, 0, dev.Timeout, out _); @@ -986,6 +995,7 @@ namespace DiscImageChef.Commands "SCSI READ DISC STRUCTURE", cmdBuf); DicConsole.WriteLine("Blu-ray Spare Area Information:\n{0}", DI.Prettify(cmdBuf)); } + sense = dev.ReadDiscStructure(out cmdBuf, out senseBuf, MmcDiscStructureMediaType.Bd, 0, 0, MmcDiscStructureFormat.RawDfl, 0, dev.Timeout, out _); if(sense) @@ -1005,6 +1015,7 @@ namespace DiscImageChef.Commands DataFile.WriteTo("Media-Info command", outputPrefix, "_readdiscinformation_001b.bin", "SCSI READ DISC INFORMATION", cmdBuf); } + sense = dev.ReadDiscInformation(out cmdBuf, out senseBuf, MmcDiscInformationDataTypes.PowResources, dev.Timeout, out _); if(sense) @@ -1016,6 +1027,7 @@ namespace DiscImageChef.Commands DataFile.WriteTo("Media-Info command", outputPrefix, "_readdiscinformation_010b.bin", "SCSI READ DISC INFORMATION", cmdBuf); } + break; #endregion Writable Blu-ray only @@ -1096,7 +1108,7 @@ namespace DiscImageChef.Commands } } - int sessions = 1; + int sessions = 1; int firstTrackLastSession = 0; sense = dev.ReadSessionInfo(out cmdBuf, out senseBuf, dev.Timeout, out _); @@ -1111,30 +1123,32 @@ namespace DiscImageChef.Commands DicConsole.WriteLine("Session information:\n{0}", Session.Prettify(session)); if(session.HasValue) { - sessions = session.Value.LastCompleteSession; + sessions = session.Value.LastCompleteSession; firstTrackLastSession = session.Value.TrackDescriptors[0].TrackNumber; } } if(dskType == MediaType.CD) { - bool hasDataTrack = false; - bool hasAudioTrack = false; + bool hasDataTrack = false; + bool hasAudioTrack = false; bool allFirstSessionTracksAreAudio = true; - bool hasVideoTrack = false; + bool hasVideoTrack = false; if(toc.HasValue) foreach(TOC.CDTOCTrackDataDescriptor track in toc.Value.TrackDescriptors) { - if(track.TrackNumber == 1 && - ((TocControl)(track.CONTROL & 0x0D) == TocControl.DataTrack || - (TocControl)(track.CONTROL & 0x0D) == TocControl.DataTrackIncremental)) + if(track.TrackNumber == 1 && + ((TocControl)(track.CONTROL & 0x0D) == + TocControl.DataTrack || + (TocControl)(track.CONTROL & 0x0D) == + TocControl.DataTrackIncremental)) allFirstSessionTracksAreAudio &= firstTrackLastSession != 1; if((TocControl)(track.CONTROL & 0x0D) == TocControl.DataTrack || (TocControl)(track.CONTROL & 0x0D) == TocControl.DataTrackIncremental) { - hasDataTrack = true; + hasDataTrack = true; allFirstSessionTracksAreAudio &= track.TrackNumber >= firstTrackLastSession; } else hasAudioTrack = true; @@ -1143,10 +1157,10 @@ namespace DiscImageChef.Commands } if(hasDataTrack && hasAudioTrack && allFirstSessionTracksAreAudio && sessions == 2) - dskType = MediaType.CDPLUS; - if(!hasDataTrack && hasAudioTrack && sessions == 1) dskType = MediaType.CDDA; - if(hasDataTrack && !hasAudioTrack && sessions == 1) dskType = MediaType.CDROM; - if(hasVideoTrack && !hasDataTrack && sessions == 1) dskType = MediaType.CDV; + dskType = MediaType.CDPLUS; + if(!hasDataTrack && hasAudioTrack && sessions == 1) dskType = MediaType.CDDA; + if(hasDataTrack && !hasAudioTrack && sessions == 1) dskType = MediaType.CDROM; + if(hasVideoTrack && !hasDataTrack && sessions == 1) dskType = MediaType.CDV; } sense = dev.ReadRawToc(out cmdBuf, out senseBuf, 1, dev.Timeout, out _); @@ -1163,9 +1177,9 @@ namespace DiscImageChef.Commands if(fullToc.HasValue) { FullTOC.TrackDataDescriptor a0Track = - fullToc.Value.TrackDescriptors.FirstOrDefault(t => t.POINT == 0xA0 && t.ADR == 1); - if(a0Track.POINT == 0xA0) - { + fullToc.Value.TrackDescriptors + .FirstOrDefault(t => t.POINT == 0xA0 && t.ADR == 1); + if(a0Track.POINT == 0xA0) switch(a0Track.PSEC) { case 0x10: @@ -1175,9 +1189,9 @@ namespace DiscImageChef.Commands dskType = MediaType.CDROMXA; break; } - } } } + sense = dev.ReadPma(out cmdBuf, out senseBuf, dev.Timeout, out _); if(sense) DicConsole.DebugWriteLine("Media-Info command", "READ TOC/PMA/ATIP: PMA\n{0}", @@ -1200,6 +1214,16 @@ namespace DiscImageChef.Commands if(CDTextOnLeadIn.Decode(cmdBuf).HasValue) DicConsole.WriteLine("CD-TEXT on Lead-In:\n{0}", CDTextOnLeadIn.Prettify(cmdBuf)); } + + sense = dev.ReadMcn(out string mcn, out _, out _, dev.Timeout, out _); + if(!sense && mcn != null && mcn != "0000000000000") DicConsole.WriteLine("MCN: {0}", mcn); + + for(byte i = toc.Value.FirstTrack; i <= toc.Value.LastTrack; i++) + { + sense = dev.ReadIsrc(i, out string isrc, out _, out _, dev.Timeout, out _); + if(!sense && isrc != null && isrc != "000000000000") + DicConsole.WriteLine("Track's {0} ISRC: {1}", i, isrc); + } } break; @@ -1223,7 +1247,7 @@ namespace DiscImageChef.Commands { DicConsole.WriteLine("PFI:\n{0}", PFI.Prettify(cmdBuf)); if(nintendoPfi.Value.DiskCategory == DiskCategory.Nintendo && - nintendoPfi.Value.PartVersion == 15) + nintendoPfi.Value.PartVersion == 15) switch(nintendoPfi.Value.DiscSize) { case DVDSize.Eighty: @@ -1294,8 +1318,9 @@ namespace DiscImageChef.Commands } totalSize = (ulong)((cmdBuf[0] << 24) + (cmdBuf[1] << 16) + (cmdBuf[2] << 8) + cmdBuf[3]); - sense = dev.ReadDiscStructure(out cmdBuf, out senseBuf, MmcDiscStructureMediaType.Dvd, 0, 0, - MmcDiscStructureFormat.PhysicalInformation, 0, 0, out _); + sense = dev.ReadDiscStructure(out cmdBuf, out senseBuf, MmcDiscStructureMediaType.Dvd, + 0, 0, + MmcDiscStructureFormat.PhysicalInformation, 0, 0, out _); if(sense) { DicConsole.ErrorWriteLine("Cannot get PFI."); @@ -1304,9 +1329,9 @@ namespace DiscImageChef.Commands DicConsole.DebugWriteLine("Dump-media command", "Video partition total size: {0} sectors", totalSize); - l0Video = PFI.Decode(cmdBuf).Value.Layer0EndPSN - + l0Video = PFI.Decode(cmdBuf).Value.Layer0EndPSN - PFI.Decode(cmdBuf).Value.DataAreaStartPSN + 1; - l1Video = totalSize - l0Video + 1; + l1Video = totalSize - l0Video + 1; // Get game partition size DicConsole.DebugWriteLine("Dump-media command", "Getting game partition size"); @@ -1346,8 +1371,9 @@ namespace DiscImageChef.Commands } totalSize = (ulong)((cmdBuf[0] << 24) + (cmdBuf[1] << 16) + (cmdBuf[2] << 8) + cmdBuf[3]); - sense = dev.ReadDiscStructure(out cmdBuf, out senseBuf, MmcDiscStructureMediaType.Dvd, 0, 0, - MmcDiscStructureFormat.PhysicalInformation, 0, 0, out _); + sense = dev.ReadDiscStructure(out cmdBuf, out senseBuf, MmcDiscStructureMediaType.Dvd, + 0, 0, + MmcDiscStructureFormat.PhysicalInformation, 0, 0, out _); if(sense) { DicConsole.ErrorWriteLine("Cannot get PFI."); @@ -1357,18 +1383,20 @@ namespace DiscImageChef.Commands DicConsole.DebugWriteLine("Dump-media command", "Unlocked total size: {0} sectors", totalSize); middleZone = - totalSize - (PFI.Decode(cmdBuf).Value.Layer0EndPSN - - PFI.Decode(cmdBuf).Value.DataAreaStartPSN + 1) - gameSize + 1; + totalSize - + (PFI.Decode(cmdBuf).Value.Layer0EndPSN - + PFI.Decode(cmdBuf).Value.DataAreaStartPSN + 1) - + gameSize + 1; - totalSize = l0Video + l1Video + middleZone * 2 + gameSize; - layerBreak = l0Video + middleZone + gameSize / 2; + totalSize = l0Video + l1Video + middleZone * 2 + gameSize; + layerBreak = l0Video + middleZone + gameSize / 2; DicConsole.WriteLine("Video layer 0 size: {0} sectors", l0Video); DicConsole.WriteLine("Video layer 1 size: {0} sectors", l1Video); - DicConsole.WriteLine("Middle zone size: {0} sectors", middleZone); - DicConsole.WriteLine("Game data size: {0} sectors", gameSize); - DicConsole.WriteLine("Total size: {0} sectors", totalSize); - DicConsole.WriteLine("Real layer break: {0}", layerBreak); + DicConsole.WriteLine("Middle zone size: {0} sectors", middleZone); + DicConsole.WriteLine("Game data size: {0} sectors", gameSize); + DicConsole.WriteLine("Total size: {0} sectors", totalSize); + DicConsole.WriteLine("Real layer break: {0}", layerBreak); DicConsole.WriteLine(); } }