⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 scsiunit.pas

📁 用于CD/DVD烧录的Delphi源码,包括source和demo
💻 PAS
📖 第 1 页 / 共 5 页
字号:
    if (Buf[7] and $20) <> 0 then
      Include(Capabilities, SDCwideBus16);
    if (Buf[7] and $10) <> 0 then
      Include(Capabilities, SDCsynchTransfer);
    if (Buf[7] and $08) <> 0 then
      Include(Capabilities, SDClinkedCommands);
    if (Buf[7] and $04) <> 0 then
      Include(Capabilities, SDCtransferDisable);
    if (Buf[7] and $02) <> 0 then
      Include(Capabilities, SDCcommandQueuing);
    ASPIstrCopy(PChar(@Buf[8]), VendorID, 8);
    ASPIstrCopy(PChar(@Buf[16]), ProductID, 16);
    ASPIstrCopy(PChar(@Buf[32]), ProductRev, 4);
    ASPIstrCopy(PChar(@Buf[36]), VendorSpecific, 20);

  end;
end;

function SCSIpreventMediumRemoval(DeviceID: TCDBurnerInfo;
  MustLock: boolean; var Sdf: TScsiDefaults): TScsiError;
var
  cdb: TCDB6;
begin
  FillChar(cdb, 6, 0);
  cdb[0] := SCSI_MED_REMOVL; {command, No Remove}
  cdb[1] := AttachLUN(cdb[1], DeviceID.DriveID);
  cdb[4] := ORD(MustLock);
  cdb[5] := 0;
  Result := ASPIsend6CDB(DeviceID, CDB, nil, 0, SRB_NODIR, Sdf);
end;

function SCSIadrByteToSubQinfoFlags(Arg: BYTE): TScsiSubQinfoFlags;
begin
  case Arg shr 4 of
    0: Result := [ssqfADRnone];
    1: Result := [ssqfADRposition];
    2: Result := [ssqfADRcatalogue];
    3: Result := [ssqfADRISRC]
  else
    Result := [];
  end;
  if (Arg and 1) <> 0 then
    Include(Result, ssqfPreEmphasis);
  if (Arg and 2) <> 0 then
    Include(Result, ssqfCopyPermit);
  case (Arg shr 2) and 3 of
    0: Include(Result, ssqfAudioTrack);
    1: Include(Result, ssqfDataTrack);
    2:
      begin
        Include(Result, ssqfAudioTrack);
        Include(Result, ssqfQuadAudio);
      end;
  end;
end;

function SCSIseek10(DeviceID: TCDBurnerInfo; GLBA: DWORD; var Sdf:
  TScsiDefaults): TScsiError;
var
  CDB: TCDB10;
begin
  FillChar(cdb, 10, 0);
  cdb[0] := SCSI_SEEK10;
  cdb[1] := AttachLUN(cdb[1], DeviceID.DriveID);
  FillDWORD(GLBA, cdb[2]);
  Result := ASPIsend10CDB(DeviceID, CDB, nil, 0, SRB_DIR_IN, Sdf);
end;

function SCSIreadCapacity(DeviceID: TCDBurnerInfo;
  var LastLBA: DWORD; var Sdf: TScsiDefaults): TScsiError;
var
  Buf: array[0..1] of DWORD;
  CDB: TCDB10;
begin
  //cdr CDB:  25 00 00 00 00 00 00 00 00 00
  FillChar(Buf, sizeof(Buf), 0);
  FillChar(cdb, 10, 0);
  cdb[0] := SCSI_RD_CAPAC;
  cdb[1] := AttachLUN(cdb[1], DeviceID.DriveID);
  FillWORD(SizeOf(Buf), cdb[7]);
  Result := ASPIsend10CDB(DeviceID, CDB, @Buf, SizeOf(Buf), SRB_DIR_IN, Sdf);
  LastLBA := BigEndianD(Buf[0]);
end;

function SCSIreadTocPmaAtipEx(DeviceID: TCDBurnerInfo;
  InMSF: boolean;
  RequestType: BYTE;
  TrackNumber: BYTE;
  Buf: pointer; BufLen: WORD;
  var Sdf: TScsiDefaults): TScsiError;
var
  Byte1: BYTE;
  DwLBA: DWORD;
  CDB: TCDB10;
begin
  FillChar(cdb, 10, 0);
  if InMSF then
    Byte1 := 2
  else
    Byte1 := 0;
  DwLBA := RequestType shl 24;

  cdb[0] := SCSI_READ_TOC;
  cdb[1] := AttachLUN(Byte1, DeviceID.DriveID);
  FillDWORD(DwLBA, cdb[2]);
  cdb[6] := TrackNumber;
  FillWORD(BufLen, cdb[7]);
  Result := ASPIsend10CDB(DeviceID, CDB, Buf, BufLen, SRB_DIR_IN, Sdf);
