Add option to select dump speed for MMC devices. Fixes #218

This commit is contained in:
2019-12-26 03:45:09 +00:00
parent 889de634fd
commit 2884a14ac6
9 changed files with 1084 additions and 2876 deletions

View File

@@ -1540,6 +1540,21 @@ namespace DiscImageChef.Core.Devices.Dumping
audioExtents.Add(audioTrack.TrackStartSector, audioTrack.TrackEndSector); audioExtents.Add(audioTrack.TrackStartSector, audioTrack.TrackEndSector);
} }
// Set speed
if(_speedMultiplier >= 0)
{
_dumpLog.WriteLine($"Setting speed to {_speed}x.");
UpdateStatus?.Invoke($"Setting speed to {_speed}x.");
_speed *= _speedMultiplier;
if(_speed == 0 ||
_speed > 0xFFFF)
_speed = 0xFFFF;
_dev.SetCdSpeed(out _, RotationalControl.ClvAndImpureCav, (ushort)_speed, 0, _dev.Timeout, out _);
}
// Start reading // Start reading
start = DateTime.UtcNow; start = DateTime.UtcNow;
currentSpeed = 0; currentSpeed = 0;

View File

@@ -40,6 +40,7 @@ namespace DiscImageChef.Core.Devices.Dumping
readonly CICMMetadataType _preSidecar; readonly CICMMetadataType _preSidecar;
readonly ushort _retryPasses; readonly ushort _retryPasses;
readonly bool _stopOnError; readonly bool _stopOnError;
readonly DumpSubchannel _subchannel;
bool _aborted; bool _aborted;
DicContext _ctx; // Master database context DicContext _ctx; // Master database context
Database.Models.Device _dbDev; // Device database entry Database.Models.Device _dbDev; // Device database entry
@@ -49,7 +50,8 @@ namespace DiscImageChef.Core.Devices.Dumping
Resume _resume; Resume _resume;
Sidecar _sidecarClass; Sidecar _sidecarClass;
uint _skip; uint _skip;
readonly DumpSubchannel _subchannel; int _speed;
int _speedMultiplier;
/// <summary>Initializes dumpers</summary> /// <summary>Initializes dumpers</summary>
/// <param name="doResume">Should resume?</param> /// <param name="doResume">Should resume?</param>
@@ -76,7 +78,7 @@ namespace DiscImageChef.Core.Devices.Dumping
bool force, bool dumpRaw, bool persistent, bool stopOnError, Resume resume, DumpLog dumpLog, bool force, bool dumpRaw, bool persistent, bool stopOnError, Resume resume, DumpLog dumpLog,
Encoding encoding, string outputPrefix, string outputPath, Dictionary<string, string> formatOptions, Encoding encoding, string outputPrefix, string outputPath, Dictionary<string, string> formatOptions,
CICMMetadataType preSidecar, uint skip, bool nometadata, bool notrim, bool dumpFirstTrackPregap, CICMMetadataType preSidecar, uint skip, bool nometadata, bool notrim, bool dumpFirstTrackPregap,
bool fixOffset, bool debug, DumpSubchannel subchannel) bool fixOffset, bool debug, DumpSubchannel subchannel, int speed)
{ {
_doResume = doResume; _doResume = doResume;
_dev = dev; _dev = dev;
@@ -103,6 +105,8 @@ namespace DiscImageChef.Core.Devices.Dumping
_debug = debug; _debug = debug;
_maximumReadable = 64; _maximumReadable = 64;
_subchannel = subchannel; _subchannel = subchannel;
_speedMultiplier = -1;
_speed = speed;
} }
/// <summary>Starts dumping with the stablished fields and autodetecting the device type</summary> /// <summary>Starts dumping with the stablished fields and autodetecting the device type</summary>

View File

