/// <summary> /// /// </summary> /// <returns></returns> public CommandStatus Scan(ScanDirection dir, uint lba, ScanType type) { if (m_logger != null) { string args = dir.ToString() + ", " + lba.ToString() + ", " + type.ToString(); m_logger.LogMessage(new UserMessage(UserMessage.Category.Debug, 8, "Bwg.Scsi.Device.Scan(" + args + ")")); } if (type == ScanType.Reserved) throw new Exception("type parameter is of type Reserved"); using (Command cmd = new Command(ScsiCommandCode.Scan, 12, 0, Command.CmdDirection.None, 10)) { if (dir == ScanDirection.Reverse) cmd.SetCDB8(1, 0x10); cmd.SetCDB32(2, lba); cmd.SetCDB8(9, (byte)((byte)type << 6)); CommandStatus st = SendCommand(cmd); if (st != CommandStatus.Success) return st; } return CommandStatus.Success; }
/// <summary> /// /// </summary> /// <returns></returns> public CommandStatus SendCueSheet(byte [] sheet) { if (m_logger != null) { string args = sheet.ToString(); m_logger.LogMessage(new UserMessage(UserMessage.Category.Debug, 8, "Bwg.Scsi.Device.SendCueSheet(" + args + ")")); m_logger.LogMessage(new UserMessage(UserMessage.Category.Debug, 1, "Cue Sheet")); m_logger.LogMessage(new UserMessage(UserMessage.Category.Debug, 1, "----------------------------------------------")); for (int i = 0; i < sheet.GetLength(0) / 8; i++) { string s = "" ; for (int j = 0; j < 8; j++) { if (j != 0) s += " "; s += sheet[i * 8 + j].ToString("x2"); } m_logger.LogMessage(new UserMessage(UserMessage.Category.Debug, 1, s)); } m_logger.LogMessage(new UserMessage(UserMessage.Category.Debug, 1, "----------------------------------------------")); } ushort len = (ushort)sheet.GetLength(0); using (Command cmd = new Command(ScsiCommandCode.SendCueSheet, 10, len, Command.CmdDirection.Out, 10)) { cmd.SetCDB32(5, len); cmd.SetCDB8(5, 0); Marshal.Copy(sheet, 0, cmd.GetBuffer(), len); CommandStatus st = SendCommand(cmd); if (st != CommandStatus.Success) return st; } return CommandStatus.Success; }
/// <summary> /// /// </summary> /// <returns></returns> public CommandStatus ReadTrackInformation(ReadTrackType type, uint addr, out TrackInformation info) { info = null; if (m_logger != null) { string args = "info"; m_logger.LogMessage(new UserMessage(UserMessage.Category.Debug, 8, "Bwg.Scsi.Device.ReadTrackInformation(" + args + ")")); } using (Command cmd = new Command(ScsiCommandCode.ReadTrackInformation, 10, 48, Command.CmdDirection.In, 5 * 60)) { cmd.SetCDB8(1, (byte)type); cmd.SetCDB32(2, addr); cmd.SetCDB16(7, 40); CommandStatus st = SendCommand(cmd); if (st != CommandStatus.Success) return st; info = new TrackInformation(cmd.GetBuffer(), cmd.BufferSize); } return CommandStatus.Success; }
/// <summary> /// /// </summary> /// <returns></returns> public CommandStatus ReserveTrack(uint size) { if (m_logger != null) { string args = size.ToString(); m_logger.LogMessage(new UserMessage(UserMessage.Category.Debug, 8, "Bwg.Scsi.Device.ReserveTrack(" + args + ")")); } using (Command cmd = new Command(ScsiCommandCode.ReserveTrack, 10, 0, Command.CmdDirection.None, 5 * 60)) { cmd.SetCDB32(5, size); CommandStatus st = SendCommand(cmd); if (st != CommandStatus.Success) return st; } return CommandStatus.Success; }
/// <summary> /// This function instructs the device to erase blocks on the disk. /// </summary> /// <param name="immd">If true, return immediately and perform the function in the background</param> /// <param name="lba">The starting block address for the erase operation</param> /// <param name="count">The number of blocks to erase. If this count is zero, the ERA bit is set in the SCSI erase request</param> /// <returns></returns> public CommandStatus Erase(bool immd, uint lba, ushort count) { if (m_logger != null) { string args = immd.ToString() + ", " + lba.ToString() + ", " + count.ToString(); m_logger.LogMessage(new UserMessage(UserMessage.Category.Debug, 8, "Bwg.Scsi.Device.Erase(" + args + ")")); } using (Command cmd = new Command(ScsiCommandCode.Erase, 10, 0, Command.CmdDirection.None, 60 * 30)) { byte b = 0; if (immd) b |= 0x02; if (count == 0) b |= 0x04; cmd.SetCDB8(1, b); cmd.SetCDB32(2, lba); cmd.SetCDB16(7, count); CommandStatus st = SendCommand(cmd); if (st != CommandStatus.Success) return st; } return CommandStatus.Success; }
/// <summary> /// /// </summary> /// <returns></returns> public CommandStatus ReadDiskStructure(uint addr, byte layer, byte format, ref byte [] data) { if (m_logger != null) { string args = string.Empty; args += "addr=" + addr.ToString(); args += ", layer=" + layer.ToString(); args += ", format=" + format.ToString(); args += "ref byte[] data"; m_logger.LogMessage(new UserMessage(UserMessage.Category.Debug, 8, "Bwg.Scsi.Device.ReadDvdStructure(" + args + ")")); } using (Command cmd = new Command(ScsiCommandCode.ReadDvdStructure, 12, 2048, Command.CmdDirection.In, 60)) { cmd.SetCDB32(2, addr) ; // Address = 0 cmd.SetCDB8(6, layer); // Layer number = 0 cmd.SetCDB8(7, format); // Read manufacturing information cmd.SetCDB16(8, 2048); // Up to 2k of data CommandStatus st = SendCommand(cmd); if (st != CommandStatus.Success) return st; int len = data.GetLength(0); if (len > 2048) len = 2048; Marshal.Copy(cmd.GetBuffer(), data, 0, len); } return CommandStatus.Success; }
/// <summary> /// /// </summary> /// <param name="submode">subchannel mode</param> /// <param name="start"></param> /// <param name="length"></param> /// <param name="data">the memory area </param> /// <param name="timeout">timeout (in seconds)</param> /// <returns></returns> public CommandStatus ReadCDDA(SubChannelMode submode, uint start, uint length, IntPtr data, int timeout) { if (m_logger != null) { string args = start.ToString() + ", " + length.ToString() + ", data"; m_logger.LogMessage(new UserMessage(UserMessage.Category.Debug, 8, "Bwg.Scsi.Device.ReadCDDA(" + args + ")")); } byte mode = (byte)(submode == SubChannelMode.QOnly ? 1 : submode == SubChannelMode.RWMode ? 2 : 0); int size = 4 * 588 + (submode == SubChannelMode.QOnly ? 16 : submode == SubChannelMode.RWMode ? 96 : 0); using (Command cmd = new Command(ScsiCommandCode.ReadCDDA, 12, data, (int)length * size, Command.CmdDirection.In, timeout)) { cmd.SetCDB8(1, 0 << 5); // lun cmd.SetCDB32(2, start); cmd.SetCDB24(7, length); cmd.SetCDB8(10, mode); // Subchannel CommandStatus st = SendCommand(cmd); if (st != CommandStatus.Success) return st; } return CommandStatus.Success; }
/// <summary> /// This method requests that the SCSI device transfer data from the given buffer to the device /// </summary> /// <param name="force">If true, the data is forced from the media and cannot be read from the cache</param> /// <param name="streaming">If true, this is a streaming read</param> /// <param name="lba">The starting logical address for the data</param> /// <param name="sector_size">the size of the sector data in bytes</param> /// <param name="length">The length of the data to write in sectors</param> /// <param name="data">The data buffer to received the data</param> /// <returns></returns> public CommandStatus Write(bool force, bool streaming, int lba, int sector_size, int length, ref byte[] data) { if (m_logger != null) { string args = force.ToString() + ", " + streaming.ToString() + ", " + lba.ToString() + ", " + length.ToString() + ", buffer"; m_logger.LogMessage(new UserMessage(UserMessage.Category.Debug, 8, "Bwg.Scsi.Device.Write(" + args + ")")); } Debug.Assert(length == data.GetLength(0) * sector_size); fixed (byte *bptr = &data[0]) { IntPtr bufptr = new IntPtr(bptr); if (streaming || length > 65535) { using (Command cmd = new Command(ScsiCommandCode.Write12, 12, bufptr, length * sector_size, Command.CmdDirection.Out, 5 * 60)) { if (force) cmd.SetCDB8(1, 4); // Set the FUA bit cmd.SetCDB32(2, lba); cmd.SetCDB32(6, length); if (streaming) cmd.SetCDB8(10, 0x80); // Set the streaming bit CommandStatus st = SendCommand(cmd); if (st != CommandStatus.Success) return st; } } else { using (Command cmd = new Command(ScsiCommandCode.Write, 10, bufptr, length * sector_size, Command.CmdDirection.Out, 5 * 60)) { if (force) cmd.SetCDB8(1, 4); // Set the FUA bit cmd.SetCDB32(2, lba); cmd.SetCDB16(7, (ushort)length); CommandStatus st = SendCommand(cmd); if (st != CommandStatus.Success) return st; } } } return CommandStatus.Success; }
/// <summary> /// /// </summary> /// <param name="exp"></param> /// <param name="dap"></param> /// <param name="start"></param> /// <param name="length"></param> /// <param name="data">the memory area </param> /// <param name="size">the size of the memory area given by the data parameter</param> /// <returns></returns> public CommandStatus ReadCD(byte exp, bool dap, uint start, uint length, IntPtr data, int size) { if (m_logger != null) { string args = exp.ToString() + ", " + dap.ToString() + ", " + start.ToString() + ", " + length.ToString() + ", data, " + size.ToString(); m_logger.LogMessage(new UserMessage(UserMessage.Category.Debug, 8, "Bwg.Scsi.Device.ReadCD(" + args + ")")); } if (exp != 1 && exp != 2 && exp != 3 && exp != 4 && exp != 5) return CommandStatus.NotSupported; using (Command cmd = new Command(ScsiCommandCode.ReadCd, 12, data, size, Command.CmdDirection.In, 5 * 60)) { byte b = (byte)((exp & 0x07) << 2); if (dap) b |= 0x02; cmd.SetCDB8(1, b); cmd.SetCDB32(2, start); cmd.SetCDB24(6, length); cmd.SetCDB8(9, 0x10); // User data only CommandStatus st = SendCommand(cmd); if (st != CommandStatus.Success) return st; } return CommandStatus.Success; }
/// <summary> /// /// </summary> /// <param name="mainmode">main channel mode</param> /// <param name="submode">subchannel mode</param> /// <param name="c2mode">C2 errors report mode</param> /// <param name="exp">expected sector type</param> /// <param name="dap"></param> /// <param name="start"></param> /// <param name="length"></param> /// <param name="data">the memory area </param> /// <param name="timeout">timeout (in seconds)</param> /// <returns></returns> public CommandStatus ReadCDAndSubChannel(MainChannelSelection mainmode, SubChannelMode submode, C2ErrorMode c2mode, byte exp, bool dap, uint start, uint length, IntPtr data, int timeout) { if (m_logger != null) { string args = exp.ToString() + ", " + dap.ToString() + ", " + start.ToString() + ", " + length.ToString() + ", data"; m_logger.LogMessage(new UserMessage(UserMessage.Category.Debug, 8, "Bwg.Scsi.Device.ReadCD(" + args + ")")); } int size = (4 * 588 + (submode == SubChannelMode.QOnly ? 16 : submode == SubChannelMode.RWMode ? 96 : 0) + (c2mode == C2ErrorMode.Mode294 ? 294 : c2mode == C2ErrorMode.Mode296 ? 296 : 0)) * (int) length; byte mode = (byte) (submode == SubChannelMode.QOnly ? 2 : submode == SubChannelMode.RWMode ? 4 : 0); if (exp != 1 && exp != 2 && exp != 3 && exp != 4 && exp != 5) return CommandStatus.NotSupported; using (Command cmd = new Command(ScsiCommandCode.ReadCd, 12, data, size, Command.CmdDirection.In, timeout)) { byte b = (byte)((exp & 0x07) << 2); if (dap) b |= 0x02; byte byte9 = (byte)(mainmode == MainChannelSelection.UserData ? 0x10 : mainmode == MainChannelSelection.F8h ? 0xF8 : 0); if (c2mode == C2ErrorMode.Mode294) byte9 |= 0x02; else if (c2mode == C2ErrorMode.Mode296) byte9 |= 0x04; cmd.SetCDB8(1, b); cmd.SetCDB32(2, start); cmd.SetCDB24(6, length); cmd.SetCDB8(9, byte9); // User data + possibly c2 errors cmd.SetCDB8(10, mode); // Subchannel CommandStatus st = SendCommand(cmd); if (st != CommandStatus.Success) return st; } return CommandStatus.Success; }
/// <summary> /// This method requests that the SCSI device transfer data to the given buffer /// </summary> /// <param name="force">If true, the data is forced from the media and cannot be read from the cache</param> /// <param name="streaming">If true, this is a streaming read</param> /// <param name="lba">The starting logical address for the data</param> /// <param name="length">The length of the data to read</param> /// <param name="data">The data buffer to received the data</param> /// <returns></returns> public CommandStatus Read(bool force, bool streaming, uint lba, uint length, ref byte [] data) { if (m_logger != null) { string args = force.ToString() + ", " + streaming.ToString() + ", " + lba.ToString() + ", " + length.ToString() + ", buffer"; m_logger.LogMessage(new UserMessage(UserMessage.Category.Debug, 8, "Bwg.Scsi.Device.Read(" + args + ")")); } if (streaming || length > 65535) { using (Command cmd = new Command(ScsiCommandCode.Read12, 12, (ushort)data.GetLength(0), Command.CmdDirection.In, 5 * 60)) { if (force) cmd.SetCDB8(1, 4); // Set the FUA bit cmd.SetCDB32(2, lba); cmd.SetCDB32(6, length); if (streaming) cmd.SetCDB8(10, 0x80); // Set the streaming bit CommandStatus st = SendCommand(cmd); if (st != CommandStatus.Success) return st; Marshal.Copy(cmd.GetBuffer(), data, 0, data.GetLength(0)); } } else { using (Command cmd = new Command(ScsiCommandCode.Read, 10, (ushort)data.GetLength(0), Command.CmdDirection.In, 5 * 60)) { if (force) cmd.SetCDB8(1, 4); // Set the FUA bit cmd.SetCDB32(2, lba); cmd.SetCDB16(7, (ushort)length); CommandStatus st = SendCommand(cmd); if (st != CommandStatus.Success) return st; Marshal.Copy(cmd.GetBuffer(), data, 0, data.GetLength(0)); } } return CommandStatus.Success; }
/// <summary> /// This command requests that the SCSI device begins an audio playback operation. /// </summary> /// <param name="lba">The starting logical block address for the playback</param> /// <param name="length">The length of the disk to play</param> /// <returns></returns> public CommandStatus PlayAudio(uint lba, uint length) { if (m_logger != null) { string args = lba.ToString() + ", " + length.ToString(); m_logger.LogMessage(new UserMessage(UserMessage.Category.Debug, 8, "Bwg.Scsi.Device.PlayAudio(" + args + ")")); } if (length > 65535) { using (Command cmd = new Command(ScsiCommandCode.PlayAudio12, 12, 0, Command.CmdDirection.None, 5)) { cmd.SetCDB32(2, lba); cmd.SetCDB32(6, length); CommandStatus st = SendCommand(cmd); if (st != CommandStatus.Success) return st; } } else { using (Command cmd = new Command(ScsiCommandCode.PlayAudio10, 10, 0, Command.CmdDirection.None, 5)) { cmd.SetCDB32(2, lba); cmd.SetCDB16(7, (ushort)length); CommandStatus st = SendCommand(cmd); if (st != CommandStatus.Success) return st; } } return CommandStatus.Success; }
/// <summary> /// /// </summary> /// <returns></returns> public CommandStatus GetPerformance(uint lba, PerformanceList.DataType rwtype, PerformanceList.ExceptType extype, out PerformanceList list) { list = null; if (m_logger != null) { string args = rwtype.ToString() + ", " + extype.ToString() + ", list"; m_logger.LogMessage(new UserMessage(UserMessage.Category.Debug, 8, "Bwg.Scsi.Device.GetPerformance(" + args + ")")); } uint len = 0; using (Command cmd = new Command(ScsiCommandCode.GetPerformance, 12, 24, Command.CmdDirection.In, 10)) { byte b = 0x10; if (rwtype == PerformanceList.DataType.WriteData) b |= 0x04 ; b |= (byte)extype; cmd.SetCDB8(1, b); cmd.SetCDB16(8, 1); if (extype == PerformanceList.ExceptType.Entire) cmd.SetCDB32(2, lba); CommandStatus st = SendCommand(cmd); if (st != CommandStatus.Success) return st; len = cmd.GetBuffer32(0); len += 4; // For the length field } using (Command cmd = new Command(ScsiCommandCode.GetPerformance, 12, (ushort)len, Command.CmdDirection.In, 10)) { byte b = 0x10; if (rwtype == PerformanceList.DataType.WriteData) b |= 0x04; b |= (byte)extype; cmd.SetCDB8(1, b); if (extype == PerformanceList.ExceptType.Entire) cmd.SetCDB32(2, lba); cmd.SetCDB16(8, (ushort)((len - 8) / 16)); CommandStatus st = SendCommand(cmd); if (st != CommandStatus.Success) return st; list = new PerformanceList(cmd.GetBuffer(), cmd.BufferSize); } return CommandStatus.Success; }
/// <summary> /// /// </summary> /// <returns></returns> public CommandStatus SetReadAhead(uint trigger, uint lba) { if (m_logger != null) { string args = trigger.ToString() + ", " + lba.ToString(); m_logger.LogMessage(new UserMessage(UserMessage.Category.Debug, 8, "Bwg.Scsi.Device.SetReadAhead(" + args + ")")); } using (Command cmd = new Command(ScsiCommandCode.SetReadAhead, 12, 0, Command.CmdDirection.None, 2)) { cmd.SetCDB32(2, trigger); cmd.SetCDB32(6, lba); CommandStatus st = SendCommand(cmd); if (st != CommandStatus.Success) return st; } return CommandStatus.Success; }
/// <summary> /// This method reads subheader CD data from a data mode 2 track /// </summary> /// <param name="sector">the sector # of the data to read</param> /// <param name="hdr">return subheader data</param> /// <returns></returns> public CommandStatus ReadCD(uint sector, out SubheaderData hdr) { hdr = null ; if (m_logger != null) { string args = sector.ToString() + ", out SubheaderData hdr"; m_logger.LogMessage(new UserMessage(UserMessage.Category.Debug, 8, "Bwg.Scsi.Device.ReadCD(" + args + ")")); } using (Command cmd = new Command(ScsiCommandCode.ReadCd, 12, 4, Command.CmdDirection.In, 10)) { cmd.SetCDB32(2, sector); cmd.SetCDB24(6, 1); cmd.SetCDB8(9, 0x40); // Header data only CommandStatus st = SendCommand(cmd); if (st != CommandStatus.Success) return st; hdr = new SubheaderData(cmd.GetBuffer(), cmd.BufferSize); } return CommandStatus.Success; }
/// <summary> /// /// </summary> /// <returns></returns> public CommandStatus Verify(int start, int size) { if (m_logger != null) { string args = start.ToString() + ", " + size.ToString(); m_logger.LogMessage(new UserMessage(UserMessage.Category.Debug, 8, "Bwg.Scsi.Device.Verify(" + args + ")")); } using (Command cmd = new Command(ScsiCommandCode.Verify, 10, 2048, Command.CmdDirection.None, 60 * 60)) { cmd.SetCDB32(2, (uint)start); cmd.SetCDB16(7, (ushort)size); CommandStatus st = SendCommand(cmd); if (st != CommandStatus.Success) return st; } return CommandStatus.Success; }
/// <summary> /// Read the subchannel data from a series of sectors /// </summary> /// <param name="sector"></param> /// <param name="length"></param> /// <param name="data"></param> /// <param name="mode">the subchannel mode</param> /// <param name="timeout">timeout (in seconds)</param> /// <returns></returns> public CommandStatus ReadSubChannel(byte mode, uint sector, uint length, ref byte[] data, int timeout) { byte bytes_per_sector; if (m_logger != null) { string args = sector.ToString() + ", " + length.ToString() + ", data"; m_logger.LogMessage(new UserMessage(UserMessage.Category.Debug, 8, "Bwg.Scsi.Device.ReadSubChannel(" + args + ")")); } if (mode != 1 && mode != 2 && mode != 4) throw new Exception("invalid read mode for ReadSubchannel() call"); bytes_per_sector = 96; if (mode == 2) bytes_per_sector = 16; if (data.GetLength(0) < length * bytes_per_sector) throw new Exception("data buffer is not large enough to hold the data requested"); using (Command cmd = new Command(ScsiCommandCode.ReadCd, 12, (int)(length * bytes_per_sector), Command.CmdDirection.In, timeout)) { byte b = (byte)(1 << 2); cmd.SetCDB8(1, b); cmd.SetCDB32(2, sector); // The sector number to start with cmd.SetCDB24(6, length); // The length in sectors cmd.SetCDB8(10, mode); // Corrected, de-interleaved P - W data CommandStatus st = SendCommand(cmd); if (st != CommandStatus.Success) return st; Marshal.Copy(cmd.GetBuffer(), data, 0, (int)(length * bytes_per_sector)); } return CommandStatus.Success ; }
/// <summary> /// Write data to the device into a memory buffer /// </summary> /// <param name="force">If true, the data is forced from the media and cannot be read from the cache</param> /// <param name="streaming">If true, this is a streaming read</param> /// <param name="lba">The starting logical address for the data</param> /// <param name="sector_size">the size of a sector in bytes</param> /// <param name="length">The length of the data to write in sectors</param> /// <param name="data">The buffer to receive the data</param> /// <returns></returns> public CommandStatus Write(bool force, bool streaming, int lba, int sector_size, int length, IntPtr data) { if (m_logger != null) { string args = force.ToString() + ", " + streaming.ToString() + ", " + lba.ToString() + ", " + length.ToString() + ", IntPtr, "; m_logger.LogMessage(new UserMessage(UserMessage.Category.Debug, 8, "Bwg.Scsi.Device.Write(" + args + ")")); } if (streaming || length > 65535) { using (Command cmd = new Command(ScsiCommandCode.Write12, 12, data, length * sector_size, Command.CmdDirection.Out, 5 * 60)) { if (force) cmd.SetCDB8(1, 4); // Set the FUA bit cmd.SetCDB32(2, lba); cmd.SetCDB32(6, length); if (streaming) cmd.SetCDB8(10, 0x80); CommandStatus st = SendCommand(cmd); if (st != CommandStatus.Success) { m_logger.LogMessage(new UserMessage(UserMessage.Category.Debug, 4, "Write failed at lba " + lba.ToString())); return st; } } } else { using (Command cmd = new Command(ScsiCommandCode.Write, 10, data, length * sector_size, Command.CmdDirection.Out, 5 * 60)) { if (force) cmd.SetCDB8(1, 4); // Set the FUA bit cmd.SetCDB32(2, lba); cmd.SetCDB16(7, (ushort)length); CommandStatus st = SendCommand(cmd); if (st != CommandStatus.Success) { m_logger.LogMessage(new UserMessage(UserMessage.Category.Debug, 4, "Write failed at lba " + lba.ToString())); return st; } } } return CommandStatus.Success; }
/// <summary> /// This function blanks a portion of the CD or DVD that is in the drive. /// </summary> /// <param name="immd"></param>If true, this function returns immediately and the blanking /// happens in the backgroun. If false, this funtion does not return until the blanking operation /// is complete /// <param name="t"></param>The type of blanking operation /// <param name="addr"></param>The address for the blanking operation if an address is required /// <returns> /// Success - the command complete sucessfully /// IoctlFailed - the windows DeviceIoControl failed, LastError give the Win32 error code /// DeviceFailed - the device failed the command, the sense information has more data /// </returns> public CommandStatus Blank(bool immd, BlankType t, int addr) { if (m_logger != null) { string args = immd.ToString() + ", " + t.ToString() + ", " + addr.ToString(); m_logger.LogMessage(new UserMessage(UserMessage.Category.Debug, 8, "Bwg.Scsi.Device.Blank(" + args + ")")); } using (Command cmd = new Command(ScsiCommandCode.Blank, 12, 0, Command.CmdDirection.None, 60*30)) { byte b = (byte)t; if (immd) b |= (1 << 4); cmd.SetCDB8(1, b); cmd.SetCDB32(2, addr); CommandStatus st = SendCommand(cmd); if (st != CommandStatus.Success) return st; } return CommandStatus.Success; }