📄 tcdbasic.pas
字号:
priority fields in the cache page.
FUA (Force Unit Access) flag controls cache using too.
FUA = TRUE indicates that the target shall access the specified
logical blocks from the media (i.e. the data is not directly
retrieved from the cache).
FUA = FALSE means that any logical blocks that are contained in
the cache memory may be transferred directly from the cache memory.
GLBA is a number of first logical block to transfer.
Sectors is a number of contiguous logical blocks of data that shall be
transferred. A transfer length of zero indicates that no logical
blocks shall be transferred (this shall not be considered an error).
BufLen is the length of data buffer "Buf" in bytes. }
function TCdRom.SCSIread10(DPO,FUA: boolean; GLBA: DWORD; Sectors: WORD;
Buf : pointer; BufLen : DWORD) : BOOLEAN;
var Arg1 : byte;
begin
FillChar(Buf^, BufLen, 0);
Arg1 := 0; if DPO then Arg1:=$10; if FUA then Arg1:=Arg1 OR 8;
result := ASPIsend10($28, Arg1, GLBA, 0, Sectors,
Buf, BufLen, SRB_DIR_IN, MediumTimeout);
end;
{======================= OPTIONAL SCSI-II COMMANDS ====================}
{ REZERO UNIT command is used in some devices to position the actuator at
cylinder zero. Some devices return GOOD status without attempting any
action. }
function TCdRom.SCSIrezeroUnit : BOOLEAN;
begin result := ASPIsend6(1,0,0,NIL,0, SRB_NODIR, ShortTimeout); end;
{ START STOP UNIT command requests that the target enable or disable the
logical unit for media access operations. Targets that contain cache
memory shall implicitly perform a SYNCHRONIZE CACHE command for the
entire medium prior to executing the STOP UNIT command.
STRT=TRUE requests the LUN be made ready for use, STRT=FALSE - be stopped
(media cannot be accessed by the initiator).
LOEJ=TRUE enables medium to be loaded (STRT=TRUE) or ejected (STRT=FALSE)
LOEJ=FALSE requests that no medium action be taken.
IMM=TRUE indicates that status shall be returned as soon as the CDB has
been validated, else status shall be returned after the operation
is completed. }
function TCdRom.SCSIstartStopUnit(STRT, LOEJ, IMM : boolean) : BOOLEAN;
var
Arg1 : DWORD;
Arg2 : byte;
begin
Arg1 := 0; if IMM then Arg1 := $10000;
Arg2 := 0; if LOEJ then Arg2:=2; if STRT then Arg2:=Arg2 OR 1;
result := ASPIsend6($1B, Arg1, Arg2, NIL, 0,
SRB_NODIR, MediumTimeout);
end;
{ PREVENT ALLOW MEDIUM REMOVAL enables or disables the removal of the
medium in the unit. While prevention of medium removal condition is in
effect the target shall inhibit mechanisms that normally allow removal
of the medium by an operator. This mechanism is independent of device
reservations and the target shall not allow medium removal if any
initiator currently has medium removal prevented.
The prevention of medium removal shall terminate:
a) after all initiators that have medium removal prevented issue this
commands with a prevent bit of zero, and the target has successfully
performed a synchronize cache operation;
b) upon the receipt of a BUS DEVICE RESET message from any initiator;
c) upon a hard RESET condition.
NOTE: We will use it only as property's SET procedure. }
procedure TCdRom.SetLockUnlock(Value : boolean);
begin
if Value = fLocked then exit;
if Value then ASPIsend6($1E,0,1,NIL,0,SRB_NODIR, ShortTimeout)
else ASPIsend6($1E,0,0,NIL,0,SRB_NODIR, ShortTimeout);
fLocked := Value;
end;
{ SEEK(10) requests LUN seek to the specified logical block address. }
function TCdRom.SCSIseek10(GLBA : DWORD) : BOOLEAN;
begin
result := ASPIsend10($2B,0,GLBA,0,0,NIL,0,SRB_NODIR, MediumTimeout);
end;
{ PRE-FETCH requests that the target transfer the specified logical blocks
to the cache memory. No data shall be transferred to the initiator.
The target shall transfer to cache memory as many logical blocks as
will fit and may elect to not transfer logical blocks that already are
contained in the cache memory.
IMM=TRUE indicates that status shall be returned as soon as the CDB has
been validated, else status shall be returned after the operation
is completed.
GLBA and Sectors specifies the block range. Sectors=0 indicates that
all remaining logical blocks shall be within the range. }
function TCdRom.SCSIpreFetch(IMM : BOOLEAN;
GLBA : DWORD; Sectors : WORD) : BOOLEAN;
begin
if IMM then result := ASPIsend10($34, 2, GLBA, 0, Sectors,
NIL, 0, SRB_NODIR, ShortTimeout)
else result := ASPIsend10($34, 0, GLBA, 0, Sectors,
NIL, 0, SRB_NODIR, MediumTimeout);
end;
{ SYNCHRONIZE CACHE ensures that logical blocks in the cache memory,
within the specified range, have their most recent data value recorded
on the physical medium. If a more recent data value exists in the cache
memory than on the physical medium, then all data from the cache memory
shall be written to the physical medium. Logical blocks are not
necessarily removed from the cache memory as a result of the operation.
IMM=TRUE indicates that status shall be returned as soon as the CDB has
been validated, else status shall be returned after the operation
is completed. If IMM=TRUE and the target does not support it then
the command shall terminate with Err_SenseIllegalRequest status.
GLBA and Sectors specifies the block range. Sectors=0 indicates that
all remaining logical blocks shall be within the range. }
function TCdRom.SCSIsynchronizeCache(IMM : BOOLEAN;
GLBA : DWORD; Sectors : WORD) : BOOLEAN;
begin
if IMM then result := ASPIsend10($35, 2, GLBA, 0, Sectors, NIL, 0,
SRB_NODIR, ShortTimeout)
else result := ASPIsend10($35, 0, GLBA, 0, Sectors, NIL, 0,
SRB_NODIR, MediumTimeout);
end;
{ LOCK UNLOCK CACHE requests that the target disallow or allow logical
blocks within the specified range to be removed from the cache memory
by the target's cache replacement algorithm. Locked logical blocks may
be written to the medium when modified, but a copy of the modified
logical block shall remain in the cache memory. Multiple locks may be
in effect from more than one initiator. Locks from different initiators
may overlap. An unlock of an overlapped area does not release the lock
of another initiator.
LOK=TRUE means that any logical block in the specified range that is
currently present in the cache memory shall be locked into cache
memory. Only logical blocks that are already present in the cache
memory are actually locked. LOK=FALSE indicates that all logical
blocks in the specified range that are currently locked into the
cache memory shall be unlocked, but not necessarily removed.
GLBA and Sectors specifies the block range. Sectors=0 indicates that
all remaining logical blocks shall be within the range. }
function TCdRom.SCSIlockUnlockCache(LOK : boolean;
GLBA : DWORD; Sectors : WORD) : BOOLEAN;
var Arg1 : byte;
begin
if LOK then Arg1 := 2 else Arg1 := 0;
result := ASPIsend10($36, Arg1, GLBA, 0, Sectors, NIL, 0,
SRB_NODIR, ShortTimeout);
end;
{ READ LONG requests to transfer data to the initiator. This data is
vendor-specific, but shall include the data bytes and the ECC bytes
recorded on the medium. Any other bytes that can be corrected by ECC
should be included (e.g. data synchronization mark within the area
covered by ECC). All tranferred bytes should be in the same order as
they are on the media.
CORR=TRUE (Corrected) causes the data to be corrected by ECC before
being transferred to the initiator, CORR=FALSE causes a LB to be
read without any correction made by the target.
GLBA is a number of first logical block to transfer.
BufLen specifies the number of bytes of data that are available for
transfer. If it does not exactly match the available data length,
the target shall terminate the command with Err_SenseIllegalRequest
status. BufLen=0 indicates that no bytes shall be transferred and
shall not be considered an error. }
function TCdRom.SCSIreadLong(CORR : BOOLEAN; GLBA : DWORD;
Buf : pointer; BufLen : DWORD) : BOOLEAN;
var Arg1 : byte;
begin
FillChar(Buf^, BufLen, 0);
if CORR then Arg1 := 2 else Arg1 := 0;
result := ASPIsend10($3E, Arg1, GLBA, 0, BufLen,
Buf, BufLen, SRB_DIR_IN, MediumTimeout);
end;
{ READ SUB-CHANNEL requests the sub-channel data plus the state of audio
play operations. Sub-channel data returned by this command may be from
the last appropriate sector encountered by a current or previous media
accessing operation. When there is no current audio play operation, the
target may access the media to read the sub-channel data. The target is
responsible that the data returned are current and consistent.
MSFform=TRUE requests that MSF format be used for address fields, FALSE
requests to LBA format. }
function TCdRom.SCSIreadSubchannel(MSFform : BOOLEAN;
var Info : TCdRomSubQinfo) : BOOLEAN;
type SCSI_SubQinfo = packed record
Reserved : byte;
AudioStatus : byte;
DataLength : word; // byte-reversed
FormatCode : byte; // no matter
ControlAndADR : byte;
TrackNumber : byte;
IndexNumber : byte;
AbsoluteAddr : DWORD; // byte-reversed
RelativeAddr : DWORD; // byte-reversed
MCVal : byte; // if bit7=1 then UPC is valid
UPC : array[0..14] of char; // Media catalogue number(UPC/Bar code)
TCVal : byte; // if bit7=1 then ISRC is valid
ISRC : array[0..14] of char; // Track international standard
end; // recording code (ISRC)
var
Arg1, B : byte;
cd : SCSI_SubQinfo;
Len : WORD;
i : integer;
begin
FillChar(cd, sizeof(cd), 0);
if MSFform then Arg1 := 2 else Arg1 := 0;
result := ASPIsend10($42, Arg1, $40000000, 0, sizeof(cd),
@cd, sizeof(cd), SRB_DIR_IN, MediumTimeout);
Len := BigEndianW(cd.DataLength);
case cd.AudioStatus of
0 : Info.AudioStatus := AudioNone;
$11 : Info.AudioStatus := AudioPlay;
$12 : Info.AudioStatus := AudioPause;
$13 : Info.AudioStatus := AudioComplete;
$14 : Info.AudioStatus := AudioError;
$15 : Info.AudioStatus := AudioStop
else Info.AudioStatus := AudioInvalid;
end;
B := (cd.ControlAndADR SHR 4) AND $0F;
if B >= 4 then Info.ADR := ADRreserved
else Info.ADR := TsubchannelADRinfo(B);
Info.PreEmphasis := (cd.ControlAndADR AND 1) <> 0;
Info.CopyPermit := (cd.ControlAndADR AND 2) <> 0;
Info.DataTrack := (cd.ControlAndADR AND 4) <> 0;
Info.QuadAudio := (cd.ControlAndADR AND 8) <> 0;
Info.TrackNumber := cd.TrackNumber;
Info.IndexNumber := cd.IndexNumber;
Info.AbsAddress := BigEndianD(cd.AbsoluteAddr);
Info.RelAddress := BigEndianD(cd.RelativeAddr);
Info.UPC := ''; i := 0;
if (cd.MCVal AND $80) <> 0 then
while (i <= 14) AND (Len >= (i + 14)) do
begin Info.UPC := Info.UPC + cd.UPC[i]; i := i + 1; end;
Info.ISRC := ''; i := 0;
if (cd.TCVal AND $80) <> 0 then
while (i <= 14) AND (Len >= (i + 30)) do
begin Info.ISRC := Info.ISRC + cd.ISRC[i]; i := i + 1; end;
if Len < 12 then begin result := FALSE; exit; end;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -