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

@@ -38,9 +38,7 @@ namespace DiscImageChef.Devices
{
public partial class Device
{
/// <summary>
/// Sends the MMC GET CONFIGURATION command for all Features
/// </summary>
/// <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>
/// <param name="buffer">Buffer where the SCSI GET CONFIGURATION response will be stored</param>
/// <param name="senseBuffer">Sense buffer.</param>
@@ -49,23 +47,19 @@ namespace DiscImageChef.Devices
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);
/// <summary>
/// Sends the MMC GET CONFIGURATION command for all Features starting with specified one
/// </summary>
/// <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>
/// <param name="buffer">Buffer where the SCSI GET CONFIGURATION response will be stored</param>
/// <param name="senseBuffer">Sense buffer.</param>
/// <param name="startingFeatureNumber">Feature number where the feature list should start from</param>
/// <param name="timeout">Timeout in seconds.</param>
/// <param name="duration">Duration in milliseconds it took for the device to execute the command.</param>
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) =>
GetConfiguration(out buffer, out senseBuffer, startingFeatureNumber, MmcGetConfigurationRt.All, timeout,
out duration);
/// <summary>
/// Sends the MMC GET CONFIGURATION command
/// </summary>
/// <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>
/// <param name="buffer">Buffer where the SCSI GET CONFIGURATION response will be stored</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="startingFeatureNumber">Starting Feature number.</param>
/// <param name="rt">Return type, <see cref="MmcGetConfigurationRt" />.</param>
public bool GetConfiguration(out byte[] buffer, out byte[] senseBuffer,
ushort startingFeatureNumber,
public bool GetConfiguration(out byte[] buffer, out byte[] senseBuffer, ushort startingFeatureNumber,
MmcGetConfigurationRt rt, uint timeout, out double duration)
{
senseBuffer = new byte[32];
@@ -91,9 +84,11 @@ namespace DiscImageChef.Devices
LastError = SendScsiCommand(cdb, ref buffer, out senseBuffer, timeout, ScsiDirection.In, out duration,
out bool sense);
Error = LastError != 0;
if(sense) return true;
if(sense)
return true;
ushort confLength = (ushort)((buffer[2] << 8) + buffer[3] + 4);
buffer = new byte[confLength];
@@ -103,6 +98,7 @@ namespace DiscImageChef.Devices
LastError = SendScsiCommand(cdb, ref buffer, out senseBuffer, timeout, ScsiDirection.In, out duration,
out sense);
Error = LastError != 0;
DicConsole.DebugWriteLine("SCSI Device", "GET CONFIGURATION took {0} ms.", duration);
@@ -110,9 +106,7 @@ namespace DiscImageChef.Devices
return sense;
}
/// <summary>
/// Sends the MMC READ DISC STRUCTURE command
/// </summary>
/// <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>
/// <param name="buffer">Buffer where the SCSI READ DISC STRUCTURE response will be stored</param>
/// <param name="senseBuffer">Sense buffer.</param>
@@ -123,10 +117,9 @@ namespace DiscImageChef.Devices
/// <param name="format">Which disc structure are we requesting</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>
public bool ReadDiscStructure(out byte[] buffer, out byte[] senseBuffer, MmcDiscStructureMediaType mediaType,
uint address, byte layerNumber, MmcDiscStructureFormat format,
byte agid,
uint timeout, out double duration)
public bool ReadDiscStructure(out byte[] buffer, out byte[] senseBuffer, MmcDiscStructureMediaType mediaType,
uint address, byte layerNumber, MmcDiscStructureFormat format, byte agid,
uint timeout, out double duration)
{
senseBuffer = new byte[32];
byte[] cdb = new byte[12];
@@ -146,9 +139,11 @@ namespace DiscImageChef.Devices
LastError = SendScsiCommand(cdb, ref buffer, out senseBuffer, timeout, ScsiDirection.In, out duration,
out bool sense);
Error = LastError != 0;
if(sense) return true;
if(sense)
return true;
ushort strctLength = (ushort)((buffer[0] << 8) + buffer[1] + 2);
@@ -158,30 +153,39 @@ namespace DiscImageChef.Devices
{
case MmcDiscStructureFormat.DiscInformation:
buffer = new byte[4100];
break;
case MmcDiscStructureFormat.BdBurstCuttingArea:
buffer = new byte[68];
break;
case MmcDiscStructureFormat.BdDds:
buffer = new byte[strctLength < 100 ? 100 : strctLength];
break;
case MmcDiscStructureFormat.CartridgeStatus:
buffer = new byte[8];
break;
case MmcDiscStructureFormat.BdSpareAreaInformation:
buffer = new byte[16];
break;
default:
buffer = new byte[strctLength];
break;
}
else buffer = new byte[strctLength];
else
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);
Error = LastError != 0;
DicConsole.DebugWriteLine("SCSI Device", "READ DISC STRUCTURE took {0} ms.", duration);
@@ -189,9 +193,7 @@ namespace DiscImageChef.Devices
return sense;
}
/// <summary>
/// Sends the MMC READ TOC/PMA/ATIP command to get formatted TOC from disc, in MM:SS:FF format
/// </summary>
/// <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>
/// <param name="buffer">Buffer where the SCSI READ TOC/PMA/ATIP response will be stored</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) =>
ReadTocPmaAtip(out buffer, out senseBuffer, true, 0, track, timeout, out duration);
/// <summary>
/// Sends the MMC READ TOC/PMA/ATIP command to get formatted TOC from disc
/// </summary>
/// <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>
/// <param name="buffer">Buffer where the SCSI READ TOC/PMA/ATIP response will be stored</param>
/// <param name="senseBuffer">Sense buffer.</param>
@@ -215,9 +215,7 @@ namespace DiscImageChef.Devices
out double duration) =>
ReadTocPmaAtip(out buffer, out senseBuffer, msf, 0, track, timeout, out duration);
/// <summary>
/// Sends the MMC READ TOC/PMA/ATIP command to get multi-session information, in MM:SS:FF format
/// </summary>
/// <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>
/// <param name="buffer">Buffer where the SCSI READ TOC/PMA/ATIP response will be stored</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) =>
ReadTocPmaAtip(out buffer, out senseBuffer, true, 1, 0, timeout, out duration);
/// <summary>
/// Sends the MMC READ TOC/PMA/ATIP command to get multi-session information
/// </summary>
/// <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>
/// <param name="buffer">Buffer where the SCSI READ TOC/PMA/ATIP response will be stored</param>
/// <param name="senseBuffer">Sense buffer.</param>
@@ -239,9 +235,7 @@ namespace DiscImageChef.Devices
out double duration) =>
ReadTocPmaAtip(out buffer, out senseBuffer, msf, 1, 0, timeout, out duration);
/// <summary>
/// Sends the MMC READ TOC/PMA/ATIP command to get raw TOC subchannels
/// </summary>
/// <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>
/// <param name="buffer">Buffer where the SCSI READ TOC/PMA/ATIP response will be stored</param>
/// <param name="senseBuffer">Sense buffer.</param>
@@ -252,9 +246,7 @@ namespace DiscImageChef.Devices
out double duration) =>
ReadTocPmaAtip(out buffer, out senseBuffer, true, 2, sessionNumber, timeout, out duration);
/// <summary>
/// Sends the MMC READ TOC/PMA/ATIP command to get PMA
/// </summary>
/// <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>
/// <param name="buffer">Buffer where the SCSI READ TOC/PMA/ATIP response will be stored</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) =>
ReadTocPmaAtip(out buffer, out senseBuffer, true, 3, 0, timeout, out duration);
/// <summary>
/// Sends the MMC READ TOC/PMA/ATIP command to get ATIP
/// </summary>
/// <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>
/// <param name="buffer">Buffer where the SCSI READ TOC/PMA/ATIP response will be stored</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) =>
ReadTocPmaAtip(out buffer, out senseBuffer, true, 4, 0, timeout, out duration);
/// <summary>
/// Sends the MMC READ TOC/PMA/ATIP command to get Lead-In CD-TEXT
/// </summary>
/// <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>
/// <param name="buffer">Buffer where the SCSI READ TOC/PMA/ATIP response will be stored</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) =>
ReadTocPmaAtip(out buffer, out senseBuffer, true, 5, 0, timeout, out duration);
/// <summary>
/// Sends the MMC READ TOC/PMA/ATIP command
/// </summary>
/// <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>
/// <param name="buffer">Buffer where the SCSI READ TOC/PMA/ATIP response will be stored</param>
/// <param name="senseBuffer">Sense buffer.</param>
@@ -296,8 +282,8 @@ namespace DiscImageChef.Devices
/// <param name="trackSessionNumber">Track/Session number</param>
/// <param name="timeout">Timeout in seconds.</param>
/// <param name="duration">Duration in milliseconds it took for the device to execute the command.</param>
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];
@@ -305,7 +291,10 @@ namespace DiscImageChef.Devices
byte[] tmpBuffer = (format & 0x0F) == 5 ? new byte[32768] : new byte[1024];
cdb[0] = (byte)ScsiCommands.ReadTocPmaAtip;
if(msf) cdb[1] = 0x02;
if(msf)
cdb[1] = 0x02;
cdb[2] = (byte)(format & 0x0F);
cdb[6] = trackSessionNumber;
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,
out bool sense);
Error = LastError != 0;
uint strctLength = (uint)((tmpBuffer[0] << 8) + tmpBuffer[1] + 2);
@@ -322,6 +312,7 @@ namespace DiscImageChef.Devices
{
Array.Copy(tmpBuffer, 0, buffer, 0, buffer.Length);
DicConsole.DebugWriteLine("SCSI Device", "READ TOC/PMA/ATIP took {0} ms.", duration);
return sense;
}
@@ -329,16 +320,16 @@ namespace DiscImageChef.Devices
LastError = SendScsiCommand(cdb, ref buffer, out senseBuffer, timeout, ScsiDirection.In, out duration,
out sense);
Error = LastError != 0;
duration += tmpDuration;
DicConsole.DebugWriteLine("SCSI Device", "READ TOC/PMA/ATIP took {0} ms.", duration);
return sense;
}
/// <summary>
/// Sends the MMC READ DISC INFORMATION command
/// </summary>
/// <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>
/// <param name="buffer">Buffer where the SCSI READ DISC INFORMATION response will be stored</param>
/// <param name="senseBuffer">Sense buffer.</param>
@@ -348,18 +339,15 @@ namespace DiscImageChef.Devices
ReadDiscInformation(out buffer, out senseBuffer, MmcDiscInformationDataTypes.DiscInformation, timeout,
out duration);
/// <summary>
/// Sends the MMC READ DISC INFORMATION command
/// </summary>
/// <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>
/// <param name="buffer">Buffer where the SCSI READ DISC INFORMATION response will be stored</param>
/// <param name="senseBuffer">Sense buffer.</param>
/// <param name="dataType">Which disc information 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>
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];
@@ -372,10 +360,13 @@ namespace DiscImageChef.Devices
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);
if(strctLength > tmpBuffer.Length) strctLength = (uint)tmpBuffer.Length;
uint strctLength = (uint)((tmpBuffer[0] << 8) + tmpBuffer[1] + 2);
if(strctLength > tmpBuffer.Length)
strctLength = (uint)tmpBuffer.Length;
buffer = new byte[strctLength];
Array.Copy(tmpBuffer, 0, buffer, 0, buffer.Length);
@@ -385,9 +376,7 @@ namespace DiscImageChef.Devices
return sense;
}
/// <summary>
/// Sends the MMC READ CD command
/// </summary>
/// <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>
/// <param name="buffer">Buffer where the MMC READ CD response will be stored</param>
/// <param name="senseBuffer">Sense buffer.</param>
@@ -405,21 +394,23 @@ namespace DiscImageChef.Devices
/// <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="subchannel">Subchannel selection.</param>
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];
cdb[0] = (byte)ScsiCommands.ReadCd;
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[3] = (byte)((lba & 0xFF0000) >> 16);
cdb[4] = (byte)((lba & 0xFF00) >> 8);
@@ -429,15 +420,23 @@ namespace DiscImageChef.Devices
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;
if(sync)
cdb[9] += 0x80;
if(userData)
cdb[9] += 0x10;
if(edcEcc)
cdb[9] += 0x08;
cdb[10] = (byte)subchannel;
buffer = new byte[blockSize * transferLength];
LastError = SendScsiCommand(cdb, ref buffer, out senseBuffer, timeout, ScsiDirection.In, out duration,
out bool sense);
Error = LastError != 0;
DicConsole.DebugWriteLine("SCSI Device", "READ CD took {0} ms.", duration);
@@ -445,9 +444,7 @@ namespace DiscImageChef.Devices
return sense;
}
/// <summary>
/// Sends the MMC READ CD MSF command
/// </summary>
/// <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>
/// <param name="buffer">Buffer where the MMC READ CD MSF response will be stored</param>
/// <param name="senseBuffer">Sense buffer.</param>
@@ -464,20 +461,20 @@ namespace DiscImageChef.Devices
/// <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="subchannel">Subchannel selection.</param>
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];
cdb[0] = (byte)ScsiCommands.ReadCdMsf;
cdb[1] = (byte)((byte)expectedSectorType << 2);
if(dap) cdb[1] += 0x02;
if(dap)
cdb[1] += 0x02;
cdb[3] = (byte)((startMsf & 0xFF0000) >> 16);
cdb[4] = (byte)((startMsf & 0xFF00) >> 8);
cdb[5] = (byte)(startMsf & 0xFF);
@@ -486,17 +483,25 @@ namespace DiscImageChef.Devices
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;
if(sync)
cdb[9] += 0x80;
if(userData)
cdb[9] += 0x10;
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]));
uint transferLength = (uint)(((cdb[6] - cdb[3]) * 60 * 75) + ((cdb[7] - cdb[4]) * 75) + (cdb[8] - cdb[5]));
buffer = new byte[blockSize * transferLength];
LastError = SendScsiCommand(cdb, ref buffer, out senseBuffer, timeout, ScsiDirection.In, out duration,
out bool sense);
Error = LastError != 0;
DicConsole.DebugWriteLine("SCSI Device", "READ CD MSF took {0} ms.", duration);
@@ -518,11 +523,16 @@ namespace DiscImageChef.Devices
byte[] buffer = new byte[0];
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,
out bool sense);
Error = LastError != 0;
DicConsole.DebugWriteLine("SCSI Device", "PREVENT ALLOW MEDIUM REMOVAL took {0} ms.", duration);
@@ -542,16 +552,18 @@ namespace DiscImageChef.Devices
public bool StopUnit(out byte[] senseBuffer, uint timeout, out double 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,
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];
byte[] buffer = new byte[0];
cdb[0] = (byte)ScsiCommands.StartStopUnit;
if(immediate) cdb[1] += 0x01;
if(immediate)
cdb[1] += 0x01;
if(changeFormatLayer)
{
cdb[3] = (byte)(formatLayer & 0x03);
@@ -559,14 +571,18 @@ namespace DiscImageChef.Devices
}
else
{
if(loadEject) cdb[4] += 0x02;
if(start) cdb[4] += 0x01;
if(loadEject)
cdb[4] += 0x02;
if(start)
cdb[4] += 0x01;
}
cdb[4] += (byte)((powerConditions & 0x0F) << 4);
LastError = SendScsiCommand(cdb, ref buffer, out senseBuffer, timeout, ScsiDirection.None, out duration,
out bool sense);
Error = LastError != 0;
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,
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);
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,
public bool ReadIsrc(byte trackNumber, out string isrc, out byte[] buffer, out byte[] senseBuffer, uint timeout,
out double duration)
{
senseBuffer = new byte[32];
@@ -621,11 +639,38 @@ namespace DiscImageChef.Devices
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);
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;
}