diff --git a/DiscImageChef.CommonTypes.csproj b/DiscImageChef.CommonTypes.csproj
index 6d28d29..4464c72 100644
--- a/DiscImageChef.CommonTypes.csproj
+++ b/DiscImageChef.CommonTypes.csproj
@@ -97,6 +97,10 @@
+
+
+
+
@@ -115,7 +119,8 @@
-
+
+
diff --git a/Metadata/DeviceReport.cs b/Metadata/DeviceReport.cs
index 6f00e06..12ab15e 100644
--- a/Metadata/DeviceReport.cs
+++ b/Metadata/DeviceReport.cs
@@ -39,9 +39,9 @@
using System;
using System.ComponentModel;
using System.Xml.Serialization;
-using DiscImageChef.Decoders.ATA;
-using DiscImageChef.Decoders.SCSI;
-using DiscImageChef.Decoders.SCSI.MMC;
+using DiscImageChef.CommonTypes.Structs.Devices.ATA;
+using DiscImageChef.CommonTypes.Structs.Devices.SCSI;
+using DiscImageChef.CommonTypes.Structs.Devices.SCSI.Modes;
using Newtonsoft.Json;
// ReSharper disable InconsistentNaming
@@ -484,57 +484,57 @@ namespace DiscImageChef.CommonTypes.Metadata
public class mmcModeType
{
- public bool AccurateCDDA { get; set; }
- public bool BCK { get; set; }
- public ushort BufferSize { get; set; }
- public bool BufferUnderRunProtection { get; set; }
- public bool CanEject { get; set; }
- public bool CanLockMedia { get; set; }
- public bool CDDACommand { get; set; }
- public bool CompositeAudioVideo { get; set; }
- public bool CSSandCPPMSupported { get; set; }
- public ushort CurrentSpeed { get; set; }
- public ushort CurrentWriteSpeed { get; set; }
- public ushort CurrentWriteSpeedSelected { get; set; }
- public bool DeterministicSlotChanger { get; set; }
- public bool DigitalPort1 { get; set; }
- public bool DigitalPort2 { get; set; }
- public bool LeadInPW { get; set; }
- public byte LoadingMechanismType { get; set; }
- public bool LockStatus { get; set; }
- public bool LSBF { get; set; }
- public ushort MaximumSpeed { get; set; }
- public ushort MaximumWriteSpeed { get; set; }
- public bool PlaysAudio { get; set; }
- public bool PreventJumperStatus { get; set; }
- public bool RCK { get; set; }
- public bool ReadsBarcode { get; set; }
- public bool ReadsBothSides { get; set; }
- public bool ReadsCDR { get; set; }
- public bool ReadsCDRW { get; set; }
- public bool ReadsDeinterlavedSubchannel { get; set; }
- public bool ReadsDVDR { get; set; }
- public bool ReadsDVDRAM { get; set; }
- public bool ReadsDVDROM { get; set; }
- public bool ReadsISRC { get; set; }
- public bool ReadsMode2Form2 { get; set; }
- public bool ReadsMode2Form1 { get; set; }
- public bool ReadsPacketCDR { get; set; }
- public bool ReadsSubchannel { get; set; }
- public bool ReadsUPC { get; set; }
- public bool ReturnsC2Pointers { get; set; }
- public byte RotationControlSelected { get; set; }
- public bool SeparateChannelMute { get; set; }
- public bool SeparateChannelVolume { get; set; }
- public bool SSS { get; set; }
- public bool SupportsMultiSession { get; set; }
- public ushort SupportedVolumeLevels { get; set; }
- public bool TestWrite { get; set; }
- public bool WritesCDR { get; set; }
- public bool WritesCDRW { get; set; }
- public bool WritesDVDR { get; set; }
- public bool WritesDVDRAM { get; set; }
- public Modes.ModePage_2A_WriteDescriptor[] WriteSpeedPerformanceDescriptors { get; set; }
+ public bool AccurateCDDA { get; set; }
+ public bool BCK { get; set; }
+ public ushort BufferSize { get; set; }
+ public bool BufferUnderRunProtection { get; set; }
+ public bool CanEject { get; set; }
+ public bool CanLockMedia { get; set; }
+ public bool CDDACommand { get; set; }
+ public bool CompositeAudioVideo { get; set; }
+ public bool CSSandCPPMSupported { get; set; }
+ public ushort CurrentSpeed { get; set; }
+ public ushort CurrentWriteSpeed { get; set; }
+ public ushort CurrentWriteSpeedSelected { get; set; }
+ public bool DeterministicSlotChanger { get; set; }
+ public bool DigitalPort1 { get; set; }
+ public bool DigitalPort2 { get; set; }
+ public bool LeadInPW { get; set; }
+ public byte LoadingMechanismType { get; set; }
+ public bool LockStatus { get; set; }
+ public bool LSBF { get; set; }
+ public ushort MaximumSpeed { get; set; }
+ public ushort MaximumWriteSpeed { get; set; }
+ public bool PlaysAudio { get; set; }
+ public bool PreventJumperStatus { get; set; }
+ public bool RCK { get; set; }
+ public bool ReadsBarcode { get; set; }
+ public bool ReadsBothSides { get; set; }
+ public bool ReadsCDR { get; set; }
+ public bool ReadsCDRW { get; set; }
+ public bool ReadsDeinterlavedSubchannel { get; set; }
+ public bool ReadsDVDR { get; set; }
+ public bool ReadsDVDRAM { get; set; }
+ public bool ReadsDVDROM { get; set; }
+ public bool ReadsISRC { get; set; }
+ public bool ReadsMode2Form2 { get; set; }
+ public bool ReadsMode2Form1 { get; set; }
+ public bool ReadsPacketCDR { get; set; }
+ public bool ReadsSubchannel { get; set; }
+ public bool ReadsUPC { get; set; }
+ public bool ReturnsC2Pointers { get; set; }
+ public byte RotationControlSelected { get; set; }
+ public bool SeparateChannelMute { get; set; }
+ public bool SeparateChannelVolume { get; set; }
+ public bool SSS { get; set; }
+ public bool SupportsMultiSession { get; set; }
+ public ushort SupportedVolumeLevels { get; set; }
+ public bool TestWrite { get; set; }
+ public bool WritesCDR { get; set; }
+ public bool WritesCDRW { get; set; }
+ public bool WritesDVDR { get; set; }
+ public bool WritesDVDRAM { get; set; }
+ public ModePage_2A_WriteDescriptor[] WriteSpeedPerformanceDescriptors { get; set; }
[XmlIgnore]
public bool MaximumSpeedSpecified { get; set; }
diff --git a/Metadata/DeviceReportV2.cs b/Metadata/DeviceReportV2.cs
index 8051563..b047bf1 100644
--- a/Metadata/DeviceReportV2.cs
+++ b/Metadata/DeviceReportV2.cs
@@ -43,9 +43,9 @@ using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Text;
using DiscImageChef.CommonTypes.Enums;
-using DiscImageChef.Decoders.ATA;
-using DiscImageChef.Decoders.SCSI;
-using DiscImageChef.Decoders.SCSI.MMC;
+using DiscImageChef.CommonTypes.Structs.Devices.ATA;
+using DiscImageChef.CommonTypes.Structs.Devices.SCSI;
+using DiscImageChef.CommonTypes.Structs.Devices.SCSI.Modes;
using Newtonsoft.Json;
// ReSharper disable VirtualMemberNeverOverridden.Global
@@ -474,10 +474,10 @@ namespace DiscImageChef.CommonTypes.Metadata
if(ata.WRVSectorCountMode2Specified)
identifyDevice.WRVSectorCountMode2 = ata.WRVSectorCountMode2;
- Identify = Decoders.ATA.Identify.Encode(identifyDevice);
+ Identify = Structs.Devices.ATA.Identify.Encode(identifyDevice);
}
- public Identify.IdentifyDevice? IdentifyDevice => Decoders.ATA.Identify.Decode(Identify);
+ public Identify.IdentifyDevice? IdentifyDevice => Structs.Devices.ATA.Identify.Decode(Identify);
[JsonIgnore]
public int Id { get; set; }
@@ -550,7 +550,7 @@ namespace DiscImageChef.CommonTypes.Metadata
if(InquiryData != null)
return;
- var inq = new Inquiry.SCSIInquiry();
+ var inq = new Inquiry();
if(scsi.Inquiry.ANSIVersionSpecified)
inq.ANSIVersion = scsi.Inquiry.ANSIVersion;
@@ -620,10 +620,10 @@ namespace DiscImageChef.CommonTypes.Metadata
inq.WBus16 = scsi.Inquiry.WideBus16;
inq.WBus32 = scsi.Inquiry.WideBus32;
- InquiryData = Decoders.SCSI.Inquiry.Encode(inq);
+ InquiryData = Structs.Devices.SCSI.Inquiry.Encode(inq);
}
- public Inquiry.SCSIInquiry? Inquiry => Decoders.SCSI.Inquiry.Decode(InquiryData);
+ public Inquiry? Inquiry => Structs.Devices.SCSI.Inquiry.Decode(InquiryData);
[JsonIgnore]
public int Id { get; set; }
@@ -766,7 +766,7 @@ namespace DiscImageChef.CommonTypes.Metadata
public Mmc(mmcType mmc)
{
if(mmc.ModeSense2A != null)
- ModeSense2AData = Modes.EncodeModePage_2A(new Modes.ModePage_2A
+ ModeSense2AData = ModePage_2A.Encode(new ModePage_2A
{
AccurateCDDA = mmc.ModeSense2A.AccurateCDDA, BCK = mmc.ModeSense2A.BCK,
BufferSize = mmc.ModeSense2A.BufferSize,
@@ -833,7 +833,7 @@ namespace DiscImageChef.CommonTypes.Metadata
[JsonIgnore]
public int Id { get; set; }
- public virtual Modes.ModePage_2A ModeSense2A => Modes.DecodeModePage_2A(ModeSense2AData);
+ public virtual ModePage_2A ModeSense2A => ModePage_2A.Decode(ModeSense2AData);
public virtual MmcFeatures Features { get; set; }
public virtual List TestedMedia { get; set; }
public byte[] ModeSense2AData { get; set; }
diff --git a/Structs/Devices/ATA/Identify.cs b/Structs/Devices/ATA/Identify.cs
new file mode 100644
index 0000000..11cdf48
--- /dev/null
+++ b/Structs/Devices/ATA/Identify.cs
@@ -0,0 +1,1036 @@
+using System;
+using System.Collections.Generic;
+using System.Diagnostics.CodeAnalysis;
+using System.Runtime.InteropServices;
+using System.Text;
+using DiscImageChef.Console;
+using Marshal = DiscImageChef.Helpers.Marshal;
+
+namespace DiscImageChef.CommonTypes.Structs.Devices.ATA
+{
+ ///
+ /// Information from following standards: T10-791D rev. 4c (ATA) T10-948D rev. 4c (ATA-2) T13-1153D rev. 18
+ /// (ATA/ATAPI-4) T13-1321D rev. 3 (ATA/ATAPI-5) T13-1410D rev. 3b (ATA/ATAPI-6) T13-1532D rev. 4b (ATA/ATAPI-7)
+ /// T13-1699D rev. 3f (ATA8-ACS) T13-1699D rev. 4a (ATA8-ACS) T13-2015D rev. 2 (ACS-2) T13-2161D rev. 5 (ACS-3) CF+
+ /// & CF Specification rev. 1.4 (CFA)
+ ///
+ [SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"),
+ SuppressMessage("ReSharper", "MemberCanBePrivate.Global")]
+ public static class Identify
+ {
+ /// Capabilities flag bits.
+ [Flags]
+ public enum CapabilitiesBit : ushort
+ {
+ /// ATAPI: Interleaved DMA supported
+ InterleavedDMA = 0x8000,
+ /// ATAPI: Command queueing supported
+ CommandQueue = 0x4000,
+ /// Standby timer values are standard
+ StandardStanbyTimer = 0x2000,
+ /// ATAPI: Overlap operation supported
+ OverlapOperation = 0x2000,
+ /// ATAPI: ATA software reset required Obsoleted in ATA/ATAPI-4
+ RequiresATASoftReset = 0x1000,
+ /// IORDY is supported
+ IORDY = 0x0800,
+ /// IORDY can be disabled
+ CanDisableIORDY = 0x0400,
+ /// LBA is supported
+ LBASupport = 0x0200,
+ /// DMA is supported
+ DMASupport = 0x0100,
+ /// Vendor unique Obsoleted in ATA/ATAPI-4
+ VendorBit7 = 0x0080,
+ /// Vendor unique Obsoleted in ATA/ATAPI-4
+ VendorBit6 = 0x0040,
+ /// Vendor unique Obsoleted in ATA/ATAPI-4
+ VendorBit5 = 0x0020,
+ /// Vendor unique Obsoleted in ATA/ATAPI-4
+ VendorBit4 = 0x0010,
+ /// Vendor unique Obsoleted in ATA/ATAPI-4
+ VendorBit3 = 0x0008,
+ /// Vendor unique Obsoleted in ATA/ATAPI-4
+ VendorBit2 = 0x0004,
+ /// Long Physical Alignment setting bit 1
+ PhysicalAlignment1 = 0x0002,
+ /// Long Physical Alignment setting bit 0
+ PhysicalAlignment0 = 0x0001
+ }
+
+ /// More capabilities flag bits.
+ [Flags]
+ public enum CapabilitiesBit2 : ushort
+ {
+ /// MUST NOT be set
+ MustBeClear = 0x8000,
+ /// MUST be set
+ MustBeSet = 0x4000, Reserved13 = 0x2000, Reserved12 = 0x1000, Reserved11 = 0x0800,
+ Reserved10 = 0x0400, Reserved09 = 0x0200, Reserved08 = 0x0100,
+ Reserved07 = 0x0080, Reserved06 = 0x0040, Reserved05 = 0x0020,
+ Reserved04 = 0x0010, Reserved03 = 0x0008, Reserved02 = 0x0004,
+ Reserved01 = 0x0002,
+ /// Indicates a device specific minimum standby timer value
+ SpecificStandbyTimer = 0x0001
+ }
+
+ [Flags]
+ public enum CapabilitiesBit3 : byte
+ {
+ /// BLOCK ERASE EXT supported
+ BlockErase = 0x0080,
+ /// OVERWRITE EXT supported
+ Overwrite = 0x0040,
+ /// CRYPTO SCRAMBLE EXT supported
+ CryptoScramble = 0x0020,
+ /// Sanitize feature set is supported
+ Sanitize = 0x0010,
+ /// If unset, sanitize commands are specified by ACS-2
+ SanitizeCommands = 0x0008,
+ /// SANITIZE ANTIFREEZE LOCK EXT is supported
+ SanitizeAntifreeze = 0x0004, Reserved01 = 0x0002,
+ /// Multiple logical sector setting is valid
+ MultipleValid = 0x0001
+ }
+
+ /// More capabilities flag bits.
+ [Flags]
+ public enum CommandSetBit : ushort
+ {
+ /// Already obsolete in ATA/ATAPI-4, reserved in ATA3
+ Obsolete15 = 0x8000,
+ /// NOP is supported
+ Nop = 0x4000,
+ /// READ BUFFER is supported
+ ReadBuffer = 0x2000,
+ /// WRITE BUFFER is supported
+ WriteBuffer = 0x1000,
+ /// Already obsolete in ATA/ATAPI-4, reserved in ATA3
+ Obsolete11 = 0x0800,
+ /// Host Protected Area is supported
+ HPA = 0x0400,
+ /// DEVICE RESET is supported
+ DeviceReset = 0x0200,
+ /// SERVICE interrupt is supported
+ Service = 0x0100,
+ /// Release is supported
+ Release = 0x0080,
+ /// Look-ahead is supported
+ LookAhead = 0x0040,
+ /// Write cache is supported
+ WriteCache = 0x0020,
+ /// PACKET command set is supported
+ Packet = 0x0010,
+ /// Power Management feature set is supported
+ PowerManagement = 0x0008,
+ /// Removable Media feature set is supported
+ RemovableMedia = 0x0004,
+ /// Security Mode feature set is supported
+ SecurityMode = 0x0002,
+ /// SMART feature set is supported
+ SMART = 0x0001
+ }
+
+ /// More capabilities flag bits.
+ [Flags]
+ public enum CommandSetBit2 : ushort
+ {
+ /// MUST NOT be set
+ MustBeClear = 0x8000,
+ /// MUST BE SET
+ MustBeSet = 0x4000,
+ /// FLUSH CACHE EXT supported
+ FlushCacheExt = 0x2000,
+ /// FLUSH CACHE supported
+ FlushCache = 0x1000,
+ /// Device Configuration Overlay feature set supported
+ DCO = 0x0800,
+ /// 48-bit LBA supported
+ LBA48 = 0x0400,
+ /// Automatic Acoustic Management supported
+ AAM = 0x0200,
+ /// SET MAX security extension supported
+ SetMax = 0x0100,
+ /// Address Offset Reserved Area Boot NCITS TR27:2001
+ AddressOffsetReservedAreaBoot = 0x0080,
+ /// SET FEATURES required to spin-up
+ SetFeaturesRequired = 0x0040,
+ /// Power-Up in standby feature set supported
+ PowerUpInStandby = 0x0020,
+ /// Removable Media Status Notification feature set is supported
+ RemovableNotification = 0x0010,
+ /// Advanced Power Management feature set is supported
+ APM = 0x0008,
+ /// Compact Flash feature set is supported
+ CompactFlash = 0x0004,
+ /// READ DMA QUEUED and WRITE DMA QUEUED are supported
+ RWQueuedDMA = 0x0002,
+ /// DOWNLOAD MICROCODE is supported
+ DownloadMicrocode = 0x0001
+ }
+
+ /// More capabilities flag bits.
+ [Flags]
+ public enum CommandSetBit3 : ushort
+ {
+ /// MUST NOT be set
+ MustBeClear = 0x8000,
+ /// MUST BE SET
+ MustBeSet = 0x4000,
+ /// IDLE IMMEDIATE with UNLOAD FEATURE is supported
+ IdleImmediate = 0x2000,
+ /// Reserved for INCITS TR-37/2004
+ Reserved12 = 0x1000,
+ /// Reserved for INCITS TR-37/2004
+ Reserved11 = 0x0800,
+ /// URG bit is supported in WRITE STREAM DMA EXT and WRITE STREAM EXT
+ WriteURG = 0x0400,
+ /// URG bit is supported in READ STREAM DMA EXT and READ STREAM EXT
+ ReadURG = 0x0200,
+ /// 64-bit World Wide Name is supported
+ WWN = 0x0100,
+ /// WRITE DMA QUEUED FUA EXT is supported
+ FUAWriteQ = 0x0080,
+ /// WRITE DMA FUA EXT and WRITE MULTIPLE FUA EXT are supported
+ FUAWrite = 0x0040,
+ /// General Purpose Logging feature supported
+ GPL = 0x0020,
+ /// Sstreaming feature set is supported
+ Streaming = 0x0010,
+ /// Media Card Pass Through command set supported
+ MCPT = 0x0008,
+ /// Media serial number supported
+ MediaSerial = 0x0004,
+ /// SMART self-test supported
+ SMARTSelfTest = 0x0002,
+ /// SMART error logging supported
+ SMARTLog = 0x0001
+ }
+
+ /// More capabilities flag bits.
+ [Flags]
+ public enum CommandSetBit4 : ushort
+ {
+ /// MUST NOT be set
+ MustBeClear = 0x8000,
+ /// MUST be set
+ MustBeSet = 0x4000, Reserved13 = 0x2000, Reserved12 = 0x1000, Reserved11 = 0x0800,
+ Reserved10 = 0x0400,
+ /// DSN feature set is supported
+ DSN = 0x0200,
+ /// Accessible Max Address Configuration is supported
+ AMAC = 0x0100,
+ /// Extended Power Conditions is supported
+ ExtPowerCond = 0x0080,
+ /// Extended Status Reporting is supported
+ ExtStatusReport = 0x0040,
+ /// Free-fall Control feature set is supported
+ FreeFallControl = 0x0020,
+ /// Supports segmented feature in DOWNLOAD MICROCODE
+ SegmentedDownloadMicrocode = 0x0010,
+ /// READ/WRITE DMA EXT GPL are supported
+ RWDMAExtGpl = 0x0008,
+ /// WRITE UNCORRECTABLE is supported
+ WriteUnc = 0x0004,
+ /// Write/Read/Verify is supported
+ WRV = 0x0002,
+ /// Reserved for DT1825
+ DT1825 = 0x0001
+ }
+
+ [Flags]
+ public enum CommandSetBit5 : ushort
+ {
+ /// Supports CFast Specification
+ CFast = 0x8000,
+ /// Deterministic read after TRIM is supported
+ DeterministicTrim = 0x4000,
+ /// Long physical sector alignment error reporting control is supported
+ LongPhysSectorAligError = 0x2000,
+ /// DEVICE CONFIGURATION IDENTIFY DMA and DEVICE CONFIGURATION SET DMA are supported
+ DeviceConfDMA = 0x1000,
+ /// READ BUFFER DMA is supported
+ ReadBufferDMA = 0x0800,
+ /// WRITE BUFFER DMA is supported
+ WriteBufferDMA = 0x0400,
+ /// SET PASSWORD DMA and SET UNLOCK DMA are supported
+ SetMaxDMA = 0x0200,
+ /// DOWNLOAD MICROCODE DMA is supported
+ DownloadMicroCodeDMA = 0x0100,
+ /// Reserved for IEEE-1667
+ IEEE1667 = 0x0080,
+ /// Optional ATA 28-bit commands are supported
+ Ata28 = 0x0040,
+ /// Read zero after TRIM is supported
+ ReadZeroTrim = 0x0020,
+ /// Device encrypts all user data
+ Encrypted = 0x0010,
+ /// Extended number of user addressable sectors is supported
+ ExtSectors = 0x0008,
+ /// All write cache is non-volatile
+ AllCacheNV = 0x0004,
+ /// Zoned capabilities bit 1
+ ZonedBit1 = 0x0002,
+ /// Zoned capabilities bit 0
+ ZonedBit0 = 0x0001
+ }
+
+ [Flags]
+ public enum DataSetMgmtBit : ushort
+ {
+ Reserved15 = 0x8000, Reserved14 = 0x4000, Reserved13 = 0x2000,
+ Reserved12 = 0x1000, Reserved11 = 0x0800, Reserved10 = 0x0400,
+ Reserved09 = 0x0200, Reserved08 = 0x0100, Reserved07 = 0x0080,
+ Reserved06 = 0x0040, Reserved05 = 0x0020, Reserved04 = 0x0010,
+ Reserved03 = 0x0008, Reserved02 = 0x0004, Reserved01 = 0x0002,
+ /// TRIM is suported
+ Trim = 0x0001
+ }
+
+ public enum DeviceFormFactorEnum : ushort
+ {
+ /// Size not reported
+ NotReported = 0,
+ /// 5.25"
+ FiveAndQuarter = 1,
+ /// 3.5"
+ ThreeAndHalf = 2,
+ /// 2.5"
+ TwoAndHalf = 3,
+ /// 1.8"
+ OnePointEight = 4,
+ /// Less than 1.8"
+ LessThanOnePointEight = 5
+ }
+
+ /// Extended identify flag bits.
+ [Flags]
+ public enum ExtendedIdentifyBit : byte
+ {
+ /// Reserved
+ Reserved07 = 0x80,
+ /// Reserved
+ Reserved06 = 0x40,
+ /// Reserved
+ Reserved05 = 0x20,
+ /// Reserved
+ Reserved04 = 0x10,
+ /// Reserved
+ Reserved03 = 0x08,
+ /// Identify word 88 is valid
+ Word88Valid = 0x04,
+ /// Identify words 64 to 70 are valid
+ Words64to70Valid = 0x02,
+ /// Identify words 54 to 58 are valid
+ Words54to58Valid = 0x01
+ }
+
+ /// General configuration flag bits.
+ [Flags]
+ public enum GeneralConfigurationBit : ushort
+ {
+ /// Set on ATAPI
+ NonMagnetic = 0x8000,
+ /// Format speed tolerance gap is required Obsoleted in ATA-2
+ FormatGapReq = 0x4000,
+ /// Track offset option is available Obsoleted in ATA-2
+ TrackOffset = 0x2000,
+ /// Data strobe offset option is available Obsoleted in ATA-2
+ DataStrobeOffset = 0x1000,
+ /// Rotational speed tolerance is higher than 0,5% Obsoleted in ATA-2
+ RotationalSpeedTolerance = 0x0800,
+ /// Disk transfer rate is > 10 Mb/s Obsoleted in ATA-2
+ UltraFastIDE = 0x0400,
+ /// Disk transfer rate is > 5 Mb/s but <= 10 Mb/s Obsoleted in ATA-2
+ FastIDE = 0x0200,
+ /// Disk transfer rate is <= 5 Mb/s Obsoleted in ATA-2
+ SlowIDE = 0x0100,
+ /// Drive uses removable media
+ Removable = 0x0080,
+ /// Drive is fixed Obsoleted in ATA/ATAPI-6
+ Fixed = 0x0040,
+ /// Spindle motor control is implemented Obsoleted in ATA-2
+ SpindleControl = 0x0020,
+ /// Head switch time is bigger than 15 µsec. Obsoleted in ATA-2
+ HighHeadSwitch = 0x0010,
+ /// Drive is not MFM encoded Obsoleted in ATA-2
+ NotMFM = 0x0008,
+ /// Drive is soft sectored Obsoleted in ATA-2
+ SoftSector = 0x0004,
+ /// Response incomplete Since ATA/ATAPI-5
+ IncompleteResponse = 0x0004,
+ /// Drive is hard sectored Obsoleted in ATA-2
+ HardSector = 0x0002,
+ /// Reserved
+ Reserved = 0x0001
+ }
+
+ /// Word 80 Major version
+ [Flags]
+ public enum MajorVersionBit : ushort
+ {
+ Reserved15 = 0x8000, Reserved14 = 0x4000, Reserved13 = 0x2000,
+ Reserved12 = 0x1000,
+ /// ACS-4
+ ACS4 = 0x0800,
+ /// ACS-3
+ ACS3 = 0x0400,
+ /// ACS-2
+ ACS2 = 0x0200,
+ /// ATA8-ACS
+ Ata8ACS = 0x0100,
+ /// ATA/ATAPI-7
+ AtaAtapi7 = 0x0080,
+ /// ATA/ATAPI-6
+ AtaAtapi6 = 0x0040,
+ /// ATA/ATAPI-5
+ AtaAtapi5 = 0x0020,
+ /// ATA/ATAPI-4
+ AtaAtapi4 = 0x0010,
+ /// ATA-3
+ Ata3 = 0x0008,
+ /// ATA-2
+ Ata2 = 0x0004,
+ /// ATA-1
+ Ata1 = 0x0002, Reserved00 = 0x0001
+ }
+
+ [Flags]
+ public enum SATACapabilitiesBit : ushort
+ {
+ /// Supports READ LOG DMA EXT
+ ReadLogDMAExt = 0x8000,
+ /// Supports device automatic partial to slumber transitions
+ DevSlumbTrans = 0x4000,
+ /// Supports host automatic partial to slumber transitions
+ HostSlumbTrans = 0x2000,
+ /// Supports NCQ priroty
+ NCQPriority = 0x1000,
+ /// Supports unload while NCQ commands are outstanding
+ UnloadNCQ = 0x0800,
+ /// Supports PHY Event Counters
+ PHYEventCounter = 0x0400,
+ /// Supports receipt of host initiated power management requests
+ PowerReceipt = 0x0200,
+ /// Supports NCQ
+ NCQ = 0x0100, Reserved07 = 0x0080, Reserved06 = 0x0040, Reserved05 = 0x0020,
+ Reserved04 = 0x0010,
+ /// Supports SATA Gen. 3 Signaling Speed (6.0Gb/s)
+ Gen3Speed = 0x0008,
+ /// Supports SATA Gen. 2 Signaling Speed (3.0Gb/s)
+ Gen2Speed = 0x0004,
+ /// Supports SATA Gen. 1 Signaling Speed (1.5Gb/s)
+ Gen1Speed = 0x0002,
+ /// MUST NOT be set
+ Clear = 0x0001
+ }
+
+ [Flags]
+ public enum SATACapabilitiesBit2 : ushort
+ {
+ Reserved15 = 0x8000, Reserved14 = 0x4000, Reserved13 = 0x2000,
+ Reserved12 = 0x1000, Reserved11 = 0x0800, Reserved10 = 0x0400,
+ Reserved09 = 0x0200, Reserved08 = 0x0100, Reserved07 = 0x0080,
+ /// Supports RECEIVE FPDMA QUEUED and SEND FPDMA QUEUED
+ FPDMAQ = 0x0040,
+ /// Supports NCQ Queue Management
+ NCQMgmt = 0x0020,
+ /// ATAPI: Supports host environment detect
+ HostEnvDetect = 0x0020,
+ /// Supports NCQ streaming
+ NCQStream = 0x0010,
+ /// ATAPI: Supports device attention on slimline connected devices
+ DevAttSlimline = 0x0010,
+ /// Coded value indicating current negotiated Serial ATA signal speed
+ CurrentSpeedBit2 = 0x0008,
+ /// Coded value indicating current negotiated Serial ATA signal speed
+ CurrentSpeedBit1 = 0x0004,
+ /// Coded value indicating current negotiated Serial ATA signal speed
+ CurrentSpeedBit0 = 0x0002,
+ /// MUST NOT be set
+ Clear = 0x0001
+ }
+
+ [Flags]
+ public enum SATAFeaturesBit : ushort
+ {
+ Reserved15 = 0x8000, Reserved14 = 0x4000, Reserved13 = 0x2000,
+ Reserved12 = 0x1000, Reserved11 = 0x0800, Reserved10 = 0x0400,
+ Reserved09 = 0x0200, Reserved08 = 0x0100,
+ /// Supports NCQ autosense
+ NCQAutoSense = 0x0080,
+ /// Automatic Partial to Slumber transitions are enabled
+ EnabledSlumber = 0x0080,
+ /// Supports Software Settings Preservation
+ SettingsPreserve = 0x0040,
+ /// Supports hardware feature control
+ HardwareFeatureControl = 0x0020,
+ /// ATAPI: Asynchronous notification
+ AsyncNotification = 0x0020,
+ /// Supports in-order data delivery
+ InOrderData = 0x0010,
+ /// Supports initiating power management
+ InitPowerMgmt = 0x0008,
+ /// Supports DMA Setup auto-activation
+ DMASetup = 0x0004,
+ /// Supports non-zero buffer offsets
+ NonZeroBufferOffset = 0x0002,
+ /// MUST NOT be set
+ Clear = 0x0001
+ }
+
+ [Flags]
+ public enum SCTCommandTransportBit : ushort
+ {
+ Vendor15 = 0x8000, Vendor14 = 0x4000, Vendor13 = 0x2000,
+ Vendor12 = 0x1000, Reserved11 = 0x0800, Reserved10 = 0x0400,
+ Reserved09 = 0x0200, Reserved08 = 0x0100, Reserved07 = 0x0080,
+ Reserved06 = 0x0040,
+ /// SCT Command Transport Data Tables supported
+ DataTables = 0x0020,
+ /// SCT Command Transport Features Control supported
+ FeaturesControl = 0x0010,
+ /// SCT Command Transport Error Recovery Control supported
+ ErrorRecoveryControl = 0x0008,
+ /// SCT Command Transport Write Same supported
+ WriteSame = 0x0004,
+ /// SCT Command Transport Long Sector Address supported
+ LongSectorAccess = 0x0002,
+ /// SCT Command Transport supported
+ Supported = 0x0001
+ }
+
+ /// More capabilities flag bits.
+ [Flags]
+ public enum SecurityStatusBit : ushort
+ {
+ Reserved15 = 0x8000, Reserved14 = 0x4000, Reserved13 = 0x2000,
+ Reserved12 = 0x1000, Reserved11 = 0x0800, Reserved10 = 0x0400,
+ Reserved09 = 0x0200,
+ /// Maximum security level
+ Maximum = 0x0100, Reserved07 = 0x0080, Reserved06 = 0x0040,
+ /// Supports enhanced security erase
+ Enhanced = 0x0020,
+ /// Security count expired
+ Expired = 0x0010,
+ /// Security frozen
+ Frozen = 0x0008,
+ /// Security locked
+ Locked = 0x0004,
+ /// Security enabled
+ Enabled = 0x0002,
+ /// Security supported
+ Supported = 0x0001
+ }
+
+ public enum SpecificConfigurationEnum : ushort
+ {
+ /// Device requires SET FEATURES to spin up and IDENTIFY DEVICE response is incomplete
+ RequiresSetIncompleteResponse = 0x37C8,
+ /// Device requires SET FEATURES to spin up and IDENTIFY DEVICE response is complete
+ RequiresSetCompleteResponse = 0x738C,
+ /// Device does not requires SET FEATURES to spin up and IDENTIFY DEVICE response is incomplete
+ NotRequiresSetIncompleteResponse = 0x8C73,
+ /// Device does not requires SET FEATURES to spin up and IDENTIFY DEVICE response is complete
+ NotRequiresSetCompleteResponse = 0xC837
+ }
+
+ [Flags]
+ public enum TransferMode : byte
+ {
+ Mode7 = 0x80, Mode6 = 0x40, Mode5 = 0x20,
+ Mode4 = 0x10, Mode3 = 0x08, Mode2 = 0x04,
+ Mode1 = 0x02, Mode0 = 0x01
+ }
+
+ [Flags]
+ public enum TrustedComputingBit : ushort
+ {
+ /// MUST NOT be set
+ Clear = 0x8000,
+ /// MUST be set
+ Set = 0x4000, Reserved13 = 0x2000, Reserved12 = 0x1000, Reserved11 = 0x0800,
+ Reserved10 = 0x0400, Reserved09 = 0x0200, Reserved08 = 0x0100,
+ Reserved07 = 0x0080, Reserved06 = 0x0040, Reserved05 = 0x0020,
+ Reserved04 = 0x0010, Reserved03 = 0x0008, Reserved02 = 0x0004,
+ Reserved01 = 0x0002,
+ /// Trusted Computing feature set is supported
+ TrustedComputing = 0x0001
+ }
+
+ [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 2)]
+ public struct IdentifyDevice
+ {
+ ///
+ /// Word 0 General device configuration On ATAPI devices: Bits 12 to 8 indicate device type as SCSI defined Bits 6
+ /// to 5: 0 = Device shall set DRQ within 3 ms of receiving PACKET 1 = Device shall assert INTRQ when DRQ is set to one
+ /// 2 = Device shall set DRQ within 50 µs of receiving PACKET Bits 1 to 0: 0 = 12 byte command packet 1 = 16 byte
+ /// command packet CompactFlash is 0x848A (non magnetic, removable, not MFM, hardsector, and UltraFAST)
+ ///
+ public GeneralConfigurationBit GeneralConfiguration;
+ /// Word 1 Cylinders in default translation mode Obsoleted in ATA/ATAPI-6
+ public ushort Cylinders;
+ /// Word 2 Specific configuration
+ public SpecificConfigurationEnum SpecificConfiguration;
+ /// Word 3 Heads in default translation mode Obsoleted in ATA/ATAPI-6
+ public ushort Heads;
+ /// Word 4 Unformatted bytes per track in default translation mode Obsoleted in ATA-2
+ public ushort UnformattedBPT;
+ /// Word 5 Unformatted bytes per sector in default translation mode Obsoleted in ATA-2
+ public ushort UnformattedBPS;
+ /// Word 6 Sectors per track in default translation mode Obsoleted in ATA/ATAPI-6
+ public ushort SectorsPerTrack;
+ /// Words 7 to 8 CFA: Number of sectors per card
+ public uint SectorsPerCard;
+ /// Word 9 Vendor unique Obsoleted in ATA/ATAPI-4
+ public ushort VendorWord9;
+ /// Words 10 to 19 Device serial number, right justified, padded with spaces
+ [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 20)]
+ public string SerialNumber;
+ ///
+ /// Word 20 Manufacturer defined Obsoleted in ATA-2 0x0001 = single ported single sector buffer 0x0002 = dual
+ /// ported multi sector buffer 0x0003 = dual ported multi sector buffer with reading
+ ///
+ public ushort BufferType;
+ /// Word 21 Size of buffer in 512 byte increments Obsoleted in ATA-2
+ public ushort BufferSize;
+ /// Word 22 Bytes of ECC available in READ/WRITE LONG commands Obsoleted in ATA/ATAPI-4
+ public ushort EccBytes;
+ /// Words 23 to 26 Firmware revision, left justified, padded with spaces
+ [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 8)]
+ public string FirmwareRevision;
+ /// Words 27 to 46 Model number, left justified, padded with spaces
+ [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 40)]
+ public string Model;
+ ///
+ /// Word 47 bits 7 to 0 Maximum number of sectors that can be transferred per interrupt on read and write multiple
+ /// commands
+ ///
+ public byte MultipleMaxSectors;
+ /// Word 47 bits 15 to 8 Vendor unique ATA/ATAPI-4 says it must be 0x80
+ public byte VendorWord47;
+ ///
+ /// Word 48 ATA-1: Set to 1 if it can perform doubleword I/O ATA-2 to ATA/ATAPI-7: Reserved ATA8-ACS: Trusted
+ /// Computing feature set
+ ///
+ public TrustedComputingBit TrustedComputing;
+ /// Word 49 Capabilities
+ public CapabilitiesBit Capabilities;
+ /// Word 50 Capabilities
+ public CapabilitiesBit2 Capabilities2;
+ /// Word 51 bits 7 to 0 Vendor unique Obsoleted in ATA/ATAPI-4
+ public byte VendorWord51;
+ /// Word 51 bits 15 to 8 Transfer timing mode in PIO Obsoleted in ATA/ATAPI-4
+ public byte PIOTransferTimingMode;
+ /// Word 52 bits 7 to 0 Vendor unique Obsoleted in ATA/ATAPI-4
+ public byte VendorWord52;
+ /// Word 52 bits 15 to 8 Transfer timing mode in DMA Obsoleted in ATA/ATAPI-4
+ public byte DMATransferTimingMode;
+ /// Word 53 bits 7 to 0 Reports if words 54 to 58 are valid
+ public ExtendedIdentifyBit ExtendedIdentify;
+ /// Word 53 bits 15 to 8 Free-fall Control Sensitivity
+ public byte FreeFallSensitivity;
+ /// Word 54 Cylinders in current translation mode Obsoleted in ATA/ATAPI-6
+ public ushort CurrentCylinders;
+ /// Word 55 Heads in current translation mode Obsoleted in ATA/ATAPI-6
+ public ushort CurrentHeads;
+ /// Word 56 Sectors per track in current translation mode Obsoleted in ATA/ATAPI-6
+ public ushort CurrentSectorsPerTrack;
+ /// Words 57 to 58 Total sectors currently user-addressable Obsoleted in ATA/ATAPI-6
+ public uint CurrentSectors;
+ /// Word 59 bits 7 to 0 Number of sectors currently set to transfer on a READ/WRITE MULTIPLE command
+ public byte MultipleSectorNumber;
+ /// Word 59 bits 15 to 8 Indicates if is valid
+ public CapabilitiesBit3 Capabilities3;
+ /// Words 60 to 61 If drive supports LBA, how many sectors are addressable using LBA
+ public uint LBASectors;
+ ///
+ /// Word 62 bits 7 to 0 Single word DMA modes available Obsoleted in ATA/ATAPI-4 In ATAPI it's not obsolete,
+ /// indicates UDMA mode (UDMA7 is instead MDMA0)
+ ///
+ public TransferMode DMASupported;
+ ///
+ /// Word 62 bits 15 to 8 Single word DMA mode currently active Obsoleted in ATA/ATAPI-4 In ATAPI it's not
+ /// obsolete, bits 0 and 1 indicate MDMA mode+1, bit 10 indicates DMA is supported and bit 15 indicates DMADIR bit in
+ /// PACKET is required for DMA transfers
+ ///
+ public TransferMode DMAActive;
+ /// Word 63 bits 7 to 0 Multiword DMA modes available
+ public TransferMode MDMASupported;
+ /// Word 63 bits 15 to 8 Multiword DMA mode currently active
+ public TransferMode MDMAActive;
+
+ /// Word 64 bits 7 to 0 Supported Advanced PIO transfer modes
+ public TransferMode APIOSupported;
+ /// Word 64 bits 15 to 8 Reserved
+ public byte ReservedWord64;
+ /// Word 65 Minimum MDMA transfer cycle time per word in nanoseconds
+ public ushort MinMDMACycleTime;
+ /// Word 66 Recommended MDMA transfer cycle time per word in nanoseconds
+ public ushort RecMDMACycleTime;
+ /// Word 67 Minimum PIO transfer cycle time without flow control in nanoseconds
+ public ushort MinPIOCycleTimeNoFlow;
+ /// Word 68 Minimum PIO transfer cycle time with IORDY flow control in nanoseconds
+ public ushort MinPIOCycleTimeFlow;
+
+ /// Word 69 Additional supported
+ public CommandSetBit5 CommandSet5;
+ /// Word 70 Reserved
+ public ushort ReservedWord70;
+ /// Word 71 ATAPI: Typical time in ns from receipt of PACKET to release bus
+ public ushort PacketBusRelease;
+ /// Word 72 ATAPI: Typical time in ns from receipt of SERVICE to clear BSY
+ public ushort ServiceBusyClear;
+ /// Word 73 Reserved
+ public ushort ReservedWord73;
+ /// Word 74 Reserved
+ public ushort ReservedWord74;
+
+ /// Word 75 Maximum Queue depth
+ public ushort MaxQueueDepth;
+
+ /// Word 76 Serial ATA Capabilities
+ public SATACapabilitiesBit SATACapabilities;
+ /// Word 77 Serial ATA Additional Capabilities
+ public SATACapabilitiesBit2 SATACapabilities2;
+
+ /// Word 78 Supported Serial ATA features
+ public SATAFeaturesBit SATAFeatures;
+ /// Word 79 Enabled Serial ATA features
+ public SATAFeaturesBit EnabledSATAFeatures;
+
+ /// Word 80 Major version of ATA/ATAPI standard supported
+ public MajorVersionBit MajorVersion;
+ /// Word 81 Minimum version of ATA/ATAPI standard supported
+ public ushort MinorVersion;
+
+ /// Word 82 Supported command/feature sets
+ public CommandSetBit CommandSet;
+ /// Word 83 Supported command/feature sets
+ public CommandSetBit2 CommandSet2;
+ /// Word 84 Supported command/feature sets
+ public CommandSetBit3 CommandSet3;
+
+ /// Word 85 Enabled command/feature sets
+ public CommandSetBit EnabledCommandSet;
+ /// Word 86 Enabled command/feature sets
+ public CommandSetBit2 EnabledCommandSet2;
+ /// Word 87 Enabled command/feature sets
+ public CommandSetBit3 EnabledCommandSet3;
+
+ /// Word 88 bits 7 to 0 Supported Ultra DMA transfer modes
+ public TransferMode UDMASupported;
+ /// Word 88 bits 15 to 8 Selected Ultra DMA transfer modes
+ public TransferMode UDMAActive;
+
+ /// Word 89 Time required for security erase completion
+ public ushort SecurityEraseTime;
+ /// Word 90 Time required for enhanced security erase completion
+ public ushort EnhancedSecurityEraseTime;
+ /// Word 91 Current advanced power management value
+ public ushort CurrentAPM;
+
+ /// Word 92 Master password revision code
+ public ushort MasterPasswordRevisionCode;
+ /// Word 93 Hardware reset result
+ public ushort HardwareResetResult;
+
+ /// Word 94 bits 7 to 0 Current AAM value
+ public byte CurrentAAM;
+ /// Word 94 bits 15 to 8 Vendor's recommended AAM value
+ public byte RecommendedAAM;
+
+ /// Word 95 Stream minimum request size
+ public ushort StreamMinReqSize;
+ /// Word 96 Streaming transfer time in DMA
+ public ushort StreamTransferTimeDMA;
+ /// Word 97 Streaming access latency in DMA and PIO
+ public ushort StreamAccessLatency;
+ /// Words 98 to 99 Streaming performance granularity
+ public uint StreamPerformanceGranularity;
+
+ /// Words 100 to 103 48-bit LBA addressable sectors
+ public ulong LBA48Sectors;
+
+ /// Word 104 Streaming transfer time in PIO
+ public ushort StreamTransferTimePIO;
+
+ /// Word 105 Maximum number of 512-byte block per DATA SET MANAGEMENT command
+ public ushort DataSetMgmtSize;
+
+ ///
+ /// Word 106 Bit 15 should be zero Bit 14 should be one Bit 13 set indicates device has multiple logical sectors
+ /// per physical sector Bit 12 set indicates logical sector has more than 256 words (512 bytes) Bits 11 to 4 are
+ /// reserved Bits 3 to 0 indicate power of two of logical sectors per physical sector
+ ///
+ public ushort PhysLogSectorSize;
+
+ /// Word 107 Interseek delay for ISO-7779 acoustic testing, in microseconds
+ public ushort InterseekDelay;
+
+ /// Words 108 to 111 World Wide Name
+ public ulong WWN;
+
+ /// Words 112 to 115 Reserved for WWN extension to 128 bit
+ public ulong WWNExtension;
+
+ /// Word 116 Reserved for technical report
+ public ushort ReservedWord116;
+
+ /// Words 117 to 118 Words per logical sector
+ public uint LogicalSectorWords;
+
+ /// Word 119 Supported command/feature sets
+ public CommandSetBit4 CommandSet4;
+ /// Word 120 Supported command/feature sets
+ public CommandSetBit4 EnabledCommandSet4;
+
+ /// Words 121 to 125 Reserved
+ [MarshalAs(UnmanagedType.ByValArray, SizeConst = 5)]
+ public ushort[] ReservedWords121;
+
+ /// Word 126 ATAPI byte count limit
+ public ushort ATAPIByteCount;
+
+ ///
+ /// Word 127 Removable Media Status Notification feature set support Bits 15 to 2 are reserved Bits 1 to 0 must be
+ /// 0 for not supported or 1 for supported. 2 and 3 are reserved. Obsoleted in ATA8-ACS
+ ///
+ public ushort RemovableStatusSet;
+
+ /// Word 128 Security status
+ public SecurityStatusBit SecurityStatus;
+
+ /// Words 129 to 159
+ [MarshalAs(UnmanagedType.ByValArray, SizeConst = 31)]
+ public ushort[] ReservedWords129;
+
+ ///
+ /// Word 160 CFA power mode Bit 15 must be set Bit 13 indicates mode 1 is required for one or more commands Bit 12
+ /// indicates mode 1 is disabled Bits 11 to 0 indicates maximum current in mA
+ ///
+ public ushort CFAPowerMode;
+
+ /// Words 161 to 167 Reserved for CFA
+ [MarshalAs(UnmanagedType.ByValArray, SizeConst = 7)]
+ public ushort[] ReservedCFA;
+
+ /// Word 168 Bits 15 to 4, reserved Bits 3 to 0, device nominal form factor
+ public DeviceFormFactorEnum DeviceFormFactor;
+ /// Word 169 DATA SET MANAGEMENT support
+ public DataSetMgmtBit DataSetMgmt;
+ /// Words 170 to 173 Additional product identifier
+ [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 8)]
+ public string AdditionalPID;
+
+ /// Word 174 Reserved
+ public ushort ReservedWord174;
+ /// Word 175 Reserved
+ public ushort ReservedWord175;
+
+ /// Words 176 to 195 Current media serial number
+ [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 40)]
+ public string MediaSerial;
+ /// Words 196 to 205 Current media manufacturer
+ [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 20)]
+ public string MediaManufacturer;
+
+ /// Word 206 SCT Command Transport features
+ public SCTCommandTransportBit SCTCommandTransport;
+
+ /// Word 207 Reserved for CE-ATA
+ public ushort ReservedCEATAWord207;
+ /// Word 208 Reserved for CE-ATA
+ public ushort ReservedCEATAWord208;
+
+ ///
+ /// Word 209 Alignment of logical block within a larger physical block Bit 15 shall be cleared to zero Bit 14
+ /// shall be set to one Bits 13 to 0 indicate logical sector offset within the first physical sector
+ ///
+ public ushort LogicalAlignment;
+
+ /// Words 210 to 211 Write/Read/Verify sector count mode 3 only
+ public uint WRVSectorCountMode3;
+ /// Words 212 to 213 Write/Read/Verify sector count mode 2 only
+ public uint WRVSectorCountMode2;
+
+ ///
+ /// Word 214 NV Cache capabilities Bits 15 to 12 feature set version Bits 11 to 18 power mode feature set version
+ /// Bits 7 to 5 reserved Bit 4 feature set enabled Bits 3 to 2 reserved Bit 1 power mode feature set enabled Bit 0
+ /// power mode feature set supported
+ ///
+ public ushort NVCacheCaps;
+ /// Words 215 to 216 NV Cache Size in Logical BLocks
+ public uint NVCacheSize;
+ /// Word 217 Nominal media rotation rate In ACS-1 meant NV Cache read speed in MB/s
+ public ushort NominalRotationRate;
+ /// Word 218 NV Cache write speed in MB/s Reserved since ACS-2
+ public ushort NVCacheWriteSpeed;
+ /// Word 219 bits 7 to 0 Estimated device spin up in seconds
+ public byte NVEstimatedSpinUp;
+ /// Word 219 bits 15 to 8 NV Cache reserved
+ public byte NVReserved;
+
+ /// Word 220 bits 7 to 0 Write/Read/Verify feature set current mode
+ public byte WRVMode;
+ /// Word 220 bits 15 to 8 Reserved
+ public byte WRVReserved;
+
+ /// Word 221 Reserved
+ public ushort ReservedWord221;
+
+ ///
+ /// Word 222 Transport major revision number Bits 15 to 12 indicate transport type. 0 parallel, 1 serial, 0xE
+ /// PCIe. Bits 11 to 0 indicate revision
+ ///
+ public ushort TransportMajorVersion;
+ /// Word 223 Transport minor revision number
+ public ushort TransportMinorVersion;
+
+ /// Words 224 to 229 Reserved for CE-ATA
+ [MarshalAs(UnmanagedType.ByValArray, SizeConst = 6)]
+ public ushort[] ReservedCEATA224;
+
+ /// Words 230 to 233 48-bit LBA if Word 69 bit 3 is set
+ public ulong ExtendedUserSectors;
+
+ /// Word 234 Minimum number of 512 byte units per DOWNLOAD MICROCODE mode 3
+ public ushort MinDownloadMicroMode3;
+ /// Word 235 Maximum number of 512 byte units per DOWNLOAD MICROCODE mode 3
+ public ushort MaxDownloadMicroMode3;
+
+ /// Words 236 to 254
+ [MarshalAs(UnmanagedType.ByValArray, SizeConst = 19)]
+ public ushort[] ReservedWords;
+
+ /// Word 255 bits 7 to 0 Should be 0xA5
+ public byte Signature;
+ /// Word 255 bits 15 to 8 Checksum
+ public byte Checksum;
+ }
+
+ public static IdentifyDevice? Decode(byte[] IdentifyDeviceResponse)
+ {
+ if(IdentifyDeviceResponse == null)
+ return null;
+
+ if(IdentifyDeviceResponse.Length != 512)
+ {
+ DicConsole.DebugWriteLine("ATA/ATAPI IDENTIFY decoder",
+ "IDENTIFY response is different than 512 bytes, not decoding.");
+
+ return null;
+ }
+
+ IdentifyDevice ATAID = Marshal.ByteArrayToStructureLittleEndian(IdentifyDeviceResponse);
+
+ ATAID.WWN = DescrambleWWN(ATAID.WWN);
+ ATAID.WWNExtension = DescrambleWWN(ATAID.WWNExtension);
+
+ ATAID.SerialNumber = DescrambleATAString(IdentifyDeviceResponse, 10 * 2, 20);
+ ATAID.FirmwareRevision = DescrambleATAString(IdentifyDeviceResponse, 23 * 2, 8);
+ ATAID.Model = DescrambleATAString(IdentifyDeviceResponse, 27 * 2, 40);
+ ATAID.AdditionalPID = DescrambleATAString(IdentifyDeviceResponse, 170 * 2, 8);
+ ATAID.MediaSerial = DescrambleATAString(IdentifyDeviceResponse, 176 * 2, 40);
+ ATAID.MediaManufacturer = DescrambleATAString(IdentifyDeviceResponse, 196 * 2, 20);
+
+ return ATAID;
+ }
+
+ public static byte[] Encode(IdentifyDevice? identify)
+ {
+ if(identify is null)
+ return null;
+
+ IdentifyDevice ataId = identify.Value;
+
+ ataId.WWN = DescrambleWWN(ataId.WWN);
+ ataId.WWNExtension = DescrambleWWN(ataId.WWNExtension);
+
+ byte[] buf = new byte[512];
+ IntPtr ptr = System.Runtime.InteropServices.Marshal.AllocHGlobal(512);
+ System.Runtime.InteropServices.Marshal.StructureToPtr(ataId, ptr, false);
+ System.Runtime.InteropServices.Marshal.Copy(ptr, buf, 0, 512);
+ System.Runtime.InteropServices.Marshal.FreeHGlobal(ptr);
+
+ byte[] str = ScrambleATAString(ataId.SerialNumber, 20);
+ Array.Copy(str, 0, buf, 10 * 2, 20);
+ str = ScrambleATAString(ataId.FirmwareRevision, 8);
+ Array.Copy(str, 0, buf, 23 * 2, 8);
+ str = ScrambleATAString(ataId.Model, 40);
+ Array.Copy(str, 0, buf, 27 * 2, 40);
+ str = ScrambleATAString(ataId.AdditionalPID, 8);
+ Array.Copy(str, 0, buf, 170 * 2, 8);
+ str = ScrambleATAString(ataId.MediaSerial, 40);
+ Array.Copy(str, 0, buf, 176 * 2, 40);
+ str = ScrambleATAString(ataId.MediaManufacturer, 20);
+ Array.Copy(str, 0, buf, 196 * 2, 20);
+
+ return buf;
+ }
+
+ static ulong DescrambleWWN(ulong WWN)
+ {
+ byte[] qwb = BitConverter.GetBytes(WWN);
+ byte[] qword = new byte[8];
+
+ qword[7] = qwb[1];
+ qword[6] = qwb[0];
+ qword[5] = qwb[3];
+ qword[4] = qwb[2];
+ qword[3] = qwb[5];
+ qword[2] = qwb[4];
+ qword[1] = qwb[7];
+ qword[0] = qwb[6];
+
+ return BitConverter.ToUInt64(qword, 0);
+ }
+
+ static string DescrambleATAString(IList buffer, int offset, int length)
+ {
+ byte[] outbuf = buffer[(offset + length) - 1] != 0x00 ? new byte[length + 1] : new byte[length];
+
+ for(int i = 0; i < length; i += 2)
+ {
+ outbuf[i] = buffer[offset + i + 1];
+ outbuf[i + 1] = buffer[offset + i];
+ }
+
+ string outStr = StringHandlers.CToString(outbuf);
+
+ return outStr.Trim();
+ }
+
+ static byte[] ScrambleATAString(string str, int length)
+ {
+ byte[] buf = new byte[length];
+
+ for(int i = 0; i < length; i++)
+ buf[i] = 0x20;
+
+ if(str is null)
+ return buf;
+
+ byte[] bytes = Encoding.ASCII.GetBytes(str);
+
+ if(bytes.Length % 2 != 0)
+ {
+ byte[] tmp = new byte[bytes.Length + 1];
+ tmp[tmp.Length - 1] = 0x20;
+ Array.Copy(bytes, 0, tmp, 0, bytes.Length);
+ bytes = tmp;
+ }
+
+ for(int i = 0; i < bytes.Length; i += 2)
+ {
+ buf[i] = bytes[i + 1];
+ buf[i + 1] = bytes[i];
+ }
+
+ string test1 = StringHandlers.CToString(buf);
+ string test2 = DescrambleATAString(buf, 0, length);
+
+ return buf;
+ }
+ }
+}
\ No newline at end of file
diff --git a/Structs/Devices/SCSI/Enums.cs b/Structs/Devices/SCSI/Enums.cs
new file mode 100644
index 0000000..8b11310
--- /dev/null
+++ b/Structs/Devices/SCSI/Enums.cs
@@ -0,0 +1,227 @@
+// /***************************************************************************
+// The Disc Image Chef
+// ----------------------------------------------------------------------------
+//
+// Filename : Enums.cs
+// Author(s) : Natalia Portillo
+//
+// Component : Device structures decoders.
+//
+// --[ Description ] ----------------------------------------------------------
+//
+// Contains various SCSI enumerations.
+//
+// --[ License ] --------------------------------------------------------------
+//
+// This library is free software; you can redistribute it and/or modify
+// it under the terms of the GNU Lesser General Public License as
+// published by the Free Software Foundation; either version 2.1 of the
+// License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful, but
+// WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, see .
+//
+// ----------------------------------------------------------------------------
+// Copyright © 2011-2020 Natalia Portillo
+// ****************************************************************************/
+
+using System.Diagnostics.CodeAnalysis;
+
+namespace DiscImageChef.CommonTypes.Structs.Devices.SCSI
+{
+ public enum PeripheralQualifiers : byte
+ {
+ /// Peripheral qualifier: Device is connected and supported
+ Supported = 0x00,
+ /// Peripheral qualifier: Device is supported but not connected
+ Unconnected = 0x01,
+ /// Peripheral qualifier: Reserved value
+ Reserved = 0x02,
+ /// Peripheral qualifier: Device is connected but unsupported
+ Unsupported = 0x03,
+ /// Peripheral qualifier: Vendor values: 0x04, 0x05, 0x06 and 0x07
+ VendorMask = 0x04
+ }
+
+ [SuppressMessage("ReSharper", "InconsistentNaming")]
+ public enum PeripheralDeviceTypes : byte
+ {
+ /// Direct-access device
+ DirectAccess = 0x00,
+ /// Sequential-access device
+ SequentialAccess = 0x01,
+ /// Printer device
+ PrinterDevice = 0x02,
+ /// Processor device
+ ProcessorDevice = 0x03,
+ /// Write-once device
+ WriteOnceDevice = 0x04,
+ /// CD-ROM/DVD/etc device
+ MultiMediaDevice = 0x05,
+ /// Scanner device
+ ScannerDevice = 0x06,
+ /// Optical memory device
+ OpticalDevice = 0x07,
+ /// Medium change device
+ MediumChangerDevice = 0x08,
+ /// Communications device
+ CommsDevice = 0x09,
+ /// Graphics arts pre-press device (defined in ASC IT8)
+ PrePressDevice1 = 0x0A,
+ /// Graphics arts pre-press device (defined in ASC IT8)
+ PrePressDevice2 = 0x0B,
+ /// Array controller device
+ ArrayControllerDevice = 0x0C,
+ /// Enclosure services device
+ EnclosureServiceDevice = 0x0D,
+ /// Simplified direct-access device
+ SimplifiedDevice = 0x0E,
+ /// Optical card reader/writer device
+ OCRWDevice = 0x0F,
+ /// Bridging Expanders
+ BridgingExpander = 0x10,
+ /// Object-based Storage Device
+ ObjectDevice = 0x11,
+ /// Automation/Drive Interface
+ ADCDevice = 0x12,
+ /// Security Manager Device
+ SCSISecurityManagerDevice = 0x13,
+ /// Host managed zoned block device
+ SCSIZonedBlockDevice = 0x14,
+ /// Well known logical unit
+ WellKnownDevice = 0x1E,
+ /// Unknown or no device type
+ UnknownDevice = 0x1F
+ }
+
+ [SuppressMessage("ReSharper", "InconsistentNaming")]
+ public enum ANSIVersions : byte
+ {
+ /// Device does not claim conformance to any ANSI version
+ ANSINoVersion = 0x00,
+ /// Device complies with ANSI X3.131:1986
+ ANSI1986Version = 0x01,
+ /// Device complies with ANSI X3.131:1994
+ ANSI1994Version = 0x02,
+ /// Device complies with ANSI X3.301:1997
+ ANSI1997Version = 0x03,
+ /// Device complies with ANSI X3.351:2001
+ ANSI2001Version = 0x04,
+ /// Device complies with ANSI X3.408:2005.
+ ANSI2005Version = 0x05,
+ /// Device complies with SPC-4
+ ANSI2008Version = 0x06
+ }
+
+ [SuppressMessage("ReSharper", "InconsistentNaming")]
+ public enum ECMAVersions : byte
+ {
+ /// Device does not claim conformance to any ECMA version
+ ECMANoVersion = 0x00,
+ /// Device complies with a ECMA-111 standard
+ ECMA111 = 0x01
+ }
+
+ [SuppressMessage("ReSharper", "InconsistentNaming")]
+ public enum ISOVersions : byte
+ {
+ /// Device does not claim conformance to any ISO/IEC version
+ ISONoVersion = 0x00,
+ /// Device complies with ISO/IEC 9316:1995
+ ISO1995Version = 0x02
+ }
+
+ [SuppressMessage("ReSharper", "InconsistentNaming")]
+ public enum SPIClocking : byte
+ {
+ /// Supports only ST
+ ST = 0x00,
+ /// Supports only DT
+ DT = 0x01,
+ /// Reserved value
+ Reserved = 0x02,
+ /// Supports ST and DT
+ STandDT = 0x03
+ }
+
+ [SuppressMessage("ReSharper", "InconsistentNaming")]
+ public enum TGPSValues : byte
+ {
+ /// Assymetrical access not supported
+ NotSupported = 0x00,
+ /// Only implicit assymetrical access is supported
+ OnlyImplicit = 0x01,
+ /// Only explicit assymetrical access is supported
+ OnlyExplicit = 0x02,
+ /// Both implicit and explicit assymetrical access are supported
+ Both = 0x03
+ }
+
+ [SuppressMessage("ReSharper", "InconsistentNaming")]
+ public enum ProtocolIdentifiers : byte
+ {
+ /// Fibre Channel
+ FibreChannel = 0,
+ /// Parallel SCSI
+ SCSI = 1,
+ /// SSA
+ SSA = 2,
+ /// IEEE-1394
+ Firewire = 3,
+ /// SCSI Remote Direct Memory Access Protocol
+ RDMAP = 4,
+ /// Internet SCSI
+ iSCSI = 5,
+ /// Serial SCSI
+ SAS = 6,
+ /// Automation/Drive Interface Transport Protocol
+ ADT = 7,
+ /// AT Attachment Interface (ATA/ATAPI)
+ ATA = 8,
+ /// USB Attached SCSI
+ UAS = 9,
+ /// SCSI over PCI Express
+ SCSIe = 10,
+ /// PCI Express
+ PCIe = 11,
+ /// No specific protocol
+ NoProtocol = 15
+ }
+
+ [SuppressMessage("ReSharper", "InconsistentNaming")]
+ public enum ScsiDefinitions : byte
+ {
+ Current = 0, SCSI1 = 1, CCS = 2,
+ SCSI2 = 3, SCSI3 = 4
+ }
+
+ [SuppressMessage("ReSharper", "InconsistentNaming")]
+ public enum PhysicalInterfaces : uint
+ {
+ /// Unspecified physical interface
+ Unspecified = 0,
+ /// SCSI
+ SCSI = 1,
+ /// ATAPI
+ ATAPI = 2,
+ /// IEEE-1394/1995
+ IEEE1394 = 3,
+ /// IEEE-1394A
+ IEEE1394A = 4,
+ /// Fibre Channel
+ FC = 5,
+ /// IEEE-1394B
+ IEEE1394B = 6,
+ /// Serial ATAPI
+ SerialATAPI = 7,
+ /// USB
+ USB = 8,
+ /// Vendor unique
+ Vendor = 0xFFFF
+ }
+}
\ No newline at end of file
diff --git a/Structs/Devices/SCSI/Inquiry.cs b/Structs/Devices/SCSI/Inquiry.cs
new file mode 100644
index 0000000..5780017
--- /dev/null
+++ b/Structs/Devices/SCSI/Inquiry.cs
@@ -0,0 +1,706 @@
+using System;
+using System.Diagnostics.CodeAnalysis;
+using System.Linq;
+using DiscImageChef.Console;
+
+namespace DiscImageChef.CommonTypes.Structs.Devices.SCSI
+{
+ ///
+ /// Information from the following standards: T9/375-D revision 10l T10/995-D revision 10 T10/1236-D revision 20
+ /// T10/1416-D revision 23 T10/1731-D revision 16 T10/502 revision 05 RFC 7144 ECMA-111
+ ///
+ [SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"),
+ SuppressMessage("ReSharper", "MemberCanBePrivate.Global")]
+ public struct Inquiry
+ {
+ /// Peripheral qualifier Byte 0, bits 7 to 5
+ public byte PeripheralQualifier;
+ /// Peripheral device type Byte 0, bits 4 to 0
+ public byte PeripheralDeviceType;
+ /// Removable device Byte 1, bit 7
+ public bool RMB;
+ /// SCSI-1 vendor-specific qualification codes Byte 1, bits 6 to 0
+ public byte DeviceTypeModifier;
+ /// ISO/IEC SCSI Standard Version Byte 2, bits 7 to 6, mask = 0xC0, >> 6
+ public byte ISOVersion;
+ /// ECMA SCSI Standard Version Byte 2, bits 5 to 3, mask = 0x38, >> 3
+ public byte ECMAVersion;
+ /// ANSI SCSI Standard Version Byte 2, bits 2 to 0, mask = 0x07
+ public byte ANSIVersion;
+ /// Asynchronous Event Reporting Capability supported Byte 3, bit 7
+ public bool AERC;
+ /// Device supports TERMINATE TASK command Byte 3, bit 6
+ public bool TrmTsk;
+ /// Supports setting Normal ACA Byte 3, bit 5
+ public bool NormACA;
+ /// Supports LUN hierarchical addressing Byte 3, bit 4
+ public bool HiSup;
+ /// Responde data format Byte 3, bit 3 to 0
+ public byte ResponseDataFormat;
+ /// Lenght of total INQUIRY response minus 4 Byte 4
+ public byte AdditionalLength;
+ /// Device contains an embedded storage array controller Byte 5, bit 7
+ public bool SCCS;
+ /// Device contains an Access Control Coordinator Byte 5, bit 6
+ public bool ACC;
+ /// Supports asymetrical logical unit access Byte 5, bits 5 to 4
+ public byte TPGS;
+ /// Supports third-party copy commands Byte 5, bit 3
+ public bool ThreePC;
+ /// Reserved Byte 5, bits 2 to 1
+ public byte Reserved2;
+ /// Supports protection information Byte 5, bit 0
+ public bool Protect;
+ /// Supports basic queueing Byte 6, bit 7
+ public bool BQue;
+ /// Device contains an embedded enclosure services component Byte 6, bit 6
+ public bool EncServ;
+ /// Vendor-specific Byte 6, bit 5
+ public bool VS1;
+ /// Multi-port device Byte 6, bit 4
+ public bool MultiP;
+ /// Device contains or is attached to a medium changer Byte 6, bit 3
+ public bool MChngr;
+ /// Device supports request and acknowledge handshakes Byte 6, bit 2
+ public bool ACKREQQ;
+ /// Supports 32-bit wide SCSI addresses Byte 6, bit 1
+ public bool Addr32;
+ /// Supports 16-bit wide SCSI addresses Byte 6, bit 0
+ public bool Addr16;
+ /// Device supports relative addressing Byte 7, bit 7
+ public bool RelAddr;
+ /// Supports 32-bit wide data transfers Byte 7, bit 6
+ public bool WBus32;
+ /// Supports 16-bit wide data transfers Byte 7, bit 5
+ public bool WBus16;
+ /// Supports synchronous data transfer Byte 7, bit 4
+ public bool Sync;
+ /// Supports linked commands Byte 7, bit 3
+ public bool Linked;
+ /// Supports CONTINUE TASK and TARGET TRANSFER DISABLE commands Byte 7, bit 2
+ public bool TranDis;
+ /// Supports TCQ queue Byte 7, bit 1
+ public bool CmdQue;
+ /// Indicates that the devices responds to RESET with soft reset Byte 7, bit 0
+ public bool SftRe;
+ /// Vendor identification Bytes 8 to 15
+ public byte[] VendorIdentification;
+ /// Product identification Bytes 16 to 31
+ public byte[] ProductIdentification;
+ /// Product revision level Bytes 32 to 35
+ public byte[] ProductRevisionLevel;
+ /// Vendor-specific data Bytes 36 to 55
+ public byte[] VendorSpecific;
+ /// Byte 56, bits 7 to 4
+ public byte Reserved3;
+ /// Supported SPI clocking Byte 56, bits 3 to 2
+ public byte Clocking;
+ /// Device supports Quick Arbitration and Selection Byte 56, bit 1
+ public bool QAS;
+ /// Supports information unit transfers Byte 56, bit 0
+ public bool IUS;
+ /// Reserved Byte 57
+ public byte Reserved4;
+ /// Array of version descriptors Bytes 58 to 73
+ public ushort[] VersionDescriptors;
+ /// Reserved Bytes 74 to 95
+ public byte[] Reserved5;
+ /// Reserved Bytes 96 to end
+ public byte[] VendorSpecific2;
+
+ // Per DLT4000/DLT4500/DLT4700 Cartridge Tape Subsystem Product Manual
+
+ #region Quantum vendor unique inquiry data structure
+ /// Means that the INQUIRY response contains 56 bytes or more, so this data has been filled
+ public bool QuantumPresent;
+ /// The product family. Byte 36, bits 7 to 5
+ public byte Qt_ProductFamily;
+ /// The released firmware. Byte 36, bits 4 to 0
+ public byte Qt_ReleasedFirmware;
+ /// The firmware major version. Byte 37
+ public byte Qt_FirmwareMajorVersion;
+ /// The firmware minor version. Byte 38
+ public byte Qt_FirmwareMinorVersion;
+ /// The EEPROM format major version. Byte 39
+ public byte Qt_EEPROMFormatMajorVersion;
+ /// The EEPROM format minor version. Byte 40
+ public byte Qt_EEPROMFormatMinorVersion;
+ /// The firmware personality. Byte 41
+ public byte Qt_FirmwarePersonality;
+ /// The firmware sub personality. Byte 42
+ public byte Qt_FirmwareSubPersonality;
+ /// The tape directory format version. Byte 43
+ public byte Qt_TapeDirectoryFormatVersion;
+ /// The controller hardware version. Byte 44
+ public byte Qt_ControllerHardwareVersion;
+ /// The drive EEPROM version. Byte 45
+ public byte Qt_DriveEEPROMVersion;
+ /// The drive hardware version. Byte 46
+ public byte Qt_DriveHardwareVersion;
+ /// The media loader firmware version. Byte 47
+ public byte Qt_MediaLoaderFirmwareVersion;
+ /// The media loader hardware version. Byte 48
+ public byte Qt_MediaLoaderHardwareVersion;
+ /// The media loader mechanical version. Byte 49
+ public byte Qt_MediaLoaderMechanicalVersion;
+ /// Is a media loader present? Byte 50
+ public bool Qt_MediaLoaderPresent;
+ /// Is a library present? Byte 51
+ public bool Qt_LibraryPresent;
+ /// The module revision. Bytes 52 to 55
+ public byte[] Qt_ModuleRevision;
+ #endregion Quantum vendor unique inquiry data structure
+
+ #region IBM vendor unique inquiry data structure
+ /// Means that the INQUIRY response contains 56 bytes or more, so this data has been filled
+ public bool IBMPresent;
+ /// Drive is not capable of automation Byte 36 bit 0
+ public bool IBM_AutDis;
+ /// If not zero, limit in MB/s = Max * (this / 256) Byte 37
+ public byte IBM_PerformanceLimit;
+ /// Byte 41
+ public byte IBM_OEMSpecific;
+ #endregion IBM vendor unique inquiry data structure
+
+ #region HP vendor unique inquiry data structure
+ /// Means that the INQUIRY response contains 49 bytes or more, so this data has been filled
+ public bool HPPresent;
+ /// WORM version Byte 40 bits 7 to 1
+ public byte HP_WORMVersion;
+ /// WORM supported Byte 40 bit 0
+ public bool HP_WORM;
+ /// Bytes 43 to 48
+ public byte[] HP_OBDR;
+ #endregion HP vendor unique inquiry data structure
+
+ #region Seagate vendor unique inquiry data structure
+ /// Means that bytes 36 to 43 are filled
+ public bool SeagatePresent;
+ /// Drive Serial Number Bytes 36 to 43
+ public byte[] Seagate_DriveSerialNumber;
+ /// Means that bytes 96 to 143 are filled
+ public bool Seagate2Present;
+ /// Contains Seagate copyright notice Bytes 96 to 143
+ public byte[] Seagate_Copyright;
+ /// Means that bytes 144 to 147 are filled
+ public bool Seagate3Present;
+ /// Reserved Seagate field Bytes 144 to 147
+ public byte[] Seagate_ServoPROMPartNo;
+ #endregion Seagate vendor unique inquiry data structure
+
+ #region Kreon vendor unique inquiry data structure
+ /// Means that firmware is Kreon
+ public bool KreonPresent;
+ /// Kreon identifier Bytes 36 to 40
+ public byte[] KreonIdentifier;
+ /// Kreon just a 0x20 Bytes 41
+ public byte KreonSpace;
+ /// Kreon version string Bytes 42 to 46
+ public byte[] KreonVersion;
+ #endregion Kreon vendor unique inquiry data structure
+ #region Public methods
+ public static Inquiry? Decode(byte[] SCSIInquiryResponse)
+ {
+ if(SCSIInquiryResponse == null)
+ return null;
+
+ if(SCSIInquiryResponse.Length < 36 &&
+ SCSIInquiryResponse.Length != 5)
+ {
+ DicConsole.DebugWriteLine("SCSI INQUIRY decoder",
+ "INQUIRY response is {0} bytes, less than minimum of 36 bytes, decoded data can be incorrect, not decoding.",
+ SCSIInquiryResponse.Length);
+
+ return null;
+ }
+
+ if(SCSIInquiryResponse.Length < SCSIInquiryResponse[4] + 4 &&
+ SCSIInquiryResponse.Length != SCSIInquiryResponse[4])
+ {
+ DicConsole.DebugWriteLine("SCSI INQUIRY decoder",
+ "INQUIRY response length ({0} bytes) is different than specified in length field ({1} bytes), decoded data can be incorrect, not decoding.",
+ SCSIInquiryResponse.Length, SCSIInquiryResponse[4] + 4);
+
+ return null;
+ }
+
+ var decoded = new Inquiry();
+
+ if(SCSIInquiryResponse.Length >= 1)
+ {
+ decoded.PeripheralQualifier = (byte)((SCSIInquiryResponse[0] & 0xE0) >> 5);
+ decoded.PeripheralDeviceType = (byte)(SCSIInquiryResponse[0] & 0x1F);
+ }
+
+ if(SCSIInquiryResponse.Length >= 2)
+ {
+ decoded.RMB = Convert.ToBoolean(SCSIInquiryResponse[1] & 0x80);
+ decoded.DeviceTypeModifier = (byte)(SCSIInquiryResponse[1] & 0x7F);
+ }
+
+ if(SCSIInquiryResponse.Length >= 3)
+ {
+ decoded.ISOVersion = (byte)((SCSIInquiryResponse[2] & 0xC0) >> 6);
+ decoded.ECMAVersion = (byte)((SCSIInquiryResponse[2] & 0x38) >> 3);
+ decoded.ANSIVersion = (byte)(SCSIInquiryResponse[2] & 0x07);
+ }
+
+ if(SCSIInquiryResponse.Length >= 4)
+ {
+ decoded.AERC = Convert.ToBoolean(SCSIInquiryResponse[3] & 0x80);
+ decoded.TrmTsk = Convert.ToBoolean(SCSIInquiryResponse[3] & 0x40);
+ decoded.NormACA = Convert.ToBoolean(SCSIInquiryResponse[3] & 0x20);
+ decoded.HiSup = Convert.ToBoolean(SCSIInquiryResponse[3] & 0x10);
+ decoded.ResponseDataFormat = (byte)(SCSIInquiryResponse[3] & 0x07);
+ }
+
+ if(SCSIInquiryResponse.Length >= 5)
+ decoded.AdditionalLength = SCSIInquiryResponse[4];
+
+ if(SCSIInquiryResponse.Length >= 6)
+ {
+ decoded.SCCS = Convert.ToBoolean(SCSIInquiryResponse[5] & 0x80);
+ decoded.ACC = Convert.ToBoolean(SCSIInquiryResponse[5] & 0x40);
+ decoded.TPGS = (byte)((SCSIInquiryResponse[5] & 0x30) >> 4);
+ decoded.ThreePC = Convert.ToBoolean(SCSIInquiryResponse[5] & 0x08);
+ decoded.Reserved2 = (byte)((SCSIInquiryResponse[5] & 0x06) >> 1);
+ decoded.Protect = Convert.ToBoolean(SCSIInquiryResponse[5] & 0x01);
+ }
+
+ if(SCSIInquiryResponse.Length >= 7)
+ {
+ decoded.BQue = Convert.ToBoolean(SCSIInquiryResponse[6] & 0x80);
+ decoded.EncServ = Convert.ToBoolean(SCSIInquiryResponse[6] & 0x40);
+ decoded.VS1 = Convert.ToBoolean(SCSIInquiryResponse[6] & 0x20);
+ decoded.MultiP = Convert.ToBoolean(SCSIInquiryResponse[6] & 0x10);
+ decoded.MChngr = Convert.ToBoolean(SCSIInquiryResponse[6] & 0x08);
+ decoded.ACKREQQ = Convert.ToBoolean(SCSIInquiryResponse[6] & 0x04);
+ decoded.Addr32 = Convert.ToBoolean(SCSIInquiryResponse[6] & 0x02);
+ decoded.Addr16 = Convert.ToBoolean(SCSIInquiryResponse[6] & 0x01);
+ }
+
+ if(SCSIInquiryResponse.Length >= 8)
+ {
+ decoded.RelAddr = Convert.ToBoolean(SCSIInquiryResponse[7] & 0x80);
+ decoded.WBus32 = Convert.ToBoolean(SCSIInquiryResponse[7] & 0x40);
+ decoded.WBus16 = Convert.ToBoolean(SCSIInquiryResponse[7] & 0x20);
+ decoded.Sync = Convert.ToBoolean(SCSIInquiryResponse[7] & 0x10);
+ decoded.Linked = Convert.ToBoolean(SCSIInquiryResponse[7] & 0x08);
+ decoded.TranDis = Convert.ToBoolean(SCSIInquiryResponse[7] & 0x04);
+ decoded.CmdQue = Convert.ToBoolean(SCSIInquiryResponse[7] & 0x02);
+ decoded.SftRe = Convert.ToBoolean(SCSIInquiryResponse[7] & 0x01);
+ }
+
+ if(SCSIInquiryResponse.Length >= 16)
+ {
+ decoded.VendorIdentification = new byte[8];
+ Array.Copy(SCSIInquiryResponse, 8, decoded.VendorIdentification, 0, 8);
+ }
+
+ if(SCSIInquiryResponse.Length >= 32)
+ {
+ decoded.ProductIdentification = new byte[16];
+ Array.Copy(SCSIInquiryResponse, 16, decoded.ProductIdentification, 0, 16);
+ }
+
+ if(SCSIInquiryResponse.Length >= 36)
+ {
+ decoded.ProductRevisionLevel = new byte[4];
+ Array.Copy(SCSIInquiryResponse, 32, decoded.ProductRevisionLevel, 0, 4);
+ }
+
+ if(SCSIInquiryResponse.Length >= 44)
+ {
+ // Seagate 1
+ decoded.SeagatePresent = true;
+ decoded.Seagate_DriveSerialNumber = new byte[8];
+ Array.Copy(SCSIInquiryResponse, 36, decoded.Seagate_DriveSerialNumber, 0, 8);
+ }
+
+ if(SCSIInquiryResponse.Length >= 46)
+ {
+ // Kreon
+ decoded.KreonIdentifier = new byte[5];
+ Array.Copy(SCSIInquiryResponse, 36, decoded.KreonIdentifier, 0, 5);
+ decoded.KreonSpace = SCSIInquiryResponse[41];
+ decoded.KreonVersion = new byte[5];
+ Array.Copy(SCSIInquiryResponse, 42, decoded.KreonVersion, 0, 5);
+
+ if(decoded.KreonSpace == 0x20 &&
+ decoded.KreonIdentifier.SequenceEqual(new byte[]
+ {
+ 0x4B, 0x52, 0x45, 0x4F, 0x4E
+ }))
+ decoded.KreonPresent = true;
+ }
+
+ if(SCSIInquiryResponse.Length >= 49)
+ {
+ // HP
+ decoded.HPPresent = true;
+ decoded.HP_WORM |= (SCSIInquiryResponse[40] & 0x01) == 0x01;
+ decoded.HP_WORMVersion = (byte)((SCSIInquiryResponse[40] & 0x7F) >> 1);
+ decoded.HP_OBDR = new byte[6];
+ Array.Copy(SCSIInquiryResponse, 43, decoded.HP_OBDR, 0, 6);
+ }
+
+ if(SCSIInquiryResponse.Length >= 56)
+ {
+ decoded.VendorSpecific = new byte[20];
+ Array.Copy(SCSIInquiryResponse, 36, decoded.VendorSpecific, 0, 20);
+
+ // Quantum
+ decoded.QuantumPresent = true;
+ decoded.Qt_ProductFamily = (byte)((SCSIInquiryResponse[36] & 0xF0) >> 4);
+ decoded.Qt_ReleasedFirmware = (byte)(SCSIInquiryResponse[36] & 0x0F);
+ decoded.Qt_FirmwareMajorVersion = SCSIInquiryResponse[37];
+ decoded.Qt_FirmwareMinorVersion = SCSIInquiryResponse[38];
+ decoded.Qt_EEPROMFormatMajorVersion = SCSIInquiryResponse[39];
+ decoded.Qt_EEPROMFormatMinorVersion = SCSIInquiryResponse[40];
+ decoded.Qt_FirmwarePersonality = SCSIInquiryResponse[41];
+ decoded.Qt_FirmwareSubPersonality = SCSIInquiryResponse[42];
+ decoded.Qt_TapeDirectoryFormatVersion = SCSIInquiryResponse[43];
+ decoded.Qt_ControllerHardwareVersion = SCSIInquiryResponse[44];
+ decoded.Qt_DriveEEPROMVersion = SCSIInquiryResponse[45];
+ decoded.Qt_DriveHardwareVersion = SCSIInquiryResponse[46];
+ decoded.Qt_MediaLoaderFirmwareVersion = SCSIInquiryResponse[47];
+ decoded.Qt_MediaLoaderHardwareVersion = SCSIInquiryResponse[48];
+ decoded.Qt_MediaLoaderMechanicalVersion = SCSIInquiryResponse[49];
+ decoded.Qt_MediaLoaderPresent = SCSIInquiryResponse[50] > 0;
+ decoded.Qt_LibraryPresent = SCSIInquiryResponse[51] > 0;
+ decoded.Qt_ModuleRevision = new byte[4];
+ Array.Copy(SCSIInquiryResponse, 52, decoded.Qt_ModuleRevision, 0, 4);
+
+ // IBM
+ decoded.IBMPresent = true;
+ decoded.IBM_AutDis |= (SCSIInquiryResponse[36] & 0x01) == 0x01;
+ decoded.IBM_PerformanceLimit = SCSIInquiryResponse[37];
+ decoded.IBM_OEMSpecific = SCSIInquiryResponse[41];
+ }
+
+ if(SCSIInquiryResponse.Length >= 57)
+ {
+ decoded.Reserved3 = (byte)((SCSIInquiryResponse[56] & 0xF0) >> 4);
+ decoded.Clocking = (byte)((SCSIInquiryResponse[56] & 0x0C) >> 2);
+ decoded.QAS = Convert.ToBoolean(SCSIInquiryResponse[56] & 0x02);
+ decoded.IUS = Convert.ToBoolean(SCSIInquiryResponse[56] & 0x01);
+ }
+
+ if(SCSIInquiryResponse.Length >= 58)
+ decoded.Reserved4 = SCSIInquiryResponse[57];
+
+ if(SCSIInquiryResponse.Length >= 60)
+ {
+ int descriptorsNo;
+
+ if(SCSIInquiryResponse.Length >= 74)
+ descriptorsNo = 8;
+ else
+ descriptorsNo = (SCSIInquiryResponse.Length - 58) / 2;
+
+ decoded.VersionDescriptors = new ushort[descriptorsNo];
+
+ for(int i = 0; i < descriptorsNo; i++)
+ decoded.VersionDescriptors[i] = BitConverter.ToUInt16(SCSIInquiryResponse, 58 + (i * 2));
+ }
+
+ if(SCSIInquiryResponse.Length >= 75 &&
+ SCSIInquiryResponse.Length < 96)
+ {
+ decoded.Reserved5 = new byte[SCSIInquiryResponse.Length - 74];
+ Array.Copy(SCSIInquiryResponse, 74, decoded.Reserved5, 0, SCSIInquiryResponse.Length - 74);
+ }
+
+ if(SCSIInquiryResponse.Length >= 96)
+ {
+ decoded.Reserved5 = new byte[22];
+ Array.Copy(SCSIInquiryResponse, 74, decoded.Reserved5, 0, 22);
+ }
+
+ if(SCSIInquiryResponse.Length > 96)
+ {
+ decoded.VendorSpecific2 = new byte[SCSIInquiryResponse.Length - 96];
+ Array.Copy(SCSIInquiryResponse, 96, decoded.VendorSpecific2, 0, SCSIInquiryResponse.Length - 96);
+ }
+
+ if(SCSIInquiryResponse.Length >= 144)
+ {
+ // Seagate 2
+ decoded.Seagate2Present = true;
+ decoded.Seagate_Copyright = new byte[48];
+ Array.Copy(SCSIInquiryResponse, 96, decoded.Seagate_Copyright, 0, 48);
+ }
+
+ if(SCSIInquiryResponse.Length < 148)
+ return decoded;
+
+ // Seagate 2
+ decoded.Seagate3Present = true;
+ decoded.Seagate_ServoPROMPartNo = new byte[4];
+ Array.Copy(SCSIInquiryResponse, 144, decoded.Seagate_ServoPROMPartNo, 0, 4);
+
+ return decoded;
+ }
+
+ public static byte[] Encode(Inquiry? inq)
+ {
+ if(inq is null)
+ return null;
+
+ Inquiry decoded = inq.Value;
+
+ byte[] buffer = new byte[512];
+ byte length = 0;
+
+ buffer[0] = (byte)(decoded.PeripheralQualifier << 5);
+ buffer[0] += decoded.PeripheralDeviceType;
+
+ if(decoded.RMB)
+ buffer[1] = 0x80;
+
+ buffer[1] += decoded.DeviceTypeModifier;
+
+ buffer[2] = (byte)(decoded.ISOVersion << 6);
+ buffer[2] += (byte)(decoded.ECMAVersion << 3);
+ buffer[2] += decoded.ANSIVersion;
+
+ if(decoded.AERC)
+ buffer[3] = 0x80;
+
+ if(decoded.TrmTsk)
+ buffer[3] += 0x40;
+
+ if(decoded.NormACA)
+ buffer[3] += 0x20;
+
+ if(decoded.HiSup)
+ buffer[3] += 0x10;
+
+ buffer[3] += decoded.ResponseDataFormat;
+
+ if(decoded.AdditionalLength > 0)
+ {
+ length = 5;
+ buffer[4] = decoded.AdditionalLength;
+ }
+
+ if(decoded.SCCS ||
+ decoded.ACC ||
+ decoded.TPGS > 0 ||
+ decoded.ThreePC ||
+ decoded.Reserved2 > 0 ||
+ decoded.Protect)
+ {
+ length = 6;
+
+ if(decoded.SCCS)
+ buffer[5] = 0x80;
+
+ if(decoded.ACC)
+ buffer[5] += 0x40;
+
+ buffer[5] += (byte)(decoded.TPGS << 4);
+
+ if(decoded.ThreePC)
+ buffer[5] += 0x08;
+
+ buffer[5] += (byte)(decoded.Reserved2 << 1);
+
+ if(decoded.Protect)
+ buffer[5] += 0x01;
+ }
+
+ if(decoded.BQue ||
+ decoded.EncServ ||
+ decoded.VS1 ||
+ decoded.MultiP ||
+ decoded.MChngr ||
+ decoded.ACKREQQ ||
+ decoded.Addr32 ||
+ decoded.Addr16)
+ {
+ length = 7;
+
+ if(decoded.BQue)
+ buffer[6] = 0x80;
+
+ if(decoded.EncServ)
+ buffer[6] += 0x40;
+
+ if(decoded.VS1)
+ buffer[6] += 0x20;
+
+ if(decoded.MultiP)
+ buffer[6] += 0x10;
+
+ if(decoded.MChngr)
+ buffer[6] += 0x08;
+
+ if(decoded.ACKREQQ)
+ buffer[6] += 0x04;
+
+ if(decoded.Addr32)
+ buffer[6] += 0x02;
+
+ if(decoded.Addr16)
+ buffer[6] += 0x01;
+ }
+
+ if(decoded.RelAddr ||
+ decoded.WBus32 ||
+ decoded.WBus16 ||
+ decoded.Sync ||
+ decoded.Linked ||
+ decoded.TranDis ||
+ decoded.CmdQue ||
+ decoded.SftRe)
+
+ {
+ length = 8;
+
+ if(decoded.RelAddr)
+ buffer[7] = 0x80;
+
+ if(decoded.WBus32)
+ buffer[7] += 0x40;
+
+ if(decoded.WBus16)
+ buffer[7] += 0x20;
+
+ if(decoded.Sync)
+ buffer[7] += 0x10;
+
+ if(decoded.Linked)
+ buffer[7] += 0x08;
+
+ if(decoded.TranDis)
+ buffer[7] += 0x04;
+
+ if(decoded.CmdQue)
+ buffer[7] += 0x02;
+
+ if(decoded.SftRe)
+ buffer[7] += 0x01;
+ }
+
+ if(decoded.VendorIdentification != null)
+ {
+ length = 16;
+
+ Array.Copy(decoded.VendorIdentification, 0, buffer, 8,
+ decoded.VendorIdentification.Length >= 8 ? 8 : decoded.VendorIdentification.Length);
+ }
+
+ if(decoded.ProductIdentification != null)
+ {
+ length = 32;
+
+ Array.Copy(decoded.ProductIdentification, 0, buffer, 16,
+ decoded.ProductIdentification.Length >= 16 ? 16 : decoded.ProductIdentification.Length);
+ }
+
+ if(decoded.ProductRevisionLevel != null)
+ {
+ length = 36;
+
+ Array.Copy(decoded.ProductRevisionLevel, 0, buffer, 32,
+ decoded.ProductRevisionLevel.Length >= 4 ? 4 : decoded.ProductRevisionLevel.Length);
+ }
+
+ if(decoded.Seagate_DriveSerialNumber != null)
+ {
+ length = 44;
+ Array.Copy(decoded.Seagate_DriveSerialNumber, 0, buffer, 36, 8);
+ }
+
+ if(decoded.KreonIdentifier != null &&
+ decoded.KreonVersion != null)
+ {
+ length = 46;
+ Array.Copy(decoded.KreonIdentifier, 0, buffer, 36, 5);
+ buffer[41] = decoded.KreonSpace;
+ Array.Copy(decoded.KreonVersion, 0, buffer, 42, 5);
+ }
+
+ if(decoded.HP_WORM ||
+ decoded.HP_WORMVersion > 0 ||
+ decoded.HP_OBDR != null)
+ {
+ length = 49;
+
+ if(decoded.HP_WORM)
+ buffer[40] = 0x01;
+
+ buffer[40] += (byte)(decoded.HP_WORMVersion << 1);
+ Array.Copy(decoded.HP_OBDR, 0, buffer, 43, 6);
+ }
+
+ if(decoded.VendorSpecific != null)
+ {
+ length = 56;
+ Array.Copy(decoded.VendorSpecific, 0, buffer, 36, 20);
+ }
+
+ if(decoded.Reserved3 > 0 ||
+ decoded.Clocking > 0 ||
+ decoded.QAS ||
+ decoded.IUS)
+ {
+ length = 57;
+ buffer[56] = (byte)(decoded.Reserved3 << 4);
+ buffer[56] += (byte)(decoded.Clocking << 2);
+
+ if(decoded.QAS)
+ buffer[56] += 0x02;
+
+ if(decoded.IUS)
+ buffer[56] += 0x01;
+ }
+
+ if(decoded.Reserved4 != 0)
+ {
+ length = 58;
+ buffer[57] = decoded.Reserved4;
+ }
+
+ if(decoded.VersionDescriptors != null)
+ {
+ length = (byte)(58 + (decoded.VersionDescriptors.Length * 2));
+
+ for(int i = 0; i < decoded.VersionDescriptors.Length; i++)
+ Array.Copy(BitConverter.GetBytes(decoded.VersionDescriptors[i]), 0, buffer, 56 + (i * 2), 2);
+ }
+
+ if(decoded.Reserved5 != null)
+ {
+ length = (byte)(74 + decoded.Reserved5.Length);
+ Array.Copy(decoded.Reserved5, 0, buffer, 74, decoded.Reserved5.Length);
+ }
+
+ if(decoded.VendorSpecific2 != null)
+ {
+ length = (byte)(96 + decoded.VendorSpecific2.Length);
+ Array.Copy(decoded.VendorSpecific2, 0, buffer, 96, decoded.VendorSpecific2.Length);
+ }
+
+ if(decoded.Seagate_Copyright != null)
+ {
+ length = 144;
+ Array.Copy(decoded.Seagate_Copyright, 0, buffer, 96, 48);
+ }
+
+ if(decoded.Seagate_ServoPROMPartNo != null)
+ {
+ length = 148;
+ Array.Copy(decoded.Seagate_ServoPROMPartNo, 0, buffer, 144, 4);
+ }
+
+ buffer[4] = length;
+ byte[] dest = new byte[length];
+ Array.Copy(buffer, 0, dest, 0, length);
+
+ return dest;
+ }
+ #endregion Public methods
+ }
+}
\ No newline at end of file
diff --git a/Structs/Devices/SCSI/Modes/2A.cs b/Structs/Devices/SCSI/Modes/2A.cs
new file mode 100644
index 0000000..e35876b
--- /dev/null
+++ b/Structs/Devices/SCSI/Modes/2A.cs
@@ -0,0 +1,474 @@
+// /***************************************************************************
+// The Disc Image Chef
+// ----------------------------------------------------------------------------
+//
+// Filename : 2A.cs
+// Author(s) : Natalia Portillo
+//
+// Component : Device structures decoders.
+//
+// --[ Description ] ----------------------------------------------------------
+//
+// Decodes SCSI MODE PAGE 2Ah: CD-ROM capabilities page.
+//
+// --[ License ] --------------------------------------------------------------
+//
+// This library is free software; you can redistribute it and/or modify
+// it under the terms of the GNU Lesser General Public License as
+// published by the Free Software Foundation; either version 2.1 of the
+// License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful, but
+// WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, see .
+//
+// ----------------------------------------------------------------------------
+// Copyright © 2011-2020 Natalia Portillo
+// ****************************************************************************/
+
+using System;
+using System.ComponentModel.DataAnnotations;
+using System.Diagnostics.CodeAnalysis;
+using Newtonsoft.Json;
+
+namespace DiscImageChef.CommonTypes.Structs.Devices.SCSI.Modes
+{
+ [SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"),
+ SuppressMessage("ReSharper", "MemberCanBePrivate.Global"), SuppressMessage("ReSharper", "NotAccessedField.Global")]
+ #region Mode Page 0x2A: CD-ROM capabilities page
+ ///
+ /// CD-ROM capabilities page Page code 0x2A 16 bytes in OB-U0077C 20 bytes in SFF-8020i 22 bytes in MMC-1 26 bytes
+ /// in MMC-2 Variable bytes in MMC-3
+ ///
+ public class ModePage_2A
+ {
+ public ModePage_2A_WriteDescriptor[] WriteSpeedPerformanceDescriptors;
+ /// Parameters can be saved
+ public bool PS { get; set; }
+ /// Drive supports multi-session and/or Photo-CD
+ public bool MultiSession { get; set; }
+ /// Drive is capable of reading sectors in Mode 2 Form 2 format
+ public bool Mode2Form2 { get; set; }
+ /// Drive is capable of reading sectors in Mode 2 Form 1 format
+ public bool Mode2Form1 { get; set; }
+ /// Drive is capable of playing audio
+ public bool AudioPlay { get; set; }
+ /// Drive can return the ISRC
+ public bool ISRC { get; set; }
+ /// Drive can return the media catalogue number
+ public bool UPC { get; set; }
+ /// Drive can return C2 pointers
+ public bool C2Pointer { get; set; }
+ /// Drive can read, deinterlave and correct R-W subchannels
+ public bool DeinterlaveSubchannel { get; set; }
+ /// Drive can read interleaved and uncorrected R-W subchannels
+ public bool Subchannel { get; set; }
+ /// Drive can continue from a loss of streaming on audio reading
+ public bool AccurateCDDA { get; set; }
+ /// Audio can be read as digital data
+ public bool CDDACommand { get; set; }
+ /// Loading Mechanism Type
+ public byte LoadingMechanism { get; set; }
+ /// Drive can eject discs
+ public bool Eject { get; set; }
+ /// Drive's optional prevent jumper status
+ public bool PreventJumper { get; set; }
+ /// Current lock status
+ public bool LockState { get; set; }
+ /// Drive can lock media
+ public bool Lock { get; set; }
+ /// Each channel can be muted independently
+ public bool SeparateChannelMute { get; set; }
+ /// Each channel's volume can be controlled independently
+ public bool SeparateChannelVolume { get; set; }
+ /// Maximum drive speed in Kbytes/second
+ public ushort MaximumSpeed { get; set; }
+ /// Supported volume levels
+ public ushort SupportedVolumeLevels { get; set; }
+ /// Buffer size in Kbytes
+ public ushort BufferSize { get; set; }
+ /// Current drive speed in Kbytes/second
+ public ushort CurrentSpeed { get; set; }
+
+ public bool Method2 { get; set; }
+ public bool ReadCDRW { get; set; }
+ public bool ReadCDR { get; set; }
+ public bool WriteCDRW { get; set; }
+ public bool WriteCDR { get; set; }
+ public bool DigitalPort2 { get; set; }
+ public bool DigitalPort1 { get; set; }
+ public bool Composite { get; set; }
+ public bool SSS { get; set; }
+ public bool SDP { get; set; }
+ public byte Length { get; set; }
+ public bool LSBF { get; set; }
+ public bool RCK { get; set; }
+ public bool BCK { get; set; }
+
+ public bool TestWrite { get; set; }
+ public ushort MaxWriteSpeed { get; set; }
+ public ushort CurrentWriteSpeed { get; set; }
+
+ public bool ReadBarcode { get; set; }
+
+ public bool ReadDVDRAM { get; set; }
+ public bool ReadDVDR { get; set; }
+ public bool ReadDVDROM { get; set; }
+ public bool WriteDVDRAM { get; set; }
+ public bool WriteDVDR { get; set; }
+ public bool LeadInPW { get; set; }
+ public bool SCC { get; set; }
+ public ushort CMRSupported { get; set; }
+
+ public bool BUF { get; set; }
+ public byte RotationControlSelected { get; set; }
+ public ushort CurrentWriteSpeedSelected { get; set; }
+
+ [JsonIgnore, Key]
+ public int Id { get; set; }
+
+ public static ModePage_2A Decode(byte[] pageResponse)
+ {
+ if((pageResponse?[0] & 0x40) == 0x40)
+ return null;
+
+ if((pageResponse?[0] & 0x3F) != 0x2A)
+ return null;
+
+ if(pageResponse[1] + 2 != pageResponse.Length)
+ return null;
+
+ if(pageResponse.Length < 16)
+ return null;
+
+ var 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]);
+
+ if(pageResponse.Length < 20)
+ return decoded;
+
+ decoded.Method2 |= (pageResponse[2] & 0x04) == 0x04;
+ decoded.ReadCDRW |= (pageResponse[2] & 0x02) == 0x02;
+ decoded.ReadCDR |= (pageResponse[2] & 0x01) == 0x01;
+
+ decoded.WriteCDRW |= (pageResponse[3] & 0x02) == 0x02;
+ decoded.WriteCDR |= (pageResponse[3] & 0x01) == 0x01;
+
+ decoded.Composite |= (pageResponse[4] & 0x02) == 0x02;
+ decoded.DigitalPort1 |= (pageResponse[4] & 0x04) == 0x04;
+ decoded.DigitalPort2 |= (pageResponse[4] & 0x08) == 0x08;
+
+ decoded.SDP |= (pageResponse[7] & 0x04) == 0x04;
+ decoded.SSS |= (pageResponse[7] & 0x08) == 0x08;
+
+ decoded.Length = (byte)((pageResponse[17] & 0x30) >> 4);
+ decoded.LSBF |= (pageResponse[17] & 0x08) == 0x08;
+ decoded.RCK |= (pageResponse[17] & 0x04) == 0x04;
+ decoded.BCK |= (pageResponse[17] & 0x02) == 0x02;
+
+ if(pageResponse.Length < 22)
+ return decoded;
+
+ decoded.TestWrite |= (pageResponse[3] & 0x04) == 0x04;
+ decoded.MaxWriteSpeed = (ushort)((pageResponse[18] << 8) + pageResponse[19]);
+ decoded.CurrentWriteSpeed = (ushort)((pageResponse[20] << 8) + pageResponse[21]);
+
+ decoded.ReadBarcode |= (pageResponse[5] & 0x80) == 0x80;
+
+ if(pageResponse.Length < 26)
+ return decoded;
+
+ decoded.ReadDVDRAM |= (pageResponse[2] & 0x20) == 0x20;
+ decoded.ReadDVDR |= (pageResponse[2] & 0x10) == 0x10;
+ decoded.ReadDVDROM |= (pageResponse[2] & 0x08) == 0x08;
+
+ decoded.WriteDVDRAM |= (pageResponse[3] & 0x20) == 0x20;
+ decoded.WriteDVDR |= (pageResponse[3] & 0x10) == 0x10;
+
+ decoded.LeadInPW |= (pageResponse[3] & 0x20) == 0x20;
+ decoded.SCC |= (pageResponse[3] & 0x10) == 0x10;
+
+ decoded.CMRSupported = (ushort)((pageResponse[22] << 8) + pageResponse[23]);
+
+ if(pageResponse.Length < 32)
+ return decoded;
+
+ decoded.BUF |= (pageResponse[4] & 0x80) == 0x80;
+ decoded.RotationControlSelected = (byte)(pageResponse[27] & 0x03);
+ decoded.CurrentWriteSpeedSelected = (ushort)((pageResponse[28] << 8) + pageResponse[29]);
+
+ ushort descriptors = (ushort)((pageResponse.Length - 32) / 4);
+ decoded.WriteSpeedPerformanceDescriptors = new ModePage_2A_WriteDescriptor[descriptors];
+
+ for(int i = 0; i < descriptors; i++)
+ decoded.WriteSpeedPerformanceDescriptors[i] = new ModePage_2A_WriteDescriptor
+ {
+ RotationControl =
+ (byte)(pageResponse[1 + 32 + (i * 4)] & 0x07),
+ WriteSpeed = (ushort)((pageResponse[2 + 32 + (i * 4)] << 8) + pageResponse[3 + 32 + (i * 4)])
+ };
+
+ return decoded;
+ }
+
+ public static byte[] Encode(ModePage_2A decoded)
+ {
+ byte[] pageResponse = new byte[512];
+ byte length = 16;
+
+ pageResponse[0] = 0x2A;
+
+ if(decoded.PS)
+ pageResponse[0] += 0x80;
+
+ if(decoded.AudioPlay)
+ pageResponse[4] += 0x01;
+
+ if(decoded.Mode2Form1)
+ pageResponse[4] += 0x10;
+
+ if(decoded.Mode2Form2)
+ pageResponse[4] += 0x20;
+
+ if(decoded.MultiSession)
+ pageResponse[4] += 0x40;
+
+ if(decoded.CDDACommand)
+ pageResponse[5] += 0x01;
+
+ if(decoded.AccurateCDDA)
+ pageResponse[5] += 0x02;
+
+ if(decoded.Subchannel)
+ pageResponse[5] += 0x04;
+
+ if(decoded.DeinterlaveSubchannel)
+ pageResponse[5] += 0x08;
+
+ if(decoded.C2Pointer)
+ pageResponse[5] += 0x10;
+
+ if(decoded.UPC)
+ pageResponse[5] += 0x20;
+
+ if(decoded.ISRC)
+ pageResponse[5] += 0x40;
+
+ decoded.LoadingMechanism = (byte)((pageResponse[6] & 0xE0) >> 5);
+
+ if(decoded.Lock)
+ pageResponse[6] += 0x01;
+
+ if(decoded.LockState)
+ pageResponse[6] += 0x02;
+
+ if(decoded.PreventJumper)
+ pageResponse[6] += 0x04;
+
+ if(decoded.Eject)
+ pageResponse[6] += 0x08;
+
+ if(decoded.SeparateChannelVolume)
+ pageResponse[7] += 0x01;
+
+ if(decoded.SeparateChannelMute)
+ pageResponse[7] += 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]);
+
+ if(decoded.Method2 ||
+ decoded.ReadCDRW ||
+ decoded.ReadCDR ||
+ decoded.WriteCDRW ||
+ decoded.WriteCDR ||
+ decoded.Composite ||
+ decoded.DigitalPort1 ||
+ decoded.DigitalPort2 ||
+ decoded.SDP ||
+ decoded.SSS ||
+ decoded.Length > 0 ||
+ decoded.LSBF ||
+ decoded.RCK ||
+ decoded.BCK)
+ {
+ length = 20;
+
+ if(decoded.Method2)
+ pageResponse[2] += 0x04;
+
+ if(decoded.ReadCDRW)
+ pageResponse[2] += 0x02;
+
+ if(decoded.ReadCDR)
+ pageResponse[2] += 0x01;
+
+ if(decoded.WriteCDRW)
+ pageResponse[3] += 0x02;
+
+ if(decoded.WriteCDR)
+ pageResponse[3] += 0x01;
+
+ if(decoded.Composite)
+ pageResponse[4] += 0x02;
+
+ if(decoded.DigitalPort1)
+ pageResponse[4] += 0x04;
+
+ if(decoded.DigitalPort2)
+ pageResponse[4] += 0x08;
+
+ if(decoded.SDP)
+ pageResponse[7] += 0x04;
+
+ if(decoded.SSS)
+ pageResponse[7] += 0x08;
+
+ pageResponse[17] = (byte)(decoded.Length << 4);
+
+ if(decoded.LSBF)
+ pageResponse[17] += 0x08;
+
+ if(decoded.RCK)
+ pageResponse[17] += 0x04;
+
+ if(decoded.BCK)
+ pageResponse[17] += 0x02;
+ }
+
+ if(decoded.TestWrite ||
+ decoded.MaxWriteSpeed > 0 ||
+ decoded.CurrentWriteSpeed > 0 ||
+ decoded.ReadBarcode)
+ {
+ length = 22;
+
+ if(decoded.TestWrite)
+ pageResponse[3] += 0x04;
+
+ pageResponse[18] = (byte)((decoded.MaxWriteSpeed & 0xFF00) >> 8);
+ pageResponse[19] = (byte)(decoded.MaxWriteSpeed & 0xFF);
+ pageResponse[20] = (byte)((decoded.CurrentWriteSpeed & 0xFF00) >> 8);
+ pageResponse[21] = (byte)(decoded.CurrentWriteSpeed & 0xFF);
+
+ if(decoded.ReadBarcode)
+ pageResponse[5] += 0x80;
+ }
+
+ if(decoded.ReadDVDRAM ||
+ decoded.ReadDVDR ||
+ decoded.ReadDVDROM ||
+ decoded.WriteDVDRAM ||
+ decoded.WriteDVDR ||
+ decoded.LeadInPW ||
+ decoded.SCC ||
+ decoded.CMRSupported > 0)
+
+ {
+ length = 26;
+
+ if(decoded.ReadDVDRAM)
+ pageResponse[2] += 0x20;
+
+ if(decoded.ReadDVDR)
+ pageResponse[2] += 0x10;
+
+ if(decoded.ReadDVDROM)
+ pageResponse[2] += 0x08;
+
+ if(decoded.WriteDVDRAM)
+ pageResponse[3] += 0x20;
+
+ if(decoded.WriteDVDR)
+ pageResponse[3] += 0x10;
+
+ if(decoded.LeadInPW)
+ pageResponse[3] += 0x20;
+
+ if(decoded.SCC)
+ pageResponse[3] += 0x10;
+
+ pageResponse[22] = (byte)((decoded.CMRSupported & 0xFF00) >> 8);
+ pageResponse[23] = (byte)(decoded.CMRSupported & 0xFF);
+ }
+
+ if(decoded.BUF ||
+ decoded.RotationControlSelected > 0 ||
+ decoded.CurrentWriteSpeedSelected > 0)
+ {
+ length = 32;
+
+ if(decoded.BUF)
+ pageResponse[4] += 0x80;
+
+ pageResponse[27] += decoded.RotationControlSelected;
+ pageResponse[28] = (byte)((decoded.CurrentWriteSpeedSelected & 0xFF00) >> 8);
+ pageResponse[29] = (byte)(decoded.CurrentWriteSpeedSelected & 0xFF);
+ }
+
+ if(decoded.WriteSpeedPerformanceDescriptors != null)
+ {
+ length = 32;
+
+ for(int i = 0; i < decoded.WriteSpeedPerformanceDescriptors.Length; i++)
+ {
+ length += 4;
+ pageResponse[1 + 32 + (i * 4)] = decoded.WriteSpeedPerformanceDescriptors[i].RotationControl;
+
+ pageResponse[2 + 32 + (i * 4)] =
+ (byte)((decoded.WriteSpeedPerformanceDescriptors[i].WriteSpeed & 0xFF00) >> 8);
+
+ pageResponse[3 + 32 + (i * 4)] =
+ (byte)(decoded.WriteSpeedPerformanceDescriptors[i].WriteSpeed & 0xFF);
+ }
+ }
+
+ pageResponse[1] = (byte)(length - 2);
+ byte[] buf = new byte[length];
+ Array.Copy(pageResponse, 0, buf, 0, length);
+
+ return buf;
+ }
+ }
+
+ public struct ModePage_2A_WriteDescriptor
+ {
+ public byte RotationControl;
+ public ushort WriteSpeed;
+ }
+ #endregion Mode Page 0x2A: CD-ROM capabilities page
+}
\ No newline at end of file