end;

function SCSIgetTOC(DeviceID: TCDBurnerInfo; var TOC: TScsiTOC; var Sdf:
  TScsiDefaults): TScsiError;

var
  Buf: TScsiTOCtemplate;
  i: integer;
begin
  FillChar(TOC, SizeOf(TOC), 0);
  Result := SCSIreadTocPmaAtipEx(DeviceID, False, 0, 0, @Buf, SizeOf(Buf), Sdf);
  TOC.FirstTrack := Buf.FirstTrack;
  TOC.LastTrack := Buf.LastTrack;
  TOC.TrackCount := (BigEndianW(Buf.Length) div
    SizeOf(TScsiTrackDescriptorTemplate));
  for i := 0 to Toc.TrackCount - 1 do
  begin
    TOC.Tracks[i].Flags := SCSIadrByteToSubQinfoFlags(Buf.Tracks[i].ADR);
    TOC.Tracks[i].TrackNumber := Buf.Tracks[i].TrackNumber;
    TOC.Tracks[i].AbsAddress := BigEndianD(Buf.Tracks[i].AbsAddress);
  end;
end;

function SCSIgetTOCCDText(DeviceID: TCDBurnerInfo; var TOCText: TCDText; var
  Sdf: TScsiDefaults): TScsiError;
begin
  FillChar(TOCText, SizeOf(TOCText), 0);
  Result := SCSIreadTocPmaAtipEx(DeviceID, False, $05, 0, @TOCText,
    SizeOf(TOCText), Sdf);
end;

function SCSIgetSessionInfo(DeviceID: TCDBurnerInfo;
  var Info: TScsiSessionInfo;
  var Sdf: TScsiDefaults): TScsiError;
var
  Buf: TScsiSessionInfoTemplate;
begin
  FillChar(Info, SizeOf(Info), 0);
  Result := SCSIreadTocPmaAtipEx(DeviceID, False, 1, 0, @Buf, SizeOf(Buf), Sdf);
  Info.Flags := SCSIadrByteToSubQinfoFlags(Buf.ADR);
  Info.FirstSession := Buf.FirstSession;
  Info.LastSession := Buf.LastSession;
  Info.FirstTrack := Buf.TrackNumber;
  Info.FirstTrackLBA := BigEndianD(Buf.AbsAddress);
end;

{$WARNINGS OFF}

function SCSIgetLayoutInfo(DeviceID: TCDBurnerInfo;
  var Info: TDiscLayout;
  var Sdf: TScsiDefaults): TScsiError;
var
  TempSessions: TScsiSessionInfo;
  TempTracks: TScsiTOC;
  TrackInformation, TrackInfoNext: TTrackInformation;
  BlockSize, Counter: Integer;
  TrackNo, SessionNo, Reminder: integer;
  TrStart, TrLength, TrEnd, TrSize: Integer;

