Click here to Skip to main content
15,891,757 members
Articles / Programming Languages / C#

SCSI Library in C# - Burn CDs and DVDs, Access Hard Disks, etc.

Rate me:
Please Sign up or sign in to vote.
4.77/5 (48 votes)
19 Jun 2017Ms-PL6 min read 145.9K   8.1K   146  
Ever wonder how programs like Nero work? They make their own SCSI libraries... like this!
using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
using Helper;
using System.ComponentModel;
namespace Scsi
{
	[StructLayout(LayoutKind.Sequential, Pack = 1)]
	public abstract class ModePage : IMarshalable
	{
		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		private const byte PAGE_CODE_MASK = 0x3F;
		protected ModePage(ModePageCode pageCode) : base() { this.PageCode = pageCode; }

		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		private BitVector8 byte0;
		/// <summary>For a Mode Sense command, indicates whether the mode page may be saved by the target in a nonvolatile, vendor specific location. Reserved for the Mode Select command.</summary>
		[System.ComponentModel.Browsable(false)]
		public bool ParametersSavable { get { return this.byte0[7]; } set { this.byte0[7] = value; } }
		[System.ComponentModel.Browsable(false)]
		public ModePageCode PageCode { get { return (ModePageCode)Bits.GetValueMask((byte)this.byte0, 0, PAGE_CODE_MASK); } private set { this.byte0 = (BitVector8)Bits.PutValueMask((byte)this.byte0, (byte)value, 0, PAGE_CODE_MASK); } }
		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		private byte _PageLength;
		[System.ComponentModel.Browsable(false)]
		public byte PageLength { get { return this._PageLength; } protected set { this._PageLength = value; } }

		protected virtual void MarshalFrom(BufferWithSize buffer) { Marshaler.DefaultPtrToStructure(buffer, this); }
		protected virtual void MarshalTo(BufferWithSize buffer) { this.PageLength = (byte)(Marshaler.SizeOf(this) - Marshaler.DefaultSizeOf<ModePage>()); Marshaler.DefaultStructureToPtr((object)this, buffer); }
		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		protected virtual int MarshaledSize { get { return Marshal.SizeOf(this); } }

		void IMarshalable.MarshalFrom(BufferWithSize buffer) { this.MarshalFrom(buffer); }
		void IMarshalable.MarshalTo(BufferWithSize buffer) { this.MarshalTo(buffer); }
		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		int IMarshalable.MarshaledSize { get { var size = this.MarshaledSize; this.PageLength = (byte)(size - Marshaler.DefaultSizeOf<ModePage>()); return size; } }

		//public override string ToString() { return Internal.GenericToString(this, true); }

		public static ModePage TryCreateInstance(ModePageCode pageCode)
		{
			switch (pageCode)
			{
				case ModePageCode.ReadWriteErrorRecoveryParameters:
					return new ReadWriteErrorRecoveryParametersPage();
				case ModePageCode.WriteParameters:
					return new Multimedia.WriteParametersPage();
				case ModePageCode.Caching:
					return new CachingModePage();
				case ModePageCode.CDDeviceParameters:
					return new Multimedia.CDParametersPage();
				case ModePageCode.CapabilitiesAndMechanicalStatus:
					return new Multimedia.CapabilitiesMechanicalStatusPage();
				default:
					return null;
			}
		}

		public static ModePage CreateInstance(ModePageCode pageCode) { var result = TryCreateInstance(pageCode); if (result == null) { throw new ArgumentOutOfRangeException("pageCode", pageCode, "Invalid mode page."); } return result; }

		internal static ModePageCode ReadPageCode(IntPtr pBuffer) { unsafe { return (ModePageCode)Bits.GetValueMask(*(byte*)pBuffer, 0, PAGE_CODE_MASK); } }

		public static ModePage FromBuffer(IntPtr pBuffer, int bufferLength) { var mp = CreateInstance(ReadPageCode(pBuffer)); Marshaler.PtrToStructure(new BufferWithSize(pBuffer, bufferLength), ref mp); return mp; }
	}