@@ -56,6 +56,7 @@ namespace DiscImageChef.Core.Devices.Dumping
byte[] tmpBuf; byte[] tmpBuf;
bool compactDisc = true; bool compactDisc = true;
bool isXbox = false; bool isXbox = false;
_speedMultiplier = 1;
// TODO: Log not only what is it reading, but if it was read correctly or not. // TODO: Log not only what is it reading, but if it was read correctly or not.
sense = _dev.GetConfiguration(out byte[] cmdBuf, out _, 0, MmcGetConfigurationRt.Current, _dev.Timeout, sense = _dev.GetConfiguration(out byte[] cmdBuf, out _, 0, MmcGetConfigurationRt.Current, _dev.Timeout,
@@ -70,9 +71,11 @@ namespace DiscImageChef.Core.Devices.Dumping
{ {
case 0x0001: case 0x0001:
dskType = MediaType.GENERIC_HDD; dskType = MediaType.GENERIC_HDD;
_speedMultiplier = -1;
goto default; goto default;
case 0x0002: case 0x0002:
dskType = MediaType.PD650; dskType = MediaType.PD650;
_speedMultiplier = -1;
goto default; goto default;
case 0x0005: case 0x0005:
dskType = MediaType.CDMO; dskType = MediaType.CDMO;
@@ -92,32 +95,41 @@ namespace DiscImageChef.Core.Devices.Dumping
break; break;
case 0x0010: case 0x0010:
dskType = MediaType.DVDROM; dskType = MediaType.DVDROM;
_speedMultiplier = 9;
goto default; goto default;
case 0x0011: case 0x0011:
dskType = MediaType.DVDR; dskType = MediaType.DVDR;
_speedMultiplier = 9;
goto default; goto default;
case 0x0012: case 0x0012:
dskType = MediaType.DVDRAM; dskType = MediaType.DVDRAM;
_speedMultiplier = 9;
goto default; goto default;
case 0x0013: case 0x0013:
case 0x0014: case 0x0014:
dskType = MediaType.DVDRW; dskType = MediaType.DVDRW;
_speedMultiplier = 9;
goto default; goto default;
case 0x0015: case 0x0015:
case 0x0016: case 0x0016:
dskType = MediaType.DVDRDL; dskType = MediaType.DVDRDL;
_speedMultiplier = 9;
goto default; goto default;
case 0x0017: case 0x0017:
dskType = MediaType.DVDRWDL; dskType = MediaType.DVDRWDL;
_speedMultiplier = 9;
goto default; goto default;
case 0x0018: case 0x0018:
dskType = MediaType.DVDDownload; dskType = MediaType.DVDDownload;
_speedMultiplier = 9;
goto default; goto default;
case 0x001A: case 0x001A:
dskType = MediaType.DVDPRW; dskType = MediaType.DVDPRW;
_speedMultiplier = 9;
goto default; goto default;
case 0x001B: case 0x001B:
dskType = MediaType.DVDPR; dskType = MediaType.DVDPR;
_speedMultiplier = 9;
goto default; goto default;
case 0x0020: case 0x0020:
dskType = MediaType.DDCD; dskType = MediaType.DDCD;
@@ -130,37 +142,48 @@ namespace DiscImageChef.Core.Devices.Dumping
goto default; goto default;
case 0x002A: case 0x002A:
dskType = MediaType.DVDPRWDL; dskType = MediaType.DVDPRWDL;
_speedMultiplier = 9;
goto default; goto default;
case 0x002B: case 0x002B:
dskType = MediaType.DVDPRDL; dskType = MediaType.DVDPRDL;
_speedMultiplier = 9;
goto default; goto default;
case 0x0040: case 0x0040:
dskType = MediaType.BDROM; dskType = MediaType.BDROM;
_speedMultiplier = 30;
goto default; goto default;
case 0x0041: case 0x0041:
case 0x0042: case 0x0042:
dskType = MediaType.BDR; dskType = MediaType.BDR;
_speedMultiplier = 30;
goto default; goto default;
case 0x0043: case 0x0043:
dskType = MediaType.BDRE; dskType = MediaType.BDRE;
_speedMultiplier = 30;
goto default; goto default;
case 0x0050: case 0x0050:
dskType = MediaType.HDDVDROM; dskType = MediaType.HDDVDROM;
_speedMultiplier = 30;
goto default; goto default;
case 0x0051: case 0x0051:
dskType = MediaType.HDDVDR; dskType = MediaType.HDDVDR;
_speedMultiplier = 30;
goto default; goto default;
case 0x0052: case 0x0052:
dskType = MediaType.HDDVDRAM; dskType = MediaType.HDDVDRAM;
_speedMultiplier = 30;
goto default; goto default;
case 0x0053: case 0x0053:
dskType = MediaType.HDDVDRW; dskType = MediaType.HDDVDRW;
_speedMultiplier = 30;
goto default; goto default;
case 0x0058: case 0x0058:
dskType = MediaType.HDDVDRDL; dskType = MediaType.HDDVDRDL;
_speedMultiplier = 30;
goto default; goto default;
case 0x005A: case 0x005A:
dskType = MediaType.HDDVDRWDL; dskType = MediaType.HDDVDRWDL;
_speedMultiplier = 30;
goto default; goto default;
default: default:
compactDisc = false; compactDisc = false;

View File

@@ -405,6 +405,21 @@ namespace DiscImageChef.Core.Devices.Dumping
_dumpLog.WriteLine("Resuming from block {0}.", _resume.NextBlock); _dumpLog.WriteLine("Resuming from block {0}.", _resume.NextBlock);
} }
// Set speed
if(_speedMultiplier >= 0)
{
_dumpLog.WriteLine($"Setting speed to {_speed}x.");
UpdateStatus?.Invoke($"Setting speed to {_speed}x.");
_speed *= _speedMultiplier;
if(_speed == 0 ||
_speed > 0xFFFF)
_speed = 0xFFFF;
_dev.SetCdSpeed(out _, RotationalControl.ClvAndImpureCav, (ushort)_speed, 0, _dev.Timeout, out _);
}
bool newTrim = false; bool newTrim = false;
DateTime timeSpeedStart = DateTime.UtcNow; DateTime timeSpeedStart = DateTime.UtcNow;
ulong sectorSpeedStart = 0; ulong sectorSpeedStart = 0;

View File

@@ -383,6 +383,21 @@ namespace DiscImageChef.Core.Devices.Dumping
_dumpLog.WriteLine("Using SCSI READ (12) command."); _dumpLog.WriteLine("Using SCSI READ (12) command.");
UpdateStatus?.Invoke("Using SCSI READ (12) command."); UpdateStatus?.Invoke("Using SCSI READ (12) command.");
// Set speed
if(_speedMultiplier >= 0)
{
_dumpLog.WriteLine($"Setting speed to {_speed}x.");
UpdateStatus?.Invoke($"Setting speed to {_speed}x.");
_speed *= _speedMultiplier;
if(_speed == 0 ||
_speed > 0xFFFF)
_speed = 0xFFFF;
_dev.SetCdSpeed(out _, RotationalControl.ClvAndImpureCav, (ushort)_speed, 0, _dev.Timeout, out _);
}
while(true) while(true)
{ {
if(read12) if(read12)

View File

@@ -38,9 +38,7 @@ namespace DiscImageChef.Devices
{ {
public partial class Device public partial class Device
{ {
/// <summary> /// <summary>Sends the MMC GET CONFIGURATION command for all Features</summary>
/// Sends the MMC GET CONFIGURATION command for all Features
/// </summary>
/// <returns><c>true</c> if the command failed and <paramref name="senseBuffer" /> contains the sense buffer.</returns> /// <returns><c>true</c> if the command failed and <paramref name="senseBuffer" /> contains the sense buffer.</returns>
/// <param name="buffer">Buffer where the SCSI GET CONFIGURATION response will be stored</param> /// <param name="buffer">Buffer where the SCSI GET CONFIGURATION response will be stored</param>
/// <param name="senseBuffer">Sense buffer.</param> /// <param name="senseBuffer">Sense buffer.</param>
@@ -49,9 +47,7 @@ namespace DiscImageChef.Devices
public bool GetConfiguration(out byte[] buffer, out byte[] senseBuffer, uint timeout, out double duration) => public bool GetConfiguration(out byte[] buffer, out byte[] senseBuffer, uint timeout, out double duration) =>
GetConfiguration(out buffer, out senseBuffer, 0x0000, MmcGetConfigurationRt.All, timeout, out duration); GetConfiguration(out buffer, out senseBuffer, 0x0000, MmcGetConfigurationRt.All, timeout, out duration);
/// <summary> /// <summary>Sends the MMC GET CONFIGURATION command for all Features starting with specified one</summary>
/// Sends the MMC GET CONFIGURATION command for all Features starting with specified one
/// </summary>
/// <returns><c>true</c> if the command failed and <paramref name="senseBuffer" /> contains the sense buffer.</returns> /// <returns><c>true</c> if the command failed and <paramref name="senseBuffer" /> contains the sense buffer.</returns>
/// <param name="buffer">Buffer where the SCSI GET CONFIGURATION response will be stored</param> /// <param name="buffer">Buffer where the SCSI GET CONFIGURATION response will be stored</param>
/// <param name="senseBuffer">Sense buffer.</param> /// <param name="senseBuffer">Sense buffer.</param>
@@ -63,9 +59,7 @@ namespace DiscImageChef.Devices
GetConfiguration(out buffer, out senseBuffer, startingFeatureNumber, MmcGetConfigurationRt.All, timeout, GetConfiguration(out buffer, out senseBuffer, startingFeatureNumber, MmcGetConfigurationRt.All, timeout,
out duration); out duration);
/// <summary> /// <summary>Sends the MMC GET CONFIGURATION command</summary>
/// Sends the MMC GET CONFIGURATION command
/// </summary>
/// <returns><c>true</c> if the command failed and <paramref name="senseBuffer" /> contains the sense buffer.</returns> /// <returns><c>true</c> if the command failed and <paramref name="senseBuffer" /> contains the sense buffer.</returns>
/// <param name="buffer">Buffer where the SCSI GET CONFIGURATION response will be stored</param> /// <param name="buffer">Buffer where the SCSI GET CONFIGURATION response will be stored</param>
/// <param name="senseBuffer">Sense buffer.</param> /// <param name="senseBuffer">Sense buffer.</param>
@@ -73,8 +67,7 @@ namespace DiscImageChef.Devices
/// <param name="duration">Duration in milliseconds it took for the device to execute the command.</param> /// <param name="duration">Duration in milliseconds it took for the device to execute the command.</param>
/// <param name="startingFeatureNumber">Starting Feature number.</param> /// <param name="startingFeatureNumber">Starting Feature number.</param>
/// <param name="rt">Return type, <see cref="MmcGetConfigurationRt" />.</param> /// <param name="rt">Return type, <see cref="MmcGetConfigurationRt" />.</param>
public bool GetConfiguration(out byte[] buffer, out byte[] senseBuffer, public bool GetConfiguration(out byte[] buffer, out byte[] senseBuffer, ushort startingFeatureNumber,
ushort startingFeatureNumber,
MmcGetConfigurationRt rt, uint timeout, out double duration) MmcGetConfigurationRt rt, uint timeout, out double duration)
{ {
senseBuffer = new byte[32]; senseBuffer = new byte[32];
@@ -91,9 +84,11 @@ namespace DiscImageChef.Devices
LastError = SendScsiCommand(cdb, ref buffer, out senseBuffer, timeout, ScsiDirection.In, out duration, LastError = SendScsiCommand(cdb, ref buffer, out senseBuffer, timeout, ScsiDirection.In, out duration,
out bool sense); out bool sense);
Error = LastError != 0; Error = LastError != 0;
if(sense) return true; if(sense)
return true;
ushort confLength = (ushort)((buffer[2] << 8) + buffer[3] + 4); ushort confLength = (ushort)((buffer[2] << 8) + buffer[3] + 4);
buffer = new byte[confLength]; buffer = new byte[confLength];
@@ -103,6 +98,7 @@ namespace DiscImageChef.Devices
LastError = SendScsiCommand(cdb, ref buffer, out senseBuffer, timeout, ScsiDirection.In, out duration, LastError = SendScsiCommand(cdb, ref buffer, out senseBuffer, timeout, ScsiDirection.In, out duration,
out sense); out sense);
Error = LastError != 0; Error = LastError != 0;
DicConsole.DebugWriteLine("SCSI Device", "GET CONFIGURATION took {0} ms.", duration); DicConsole.DebugWriteLine("SCSI Device", "GET CONFIGURATION took {0} ms.", duration);
@@ -110,9 +106,7 @@ namespace DiscImageChef.Devices
return sense; return sense;
} }
/// <summary> /// <summary>Sends the MMC READ DISC STRUCTURE command</summary>
/// Sends the MMC READ DISC STRUCTURE command
/// </summary>
/// <returns><c>true</c> if the command failed and <paramref name="senseBuffer" /> contains the sense buffer.</returns> /// <returns><c>true</c> if the command failed and <paramref name="senseBuffer" /> contains the sense buffer.</returns>
/// <param name="buffer">Buffer where the SCSI READ DISC STRUCTURE response will be stored</param> /// <param name="buffer">Buffer where the SCSI READ DISC STRUCTURE response will be stored</param>
/// <param name="senseBuffer">Sense buffer.</param> /// <param name="senseBuffer">Sense buffer.</param>
@@ -124,8 +118,7 @@ namespace DiscImageChef.Devices
/// <param name="agid">AGID used in medium copy protection</param> /// <param name="agid">AGID used in medium copy protection</param>
/// <param name="duration">Duration in milliseconds it took for the device to execute the command.</param> /// <param name="duration">Duration in milliseconds it took for the device to execute the command.</param>
public bool ReadDiscStructure(out byte[] buffer, out byte[] senseBuffer, MmcDiscStructureMediaType mediaType, public bool ReadDiscStructure(out byte[] buffer, out byte[] senseBuffer, MmcDiscStructureMediaType mediaType,
uint address, byte layerNumber, MmcDiscStructureFormat format, uint address, byte layerNumber, MmcDiscStructureFormat format, byte agid,
byte agid,
uint timeout, out double duration) uint timeout, out double duration)
{ {
senseBuffer = new byte[32]; senseBuffer = new byte[32];
@@ -146,9 +139,11 @@ namespace DiscImageChef.Devices
LastError = SendScsiCommand(cdb, ref buffer, out senseBuffer, timeout, ScsiDirection.In, out duration, LastError = SendScsiCommand(cdb, ref buffer, out senseBuffer, timeout, ScsiDirection.In, out duration,
out bool sense); out bool sense);
Error = LastError != 0; Error = LastError != 0;
if(sense) return true; if(sense)
return true;
ushort strctLength = (ushort)((buffer[0] << 8) + buffer[1] + 2); ushort strctLength = (ushort)((buffer[0] << 8) + buffer[1] + 2);
@@ -158,30 +153,39 @@ namespace DiscImageChef.Devices
{ {
case MmcDiscStructureFormat.DiscInformation: case MmcDiscStructureFormat.DiscInformation:
buffer = new byte[4100]; buffer = new byte[4100];
break; break;
case MmcDiscStructureFormat.BdBurstCuttingArea: case MmcDiscStructureFormat.BdBurstCuttingArea:
buffer = new byte[68]; buffer = new byte[68];
break; break;
case MmcDiscStructureFormat.BdDds: case MmcDiscStructureFormat.BdDds:
buffer = new byte[strctLength < 100 ? 100 : strctLength]; buffer = new byte[strctLength < 100 ? 100 : strctLength];
break; break;
case MmcDiscStructureFormat.CartridgeStatus: case MmcDiscStructureFormat.CartridgeStatus:
buffer = new byte[8]; buffer = new byte[8];
break; break;
case MmcDiscStructureFormat.BdSpareAreaInformation: case MmcDiscStructureFormat.BdSpareAreaInformation:
buffer = new byte[16]; buffer = new byte[16];
break; break;
default: default:
buffer = new byte[strctLength]; buffer = new byte[strctLength];
break; break;
} }
else buffer = new byte[strctLength]; else
buffer = new byte[strctLength];
cdb[8] = (byte)((buffer.Length & 0xFF00) >> 8); cdb[8] = (byte)((buffer.Length & 0xFF00) >> 8);
cdb[9] = (byte)(buffer.Length & 0xFF); cdb[9] = (byte)(buffer.Length & 0xFF);
senseBuffer = new byte[32]; senseBuffer = new byte[32];
LastError = SendScsiCommand(cdb, ref buffer, out senseBuffer, timeout, ScsiDirection.In, out duration, LastError = SendScsiCommand(cdb, ref buffer, out senseBuffer, timeout, ScsiDirection.In, out duration,
out sense); out sense);
Error = LastError != 0; Error = LastError != 0;
DicConsole.DebugWriteLine("SCSI Device", "READ DISC STRUCTURE took {0} ms.", duration); DicConsole.DebugWriteLine("SCSI Device", "READ DISC STRUCTURE took {0} ms.", duration);
@@ -189,9 +193,7 @@ namespace DiscImageChef.Devices
return sense; return sense;
} }
/// <summary> /// <summary>Sends the MMC READ TOC/PMA/ATIP command to get formatted TOC from disc, in MM:SS:FF format</summary>
/// Sends the MMC READ TOC/PMA/ATIP command to get formatted TOC from disc, in MM:SS:FF format
/// </summary>
/// <returns><c>true</c> if the command failed and <paramref name="senseBuffer" /> contains the sense buffer.</returns> /// <returns><c>true</c> if the command failed and <paramref name="senseBuffer" /> contains the sense buffer.</returns>
/// <param name="buffer">Buffer where the SCSI READ TOC/PMA/ATIP response will be stored</param> /// <param name="buffer">Buffer where the SCSI READ TOC/PMA/ATIP response will be stored</param>
/// <param name="senseBuffer">Sense buffer.</param> /// <param name="senseBuffer">Sense buffer.</param>
@@ -201,9 +203,7 @@ namespace DiscImageChef.Devices
public bool ReadToc(out byte[] buffer, out byte[] senseBuffer, byte track, uint timeout, out double duration) => public bool ReadToc(out byte[] buffer, out byte[] senseBuffer, byte track, uint timeout, out double duration) =>
ReadTocPmaAtip(out buffer, out senseBuffer, true, 0, track, timeout, out duration); ReadTocPmaAtip(out buffer, out senseBuffer, true, 0, track, timeout, out duration);
/// <summary> /// <summary>Sends the MMC READ TOC/PMA/ATIP command to get formatted TOC from disc</summary>
/// Sends the MMC READ TOC/PMA/ATIP command to get formatted TOC from disc
/// </summary>
/// <returns><c>true</c> if the command failed and <paramref name="senseBuffer" /> contains the sense buffer.</returns> /// <returns><c>true</c> if the command failed and <paramref name="senseBuffer" /> contains the sense buffer.</returns>
/// <param name="buffer">Buffer where the SCSI READ TOC/PMA/ATIP response will be stored</param> /// <param name="buffer">Buffer where the SCSI READ TOC/PMA/ATIP response will be stored</param>
/// <param name="senseBuffer">Sense buffer.</param> /// <param name="senseBuffer">Sense buffer.</param>
@@ -215,9 +215,7 @@ namespace DiscImageChef.Devices
out double duration) => out double duration) =>
ReadTocPmaAtip(out buffer, out senseBuffer, msf, 0, track, timeout, out duration); ReadTocPmaAtip(out buffer, out senseBuffer, msf, 0, track, timeout, out duration);
/// <summary> /// <summary>Sends the MMC READ TOC/PMA/ATIP command to get multi-session information, in MM:SS:FF format</summary>
/// Sends the MMC READ TOC/PMA/ATIP command to get multi-session information, in MM:SS:FF format
/// </summary>
/// <returns><c>true</c> if the command failed and <paramref name="senseBuffer" /> contains the sense buffer.</returns> /// <returns><c>true</c> if the command failed and <paramref name="senseBuffer" /> contains the sense buffer.</returns>
/// <param name="buffer">Buffer where the SCSI READ TOC/PMA/ATIP response will be stored</param> /// <param name="buffer">Buffer where the SCSI READ TOC/PMA/ATIP response will be stored</param>
/// <param name="senseBuffer">Sense buffer.</param> /// <param name="senseBuffer">Sense buffer.</param>
@@ -226,9 +224,7 @@ namespace DiscImageChef.Devices
public bool ReadSessionInfo(out byte[] buffer, out byte[] senseBuffer, uint timeout, out double duration) => public bool ReadSessionInfo(out byte[] buffer, out byte[] senseBuffer, uint timeout, out double duration) =>
ReadTocPmaAtip(out buffer, out senseBuffer, true, 1, 0, timeout, out duration); ReadTocPmaAtip(out buffer, out senseBuffer, true, 1, 0, timeout, out duration);
/// <summary> /// <summary>Sends the MMC READ TOC/PMA/ATIP command to get multi-session information</summary>
/// Sends the MMC READ TOC/PMA/ATIP command to get multi-session information
/// </summary>
/// <returns><c>true</c> if the command failed and <paramref name="senseBuffer" /> contains the sense buffer.</returns> /// <returns><c>true</c> if the command failed and <paramref name="senseBuffer" /> contains the sense buffer.</returns>
/// <param name="buffer">Buffer where the SCSI READ TOC/PMA/ATIP response will be stored</param> /// <param name="buffer">Buffer where the SCSI READ TOC/PMA/ATIP response will be stored</param>
/// <param name="senseBuffer">Sense buffer.</param> /// <param name="senseBuffer">Sense buffer.</param>
@@ -239,9 +235,7 @@ namespace DiscImageChef.Devices
out double duration) => out double duration) =>
ReadTocPmaAtip(out buffer, out senseBuffer, msf, 1, 0, timeout, out duration); ReadTocPmaAtip(out buffer, out senseBuffer, msf, 1, 0, timeout, out duration);
/// <summary> /// <summary>Sends the MMC READ TOC/PMA/ATIP command to get raw TOC subchannels</summary>
/// Sends the MMC READ TOC/PMA/ATIP command to get raw TOC subchannels
/// </summary>
/// <returns><c>true</c> if the command failed and <paramref name="senseBuffer" /> contains the sense buffer.</returns> /// <returns><c>true</c> if the command failed and <paramref name="senseBuffer" /> contains the sense buffer.</returns>
/// <param name="buffer">Buffer where the SCSI READ TOC/PMA/ATIP response will be stored</param> /// <param name="buffer">Buffer where the SCSI READ TOC/PMA/ATIP response will be stored</param>
/// <param name="senseBuffer">Sense buffer.</param> /// <param name="senseBuffer">Sense buffer.</param>
@@ -252,9 +246,7 @@ namespace DiscImageChef.Devices
out double duration) => out double duration) =>
ReadTocPmaAtip(out buffer, out senseBuffer, true, 2, sessionNumber, timeout, out duration); ReadTocPmaAtip(out buffer, out senseBuffer, true, 2, sessionNumber, timeout, out duration);
/// <summary> /// <summary>Sends the MMC READ TOC/PMA/ATIP command to get PMA</summary>
/// Sends the MMC READ TOC/PMA/ATIP command to get PMA
/// </summary>
/// <returns><c>true</c> if the command failed and <paramref name="senseBuffer" /> contains the sense buffer.</returns> /// <returns><c>true</c> if the command failed and <paramref name="senseBuffer" /> contains the sense buffer.</returns>
/// <param name="buffer">Buffer where the SCSI READ TOC/PMA/ATIP response will be stored</param> /// <param name="buffer">Buffer where the SCSI READ TOC/PMA/ATIP response will be stored</param>
/// <param name="senseBuffer">Sense buffer.</param> /// <param name="senseBuffer">Sense buffer.</param>
@@ -263,9 +255,7 @@ namespace DiscImageChef.Devices
public bool ReadPma(out byte[] buffer, out byte[] senseBuffer, uint timeout, out double duration) => public bool ReadPma(out byte[] buffer, out byte[] senseBuffer, uint timeout, out double duration) =>
ReadTocPmaAtip(out buffer, out senseBuffer, true, 3, 0, timeout, out duration); ReadTocPmaAtip(out buffer, out senseBuffer, true, 3, 0, timeout, out duration);
/// <summary> /// <summary>Sends the MMC READ TOC/PMA/ATIP command to get ATIP</summary>
/// Sends the MMC READ TOC/PMA/ATIP command to get ATIP
/// </summary>
/// <returns><c>true</c> if the command failed and <paramref name="senseBuffer" /> contains the sense buffer.</returns> /// <returns><c>true</c> if the command failed and <paramref name="senseBuffer" /> contains the sense buffer.</returns>
/// <param name="buffer">Buffer where the SCSI READ TOC/PMA/ATIP response will be stored</param> /// <param name="buffer">Buffer where the SCSI READ TOC/PMA/ATIP response will be stored</param>
/// <param name="senseBuffer">Sense buffer.</param> /// <param name="senseBuffer">Sense buffer.</param>
@@ -274,9 +264,7 @@ namespace DiscImageChef.Devices
public bool ReadAtip(out byte[] buffer, out byte[] senseBuffer, uint timeout, out double duration) => public bool ReadAtip(out byte[] buffer, out byte[] senseBuffer, uint timeout, out double duration) =>
ReadTocPmaAtip(out buffer, out senseBuffer, true, 4, 0, timeout, out duration); ReadTocPmaAtip(out buffer, out senseBuffer, true, 4, 0, timeout, out duration);
/// <summary> /// <summary>Sends the MMC READ TOC/PMA/ATIP command to get Lead-In CD-TEXT</summary>
/// Sends the MMC READ TOC/PMA/ATIP command to get Lead-In CD-TEXT
/// </summary>
/// <returns><c>true</c> if the command failed and <paramref name="senseBuffer" /> contains the sense buffer.</returns> /// <returns><c>true</c> if the command failed and <paramref name="senseBuffer" /> contains the sense buffer.</returns>
/// <param name="buffer">Buffer where the SCSI READ TOC/PMA/ATIP response will be stored</param> /// <param name="buffer">Buffer where the SCSI READ TOC/PMA/ATIP response will be stored</param>
/// <param name="senseBuffer">Sense buffer.</param> /// <param name="senseBuffer">Sense buffer.</param>
@@ -285,9 +273,7 @@ namespace DiscImageChef.Devices
public bool ReadCdText(out byte[] buffer, out byte[] senseBuffer, uint timeout, out double duration) => public bool ReadCdText(out byte[] buffer, out byte[] senseBuffer, uint timeout, out double duration) =>
ReadTocPmaAtip(out buffer, out senseBuffer, true, 5, 0, timeout, out duration); ReadTocPmaAtip(out buffer, out senseBuffer, true, 5, 0, timeout, out duration);
/// <summary> /// <summary>Sends the MMC READ TOC/PMA/ATIP command</summary>
/// Sends the MMC READ TOC/PMA/ATIP command
/// </summary>
/// <returns><c>true</c> if the command failed and <paramref name="senseBuffer" /> contains the sense buffer.</returns> /// <returns><c>true</c> if the command failed and <paramref name="senseBuffer" /> contains the sense buffer.</returns>
/// <param name="buffer">Buffer where the SCSI READ TOC/PMA/ATIP response will be stored</param> /// <param name="buffer">Buffer where the SCSI READ TOC/PMA/ATIP response will be stored</param>
/// <param name="senseBuffer">Sense buffer.</param> /// <param name="senseBuffer">Sense buffer.</param>
@@ -305,7 +291,10 @@ namespace DiscImageChef.Devices
byte[] tmpBuffer = (format & 0x0F) == 5 ? new byte[32768] : new byte[1024]; 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;
if(msf)
cdb[1] = 0x02;
cdb[2] = (byte)(format & 0x0F); cdb[2] = (byte)(format & 0x0F);
cdb[6] = trackSessionNumber; cdb[6] = trackSessionNumber;
cdb[7] = (byte)((tmpBuffer.Length & 0xFF00) >> 8); cdb[7] = (byte)((tmpBuffer.Length & 0xFF00) >> 8);
@@ -313,6 +302,7 @@ namespace DiscImageChef.Devices
LastError = SendScsiCommand(cdb, ref tmpBuffer, out senseBuffer, timeout, ScsiDirection.In, out duration, LastError = SendScsiCommand(cdb, ref tmpBuffer, out senseBuffer, timeout, ScsiDirection.In, out duration,
out bool sense); out bool sense);
Error = LastError != 0; Error = LastError != 0;
uint strctLength = (uint)((tmpBuffer[0] << 8) + tmpBuffer[1] + 2); uint strctLength = (uint)((tmpBuffer[0] << 8) + tmpBuffer[1] + 2);
@@ -322,6 +312,7 @@ namespace DiscImageChef.Devices
{ {
Array.Copy(tmpBuffer, 0, buffer, 0, buffer.Length); Array.Copy(tmpBuffer, 0, buffer, 0, buffer.Length);
DicConsole.DebugWriteLine("SCSI Device", "READ TOC/PMA/ATIP took {0} ms.", duration); DicConsole.DebugWriteLine("SCSI Device", "READ TOC/PMA/ATIP took {0} ms.", duration);
return sense; return sense;
} }
@@ -329,16 +320,16 @@ namespace DiscImageChef.Devices
LastError = SendScsiCommand(cdb, ref buffer, out senseBuffer, timeout, ScsiDirection.In, out duration, LastError = SendScsiCommand(cdb, ref buffer, out senseBuffer, timeout, ScsiDirection.In, out duration,
out sense); out sense);
Error = LastError != 0; Error = LastError != 0;
duration += tmpDuration; duration += tmpDuration;
DicConsole.DebugWriteLine("SCSI Device", "READ TOC/PMA/ATIP took {0} ms.", duration); DicConsole.DebugWriteLine("SCSI Device", "READ TOC/PMA/ATIP took {0} ms.", duration);
return sense; return sense;
} }
/// <summary> /// <summary>Sends the MMC READ DISC INFORMATION command</summary>
/// Sends the MMC READ DISC INFORMATION command
/// </summary>
/// <returns><c>true</c> if the command failed and <paramref name="senseBuffer" /> contains the sense buffer.</returns> /// <returns><c>true</c> if the command failed and <paramref name="senseBuffer" /> contains the sense buffer.</returns>
/// <param name="buffer">Buffer where the SCSI READ DISC INFORMATION response will be stored</param> /// <param name="buffer">Buffer where the SCSI READ DISC INFORMATION response will be stored</param>
/// <param name="senseBuffer">Sense buffer.</param> /// <param name="senseBuffer">Sense buffer.</param>
@@ -348,17 +339,14 @@ namespace DiscImageChef.Devices
ReadDiscInformation(out buffer, out senseBuffer, MmcDiscInformationDataTypes.DiscInformation, timeout, ReadDiscInformation(out buffer, out senseBuffer, MmcDiscInformationDataTypes.DiscInformation, timeout,
out duration); out duration);
/// <summary> /// <summary>Sends the MMC READ DISC INFORMATION command</summary>
/// Sends the MMC READ DISC INFORMATION command
/// </summary>
/// <returns><c>true</c> if the command failed and <paramref name="senseBuffer" /> contains the sense buffer.</returns> /// <returns><c>true</c> if the command failed and <paramref name="senseBuffer" /> contains the sense buffer.</returns>
/// <param name="buffer">Buffer where the SCSI READ DISC INFORMATION response will be stored</param> /// <param name="buffer">Buffer where the SCSI READ DISC INFORMATION response will be stored</param>
/// <param name="senseBuffer">Sense buffer.</param> /// <param name="senseBuffer">Sense buffer.</param>
/// <param name="dataType">Which disc information to read</param> /// <param name="dataType">Which disc information to read</param>
/// <param name="timeout">Timeout in seconds.</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="duration">Duration in milliseconds it took for the device to execute the command.</param>
public bool ReadDiscInformation(out byte[] buffer, out byte[] senseBuffer, public bool ReadDiscInformation(out byte[] buffer, out byte[] senseBuffer, MmcDiscInformationDataTypes dataType,
MmcDiscInformationDataTypes dataType,
uint timeout, out double duration) uint timeout, out double duration)
{ {
senseBuffer = new byte[32]; senseBuffer = new byte[32];
@@ -372,10 +360,13 @@ namespace DiscImageChef.Devices
LastError = SendScsiCommand(cdb, ref tmpBuffer, out senseBuffer, timeout, ScsiDirection.In, out duration, LastError = SendScsiCommand(cdb, ref tmpBuffer, out senseBuffer, timeout, ScsiDirection.In, out duration,
out bool sense); out bool sense);
Error = LastError != 0; Error = LastError != 0;
uint strctLength = (uint)((tmpBuffer[0] << 8) + tmpBuffer[1] + 2); uint strctLength = (uint)((tmpBuffer[0] << 8) + tmpBuffer[1] + 2);
if(strctLength > tmpBuffer.Length) strctLength = (uint)tmpBuffer.Length;
if(strctLength > tmpBuffer.Length)
strctLength = (uint)tmpBuffer.Length;
buffer = new byte[strctLength]; buffer = new byte[strctLength];
Array.Copy(tmpBuffer, 0, buffer, 0, buffer.Length); Array.Copy(tmpBuffer, 0, buffer, 0, buffer.Length);
@@ -385,9 +376,7 @@ namespace DiscImageChef.Devices
return sense; return sense;
} }
/// <summary> /// <summary>Sends the MMC READ CD command</summary>
/// Sends the MMC READ CD command
/// </summary>
/// <returns><c>true</c> if the command failed and <paramref name="senseBuffer" /> contains the sense buffer.</returns> /// <returns><c>true</c> if the command failed and <paramref name="senseBuffer" /> contains the sense buffer.</returns>
/// <param name="buffer">Buffer where the MMC READ CD response will be stored</param> /// <param name="buffer">Buffer where the MMC READ CD response will be stored</param>
/// <param name="senseBuffer">Sense buffer.</param> /// <param name="senseBuffer">Sense buffer.</param>
@@ -405,12 +394,9 @@ namespace DiscImageChef.Devices
/// <param name="edcEcc">If set to <c>true</c> we request the EDC/ECC fields for data sectors.</param> /// <param name="edcEcc">If set to <c>true</c> we request the EDC/ECC fields for data sectors.</param>
/// <param name="c2Error">C2 error options.</param> /// <param name="c2Error">C2 error options.</param>
/// <param name="subchannel">Subchannel selection.</param> /// <param name="subchannel">Subchannel selection.</param>
public bool ReadCd(out byte[] buffer, out byte[] senseBuffer, uint lba, public bool ReadCd(out byte[] buffer, out byte[] senseBuffer, uint lba, uint blockSize, uint transferLength,
uint blockSize, uint transferLength, MmcSectorTypes expectedSectorType, bool dap, bool relAddr, bool sync,
MmcSectorTypes expectedSectorType, bool dap, bool relAddr, MmcHeaderCodes headerCodes, bool userData, bool edcEcc, MmcErrorField c2Error,
bool sync,
MmcHeaderCodes headerCodes, bool userData, bool edcEcc,
MmcErrorField c2Error,
MmcSubchannel subchannel, uint timeout, out double duration) MmcSubchannel subchannel, uint timeout, out double duration)
{ {
senseBuffer = new byte[32]; senseBuffer = new byte[32];
@@ -418,8 +404,13 @@ namespace DiscImageChef.Devices
cdb[0] = (byte)ScsiCommands.ReadCd; cdb[0] = (byte)ScsiCommands.ReadCd;
cdb[1] = (byte)((byte)expectedSectorType << 2); cdb[1] = (byte)((byte)expectedSectorType << 2);
if(dap) cdb[1] += 0x02;
if(relAddr) cdb[1] += 0x01; if(dap)
cdb[1] += 0x02;
if(relAddr)
cdb[1] += 0x01;
cdb[2] = (byte)((lba & 0xFF000000) >> 24); cdb[2] = (byte)((lba & 0xFF000000) >> 24);
cdb[3] = (byte)((lba & 0xFF0000) >> 16); cdb[3] = (byte)((lba & 0xFF0000) >> 16);
cdb[4] = (byte)((lba & 0xFF00) >> 8); cdb[4] = (byte)((lba & 0xFF00) >> 8);
@@ -429,15 +420,23 @@ namespace DiscImageChef.Devices
cdb[8] = (byte)(transferLength & 0xFF); cdb[8] = (byte)(transferLength & 0xFF);
cdb[9] = (byte)((byte)c2Error << 1); cdb[9] = (byte)((byte)c2Error << 1);
cdb[9] += (byte)((byte)headerCodes << 5); cdb[9] += (byte)((byte)headerCodes << 5);
if(sync) cdb[9] += 0x80;
if(userData) cdb[9] += 0x10; if(sync)
if(edcEcc) cdb[9] += 0x08; cdb[9] += 0x80;
if(userData)
cdb[9] += 0x10;
if(edcEcc)
cdb[9] += 0x08;
cdb[10] = (byte)subchannel; cdb[10] = (byte)subchannel;
buffer = new byte[blockSize * transferLength]; buffer = new byte[blockSize * transferLength];
LastError = SendScsiCommand(cdb, ref buffer, out senseBuffer, timeout, ScsiDirection.In, out duration, LastError = SendScsiCommand(cdb, ref buffer, out senseBuffer, timeout, ScsiDirection.In, out duration,
out bool sense); out bool sense);
Error = LastError != 0; Error = LastError != 0;
DicConsole.DebugWriteLine("SCSI Device", "READ CD took {0} ms.", duration); DicConsole.DebugWriteLine("SCSI Device", "READ CD took {0} ms.", duration);
@@ -445,9 +444,7 @@ namespace DiscImageChef.Devices
return sense; return sense;
} }
/// <summary> /// <summary>Sends the MMC READ CD MSF command</summary>
/// Sends the MMC READ CD MSF command
/// </summary>
/// <returns><c>true</c> if the command failed and <paramref name="senseBuffer" /> contains the sense buffer.</returns> /// <returns><c>true</c> if the command failed and <paramref name="senseBuffer" /> contains the sense buffer.</returns>
/// <param name="buffer">Buffer where the MMC READ CD MSF response will be stored</param> /// <param name="buffer">Buffer where the MMC READ CD MSF response will be stored</param>
/// <param name="senseBuffer">Sense buffer.</param> /// <param name="senseBuffer">Sense buffer.</param>
@@ -464,12 +461,9 @@ namespace DiscImageChef.Devices
/// <param name="edcEcc">If set to <c>true</c> we request the EDC/ECC fields for data sectors.</param> /// <param name="edcEcc">If set to <c>true</c> we request the EDC/ECC fields for data sectors.</param>
/// <param name="c2Error">C2 error options.</param> /// <param name="c2Error">C2 error options.</param>
/// <param name="subchannel">Subchannel selection.</param> /// <param name="subchannel">Subchannel selection.</param>
public bool ReadCdMsf(out byte[] buffer, out byte[] senseBuffer, uint startMsf, public bool ReadCdMsf(out byte[] buffer, out byte[] senseBuffer, uint startMsf, uint endMsf, uint blockSize,
uint endMsf, uint blockSize, MmcSectorTypes expectedSectorType, bool dap, bool sync, MmcHeaderCodes headerCodes,
MmcSectorTypes expectedSectorType, bool dap, bool sync, bool userData, bool edcEcc, MmcErrorField c2Error, MmcSubchannel subchannel, uint timeout,
MmcHeaderCodes headerCodes,
bool userData, bool edcEcc, MmcErrorField c2Error,
MmcSubchannel subchannel, uint timeout,
out double duration) out double duration)
{ {
senseBuffer = new byte[32]; senseBuffer = new byte[32];
@@ -477,7 +471,10 @@ namespace DiscImageChef.Devices
cdb[0] = (byte)ScsiCommands.ReadCdMsf; cdb[0] = (byte)ScsiCommands.ReadCdMsf;
cdb[1] = (byte)((byte)expectedSectorType << 2); cdb[1] = (byte)((byte)expectedSectorType << 2);
if(dap) cdb[1] += 0x02;
if(dap)
cdb[1] += 0x02;
cdb[3] = (byte)((startMsf & 0xFF0000) >> 16); cdb[3] = (byte)((startMsf & 0xFF0000) >> 16);
cdb[4] = (byte)((startMsf & 0xFF00) >> 8); cdb[4] = (byte)((startMsf & 0xFF00) >> 8);
cdb[5] = (byte)(startMsf & 0xFF); cdb[5] = (byte)(startMsf & 0xFF);
@@ -486,17 +483,25 @@ namespace DiscImageChef.Devices
cdb[8] = (byte)(endMsf & 0xFF); cdb[8] = (byte)(endMsf & 0xFF);
cdb[9] = (byte)((byte)c2Error << 1); cdb[9] = (byte)((byte)c2Error << 1);
cdb[9] += (byte)((byte)headerCodes << 5); cdb[9] += (byte)((byte)headerCodes << 5);
if(sync) cdb[9] += 0x80;
if(userData) cdb[9] += 0x10; if(sync)
if(edcEcc) cdb[9] += 0x08; cdb[9] += 0x80;
if(userData)
cdb[9] += 0x10;
if(edcEcc)
cdb[9] += 0x08;
cdb[10] = (byte)subchannel; cdb[10] = (byte)subchannel;
uint transferLength = (uint)((cdb[6] - cdb[3]) * 60 * 75 + (cdb[7] - cdb[4]) * 75 + (cdb[8] - cdb[5])); uint transferLength = (uint)(((cdb[6] - cdb[3]) * 60 * 75) + ((cdb[7] - cdb[4]) * 75) + (cdb[8] - cdb[5]));
buffer = new byte[blockSize * transferLength]; buffer = new byte[blockSize * transferLength];
LastError = SendScsiCommand(cdb, ref buffer, out senseBuffer, timeout, ScsiDirection.In, out duration, LastError = SendScsiCommand(cdb, ref buffer, out senseBuffer, timeout, ScsiDirection.In, out duration,
out bool sense); out bool sense);
Error = LastError != 0; Error = LastError != 0;
DicConsole.DebugWriteLine("SCSI Device", "READ CD MSF took {0} ms.", duration); DicConsole.DebugWriteLine("SCSI Device", "READ CD MSF took {0} ms.", duration);
@@ -518,11 +523,16 @@ namespace DiscImageChef.Devices
byte[] buffer = new byte[0]; byte[] buffer = new byte[0];
cdb[0] = (byte)ScsiCommands.PreventAllowMediumRemoval; cdb[0] = (byte)ScsiCommands.PreventAllowMediumRemoval;
if(prevent) cdb[4] += 0x01;
if(persistent) cdb[4] += 0x02; if(prevent)
cdb[4] += 0x01;
if(persistent)
cdb[4] += 0x02;
LastError = SendScsiCommand(cdb, ref buffer, out senseBuffer, timeout, ScsiDirection.None, out duration, LastError = SendScsiCommand(cdb, ref buffer, out senseBuffer, timeout, ScsiDirection.None, out duration,
out bool sense); out bool sense);
Error = LastError != 0; Error = LastError != 0;
DicConsole.DebugWriteLine("SCSI Device", "PREVENT ALLOW MEDIUM REMOVAL took {0} ms.", duration); DicConsole.DebugWriteLine("SCSI Device", "PREVENT ALLOW MEDIUM REMOVAL took {0} ms.", duration);
@@ -543,15 +553,17 @@ namespace DiscImageChef.Devices
StartStopUnit(out senseBuffer, false, 0, 0, false, false, false, timeout, out duration); StartStopUnit(out senseBuffer, false, 0, 0, false, false, false, timeout, out duration);
public bool StartStopUnit(out byte[] senseBuffer, bool immediate, byte formatLayer, byte powerConditions, public bool StartStopUnit(out byte[] senseBuffer, bool immediate, byte formatLayer, byte powerConditions,
bool changeFormatLayer, bool loadEject, bool start, uint timeout, bool changeFormatLayer, bool loadEject, bool start, uint timeout, out double duration)
out double duration)
{ {
senseBuffer = new byte[32]; senseBuffer = new byte[32];
byte[] cdb = new byte[6]; byte[] cdb = new byte[6];
byte[] buffer = new byte[0]; byte[] buffer = new byte[0];
cdb[0] = (byte)ScsiCommands.StartStopUnit; cdb[0] = (byte)ScsiCommands.StartStopUnit;
if(immediate) cdb[1] += 0x01;
if(immediate)
cdb[1] += 0x01;
if(changeFormatLayer) if(changeFormatLayer)
{ {
cdb[3] = (byte)(formatLayer & 0x03); cdb[3] = (byte)(formatLayer & 0x03);
@@ -559,14 +571,18 @@ namespace DiscImageChef.Devices
} }
else else
{ {
if(loadEject) cdb[4] += 0x02; if(loadEject)
if(start) cdb[4] += 0x01; cdb[4] += 0x02;
if(start)
cdb[4] += 0x01;
} }
cdb[4] += (byte)((powerConditions & 0x0F) << 4); cdb[4] += (byte)((powerConditions & 0x0F) << 4);
LastError = SendScsiCommand(cdb, ref buffer, out senseBuffer, timeout, ScsiDirection.None, out duration, LastError = SendScsiCommand(cdb, ref buffer, out senseBuffer, timeout, ScsiDirection.None, out duration,
out bool sense); out bool sense);
Error = LastError != 0; Error = LastError != 0;
DicConsole.DebugWriteLine("SCSI Device", "START STOP UNIT took {0} ms.", duration); DicConsole.DebugWriteLine("SCSI Device", "START STOP UNIT took {0} ms.", duration);
@@ -592,17 +608,19 @@ namespace DiscImageChef.Devices
LastError = SendScsiCommand(cdb, ref buffer, out senseBuffer, timeout, ScsiDirection.In, out duration, LastError = SendScsiCommand(cdb, ref buffer, out senseBuffer, timeout, ScsiDirection.In, out duration,
out bool sense); out bool sense);
Error = LastError != 0; Error = LastError != 0;
DicConsole.DebugWriteLine("SCSI Device", "READ READ SUB-CHANNEL (MCN) took {0} ms.", duration); 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); if(!sense &&
(buffer[8] & 0x80) == 0x80)
mcn = Encoding.ASCII.GetString(buffer, 9, 13);
return sense; return sense;
} }
public bool ReadIsrc(byte trackNumber, out string isrc, out byte[] buffer, out byte[] senseBuffer, public bool ReadIsrc(byte trackNumber, out string isrc, out byte[] buffer, out byte[] senseBuffer, uint timeout,
uint timeout,
out double duration) out double duration)
{ {
senseBuffer = new byte[32]; senseBuffer = new byte[32];
@@ -621,11 +639,38 @@ namespace DiscImageChef.Devices
LastError = SendScsiCommand(cdb, ref buffer, out senseBuffer, timeout, ScsiDirection.In, out duration, LastError = SendScsiCommand(cdb, ref buffer, out senseBuffer, timeout, ScsiDirection.In, out duration,
out bool sense); out bool sense);
Error = LastError != 0; Error = LastError != 0;
DicConsole.DebugWriteLine("SCSI Device", "READ READ SUB-CHANNEL (ISRC) took {0} ms.", duration); 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); if(!sense &&
(buffer[8] & 0x80) == 0x80)
isrc = Encoding.ASCII.GetString(buffer, 9, 12);
return sense;
}
public bool SetCdSpeed(out byte[] senseBuffer, RotationalControl rotationalControl, ushort readSpeed,
ushort writeSpeed, uint timeout, out double duration)
{
senseBuffer = new byte[32];
byte[] cdb = new byte[12];
byte[] buffer = new byte[0];
cdb[0] = (byte)ScsiCommands.SetCdSpeed;
cdb[1] = (byte)((byte)rotationalControl & 0x03);
cdb[2] = (byte)((readSpeed & 0xFF00) >> 8);
cdb[3] = (byte)(readSpeed & 0xFF);
cdb[4] = (byte)((writeSpeed & 0xFF00) >> 8);
cdb[5] = (byte)(writeSpeed & 0xFF);
LastError = SendScsiCommand(cdb, ref buffer, out senseBuffer, timeout, ScsiDirection.None, out duration,
out bool sense);
Error = LastError != 0;
DicConsole.DebugWriteLine("SCSI Device", "SET CD SPEED took {0} ms.", duration);
return sense; return sense;
} }

