📄 scsiunit.pas
字号:
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 + -