	[StructLayout(LayoutKind.Sequential, Pack = 1)]
	public class ReadWriteErrorRecoveryParametersPage : ModePage
	{
		public ReadWriteErrorRecoveryParametersPage() : base(ModePageCode.ReadWriteErrorRecoveryParameters) { }

		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		private BitVector8 errorRecoveryParameter;
		public bool AutomaticWriteReallocationEnabled { get { return this.errorRecoveryParameter[7]; } set { this.errorRecoveryParameter[7] = value; } }
		public bool AutomaticReadReallocationEnabled { get { return this.errorRecoveryParameter[6]; } set { this.errorRecoveryParameter[6] = value; } }
		public bool TransferBlock { get { return this.errorRecoveryParameter[5]; } set { this.errorRecoveryParameter[5] = value; } }
		public bool ReadContinuous { get { return this.errorRecoveryParameter[4]; } set { this.errorRecoveryParameter[4] = value; } }
		public bool PostError { get { return this.errorRecoveryParameter[2]; } set { this.errorRecoveryParameter[2] = value; } }
		public bool DisableTransferOnError { get { return this.errorRecoveryParameter[1]; } set { this.errorRecoveryParameter[1] = value; } }
		public bool DisableCorrection { get { return this.errorRecoveryParameter[0]; } set { this.errorRecoveryParameter[0] = value; } }
		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		private byte _ReadRetryCount;
		public byte ReadRetryCount { get { return this._ReadRetryCount; } set { this._ReadRetryCount = value; } }
		private byte _CorrectionSpan;
		private byte _HeadOffsetCount;
		private byte _DataStrobeOffsetCount;
		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		private byte byte7;
		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		private byte _WriteRetryCount;
		public byte WriteRetryCount { get { return this._WriteRetryCount; } set { this._WriteRetryCount = value; } }
		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		private byte byte9;
		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		private ushort _RecoveryTimeLimit;
		/// <summary>Should be zero.</summary>
		public ushort RecoveryTimeLimit { get { return Bits.BigEndian(this._RecoveryTimeLimit); } set { this._RecoveryTimeLimit = Bits.BigEndian(value); } }
	}

	[StructLayout(LayoutKind.Sequential, Pack = 1)]
	public class CachingModePage : ModePage
	{
		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		private const byte DEMAND_READ_RETENTION_PRIORITY_MASK = 0xF0;
		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		private const byte DEMAND_WRITE_RETENTION_PRIORITY_MASK = 0x0F;

		public CachingModePage() : base(ModePageCode.Caching) { }

		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		private BitVector8 byte2;
		public bool InitiatorControl { get { return this.byte2[7]; } set { this.byte2[7] = value; } }
		public bool AbortPrefetch { get { return this.byte2[6]; } set { this.byte2[6] = value; } }
		public bool CacheAnalysisPermitted { get { return this.byte2[5]; } set { this.byte2[5] = value; } }
		public bool Discontinuity { get { return this.byte2[4]; } set { this.byte2[4] = value; } }
		public bool SizeEnable { get { return this.byte2[3]; } set { this.byte2[3] = value; } }
		public bool WritebackCacheEnable { get { return this.byte2[2]; } set { this.byte2[2] = value; } }
		public bool MultiplicationFactor { get { return this.byte2[1]; } set { this.byte2[1] = value; } }
		public bool ReadCacheDisable { get { return this.byte2[0]; } set { this.byte2[0] = value; } }
		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		private byte byte3;
		public DemandReadRetentionPriority DemandReadRetentionPriority
		{
			get { return (DemandReadRetentionPriority)Bits.GetValueMask((byte)this.byte3, 4, DEMAND_READ_RETENTION_PRIORITY_MASK); }
			set { this.byte3 = Bits.PutValueMask(this.byte3, (byte)value, 4, DEMAND_READ_RETENTION_PRIORITY_MASK); }
		}
		public DemandWriteRetentionPriority DemandWriteRetentionPriority
		{
			get { return (DemandWriteRetentionPriority)Bits.GetValueMask((byte)this.byte3, 4, DEMAND_WRITE_RETENTION_PRIORITY_MASK); }
			set { this.byte3 = Bits.PutValueMask(this.byte3, (byte)value, 4, DEMAND_WRITE_RETENTION_PRIORITY_MASK); }
		}
		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		private ushort _DisablePrefetchTransferLength;
		public ushort DisablePrefetchTransferLength { get { return Bits.BigEndian(this._DisablePrefetchTransferLength); } set { this._DisablePrefetchTransferLength = Bits.BigEndian(value); } }
		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		private ushort _MinimumPrefetch;
		public ushort MinimumPrefetch { get { return Bits.BigEndian(this._MinimumPrefetch); } set { this._MinimumPrefetch = Bits.BigEndian(value); } }
		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		private ushort _MaximumPrefetch;
		public ushort MaximumPrefetch { get { return Bits.BigEndian(this._MaximumPrefetch); } set { this._MaximumPrefetch = Bits.BigEndian(value); } }
		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		private ushort _MaximumPrefetchCeiling;
		public ushort MaximumPrefetchCeiling { get { return Bits.BigEndian(this._MaximumPrefetchCeiling); } set { this._MaximumPrefetchCeiling = Bits.BigEndian(value); } }
		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		private BitVector8 byte12;
		public bool ForceSequentialWrite { get { return this.byte12[7]; } set { this.byte12[7] = value; } }
		public bool LogicalBlockCacheSegmentSize { get { return this.byte12[6]; } set { this.byte12[6] = value; } }
		public bool DisableReadAhead { get { return this.byte12[5]; } set { this.byte12[5] = value; } }
		public bool NonvolatileCacheDisabled { get { return this.byte12[0]; } set { this.byte12[0] = value; } }
		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		private byte _NumberOfCacheSegments;
		public byte NumberOfCacheSegments { get { return this._NumberOfCacheSegments; } set { this._NumberOfCacheSegments = value; } }
		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		private ushort _CacheSegmentSize;
		public ushort CacheSegmentSize { get { return Bits.BigEndian(this._CacheSegmentSize); } set { this._CacheSegmentSize = Bits.BigEndian(value); } }
		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
#pragma warning disable 0169
		private byte byte16;
#pragma warning restore 0169
		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		private byte _byte17; //MSB
		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		private byte _byte18;
		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		private byte _byte19; //LSB
		[Obsolete]
		public uint NonCacheSegmentSize
		{
			get { unchecked { return (uint)this._byte19 | ((uint)this._byte18 << 8) | ((uint)this._byte17 << 16); } }
			set { unchecked { this._byte19 = (byte)(value >> 0); this._byte18 = (byte)(value >> 8); this._byte17 = (byte)(value >> 16); } }
		}
	}

