📄 tcdbasic.pas
字号:
GLBA : DWORD; Sectors : WORD) : BOOLEAN;
function SCSIsynchronizeCache(IMM : BOOLEAN;
GLBA : DWORD; Sectors : WORD) : BOOLEAN;
function SCSIlockUnlockCache(LOK : boolean;
GLBA : DWORD; Sectors : WORD) : BOOLEAN;
function SCSIreadLong(CORR : BOOLEAN; GLBA : DWORD;
Buf : pointer; BufLen : DWORD) : BOOLEAN;
function SCSIreadSubchannel(MSFform : BOOLEAN;
var Info : TCdRomSubQinfo) : BOOLEAN;
function SCSIreadToc(MSFform : BOOLEAN; Start : BYTE;
var Toc : TCdRomToc) : BOOLEAN;
function SCSIreadHeaderLBA(GLBA : DWORD;
var CDmode : BYTE; var Address : DWORD) : BOOLEAN;
function SCSIreadHeaderMSF(GLBA : DWORD;
var CDmode, AddressM, AddressS, AddressF : BYTE) : BOOLEAN;
function SCSImodeSelectEX(PF, SP : BOOLEAN;
Buf : pointer; BufLen : DWORD) : BOOLEAN;
function SCSImodeSelect(Buf : pointer; BufLen : DWORD) : BOOLEAN;
function SCSImodeSense(DBD : BOOLEAN; PCTL : TCdRomModePageType;
PAGE : BYTE; Buf : pointer; BufLen : DWORD) : BOOLEAN;
// The function set below have to describe all possible MODE SELECT
// and MODE SENSE implementations for various mode pages. Almost
// each function is in two forms - full-featured with 'EX' suffix
// in name, and shortened-form (without any suffixes).
// For now, the only MODE SENSE is implemented. It is necessary to
// manipulate with mode parameters highly carefull. I'm not ready
// yet. That's why.
// Unimplemented mode pages are:
// 02h Disconnect-reconnect page \
// 09h Peripheral device page > unuseful with ATAPI devices
// 0Ah Control mode page /
// 07h Verify error recovery page - verify command are not used
// 08h Caching page - do you need to control CD-ROM's cache?
function SCSImodeSenseHeader(var sh : TCdRomModeHeader) : BOOLEAN;
function SCSImodeSenseRecoverEX(PCTL: TCdRomModePageType;
var PSAV : BOOLEAN; var RLEV, RETR : BYTE) : BOOLEAN;
function SCSImodeSenseRecover(var RLEV, RETR : BYTE) : BOOLEAN;
function SCSImodeSenseMediumEX(PCTL : TCdRomModePageType;
var PSAV : BOOLEAN;
var Med1,Med2,Med3,Med4 : TCdRomMediumType) : BOOLEAN;
function SCSImodeSenseDeviceEX(PCTL : TCdRomModePageType;
var PSAV : BOOLEAN; var ITimer : BYTE;
var SperMunits, FperSunits : WORD) : BOOLEAN;
function SCSImodeSenseDevice(var ITimer : BYTE) : BOOLEAN;
function SCSImodeSenseAudioEX(PCTL : TCdRomModePageType;
var sh : TCdRomModePageAudio) : BOOLEAN;
function SCSImodeSenseAudio(var sh: TCdRomModePageAudio) : BOOLEAN;
{============== OPTIONAL AUDIO PLAYBACK COMMANDS =============}
function SCSIplayAudio10(GLBA : DWORD; Sectors : WORD) : BOOLEAN;
function SCSIplayAudio12(GLBA, Sectors : DWORD) : BOOLEAN;
function SCSIplayAudioMSF(StartM, StartS, StartF,
StopM, StopS, StopF : BYTE ) : BOOLEAN;
function SCSIplayAudioTI(StartTrack, StartIndex,
StopTrack, StopIndex : BYTE ) : BOOLEAN;
function SCSIplayAudioR10(TRLBA : DWORD;
StartTrack : BYTE; Sectors : WORD) : BOOLEAN;
function SCSIplayAudioR12(TRLBA : DWORD;
StartTrack : BYTE; Sectors : DWORD) : BOOLEAN;
function SCSIpauseAudio : BOOLEAN;
function SCSIresumeAudio : BOOLEAN;
property Locked : BOOLEAN read fLocked write SetLockUnlock;
end;
implementation
constructor TCdRom.Create;
begin
inherited Create(AOwner);
fLocked := FALSE;
end;
destructor TCdRom.Destroy;
begin
SetLockUnlock(FALSE); // Unlock the medium
SCSIlockUnlockCache(FALSE, 0, 0); // Unlock entire cache
inherited Destroy;
end;
procedure TCdRom.ChangeDevice(Value : TdeviceID);
begin
SetLockUnlock(FALSE); // Unlock the medium
SCSIlockUnlockCache(FALSE, 0, 0); // Unlock entire cache
inherited ChangeDevice(Value);
end;
{======================= MANDATORY SCSI-II COMMANDS ====================}
{ TEST UNIT READY command provides a means to check if the logical unit
is ready. This is not a request for a self-test. It is especially
useful to check cartridge status of logical units with removable media.
===================== Possible LastError codes: =========================
|Status|Sense key| ASC and ASCQ |LastError code(Err_..)
|------+---------+------------------------------------+---------------------|
| GOOD | --- | --- | None |
| BUSY | --- | --- | TargetBusy |
| RESERVATION CONFLICT --- | ReservationConflict |
|------+---------+------------------------------------+---------------------|
| CHECK| ILLEGAL | LOGICAL UNIT NOT SUPPORTED | SenseIllegalRequest |
|CONDI-| REQUEST | | |
| TION ----------+------------------------------------+---------------------|
| | NOT | LUN DOES NOT RESPOND TO SELECTION | SenseNotReady |
| | READY | MEDIUM NOT PRESENT | |
| | | LUN IS IN PROCESS OF BECOMING READY| |
| | | INIT COMMAND REQUIRED | |
| | | MANUAL INTERVENTION REQUIRED | |
| | | FORMAT IS IN PROGRESS | |
| | | LUN NOT READY,CAUSE NOT REPORTABLE | |
|------+---------+------------------------------------+---------------------|}
function TCdRom.SCSItestReady : BOOLEAN; //True if READY
begin result := ASPIsend6(0, 0, 0, NIL, 0, SRB_NODIR, ShortTimeout); end;
{ REQUEST SENSE command (code 03h) is fully implemented in ASPI layer.
If still need it, you got it below. }
function TCdRom.SCSIrequestSense(Pbuf : pointer; BufLen : BYTE) : BOOLEAN;
var I : DWORD;
begin
I := DWORD(BufLen) AND $FF;
result := ASPIsend6(3, 0, BufLen, PBuf, I, SRB_NODIR, ShortTimeout);
end;
{ INQUIRY command requests some parameters of the target and its attached
peripheral device(s). In the common case it seems like below.
More practical styled call is GetDeviceInfo included into TASPIdevice. }
function TCdRom.SCSIinquiry(Vital : BOOLEAN; CodePage : BYTE;
Pbuf : pointer; BufLen : BYTE) : BOOLEAN;
var I, J : DWORD;
begin
J := DWORD(CodePage) AND $FF;
if Vital then J := (J OR $100) SHL 8 else J := 0;
I := DWORD(BufLen) AND $FF;
result := ASPIsend6($12, J, BufLen, PBuf, I, SRB_NODIR, ShortTimeout);
end;
{ RESERVE and RELEASE commands define how different types of
restricted access may be achieved, and to whom the access is restricted.
Use reservations to gain a level of exclusivity in access to all or part
of the medium. It is expected that the reservation will be retained until
released. Partial medium reservation is excluded from this implementation
because it's not-so-useful and optional in SCSI-2 terms.
RESERVE requests that the entire logical unit be reserved for the
exclusive use until released by a RELEASE command or by a hard/soft RESET
condition. A reservation is not granted if the logical unit is reserved
by another task. If, after honouring the reservation, any other initiator
attempts to perform any command on the reserved LUN other than INQUIRY or
REQUEST SENSE, it shall be rejected with Err_SenseReservationConflict
status. }
function TCdRom.SCSIreserve : BOOLEAN;
begin result := ASPIsend6($16, 0,0, NIL,0, SRB_NODIR, ShortTimeout); end;
function TCdRom.SCSIrelease : BOOLEAN;
begin result := ASPIsend6($17, 0,0, NIL,0, SRB_NODIR, ShortTimeout); end;
{ The third-party reservation for RESERVE command allows to reserve
the logical unit for another SCSI device specified in the third-party
DeviceID field. This is intended for use in multiple-initiator systems
that use the COPY command. }
function TCdRom.SCSIreserve3rdParty(TrdPartyDeviceID: BYTE): BOOLEAN;
var I : DWORD;
begin
I := DWORD(TrdPartyDeviceID) AND 7; I := (I SHL 17) OR $100000;
result := ASPIsend6($16, I, 0, NIL, 0, SRB_NODIR, ShortTimeout);
end;
function TCdRom.SCSIrelease3rdParty(TrdPartyDeviceID: BYTE): BOOLEAN;
var I : DWORD;
begin
I := DWORD(TrdPartyDeviceID) AND 7; I := (I SHL 17) OR $100000;
result := ASPIsend6($17, I, 0, NIL, 0, SRB_NODIR, ShortTimeout);
end;
{ SelfSets is the mandatory subset implementation of SEND DIAGNOSTIC
command. SEND DIAGNOSTIC requests the target to perform diagnostic
operations on itself. Here is only mandatory implementation of this
command: self-test feature with the parameter list length of zero.
Full command implementation (with page structure) is OPTIONAL.
DOFF=TRUE (Device Off-line) and UOFF=TRUE (Unit Off-line) flags grant
permission to perform vendor-specific diagnostic operations on the
target that may be visible to attached initiators, e.g. writings
to the user accessible medium, or repositioning of the medium on
sequential access devices. Setting this flags FALSE prohibits all
diagnostic operations that may be detected by other I/O processes.}
function TCdRom.SCSIselfTest(DOFF, UOFF : BOOLEAN) : BOOLEAN;
var I : DWORD;
begin
I := $40000;
if DOFF then I := I OR $20000;
if UOFF then I := I OR $10000;
result := ASPIsend6($1D, I, 0, NIL, 0, SRB_NODIR, ShortTimeout);
end;
{ READ CAPACITY command returns logical block address and block length
(in bytes) of the last valid logical block of the logical unit for seek
operations. BlkCount may be greater (up to +75) than or equal to the
last readable or playable block. If greater, this address may be in a
transition area beyond the last valid logical block for read or audio
play operations because the CD-ROM TOC (table of contents) lead-out
track location has a +/- 75 sector tolerance when the lead-out track
is encoded as an audio track. }
function TCdRom.SCSIreadCapacity(var BlkCount, BlkSize : DWORD) : BOOLEAN;
var cd : array[0..1] of DWORD;
begin
FillChar(cd, sizeof(cd), 0);
result := ASPIsend10($25, 0,0,0,0, @cd,8, SRB_DIR_IN, ShortTimeout);
BlkCount := BigEndianD(cd[0]);
BlkSize := BigEndianD(cd[1]);
end;
{ READ CAPACITY command with enabled partial medium feature returns
logical block address and block length (in bytes) of the last logical
block address after which a substantial delay in data transfer will be
encountered. This logical block address shall be greater than or equal
to the logical block address specified in GLBA parameter.
On CD-ROM media, this is interpreted as being the last readable or
playable logical block beyond the specified GLBA.
NOTE: This option may take several seconds to complete. }
function TCdRom.SCSIreadCapacityPM(Partition : WORD; GLBA : DWORD;
var BlkCount, BlkSize : DWORD) : BOOLEAN;
var cd : array[0..1] of DWORD;
begin
FillChar(cd, sizeof(cd), 0);
result := ASPIsend10($25,0,GLBA,0,((Partition AND $7F) SHL 1) OR 1,
@cd, 8, SRB_DIR_IN, LongTimeout);
BlkCount := BigEndianD(cd[0]);
BlkSize := BigEndianD(cd[1]);
end;
{ READ(10) command requests data from the target.
DPO (Disable Page Out) flag is used to control replacement of logical
blocks in the device's cache memory when the host has information
on the future usage of the logical blocks.
DPO = TRUE indicates that the target shall assign the logical
blocks accessed the lowest caching priority. It overrides any
retention priority specified in the cache page. If the DPO = TRUE,
the host knows the logical blocks are not likely to be accessed
again in the near future and should not be put in the cache
memory nor retained by the cache memory.
DPO = FALSE means that the host expects that logical blocks
accessed by this command are likely to be accessed again in the
near future and the priority shall be determined by the retention
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -