ASPIUnit.pas
上传用户:wanyu_2000
上传日期:2021-02-21
资源大小:527k
文件大小:21k
源码类别:

DVD

开发平台:

Delphi

  1. {-----------------------------------------------------------------------------
  2.  Unit Name: ASPIUnit
  3.  Author:    Sergey Kabikov
  4.  Purpose:   ASPI Functions
  5.  History:   Functions by Sergey Kabikov based on his code ASPI Library
  6.       Rewritten by Dancemammal for the burning code
  7. -----------------------------------------------------------------------------}
  8. unit ASPIUnit;
  9. interface
  10. uses Windows, wnaspi32, Registry, SCSIDefs, SCSITypes, SysUtils;
  11. type
  12.   {CDB types for Aspi commands}
  13.   TCDB12 = array[0..11] of BYTE;
  14.   TCDB10 = array[0..9] of BYTE;
  15.   TCDB6 = array[0..5] of BYTE;
  16.   TScsiInt13info = packed record
  17.     Support,
  18.       DosSupport: BOOLEAN;
  19.     DriveNumber,
  20.       Heads,
  21.       Sectors: BYTE;
  22.   end;
  23. type
  24.   TAspiDeviceEnumCallBack
  25.     = function(Caller: pointer; Device: TCDBurnerInfo; FoundName: string):
  26.     boolean;
  27. type
  28.   TScsiDeviceType = (TSDDisk, TSDTape, TSDPrinter, TSDProcessor,
  29.     TSDWORM, TSDCDROM, TSDScanner, TSDOptical,
  30.     TSDChanger, TSDCommunication,
  31.     TSDInvalid, TSDAny, TSDOther);
  32. var
  33.   TScsiDeviceTypeName: array[TScsiDeviceType] of string = ('Disk Drive',
  34.     'Tape Drive', 'Printer', 'Processor', 'WORM Drive', 'CD-ROM Drive',
  35.     'Scanner', 'Optical Drive', 'Changer', 'Communication Device',
  36.     'Invalid', 'Any Type Device', 'Other Type Device');
  37. function ScatterCDDevice(CDDevice: DWORD; var Adapter, Target, Lun: byte): char;
  38. function CDDevicetoLetter(CDDevice: DWORD): char;
  39. procedure ScatterDWORD(Arg: DWORD; var b3, b2, b1, b0: byte);
  40. function GatherDeviceID(Adapter, Target, Lun: byte; Letter: char): TBurnerID;
  41. procedure FillWORD(Src: WORD; var Dst: BYTE);
  42. procedure FillDWORD(Src: DWORD; var Dst: BYTE);
  43. function AttachLUN(var Arg: BYTE; DeviceID: TBurnerID): BYTE;
  44. function ScatterDeviceID(DeviceID: TBurnerID;
  45.   var Adapter, Target, Lun: byte): char;
  46. function AspiEnumDevices(CallBack: TAspiDeviceEnumCallBack; Caller: pointer):
  47.   integer;
  48. function AspiCheck(Err: TScsiError): boolean;
  49. function AspiInstalled: Integer;
  50. function GetAdapterNumbers: Integer;
  51. function ASPIhaInquiry(HaId: BYTE; var sh: TScsiHAinfo): TScsiError;
  52. function GetCDRegName(ID, Target, LUN: Integer): string;
  53. function BigEndianW(Arg: WORD): WORD;
  54. function BigEndianD(Arg: DWORD): DWORD;
  55. procedure BigEndian(const Source; var Dest; Count: integer);
  56. function GatherWORD(b1, b0: byte): WORD;
  57. function GatherDWORD(b3, b2, b1, b0: byte): DWORD;
  58. procedure ASPIstrCopy(Src: PChar; var Dst: ShortString; Leng: Integer);
  59. procedure ASPIsetDeviceIDflag(var DeviceID: TBurnerID;
  60.   Flag: TAspiDeviceIDflag; Value: boolean);
  61. function ASPIgetDeviceType(DeviceID: TBurnerID;
  62.   var DeviceType: TScsiDeviceType): TScsiError;
  63. function ASPIgetDriveInt13info(DeviceID: TBurnerID;
  64.   var Info: TScsiInt13info): TScsiError;
  65. function ASPIgetDeviceIDflag(DeviceID: TBurnerID;
  66.   Flag: TAspiDeviceIDflag): boolean;
  67. function GetAspiErrorSense(Status, HaStat, TargStat: BYTE;
  68.   Sense: PscsiSenseInfo): TScsiError;
  69. procedure ASPIabortCommand(HaId: BYTE; Psrb: pointer);
  70. function ASPIsendScsiCommand(DeviceID: TCDBurnerInfo;
  71.   Pcdb: pointer; CdbLen: DWORD;
  72.   Pbuf: pointer; BufLen: DWORD;
  73.   Direction: DWORD; var Sdf: TScsiDefaults): TScsiError;
  74. function ASPIsend6CDB(DeviceID: TCDBurnerInfo; CDB: TCDB6; Pbuf: pointer;
  75.   BufLen: DWORD;
  76.   Direction: DWORD; var Sdf: TScsiDefaults): TScsiError;
  77. function ASPIsend10CDB(DeviceID: TCDBurnerInfo; CDB: TCDB10; Pbuf: pointer;
  78.   BufLen: DWORD;
  79.   Direction: DWORD; var Sdf: TScsiDefaults): TScsiError;
  80. function ASPIsend12CDB(DeviceID: TCDBurnerInfo; CDB: TCDB12; Pbuf: pointer;
  81.   BufLen: DWORD;
  82.   Direction: DWORD; var Sdf: TScsiDefaults): TScsiError;
  83. implementation
  84. uses SCSIUnit;
  85. function AspiInstalled: Integer;
  86. var
  87.   AspiStatus: Cardinal;
  88. begin
  89.   if WNASPI_LOADED then
  90.   begin
  91.     AspiStatus := GetASPI32SupportInfo;
  92.     if HIBYTE(LOWORD(AspiStatus)) = SS_COMP then
  93.     begin
  94.       // get number of host installed on the system
  95.       Result := LOBYTE(LOWORD(AspiStatus));
  96.     end
  97.     else
  98.       Result := -1
  99.   end
  100.   else
  101.     Result := -1
  102. end;
  103. function GetAspiError(Status, HaStat, TargStat: BYTE): TScsiError;
  104. begin
  105.   result := Err_Unknown;
  106.   case Status of
  107.     0, 1: result := Err_None;
  108.     2, 3: result := Err_Aborted;
  109.     $80: result := Err_InvalidRequest;
  110.     $81: result := Err_InvalidHostAdapter;
  111.     $82: result := Err_NoDevice;
  112.     $E0: result := Err_InvalidSrb;
  113.     $E1: result := Err_BufferAlign;
  114.     $E5: result := Err_AspiIsBusy;
  115.     $E6: result := Err_BufferTooBig;
  116.     4: case HaStat of
  117.         $09: result := Err_CommandTimeout;
  118.         $0B: result := Err_SrbTimeout;
  119.         $0D: result := Err_MessageReject;
  120.         $0E: result := Err_BusReset;
  121.         $0F: result := Err_ParityError;
  122.         $10: result := Err_RequestSenseFailed;
  123.         $11: result := Err_SelectionTimeout;
  124.         $12: result := Err_DataOverrun;
  125.         $13: result := Err_UnexpectedBusFree;
  126.         $14: result := Err_BusPhaseSequence;
  127.         $00: case TargStat of
  128.             0, 2: result := Err_CheckCondition;
  129.             $08: result := Err_TargetBusy;
  130.             $18: result := Err_TargetReservationConflict;
  131.             $28: result := Err_TargetQueueFull;
  132.           end;
  133.       end;
  134.   end;
  135. end;
  136. function AttachLUN(var Arg: BYTE; DeviceID: TBurnerID): BYTE;
  137. var
  138.   i, j, Lun: BYTE;
  139. begin
  140.   ScatterDeviceID(DeviceID, i, j, Lun);
  141.   Result := ((Lun and 7) shl 5) or (Arg and $1F);
  142. end;
  143. procedure FillWORD(Src: WORD; var Dst: BYTE);
  144. begin
  145.   BigEndian(Src, Dst, 2);
  146. end;
  147. procedure FillDWORD(Src: DWORD; var Dst: BYTE);
  148. begin
  149.   BigEndian(Src, Dst, 4);
  150. end;
  151. procedure ASPIstrCopy(Src: PChar; var Dst: ShortString; Leng: Integer);
  152. var
  153.   i: integer;
  154. begin
  155.   i := 0;
  156.   while (i < Leng) and (Src[i] >= ' ') do
  157.   begin
  158.     Dst[i + 1] := Src[i];
  159.     inc(i);
  160.   end;
  161.   while (i > 0) and (Dst[i] = ' ') do
  162.     Dec(i); // Trim it Right
  163.   Dst[0] := CHR(i);
  164. end;
  165. procedure ScatterDWORD(Arg: DWORD; var b3, b2, b1, b0: byte);
  166. begin
  167.   b3 := (Arg shr 24) and $FF;
  168.   b2 := (Arg shr 16) and $FF;
  169.   b1 := (Arg shr 8) and $FF;
  170.   b0 := Arg and $FF;
  171. end;
  172. function ScatterDeviceID(DeviceID: TBurnerID;
  173.   var Adapter, Target, Lun: byte): char;
  174. var
  175.   Res: BYTE;
  176. begin
  177.   ScatterDWORD(DeviceID, Adapter, Target, Lun, Res);
  178.   Result := CHR((Lun and $1F) or $40);
  179.   Lun := (Lun shr 5) and 7;
  180. end;
  181. function ScatterCDDevice(CDDevice: DWord; var Adapter, Target, Lun: byte): char;
  182. var
  183.   Res: BYTE;
  184. begin
  185.   ScatterDWORD(CDDevice, Adapter, Target, Lun, Res);
  186.   Result := CHR((Lun and $1F) or $40);
  187.   Lun := (Lun shr 5) and 7;
  188. end;
  189. function BigEndianW(Arg: WORD): WORD;
  190. begin
  191.   result := ((Arg shl 8) and $FF00) or
  192.     ((Arg shr 8) and $00FF);
  193. end;
  194. function BigEndianD(Arg: DWORD): DWORD;
  195. begin
  196.   result := ((Arg shl 24) and $FF000000) or
  197.     ((Arg shl 8) and $00FF0000) or
  198.     ((Arg shr 8) and $0000FF00) or
  199.     ((Arg shr 24) and $000000FF);
  200. end;
  201. procedure BigEndian(const Source; var Dest; Count: integer);
  202. var
  203.   pSrc, pDst: PChar;
  204.   i: integer;
  205. begin
  206.   pSrc := @Source;
  207.   pDst := PChar(@Dest) + Count;
  208.   for i := 0 to Count - 1 do
  209.   begin
  210.     Dec(pDst);
  211.     pDst^ := pSrc^;
  212.     Inc(pSrc);
  213.   end;
  214. end;
  215. function GatherWORD(b1, b0: byte): WORD;
  216. begin
  217.   result := ((WORD(b1) shl 8) and $FF00) or
  218.     ((WORD(b0)) and $00FF);
  219. end;
  220. {$WARNINGS OFF}
  221. function GatherDWORD(b3, b2, b1, b0: byte): DWORD;
  222. begin
  223.   result := ((LongInt(b3) shl 24) and $FF000000) or
  224.     ((LongInt(b2) shl 16) and $00FF0000) or
  225.     ((LongInt(b1) shl 8) and $0000FF00) or
  226.     ((LongInt(b0)) and $000000FF);
  227. end;
  228. {$WARNINGS ON}
  229. function CDDevicetoLetter(CDDevice: DWord): char;
  230. var
  231.   Adapter, Target, Lun: byte;
  232. begin
  233.   Result := ScatterCDDevice(CDDevice, Adapter, Target, Lun);
  234. end;
  235. function AspiCheck(Err: TScsiError): boolean;
  236. begin
  237.   Result := Err in [Err_None, Err_DataOverrun, Err_SenseRecoveredError];
  238. end;
  239. function GatherDeviceID(Adapter, Target, Lun: byte; Letter: char): TBurnerID;
  240. begin
  241.   Result := GatherDWORD(Adapter, Target,
  242.     ((Lun and 7) shl 5) or (ORD(Letter) and $1F), 0);
  243. end;
  244. function ASPIgetDeviceIDflag(DeviceID: TBurnerID;
  245.   Flag: TAspiDeviceIDflag): boolean;
  246. begin
  247.   Result := (DeviceID and (1 shl ORD(Flag))) <> 0;
  248. end;
  249. function GetAdapterNumbers: Integer;
  250. var
  251.   AspiStatus: DWord;
  252.   Adaptors: Byte;
  253. begin
  254.   try
  255.     AspiStatus := GetASPI32SupportInfo;
  256.     Adaptors := Lo(loword(AspiStatus));
  257.     Result := Adaptors;
  258.   except
  259.     Result := 0;
  260.   end;
  261. end;
  262. function GetCDRegName(ID, Target, LUN: Integer): string;
  263. var
  264.   DEVName: string;
  265.   Registry: TRegistry;
  266.   Root2000: string;
  267.   Root98: string;
  268.   FormatKey: string;
  269. begin
  270.   DEVName := 'Cannot Find Name';
  271.   Root2000 := 'HKEY_LOCAL_MACHINE';
  272.   Root98 := 'HKEY_LOCAL_MACHINEEnumScsi';
  273.   FormatKey := 'HARDWAREDEVICEMAPScsiScsi Port ' + inttostr(ID) +
  274.     'Scsi Bus 0Target Id ' + inttostr(Target) + 'Logical Unit Id ' +
  275.     inttostr(LUN);
  276.   Registry := TRegistry.Create;
  277.   Registry.RootKey := HKEY_LOCAL_MACHINE;
  278.   Registry.OpenKey(FormatKey, False);
  279.   DEVName := Registry.ReadString('Identifier');
  280.   Registry.Free;
  281.   Result := DEVName;
  282. end;
  283. function AspiEnumDevices(CallBack: TAspiDeviceEnumCallBack; Caller: pointer):
  284.   integer;
  285. var
  286.   DID: TCDBurnerInfo;
  287.   DIDtype: TScsiDeviceType;
  288.   Dadapter, Dtarget, Dlun, HAcount: BYTE;
  289.   HAinfo: TScsiHAinfo;
  290.   DevInfo: TScsiInt13info;
  291.   CDName: string;
  292.   //  ModeSenseBuf: array[0..255] of BYTE;
  293.   function TestModeSense: boolean;
  294.   begin
  295.     //      Result := Not AspiCheck(SCSImodeSense(DID, $3F, @ModeSenseBuf, 255, SCSI_Def));
  296.   end;
  297. begin
  298.   Result := 0;
  299.   HAcount := GetAdapterNumbers;
  300.   if HAcount = 0 {// no ASPI hosts, no devices} then
  301.   begin
  302.     Result := -1;
  303.     exit;
  304.   end;
  305.   for Dadapter := 0 to HAcount - 1 do
  306.     if ASPIhaInquiry(Dadapter, HAinfo) = Err_None then
  307.       for Dtarget := 0 to HAinfo.MaxTargetCount - 1 do
  308.         for Dlun := 0 to 7 do
  309.         begin
  310.           DID.DriveID := GatherDeviceID(Dadapter, Dtarget, Dlun, #0);
  311.           CDName := GetCDRegName(Dadapter, Dtarget, Dlun);
  312.           if ASPIgetDeviceType(DID.DriveID, DIDtype) = Err_None then
  313.             //if device exists
  314.             if (DIDtype = TSDCDROM) then
  315.             begin
  316.               if (ASPIgetDriveInt13info(DID.DriveID, DevInfo) = Err_None)
  317.                 and (DevInfo.DriveNumber > 0) then
  318.                 DID.DriveID := GatherDeviceID(Dadapter, Dtarget, Dlun,
  319.                   CHR(DevInfo.DriveNumber + $41));
  320.               if TestModeSense then
  321.               begin
  322.                 ASPIsetDeviceIDflag(DID.DriveID, ADIDmodeSense6, True);
  323.                 if TestModeSense then
  324.                 begin
  325.                   ASPIsetDeviceIDflag(DID.DriveID, ADIDmodeSense6, False);
  326.                   ASPIsetDeviceIDflag(DID.DriveID, ADIDmodeSenseDBD, True);
  327.                   if TestModeSense then
  328.                     ASPIsetDeviceIDflag(DID.DriveID, ADIDmodeSense6, True);
  329.                 end;
  330.               end;
  331.               if not CallBack(Caller, DID, CDName) then
  332.                 exit;
  333.               Inc(Result);
  334.             end;
  335.         end;
  336. end;
  337. procedure ASPIsetDeviceIDflag(var DeviceID: TBurnerID;
  338.   Flag: TAspiDeviceIDflag; Value: boolean);
  339. begin
  340.   if Value then
  341.     DeviceID := DeviceID or (1 shl ORD(Flag))
  342.   else
  343.     DeviceID := DeviceID and not (1 shl ORD(Flag));
  344. end;
  345. {$WARNINGS OFF}
  346. function ASPIgetDeviceType(DeviceID: TBurnerID;
  347.   var DeviceType: TScsiDeviceType): TScsiError;
  348. var
  349.   Gsrb: SRB_GetDeviceType;
  350. begin
  351.   FillChar(Gsrb, sizeof(Gsrb), 0);
  352.   Gsrb.SRB_Cmd := 1;
  353.   ScatterDeviceID(DeviceID, Gsrb.SRB_HaId, Gsrb.SRB_Target, Gsrb.SRB_Lun);
  354.   SendASPI32Command(@Gsrb);
  355.   Result := GetAspiError(Gsrb.SRB_Status, $FF, $FF);
  356.   if (Result = Err_None) and (Gsrb.SRB_DeviceType < ORD(TSDInvalid)) then
  357.     DeviceType := TScsiDeviceType(Gsrb.SRB_DeviceType)
  358.   else
  359.     DeviceType := TSDInvalid;
  360. end;
  361. {$WARNINGS ON}
  362. function ASPIgetDriveInt13info(DeviceID: TBurnerID;
  363.   var Info: TScsiInt13info): TScsiError;
  364. var
  365.   Isrb: SRB_Int13info;
  366. begin
  367.   FillChar(Isrb, sizeof(Isrb), 0);
  368.   with Isrb do
  369.   begin
  370.     SRB_Cmd := 6;
  371.     ScatterDeviceID(DeviceID, SRB_HaId, SRB_Target, SRB_Lun);
  372.   end;
  373.   SendASPI32Command(@Isrb);
  374.   with Info, Isrb do
  375.   begin
  376.     Result := GetAspiError(SRB_Status, $FF, $FF);
  377.     Support := (Result = Err_None) and ((SRB_DriveFlags and 3) <> 0);
  378.     DosSupport := (Result = Err_None) and ((SRB_DriveFlags and 1) <> 0);
  379.     DriveNumber := SRB_Int13Drive;
  380.     Heads := SRB_Heads;
  381.     Sectors := SRB_Sectors;
  382.   end;
  383. end;
  384. function ASPIhaInquiry(HaId: BYTE; var sh: TScsiHAinfo): TScsiError;
  385. var
  386.   Isrb: SRB_Inquiry;
  387. begin
  388.   FillChar(Isrb, sizeof(Isrb), 0);
  389.   Isrb.SRB_Cmd := 0;
  390.   Isrb.SRB_HaId := HaId;
  391.   SendASPI32Command(@Isrb);
  392.   with Isrb do
  393.   begin
  394.     Result := GetAspiError(SRB_Status, $FF, $FF);
  395.     sh.ScsiId := SRB_HA_SCSIID;
  396.     ASPIstrCopy(SRB_ManagerID, sh.ScsiManagerId, 16);
  397.     ASPIstrCopy(SRB_AdapterID, sh.HostAdapterId, 16);
  398.     sh.BufferAlignMask := SRB_BufAlign;
  399.     sh.ResidualSupport := (SRB_Residual and 2) <> 0;
  400.     if SRB_Targets = 0 then
  401.       sh.MaxTargetCount := 8
  402.     else
  403.       sh.MaxTargetCount := SRB_Targets;
  404.     sh.MaxTransferLength := SRB_TransfLen;
  405.   end;
  406. end;
  407. function ResetAspi(ID, Target, LUN: Integer): Boolean;
  408. var
  409.   AdaptorSRB: PSRB_GDEVBlock;
  410.   //  ASPI_Status: DWord;
  411. begin
  412.   //  result := False;
  413.   New(AdaptorSRB);
  414.   FillChar(AdaptorSRB^, Sizeof(SRB_HAInquiry), #0);
  415.   AdaptorSRB^.SRB_Cmd := SC_RESET_DEV;
  416.   AdaptorSRB^.SRB_HaId := ID;
  417.   AdaptorSRB^.SRB_Target := Target;
  418.   AdaptorSRB^.SRB_Lun := LUN;
  419.   AdaptorSRB^.SRB_Flags := 0;
  420.   AdaptorSRB^.SRB_Hdr_Rsvd := 0;
  421.   //  ASPI_Status :=
  422.   SendASPI32Command(AdaptorSRB);
  423.   if AdaptorSRB^.SRB_Status <> SS_COMP then
  424.     result := False
  425.   else
  426.     result := True;
  427.   Dispose(AdaptorSRB);
  428. end;
  429. function GetAdaptorName(ID: Integer): string;
  430. var
  431.   AdaptorSRB: PSRB_HAInquiry;
  432.   //  ASPI_Status: DWord;
  433.   Res: string;
  434. begin
  435.   setlength(Res, 16);
  436.   New(AdaptorSRB);
  437.   FillChar(AdaptorSRB^, Sizeof(SRB_HAInquiry), #0);
  438.   AdaptorSRB^.SRB_Cmd := SC_HA_INQUIRY;
  439.   AdaptorSRB^.SRB_HaId := ID;
  440.   AdaptorSRB^.SRB_Flags := 0;
  441.   AdaptorSRB^.SRB_Hdr_Rsvd := 0;
  442.   //  ASPI_Status :=
  443.   SendASPI32Command(AdaptorSRB);
  444.   if AdaptorSRB^.SRB_Status <> SS_COMP then
  445.     RES := 'Inquery Error'
  446.   else
  447.   begin
  448.     Res := AdaptorSRB^.HA_Identifier;
  449.   end;
  450.   Result := Res;
  451.   Dispose(AdaptorSRB);
  452. end;
  453. function GetAspiErrorSense(Status, HaStat, TargStat: BYTE;
  454.   Sense: PscsiSenseInfo): TScsiError;
  455. begin
  456.   Result := GetAspiError(Status, HaStat, TargStat);
  457.   if (Result = Err_CheckCondition) and Assigned(Sense) then
  458.     if Sense^[0] = 0 then
  459.       Result := Err_None
  460.     else if (Sense^[0] and $7E) <> $70 {// recognized values} then
  461.       Result := Err_SenseUnknown
  462.     else
  463.       case (Sense^[2] and $0F) of
  464.         0:
  465.           begin // Skey_NoSense
  466.             if (Sense^[2] and $80) <> 0 {// FileMark flag} then
  467.               Result := Err_SenseFileMark
  468.             else if (Sense^[2] and $40) <> 0 {// EndOfMedia flag} then
  469.               Result := Err_SenseEndOfMedia
  470.             else if (Sense^[2] and $20) <> 0 {// IllegalLength flag} then
  471.               Result := Err_SenseIllegalLength
  472.             else if (Sense^[3] and $80) <> 0 {// ResidualCount < 0} then
  473.               Result := Err_SenseIncorrectLength
  474.             else
  475.               Result := Err_SenseNoSense;
  476.           end;
  477.         1: Result := Err_SenseRecoveredError; //Skey_RecoveredError
  478.         2: Result := Err_SenseNotReady; //Skey_NotReady
  479.         3: Result := Err_SenseMediumError; //Skey_MediumError
  480.         4: Result := Err_SenseHardwareError; //Skey_HardwareError
  481.         5: Result := Err_SenseIllegalRequest; //Skey_IllegalRequest
  482.         6: Result := Err_SenseUnitAttention; //Skey_UnitAttention
  483.         7: Result := Err_SenseDataProtect; //Skey_DataProtect
  484.         8: Result := Err_SenseBlankCheck; //Skey_BlankCheck
  485.         9: Result := Err_SenseVendorSpecific; // Skey_VendorSpecific
  486.         10: Result := Err_SenseCopyAborted; // Skey_CopyAborted
  487.         11: Result := Err_SenseAbortedCommand; // Skey_AbortedCommand
  488.         12: Result := Err_SenseEqual; // Skey_Equal
  489.         13: Result := Err_SenseVolumeOverflow; // Skey_VolumeOverflow
  490.         14: Result := Err_SenseMiscompare; // Skey_Miscompare
  491.         15: Result := Err_SenseReserved; // Skey_Reserved
  492.       end;
  493. end;
  494. function ASPIsend12CDB(DeviceID: TCDBurnerInfo; CDB: TCDB12; Pbuf: pointer;
  495.   BufLen: DWORD;
  496.   Direction: DWORD; var Sdf: TScsiDefaults): TScsiError;
  497. begin
  498.   if Assigned(Pbuf) and (Direction = SRB_DIR_IN) then
  499.     FillChar(Pbuf^, BufLen, 0);
  500.   Result := ASPIsendScsiCommand(DeviceID, @cdb, 12, Pbuf, BufLen, Direction,
  501.     Sdf);
  502. end;
  503. function ASPIsend10CDB(DeviceID: TCDBurnerInfo; CDB: TCDB10; Pbuf: pointer;
  504.   BufLen: DWORD;
  505.   Direction: DWORD; var Sdf: TScsiDefaults): TScsiError;
  506. begin
  507.   if Assigned(Pbuf) and (Direction = SRB_DIR_IN) then
  508.     FillChar(Pbuf^, BufLen, 0);
  509.   Result := ASPIsendScsiCommand(DeviceID, @cdb, 10, Pbuf, BufLen, Direction,
  510.     Sdf);
  511. end;
  512. function ASPIsend6CDB(DeviceID: TCDBurnerInfo; CDB: TCDB6; Pbuf: pointer;
  513.   BufLen: DWORD;
  514.   Direction: DWORD; var Sdf: TScsiDefaults): TScsiError;
  515. begin
  516.   if Assigned(Pbuf) and (Direction = SRB_DIR_IN) then
  517.     FillChar(Pbuf^, BufLen, 0);
  518.   Result := ASPIsendScsiCommand(DeviceID, @cdb, 6, Pbuf, BufLen, Direction,
  519.     Sdf);
  520. end;
  521. function ASPIsend6(DeviceID: TCDBurnerInfo;
  522.   OpCode: BYTE; Lba: DWORD; Byte4: BYTE;
  523.   Pbuf: pointer; BufLen: DWORD;
  524.   Direction: DWORD; var Sdf: TScsiDefaults): TScsiError;
  525. var
  526.   cdb: array[0..5] of BYTE;
  527. begin
  528.   if Assigned(Pbuf) and (Direction = SRB_DIR_IN) then
  529.     FillChar(Pbuf^, BufLen, 0);
  530.   cdb[5] := 0;
  531.   cdb[4] := Byte4;
  532.   FillDWORD(LBA, cdb[0]);
  533.   cdb[1] := AttachLUN(cdb[1], DeviceID.DriveID);
  534.   cdb[0] := OpCode;
  535.   Result := ASPIsendScsiCommand(DeviceID, @cdb, 6, Pbuf, BufLen, Direction,
  536.     Sdf);
  537. end;
  538. function ASPIsend10(DeviceID: TCDBurnerInfo; OpCode: BYTE;
  539.   Byte1: BYTE; Lba: DWORD; Byte6: BYTE; Word7: WORD;
  540.   Pbuf: pointer; BufLen: DWORD;
  541.   Direction: DWORD; var Sdf: TScsiDefaults): TScsiError;
  542. var
  543.   cdb: array[0..9] of BYTE;
  544. begin
  545.   if Assigned(Pbuf) and (Direction = SRB_DIR_IN) then
  546.     FillChar(Pbuf^, BufLen, 0);
  547.   cdb[9] := 0;
  548.   FillWORD(Word7, cdb[7]);
  549.   cdb[6] := Byte6;
  550.   FillDWORD(LBA, cdb[2]);
  551.   cdb[1] := AttachLUN(Byte1, DeviceID.DriveID);
  552.   cdb[0] := OpCode;
  553.   Result := ASPIsendScsiCommand(DeviceID, @cdb, 10, Pbuf, BufLen, Direction,
  554.     Sdf);
  555. end;
  556. function ASPIsend12(DeviceID: TCDBurnerInfo; OpCode: BYTE;
  557.   Byte1: BYTE; Lba: DWORD; TLength: DWORD; Byte10: BYTE;
  558.   Pbuf: pointer; BufLen: DWORD;
  559.   Direction: DWORD; var Sdf: TScsiDefaults): TScsiError;
  560. var
  561.   cdb: array[0..11] of BYTE;
  562. begin
  563.   if Assigned(Pbuf) and (Direction = SRB_DIR_IN) then
  564.     FillChar(Pbuf^, BufLen, 0);
  565.   cdb[11] := 0;
  566.   cdb[10] := Byte10;
  567.   FillDWORD(TLength, cdb[6]);
  568.   FillDWORD(LBA, cdb[2]);
  569.   cdb[1] := AttachLUN(Byte1, DeviceID.DriveID);
  570.   cdb[0] := OpCode;
  571.   Result := ASPIsendScsiCommand(DeviceID, @cdb, 12, Pbuf, BufLen, Direction,
  572.     Sdf);
  573. end;
  574. function ASPIsendScsiCommandInternal(DeviceID: TCDBurnerInfo;
  575.   Pcdb: pointer; CdbLen: DWORD;
  576.   Pbuf: pointer; BufLen: DWORD;
  577.   Direction: DWORD; var Sdf: TScsiDefaults): TScsiError;
  578. var
  579.   Esrb: SRB_ExecSCSICmd;
  580.   hEvent: THandle;
  581. begin
  582.   Result := Err_None;
  583.   hEvent := CreateEvent(nil, true, false, nil); // event to notify completion
  584.   if hEvent = 0 then
  585.   begin
  586.     Result := Err_NoEvent;
  587.     exit;
  588.   end;
  589.   ResetEvent(hEvent);
  590.   FillChar(Esrb, sizeof(Esrb), 0); // Scsi Request Block init
  591.   with Esrb do
  592.   begin
  593.     SRB_Cmd := 2; // SC_EXEC_SCSI_CMD
  594.     ScatterDeviceID(DeviceID.DriveID, SRB_HaId, SRB_Target, SRB_Lun);
  595.     SRB_Flags := Direction or $40; // set SRB_EVENT_NOTIFY flag
  596.     SRB_BufLen := BufLen;
  597.     SRB_BufPtr := Pbuf;
  598.     SRB_SenseLen := sizeof(TscsiSenseInfo) - 2;
  599.     if CdbLen > 16 then
  600.       SRB_CDBLen := 16
  601.     else
  602.       SRB_CDBLen := CdbLen;
  603.     SRB_PostProc := hEvent;
  604.     Move(Pcdb^, SRB_CDBByte, SRB_CDBLen);
  605.   end;
  606.   SendASPI32Command(@Esrb); // send command to aspi
  607.   if Esrb.SRB_Status = 0 then
  608.   begin // signaled SS_PENDING  >> WAIT !
  609.     if WaitForSingleObject(hEvent, Sdf.Timeout) <> WAIT_OBJECT_0 then
  610.     begin
  611.       Result := Err_NotifyTimeout;
  612.       ASPIabortCommand(Esrb.SRB_HaId, @Esrb);
  613.     end;
  614.   end;
  615.   if Esrb.SRB_Status <> 1 then
  616.     Result := Err_NoDevice;
  617.   CloseHandle(hEvent);
  618.   if Result = Err_None then
  619.     with Esrb do
  620.     begin
  621.       Sdf.Sense := SRB_Sense;
  622.       Result := GetAspiErrorSense(SRB_Status, SRB_HaStat,
  623.         SRB_TargStat, @SRB_Sense);
  624.     end;
  625. end;
  626. function ASPIsendScsiCommand(DeviceID: TCDBurnerInfo;
  627.   Pcdb: pointer; CdbLen: DWORD;
  628.   Pbuf: pointer; BufLen: DWORD;
  629.   Direction: DWORD; var Sdf: TScsiDefaults): TScsiError;
  630. begin
  631.   //  Result := Err_None;
  632.   FillChar(Sdf.Sense, sizeof(TscsiSenseInfo), 0);
  633.   Result := ASPIsendScsiCommandInternal(DeviceID,
  634.     Pcdb, CdbLen, Pbuf, BufLen, Direction, Sdf);
  635.   if Assigned(Sdf.fOnCommandSent) then
  636.     Sdf.fOnCommandSent(DeviceID, Pcdb, CdbLen, Pbuf, BufLen, Direction, @Sdf,
  637.       Result);
  638. end;
  639. procedure ASPIabortCommand(HaId: BYTE; Psrb: pointer);
  640. var
  641.   Asrb: SRB_Abort;
  642. begin
  643.   FillChar(Asrb, sizeof(Asrb), 0);
  644.   Asrb.SRB_Cmd := 3;
  645.   Asrb.SRB_HaId := HaId;
  646.   Asrb.SRB_ToAbort := Psrb;
  647.   SendASPI32Command(@Asrb);
  648. end;
  649. end.