	[StructLayout(LayoutKind.Sequential, Pack = 1)]
	public class PowerConditionsModePage : ModePage
	{
		public PowerConditionsModePage() : base(ModePageCode.PowerConditions) { }

		[DebuggerBrowsableAttribute(DebuggerBrowsableState.Never)]
		private byte byte2;
		[DebuggerBrowsableAttribute(DebuggerBrowsableState.Never)]
		private BitVector8 byte3;
		[DebuggerBrowsableAttribute(DebuggerBrowsableState.Never)]
		private bool IdleTimerActive { get { return this.byte3[1]; } set { this.byte3[1] = value; } }
		[DebuggerBrowsableAttribute(DebuggerBrowsableState.Never)]
		private bool StandbyTimerActive { get { return this.byte3[0]; } set { this.byte3[0] = value; } }
		[DebuggerBrowsableAttribute(DebuggerBrowsableState.Never)]
		private uint _IdleConditionTimer;
		/// <summary>The inactivity time in 100 millisecond increments that the logical unit waits before transitioning to the idle power condition.</summary>
		public uint? IdleConditionTimer { get { return this.IdleTimerActive ? Bits.BigEndian(this._IdleConditionTimer) : (uint?)null; } set { this.IdleTimerActive = value != null; this._IdleConditionTimer = Bits.BigEndian(value.GetValueOrDefault()); } }
		public TimeSpan? IdleCondition { get { var timer = this.IdleConditionTimer; return TimeSpan.FromMilliseconds(timer.GetValueOrDefault() * 100); } set { this.IdleConditionTimer = value != null ? (uint)(value.Value.TotalMilliseconds / 100) : (uint?)0; } }
		[DebuggerBrowsableAttribute(DebuggerBrowsableState.Never)]
		private uint _StandbyConditionTimer;
		/// <summary>The inactivity time in 100 millisecond increments that the logical unit waits before transitioning to the standby power condition.</summary>
		public uint? StandbyConditionTimer { get { return this.StandbyTimerActive ? Bits.BigEndian(this._StandbyConditionTimer) : (uint?)null; } set { this.StandbyTimerActive = value != null; this._StandbyConditionTimer = Bits.BigEndian(value.GetValueOrDefault()); } }
		public TimeSpan? StandbyCondition { get { var timer = this.StandbyConditionTimer; return TimeSpan.FromMilliseconds(timer.GetValueOrDefault() * 100); } set { this.StandbyConditionTimer = value != null ? (uint)(value.Value.TotalMilliseconds / 100) : (uint?)0; } }
	}
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Microsoft Public License (Ms-PL)


Written By
United States United States
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions