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

📄 tcdbasic.pas

📁 使用ASPI读SCSI/IDE/ATAPI的CDROM数据或音乐磁道数据的程序
💻 PAS
📖 第 1 页 / 共 5 页
字号:
       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 + -