begin
  SCSIgetSessionInfo(DeviceID, TempSessions, SDF);
  SetLength(Info.Sessions, TempSessions.LastSession + 1);
  Info.FirstSession := TempSessions.FirstSession;
  Info.LastSession := TempSessions.LastSession;

  SCSIgetTOC(DeviceID, TempTracks, SDF);
  BlockSize := ConvertDataBlock(MODE_1);
  Reminder := 1;

  for Counter := TempTracks.FirstTrack to TempTracks.LastTrack do
  begin
    SCSIReadTrackInformation(DeviceID, Counter, TrackInformation, SDF);
    SessionNo := TrackInformation.SessionNumber;
    if SessionNo > Reminder then
    begin
      Reminder := SessionNo;
      TrackNo := 1;
    end
    else
      TrackNo := Counter;

    if TrackInformation.TrackMode = $00 then { Audio }
    begin
      BlockSize := ConvertDataBlock(RAW_DATA_BLOCK); //BLOCK_AUDIO;
      Info.Sessions[SessionNo].Tracks[TrackNo].fType := BlockSize;
      Info.Sessions[SessionNo].Tracks[TrackNo].fTypeStr := 'Audio';
    end;
    if TrackInformation.TrackMode = $04 then { Data }
    begin
      if TrackInformation.DataMode = $01 then { Data Mode 1 }
      begin
        BlockSize := ConvertDataBlock(MODE_1);
        Info.Sessions[SessionNo].Tracks[TrackNo].fType := BlockSize;
        Info.Sessions[SessionNo].Tracks[TrackNo].fTypeStr := 'Data (Mode 1)';
      end;
      if TrackInformation.DataMode = $02 then { Data Mode 2 }
      begin
        BlockSize := ConvertDataBlock(MODE_2);
        Info.Sessions[SessionNo].Tracks[TrackNo].fType := BlockSize;
        Info.Sessions[SessionNo].Tracks[TrackNo].fTypeStr := 'Data (Mode 2)';
      end;
    end;

    TrStart := TrackInformation.TrackStartAddress;
    TrLength := TrackInformation.TrackSize;
    if SCSIReadTrackInformation(DeviceID, Counter + 1, TrackInfoNext, SDF) =
      Err_None then
      if TrackInformation.SessionNumber = TrackInfoNext.SessionNumber then
        TrLength := TrackInfoNext.TrackStartAddress -
          TrackInformation.TrackStartAddress;

    TrEnd := TrStart + TrLength;

    TrSize := LBA2MB(TrLength, BlockSize);

    Info.Sessions[SessionNo].fSize := Info.Sessions[SessionNo].fSize + TrLength;
    Info.Sessions[SessionNo].fSizeMB := LBA2MB(Info.Sessions[SessionNo].fSize,
      BlockSize);
    Info.Sessions[SessionNo].FirstTrack := 1;
    Info.Sessions[SessionNo].LastTrack := TrackNo;
    Info.Sessions[SessionNo].Tracks[TrackNo].StartAddress := TrStart;
    Info.Sessions[SessionNo].Tracks[TrackNo].Length := TrLength;
    Info.Sessions[SessionNo].Tracks[TrackNo].EndAddress := TrEnd;
    Info.Sessions[SessionNo].Tracks[TrackNo].fSizeMB := TrSize;
    Info.Sessions[SessionNo].Tracks[TrackNo].StartAddressStr :=
      LBA2HMSF(TrStart);
    Info.Sessions[SessionNo].Tracks[TrackNo].LengthStr := LBA2HMSF(TrLength);
    Info.Sessions[SessionNo].Tracks[TrackNo].EndAddressStr := LBA2HMSF(TrEnd);
  end; //track loop
end;
{$WARNINGS ON}

function SCSIreadHeaderEx(DeviceID: TCDBurnerInfo;
  InMSF: boolean; // Form of GLBA as result
  var GLBA: DWORD; // at enter: LBA to read, at exit: address of
  //   block processed, in LBA (InMSF=False) or
  //   MSF (InMSF=True) form.
  var SectorType: TScsiReadCdSectorType; // type of block, may
  // be csfAudio, csfDataMode1, csfDataMode2,
  // or csfAnyType (if error occurs) only
  var Sdf: TScsiDefaults): TScsiError;
var
  Buf: array[0..1] of DWORD;
  Byte1: BYTE;
  CDB: TCDB10;
begin
  FillChar(Buf, sizeof(Buf), 0);
  FillChar(cdb, 10, 0);
  if InMSF then
    Byte1 := 2
  else
    Byte1 := 0;

  cdb[0] := SCSI_READHEADER;
  cdb[1] := AttachLUN(Byte1, DeviceID.DriveID);
  FillDWORD(GLBA, cdb[2]);
  cdb[6] := 0;
  FillWORD(SizeOf(Buf), cdb[7]);
  cdb[9] := 0;

  Result := ASPIsend10CDB(DeviceID, CDB, @Buf, SizeOf(Buf), SRB_DIR_IN, Sdf);

  case Buf[0] and $FF of
    0: SectorType := csfAudio;
    1: SectorType := csfDataMode1;
    2: SectorType := csfDataMode2
  else
    SectorType := csfAnyType;
  end;
  GLBA := BigEndianD(Buf[1]);
end;

function SCSIreadHeader(DeviceID: TCDBurnerInfo; GLBA: DWORD;
  var SectorType: TScsiReadCdSectorType; // type of block, may
  // be csfAudio, csfDataMode1, csfDataMode2,
  // or csfAnyType (if error occurs) only
  var Sdf: TScsiDefaults): TScsiError;
var
  iLBA: Cardinal;
begin
  iLBA := GLBA;
  Result := SCSIreadHeaderEx(DeviceID, False, iLBA, SectorType, Sdf);
end;

function SCSIreadSubChannelEx(DeviceID: TCDBurnerInfo;
  InMSF: boolean; // Form of resulting GLBA
  GetSubQ: boolean; // requests the Q sub-channel data if True
  RequestType: BYTE;
  TrackNumber: BYTE;
  Buf: pointer; BufLen: DWORD;
  var Sdf: TScsiDefaults): TScsiError;
var
  Byte1: BYTE;
  DwLBA: DWORD;
  CDB: TCDB10;