File diff suppressed because it is too large Load Diff

View File

@@ -527,7 +527,7 @@ namespace DiscImageChef.Gui.Forms
chkStopOnError.Checked == true, _resume, dumpLog, encoding, _outputPrefix, chkStopOnError.Checked == true, _resume, dumpLog, encoding, _outputPrefix,
txtDestination.Text, parsedOptions, _sidecar, (uint)stpSkipped.Value, txtDestination.Text, parsedOptions, _sidecar, (uint)stpSkipped.Value,
chkExistingMetadata.Checked == false, chkTrim.Checked == false, chkExistingMetadata.Checked == false, chkTrim.Checked == false,
chkTrack1Pregap.Checked == true, true, false, DumpSubchannel.Any); chkTrack1Pregap.Checked == true, true, false, DumpSubchannel.Any, 0);
new Thread(DoWork).Start(); new Thread(DoWork).Start();
} }

View File

@@ -70,6 +70,7 @@ namespace DiscImageChef.Commands
ushort _retryPasses = 5; ushort _retryPasses = 5;
bool _showHelp; bool _showHelp;
int _skip = 512; int _skip = 512;
int _speed;
bool _stopOnError; bool _stopOnError;
string _wantedOutputFormat; string _wantedOutputFormat;
string _wantedSubchannel; string _wantedSubchannel;
@@ -123,6 +124,9 @@ namespace DiscImageChef.Commands
"Subchannel to dump. Only applicable to CD/GD. Values: any, rw, rw-or-pq, pq, none", "Subchannel to dump. Only applicable to CD/GD. Values: any, rw, rw-or-pq, pq, none",
s => _wantedSubchannel = s); s => _wantedSubchannel = s);
Options.Add("speed", "Speed to dump. Only applicable to optical drives, 0 for maximum",
(int i) => _speed = i);
/* TODO: Disabled temporarily /* TODO: Disabled temporarily
Options.Add("raw|r", "Dump sectors with tags included. For optical media, dump scrambled sectors.", (b) => raw = b != null);*/ Options.Add("raw|r", "Dump sectors with tags included. For optical media, dump scrambled sectors.", (b) => raw = b != null);*/
} }
@@ -381,7 +385,7 @@ namespace DiscImageChef.Commands
var dumper = new Dump(_doResume, dev, _devicePath, outputFormat, _retryPasses, _force, false, _persistent, var dumper = new Dump(_doResume, dev, _devicePath, outputFormat, _retryPasses, _force, false, _persistent,
_stopOnError, resume, dumpLog, encoding, outputPrefix, _outputFile, parsedOptions, _stopOnError, resume, dumpLog, encoding, outputPrefix, _outputFile, parsedOptions,
sidecar, (uint)_skip, _noMetadata, _noTrim, _firstTrackPregap, _fixOffset, sidecar, (uint)_skip, _noMetadata, _noTrim, _firstTrackPregap, _fixOffset,
MainClass.Debug, subchannel); MainClass.Debug, subchannel, _speed);
dumper.UpdateStatus += Progress.UpdateStatus; dumper.UpdateStatus += Progress.UpdateStatus;
dumper.ErrorMessage += Progress.ErrorMessage; dumper.ErrorMessage += Progress.ErrorMessage;