From 59789502931fafc30882b725593a196657f8ec5a Mon Sep 17 00:00:00 2001 From: Natalia Portillo Date: Fri, 30 Oct 2015 18:35:56 +0000 Subject: [PATCH] Implemented decoding mode page 2Ah. --- ChangeLog | 5 + SCSI/Modes.cs | 246 ++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 251 insertions(+) diff --git a/ChangeLog b/ChangeLog index dd954a8fb..d4fac3575 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +2015-10-30 Natalia Portillo + + * SCSI/Modes.cs: + Implemented decoding mode page 2Ah. + 2015-10-30 Natalia Portillo * SCSI/Modes.cs: diff --git a/SCSI/Modes.cs b/SCSI/Modes.cs index 6de0e2168..78fba4a2f 100644 --- a/SCSI/Modes.cs +++ b/SCSI/Modes.cs @@ -3491,6 +3491,252 @@ namespace DiscImageChef.Decoders.SCSI return sb.ToString(); } #endregion Mode Page 0x06: Optical memory page + + #region Mode Page 0x2A: CD-ROM capabilities page + /// + /// CD-ROM capabilities page + /// Page code 0x2A + /// 16 bytes in OB-U0077C + /// + public struct ModePage_2A + { + /// + /// Parameters can be saved + /// + public bool PS; + /// + /// Drive supports multi-session and/or Photo-CD + /// + public bool MultiSession; + /// + /// Drive is capable of reading sectors in Mode 2 Form 2 format + /// + public bool Mode2Form2; + /// + /// Drive is capable of reading sectors in Mode 2 Form 1 format + /// + public bool Mode2Form1; + /// + /// Drive is capable of playing audio + /// + public bool AudioPlay; + /// + /// Drive can return the ISRC + /// + public bool ISRC; + /// + /// Drive can return the media catalogue number + /// + public bool UPC; + /// + /// Drive can return C2 pointers + /// + public bool C2Pointer; + /// + /// Drive can read, deinterlave and correct R-W subchannels + /// + public bool DeinterlaveSubchannel; + /// + /// Drive can read interleaved and uncorrected R-W subchannels + /// + public bool Subchannel; + /// + /// Drive can continue from a loss of streaming on audio reading + /// + public bool AccurateCDDA; + /// + /// Audio can be read as digital data + /// + public bool CDDACommand; + /// + /// Loading Mechanism Type + /// + public byte LoadingMechanism; + /// + /// Drive can eject discs + /// + public bool Eject; + /// + /// Drive's optional prevent jumper status + /// + public bool PreventJumper; + /// + /// Current lock status + /// + public bool LockState; + /// + /// Drive can lock media + /// + public bool Lock; + /// + /// Each channel can be muted independently + /// + public bool SeparateChannelMute; + /// + /// Each channel's volume can be controlled independently + /// + public bool SeparateChannelVolume; + /// + /// Maximum drive speed in Kbytes/second + /// + public ushort MaximumSpeed; + /// + /// Supported volume levels + /// + public ushort SupportedVolumeLevels; + /// + /// Buffer size in Kbytes + /// + public ushort BufferSize; + /// + /// Current drive speed in Kbytes/second + /// + public ushort CurrentSpeed; + } + + public static ModePage_2A? DecodeModePage_2A(byte[] pageResponse) + { + if (pageResponse == null) + return null; + + if ((pageResponse[0] & 0x3F) != 0x2A) + return null; + + if (pageResponse[1] + 2 != pageResponse.Length) + return null; + + if (pageResponse.Length < 16) + return null; + + ModePage_2A decoded = new ModePage_2A(); + + decoded.PS |= (pageResponse[0] & 0x80) == 0x80; + + decoded.AudioPlay |= (pageResponse[4] & 0x01) == 0x01; + decoded.Mode2Form1 |= (pageResponse[4] & 0x10) == 0x10; + decoded.Mode2Form2 |= (pageResponse[4] & 0x20) == 0x20; + decoded.MultiSession |= (pageResponse[4] & 0x40) == 0x40; + + decoded.CDDACommand |= (pageResponse[5] & 0x01) == 0x01; + decoded.AccurateCDDA |= (pageResponse[5] & 0x02) == 0x02; + decoded.Subchannel |= (pageResponse[5] & 0x04) == 0x04; + decoded.DeinterlaveSubchannel |= (pageResponse[5] & 0x08) == 0x08; + decoded.C2Pointer |= (pageResponse[5] & 0x10) == 0x10; + decoded.UPC |= (pageResponse[5] & 0x20) == 0x20; + decoded.ISRC |= (pageResponse[5] & 0x40) == 0x40; + + decoded.LoadingMechanism = (byte)((pageResponse[6] & 0xE0) >> 5); + decoded.Lock |= (pageResponse[6] & 0x01) == 0x01; + decoded.LockState |= (pageResponse[6] & 0x02) == 0x02; + decoded.PreventJumper |= (pageResponse[6] & 0x04) == 0x04; + decoded.Eject |= (pageResponse[6] & 0x08) == 0x08; + + decoded.SeparateChannelVolume |= (pageResponse[7] & 0x01) == 0x01; + decoded.SeparateChannelMute |= (pageResponse[7] & 0x02) == 0x02; + + decoded.MaximumSpeed = (ushort)((pageResponse[8] << 8) + pageResponse[9]); + decoded.SupportedVolumeLevels = (ushort)((pageResponse[10] << 8) + pageResponse[11]); + decoded.BufferSize = (ushort)((pageResponse[12] << 8) + pageResponse[13]); + decoded.CurrentSpeed = (ushort)((pageResponse[14] << 8) + pageResponse[15]); + + return decoded; + } + + public static string PrettifyModePage_2A(byte[] pageResponse) + { + return PrettifyModePage_2A(DecodeModePage_2A(pageResponse)); + } + + public static string PrettifyModePage_2A(ModePage_2A? modePage) + { + if (!modePage.HasValue) + return null; + + ModePage_2A page = modePage.Value; + StringBuilder sb = new StringBuilder(); + + sb.AppendLine("SCSI CD-ROM capabilities page:"); + + if (page.PS) + sb.AppendLine("\tParameters can be saved"); + + if (page.AudioPlay) + sb.AppendLine("\tDrive can play audio"); + if (page.Mode2Form1) + sb.AppendLine("\tDrive can read sectors in Mode 2 Form 1 format"); + if (page.Mode2Form2) + sb.AppendLine("\tDrive can read sectors in Mode 2 Form 2 format"); + if (page.MultiSession) + sb.AppendLine("\tDrive supports multi-session discs and/or Photo-CD"); + + if (page.CDDACommand) + sb.AppendLine("\tDrive can read digital audio"); + if (page.AccurateCDDA) + sb.AppendLine("\tDrive can continue from streaming loss"); + if (page.Subchannel) + sb.AppendLine("\tDrive can read uncorrected and interleaved R-W subchannels"); + if (page.DeinterlaveSubchannel) + sb.AppendLine("\tDrive can read, deinterleave and correct R-W subchannels"); + if (page.C2Pointer) + sb.AppendLine("\tDrive supports C2 pointers"); + if (page.UPC) + sb.AppendLine("\tDrive can read Media Catalogue Number"); + if (page.ISRC) + sb.AppendLine("\tDrive can read ISRC"); + + switch (page.LoadingMechanism) + { + case 0: + sb.AppendLine("\tDrive uses media caddy"); + break; + case 1: + sb.AppendLine("\tDrive uses a tray"); + break; + case 2: + sb.AppendLine("\tDrive is pop-up"); + break; + default: + sb.AppendFormat("\tDrive uses unknown loading mechanism type {0}", page.LoadingMechanism).AppendLine(); + break; + } + + if (page.Lock) + sb.AppendLine("\tDrive can lock media"); + if (page.PreventJumper) + { + sb.AppendLine("\tDrive power ups locked"); + if (page.LockState) + sb.AppendLine("\tDrive is locked, media cannot be ejected or inserted"); + else + sb.AppendLine("\tDrive is not locked, media can be ejected and inserted"); + } + else + { + if (page.LockState) + sb.AppendLine("\tDrive is locked, media cannot be ejected, but if empty, can be inserted"); + else + sb.AppendLine("\tDrive is not locked, media can be ejected and inserted"); + } + if (page.Eject) + sb.AppendLine("\tDrive can eject media"); + + if (page.SeparateChannelMute) + sb.AppendLine("\tEach channel can be muted independently"); + if (page.SeparateChannelVolume) + sb.AppendLine("\tEach channel's volume can be controlled independently"); + + if (page.SupportedVolumeLevels > 0) + sb.AppendFormat("\tDrive supports {0} volume levels", page.SupportedVolumeLevels).AppendLine(); + if(page.BufferSize > 0) + sb.AppendFormat("\tDrive has {0} Kbyte of buffer", page.BufferSize).AppendLine(); + if (page.MaximumSpeed > 0) + sb.AppendFormat("\tDrive's maximum speed is {0} Kbyte/sec.", page.MaximumSpeed).AppendLine(); + if (page.CurrentSpeed > 0) + sb.AppendFormat("\tDrive's current speed is {0} Kbyte/sec.", page.CurrentSpeed).AppendLine(); + + return sb.ToString(); + } + #endregion Mode Page 0x2A: CD-ROM capabilities page } }