begin
  FillChar(Buf^, BufLen, 0);
  FillChar(cdb, 10, 0);
  if InMSF then
    Byte1 := 2
  else
    Byte1 := 0;
  DwLBA := RequestType shl 16;
  if GetSubQ then
    DwLBA := DwLBA or $40000000;

  cdb[0] := SCSI_SUBCHANNEL;
  cdb[1] := AttachLUN(Byte1, DeviceID.DriveID);
  FillDWORD(DwLBA, cdb[2]);
  cdb[6] := TrackNumber;
  FillWORD(SizeOf(Buf), cdb[7]);
  cdb[9] := 0;

  Result := ASPIsend10CDB(DeviceID, CDB, @Buf, SizeOf(Buf), SRB_DIR_IN, Sdf);

end;

{function SCSIread10EX(DeviceID: TCDBurnerInfo;
  DisablePageOut, ForceUnitAccess: boolean;
  GLBA, SectorCount: DWORD; Buf: pointer; BufLen: DWORD;
  var Sdf: TScsiDefaults): TScsiError;
var
  Arg1: byte;
  SdfTemp: DWORD;
  CDB: TCDB10;
begin
  FillChar(cdb, 10, 0);
  Arg1 := 0;
  if DisablePageOut then Arg1 := $10;
  if ForceUnitAccess then Arg1 := Arg1 or 8;
  SdfTemp := Sdf.Timeout;
  Sdf.Timeout := Sdf.ReadTimeout;

  cdb[0] := SCSI_READ10;
  cdb[1] := AttachLUN(Arg1, DeviceID.DriveID);
  FillDWORD(GLBA, cdb[2]);
  cdb[6] := 0;
  FillWORD(SectorCount, cdb[7]);
  cdb[9] := 0;
  Result := ASPIsend10CDB(DeviceID, CDB, Buf, SizeOf(Buf), SRB_DIR_IN, Sdf);
  Sdf.Timeout := SdfTemp;
end;   }

function SCSIread10EX(DeviceID : TCDBurnerInfo;
              DisablePageOut, ForceUnitAccess : boolean;
              GLBA, SectorCount : DWORD; Buf : pointer; BufLen : DWORD;
              var Sdf : TScsiDefaults) : TScsiError;
var Arg1    : byte;
    SdfTemp : DWORD;
begin
   Arg1 := 0;
   if DisablePageOut  then Arg1 := $10;
   if ForceUnitAccess then Arg1 := Arg1 OR 8;
   SdfTemp     := Sdf.Timeout;
   Sdf.Timeout := Sdf.ReadTimeout;
   Result := ASPIsend10(DeviceID, $28, Arg1, GLBA, 0, SectorCount,
                        Buf, BufLen, SRB_DIR_IN, Sdf);
   Sdf.Timeout := SdfTemp;
end;

function SCSIread10(DeviceID: TCDBurnerInfo;
  GLBA, SectorCount: DWORD; Buf: pointer; BufLen: DWORD;
  var Sdf: TScsiDefaults): TScsiError;
begin
  Result := SCSIread10EX(DeviceID, False, False,
    GLBA, SectorCount, Buf, BufLen, Sdf);
end;

function SCSIheaderByteToAudioStatus(Arg: BYTE): TScsiAudioStatus;
begin
  case Arg and $FF of
    0: Result := sasInvalid;
    $11: Result := sasPlay;
    $12: Result := sasPause;
    $13: Result := sasCompleted;
    $14: Result := sasError;
    $15: Result := sasStop;
  else
    Result := sasUnknown;
  end;
end;

function SCSIgetISRC(DeviceID: TCDBurnerInfo; TrackNumber: BYTE;
  var Info: TScsiISRC;
  var Sdf: TScsiDefaults): TScsiError;
var
  Buf: TScsiISRCTemplate;
  SdfTemp: DWORD;
begin
  FillChar(Info, SizeOf(Info), 0);
  SdfTemp := Sdf.Timeout;
  Sdf.Timeout := Sdf.ReadTimeout;
  Result := SCSIreadSubChannelEx(DeviceID, False, True, 3, TrackNumber,
    @Buf, SizeOf(Buf), Sdf);
  Sdf.Timeout := SdfTemp;
  Info.Status := SCSIheaderByteToAudioStatus(Buf.sitStatus);
  Info.Flags := SCSIadrByteToSubQinfoFlags(Buf.sitADR);
  if (Buf.sitValid and $80) <> 0 then
  begin // MCN is valid
    ASPIstrCopy(@Buf.sitNumber[0], Info.IsrcNumber, 12);
    Info.FrameNumber := Buf.sitAFrame;
  end;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -