diff --git a/DiscImageChef.Devices/ChangeLog b/DiscImageChef.Devices/ChangeLog index 24dc49e5a..38640d6d8 100644 --- a/DiscImageChef.Devices/ChangeLog +++ b/DiscImageChef.Devices/ChangeLog @@ -1,3 +1,9 @@ +2015-11-23 Natalia Portillo + + * Enums.cs: + * Device/ScsiCommands.cs: + Implemented SCSI READ DISC INFORMATION. + 2015-11-23 Natalia Portillo * Device/ScsiCommands.cs: diff --git a/DiscImageChef.Devices/Device/ScsiCommands.cs b/DiscImageChef.Devices/Device/ScsiCommands.cs index 7dcce897d..94b612552 100644 --- a/DiscImageChef.Devices/Device/ScsiCommands.cs +++ b/DiscImageChef.Devices/Device/ScsiCommands.cs @@ -670,7 +670,6 @@ namespace DiscImageChef.Devices cdb[12] = (byte)((buffer.Length & 0xFF00) >> 8); cdb[13] = (byte)(buffer.Length & 0xFF); - lastError = SendScsiCommand(cdb, ref buffer, out senseBuffer, timeout, ScsiDirection.In, out duration, out sense); error = lastError != 0; @@ -678,6 +677,259 @@ namespace DiscImageChef.Devices return sense; } + + /// + /// Sends the SCSI READ MEDIA SERIAL NUMBER command + /// + /// true if the command failed and contains the sense buffer. + /// Buffer where the SCSI READ MEDIA SERIAL NUMBER response will be stored + /// Sense buffer. + /// Timeout in seconds. + /// Duration in milliseconds it took for the device to execute the command. + public bool ReadMediaSerialNumber(out byte[] buffer, out byte[] senseBuffer, uint timeout, out double duration) + { + senseBuffer = new byte[32]; + byte[] cdb = new byte[12]; + buffer = new byte[4]; + bool sense; + + cdb[0] = (byte)ScsiCommands.ReadSerialNumber; + cdb[1] = 0x01; + cdb[6] = (byte)((buffer.Length & 0xFF000000) >> 24); + cdb[7] = (byte)((buffer.Length & 0xFF0000) >> 16); + cdb[8] = (byte)((buffer.Length & 0xFF00) >> 8); + cdb[9] = (byte)(buffer.Length & 0xFF); + + lastError = SendScsiCommand(cdb, ref buffer, out senseBuffer, timeout, ScsiDirection.In, out duration, out sense); + error = lastError != 0; + + if (sense) + return true; + + uint strctLength = (uint)(((int)buffer[0] << 24) + ((int)buffer[1] << 16) + ((int)buffer[2] << 8) + buffer[3] + 4); + cdb[6] = (byte)((buffer.Length & 0xFF000000) >> 24); + cdb[7] = (byte)((buffer.Length & 0xFF0000) >> 16); + cdb[8] = (byte)((buffer.Length & 0xFF00) >> 8); + cdb[9] = (byte)(buffer.Length & 0xFF); + buffer = new byte[strctLength]; + 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 MEDIA SERIAL NUMBER took {0} ms.", duration); + + return sense; + } + + /// + /// Sends the SCSI READ TOC/PMA/ATIP command to get formatted TOC from disc, in MM:SS:FF format + /// + /// true if the command failed and contains the sense buffer. + /// Buffer where the SCSI READ TOC/PMA/ATIP response will be stored + /// Sense buffer. + /// Start TOC from this track + /// Timeout in seconds. + /// Duration in milliseconds it took for the device to execute the command. + public bool ReadToc(out byte[] buffer, out byte[] senseBuffer, byte track, uint timeout, out double duration) + { + return ReadTocPmaAtip(out buffer, out senseBuffer, true, 0, track, timeout, out duration); + } + + /// + /// Sends the SCSI READ TOC/PMA/ATIP command to get formatted TOC from disc + /// + /// true if the command failed and contains the sense buffer. + /// Buffer where the SCSI READ TOC/PMA/ATIP response will be stored + /// Sense buffer. + /// If true, request data in MM:SS:FF units, otherwise, in blocks + /// Start TOC from this track + /// Timeout in seconds. + /// Duration in milliseconds it took for the device to execute the command. + public bool ReadToc(out byte[] buffer, out byte[] senseBuffer, bool MSF, byte track, uint timeout, out double duration) + { + return ReadTocPmaAtip(out buffer, out senseBuffer, MSF, 0, track, timeout, out duration); + } + + /// + /// Sends the SCSI READ TOC/PMA/ATIP command to get multi-session information, in MM:SS:FF format + /// + /// true if the command failed and contains the sense buffer. + /// Buffer where the SCSI READ TOC/PMA/ATIP response will be stored + /// Sense buffer. + /// Timeout in seconds. + /// Duration in milliseconds it took for the device to execute the command. + public bool ReadSessionInfo(out byte[] buffer, out byte[] senseBuffer, uint timeout, out double duration) + { + return ReadTocPmaAtip(out buffer, out senseBuffer, true, 1, 0, timeout, out duration); + } + + /// + /// Sends the SCSI READ TOC/PMA/ATIP command to get multi-session information + /// + /// true if the command failed and contains the sense buffer. + /// Buffer where the SCSI READ TOC/PMA/ATIP response will be stored + /// Sense buffer. + /// If true, request data in MM:SS:FF units, otherwise, in blocks + /// Timeout in seconds. + /// Duration in milliseconds it took for the device to execute the command. + public bool ReadSessionInfo(out byte[] buffer, out byte[] senseBuffer, bool MSF, uint timeout, out double duration) + { + return ReadTocPmaAtip(out buffer, out senseBuffer, MSF, 1, 0, timeout, out duration); + } + + /// + /// Sends the SCSI READ TOC/PMA/ATIP command to get raw TOC subchannels + /// + /// true if the command failed and contains the sense buffer. + /// Buffer where the SCSI READ TOC/PMA/ATIP response will be stored + /// Sense buffer. + /// Session which TOC to get + /// Timeout in seconds. + /// Duration in milliseconds it took for the device to execute the command. + public bool ReadRawToc(out byte[] buffer, out byte[] senseBuffer, byte sessionNumber, uint timeout, out double duration) + { + return ReadTocPmaAtip(out buffer, out senseBuffer, true, 2, sessionNumber, timeout, out duration); + } + + /// + /// Sends the SCSI READ TOC/PMA/ATIP command to get PMA + /// + /// true if the command failed and contains the sense buffer. + /// Buffer where the SCSI READ TOC/PMA/ATIP response will be stored + /// Sense buffer. + /// Timeout in seconds. + /// Duration in milliseconds it took for the device to execute the command. + public bool ReadPma(out byte[] buffer, out byte[] senseBuffer, uint timeout, out double duration) + { + return ReadTocPmaAtip(out buffer, out senseBuffer, true, 3, 0, timeout, out duration); + } + + /// + /// Sends the SCSI READ TOC/PMA/ATIP command to get ATIP + /// + /// true if the command failed and contains the sense buffer. + /// Buffer where the SCSI READ TOC/PMA/ATIP response will be stored + /// Sense buffer. + /// Timeout in seconds. + /// Duration in milliseconds it took for the device to execute the command. + public bool ReadAtip(out byte[] buffer, out byte[] senseBuffer, uint timeout, out double duration) + { + return ReadTocPmaAtip(out buffer, out senseBuffer, true, 4, 0, timeout, out duration); + } + + /// + /// Sends the SCSI READ TOC/PMA/ATIP command to get Lead-In CD-TEXT + /// + /// true if the command failed and contains the sense buffer. + /// Buffer where the SCSI READ TOC/PMA/ATIP response will be stored + /// Sense buffer. + /// Timeout in seconds. + /// Duration in milliseconds it took for the device to execute the command. + public bool ReadCdText(out byte[] buffer, out byte[] senseBuffer, uint timeout, out double duration) + { + return ReadTocPmaAtip(out buffer, out senseBuffer, true, 5, 0, timeout, out duration); + } + + /// + /// Sends the SCSI READ TOC/PMA/ATIP command + /// + /// true if the command failed and contains the sense buffer. + /// Buffer where the SCSI READ TOC/PMA/ATIP response will be stored + /// Sense buffer. + /// If true, request data in MM:SS:FF units, otherwise, in blocks + /// What structure is requested + /// 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) + { + senseBuffer = new byte[32]; + byte[] cdb = new byte[10]; + buffer = new byte[2]; + bool sense; + + cdb[0] = (byte)ScsiCommands.ReadTocPmaAtip; + if (MSF) + cdb[1] = 0x02; + cdb[2] = (byte)(format & 0x0F); + cdb[6] = trackSessionNumber; + cdb[7] = (byte)((buffer.Length & 0xFF00) >> 8); + cdb[8] = (byte)(buffer.Length & 0xFF); + + lastError = SendScsiCommand(cdb, ref buffer, out senseBuffer, timeout, ScsiDirection.In, out duration, out sense); + error = lastError != 0; + + if (sense) + return true; + + uint strctLength = (uint)(((int)buffer[0] << 8) + buffer[1] + 2); + cdb[7] = (byte)((buffer.Length & 0xFF00) >> 8); + cdb[8] = (byte)(buffer.Length & 0xFF); + buffer = new byte[strctLength]; + 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 TOC/PMA/ATIP took {0} ms.", duration); + + return sense; + } + + /// + /// Sends the SCSI READ DISC INFORMATION command + /// + /// true if the command failed and contains the sense buffer. + /// Buffer where the SCSI READ DISC INFORMATION response will be stored + /// Sense buffer. + /// Timeout in seconds. + /// Duration in milliseconds it took for the device to execute the command. + 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); + } + + /// + /// Sends the SCSI READ DISC INFORMATION command + /// + /// true if the command failed and contains the sense buffer. + /// Buffer where the SCSI READ DISC INFORMATION response will be stored + /// Sense buffer. + /// 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) + { + senseBuffer = new byte[32]; + byte[] cdb = new byte[10]; + buffer = new byte[2]; + bool sense; + + cdb[0] = (byte)ScsiCommands.ReadDiscInformation; + cdb[1] = (byte)dataType; + cdb[7] = (byte)((buffer.Length & 0xFF00) >> 8); + cdb[8] = (byte)(buffer.Length & 0xFF); + + lastError = SendScsiCommand(cdb, ref buffer, out senseBuffer, timeout, ScsiDirection.In, out duration, out sense); + error = lastError != 0; + + if (sense) + return true; + + uint strctLength = (uint)(((int)buffer[0] << 8) + buffer[1] + 2); + cdb[7] = (byte)((buffer.Length & 0xFF00) >> 8); + cdb[8] = (byte)(buffer.Length & 0xFF); + buffer = new byte[strctLength]; + 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 INFORMATION took {0} ms.", duration); + + return sense; + } } } diff --git a/DiscImageChef.Devices/Enums.cs b/DiscImageChef.Devices/Enums.cs index d3cc5ea99..54268244b 100644 --- a/DiscImageChef.Devices/Enums.cs +++ b/DiscImageChef.Devices/Enums.cs @@ -3018,5 +3018,21 @@ namespace DiscImageChef.Devices /// WriteLong16 = ReadLong16 } + + public enum MmcDiscInformationDataTypes : byte + { + /// + /// Standard Disc Information + /// + DiscInformation = 0x00, + /// + /// Track Resources Information + /// + TrackResources = 0x01, + /// + /// POW Resources Information + /// + POWResources = 0x02 + } }