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

DVD

开发平台:

Delphi

  1. {-----------------------------------------------------------------------------
  2.  Unit Name: SptiFunctions
  3.  Author:    Dancemammal
  4.  Purpose:   w2k spti functions version
  5.  History:  First Code Release
  6. -----------------------------------------------------------------------------}
  7. unit SptiUnit;
  8. interface
  9. uses Windows, CovertFuncs, wnaspi32, skSCSI, CDROMIOCTL, dialogs, SCSITypes,
  10.   scsidefs, sysutils, Registry;
  11. {Const //=======  Possible values of Direction parameter ========
  12.    SRB_NODIR = 2; // No data I/O is performed
  13.    SRB_DIR_IN = 1; // Transfer from SCSI target to host
  14.    SRB_DIR_OUT = 0; // Transfer from host to SCSI target
  15. }
  16. type
  17.   SCSI_ADDRESS = record
  18.     Length: LongInt;
  19.     PortNumber: Byte;
  20.     PathId: Byte;
  21.     TargetId: Byte;
  22.     Lun: Byte;
  23.   end;
  24.   PSCSI_ADDRESS = ^SCSI_ADDRESS;
  25.   ENotAdmin = Exception;
  26.   NTSCSIDRIVE = record
  27.     ha: byte;
  28.     tgt: byte;
  29.     lun: byte;
  30.     driveLetter: Char; //Was byte
  31.     bUsed: Bool;
  32.     hDevice: THandle;
  33.     inqData: array[0..36 - 1] of byte;
  34.   end;
  35.   PNTSCSIDRIVE = ^NTSCSIDRIVE;
  36. type
  37.   {CDB types for Spti commands}
  38.   TCDB12 = array[0..11] of BYTE;
  39.   PCDB12 = ^TCDB12;
  40.   TCDB10 = array[0..9] of BYTE;
  41.   PCDB10 = ^TCDB10;
  42.   TCDB6 = array[0..5] of BYTE;
  43.   PCDB6 = ^TCDB6;
  44. type
  45.   TScsiInt13info = packed record
  46.     Support,
  47.       DosSupport: BOOLEAN;
  48.     DriveNumber,
  49.       Heads,
  50.       Sectors: BYTE;
  51.   end;
  52.   // Request for information about host adapter.
  53. type
  54.   TScsiHAinfo = packed record
  55.     ScsiId: BYTE; // SCSI Id of selected host adapter
  56.     MaxTargetCount: BYTE; // Max target count for selected HA
  57.     ResidualSupport: BOOLEAN; // True if HA supports residual I/O
  58.     MaxTransferLength: DWORD; // Max transfer length in bytes
  59.     BufferAlignMask: WORD; // Buffer for data I/O must be aligned by:
  60.     // 0=byte, 1=word, 3=dword, 7=8-byte, etc. 65536 bytes max
  61.     ScsiManagerId, // MustBe = 'ASPI for WIN32'
  62.     HostAdapterId: string[16]; // String describing selected HA
  63.   end;
  64. type
  65.   TScsiDeviceType = (TSDDisk, TSDTape, TSDPrinter, TSDProcessor,
  66.     TSDWORM, TSDCDROM, TSDScanner, TSDOptical,
  67.     TSDChanger, TSDCommunication,
  68.     TSDInvalid, TSDAny, TSDOther);
  69. var
  70.   TScsiDeviceTypeName: array[TScsiDeviceType] of string = ('Disk Drive',
  71.     'Tape Drive', 'Printer', 'Processor', 'WORM Drive', 'CD-ROM Drive',
  72.     'Scanner', 'Optical Drive', 'Changer', 'Communication Device',
  73.     'Invalid', 'Any Type Device', 'Other Type Device');
  74.   {Aspi Functions}
  75. function GetAdaptorName(ID: Integer): string;
  76. function GetSCSIID(ID: Integer): string;
  77. function ISCDROM(ID, Target, LUN: Integer): Boolean;
  78. function GetCDRegName(ID, Target, LUN: Integer): string;
  79. function ResetAspi(ID, Target, LUN: Integer): Boolean;
  80. function AttachLUN(var Arg: BYTE; DeviceID: TBurnerID): BYTE;
  81. function CloseDriveHandle(DeviceID: TCDBurnerInfo): Boolean;
  82. function GetDriveTempHandle(DeviceID: TCDBurnerInfo): Thandle;
  83. procedure GetDriveHandle(var DeviceID: TCDBurnerInfo);
  84. // =================== Helper routines ======================
  85. // Intel/Windows/Delphi <-> Motorola/ASPI format conversion routines
  86. function BigEndianW(Arg: WORD): WORD;
  87. function BigEndianD(Arg: DWORD): DWORD;
  88. procedure BigEndian(const Source; var Dest; Count: integer);
  89. function GatherWORD(b1, b0: byte): WORD;
  90. function GatherDWORD(b3, b2, b1, b0: byte): DWORD;
  91. procedure ScatterDWORD(Arg: DWORD; var b3, b2, b1, b0: byte);
  92. procedure ASPIstrCopy(Src: PChar; var Dst: ShortString; Leng: Integer);
  93. // ASPI Error decoding routines
  94. function GetAspiError(Status, HaStat, TargStat: BYTE): TScsiError;
  95. function GetAspiErrorSense(Status, HaStat, TargStat: BYTE;
  96.   Sense: PscsiSenseInfo): TScsiError;
  97. function AspiCheck(Err: TScsiError): boolean;
  98. // TBurnerID helper definitions and functions
  99. procedure FillWORD(Src: WORD; var Dst: BYTE);
  100. procedure FillDWORD(Src: DWORD; var Dst: BYTE);
  101. function GatherDeviceID(Adapter, Target, Lun: byte; Letter: char): TBurnerID;
  102. function ScatterDeviceID(DeviceID: TBurnerID;
  103.   var Adapter, Target, Lun: byte): char;
  104. function DeviceIDtoLetter(DeviceID: TBurnerID): char;
  105. function ASPIgetDeviceIDflag(DeviceID: TBurnerID;
  106.   Flag: TAspiDeviceIDflag): boolean;
  107. procedure ASPIsetDeviceIDflag(var DeviceID: TBurnerID;
  108.   Flag: TAspiDeviceIDflag; Value: boolean);
  109. // ============= Base-level ASPI request routines ==============
  110. function ASPIhaInquiry(HaId: BYTE; var sh: TScsiHAinfo): TScsiError;
  111. // Request for device type.
  112. function ASPIgetDeviceType(DeviceID: TBurnerID;
  113.   var DeviceType: TScsiDeviceType): TScsiError;
  114. // SCSI command execution.
  115. //   DeviceID     identifies the device to be accessed.
  116. //   Pcdb/CdbLen  SCSI Command Descriptor Block pointer/size
  117. //   Pbuf/BufLen  Data buffer pointer/size.
  118. //                Must be nil/0 if command does not requires data I/O.
  119. //   Direction    Data transfer direction. Must be one of SRB_DIR constants.
  120. function ASPIsendScsiCommand(DeviceID: TCDBurnerInfo;
  121.   Pcdb: pointer; CdbLen: DWORD;
  122.   Pbuf: pointer; BufLen: DWORD;
  123.   Direction: DWORD; var Sdf: TScsiDefaults): TScsiError;
  124. // Abort issued by ASPIsendScsiCommand() request for a given host adapter.
  125. procedure ASPIabortCommand(HaId: BYTE; Psrb: pointer);
  126. // Soft reset for the given device.
  127. function ASPIresetDevice(DeviceID: TCDBurnerInfo; Timeout: DWORD): TScsiError;
  128. // Retrieves some DOS-related info about device.
  129. function ASPIgetDriveInt13info(DeviceID: TCDBurnerInfo;
  130.   var Info: TScsiInt13info): TScsiError;
  131. //=================== Device enumerator routine ====================
  132. //  Callback function definition.
  133. //    lpUserData  specifies the user-defined value given in AspiEnumDevices
  134. //    Device      identifies the device found
  135. //    Return Value  To continue enumeration, the callback function must
  136. //                  return TRUE; to stop enumeration, it must return FALSE.
  137. //  Enumerator routine definition.
  138. //    DeviceType  Type of devices to enumerate. Set it to TSDAny to
  139. //                obtain all devices available.
  140. //    CallBack    Points to an user-defined callback function (see above).
  141. //    lpUserData  Specifies a user-defined value to be passed to the callback.
  142. //    Return Value  Number of devices found. Zero if no devices of specified
  143. //                  type exists, -1 if search fails.
  144. type
  145.   TAspiDeviceEnumCallBack
  146.     = function(lpUserData: pointer; Device: TCDBurnerInfo; FoundName: string):
  147.     boolean;
  148.   // ================== Mid-level SCSI request routines ================
  149.   // Three most frequent cases of ASPISendScsiCommand(),
  150.   // for CDB of 6, 10 and 12 bytes length.
  151. function ASPIsend6(DeviceID: TCDBurnerInfo;
  152.   OpCode: BYTE; Lba: DWORD; Byte4: BYTE;
  153.   Pbuf: pointer; BufLen: DWORD;
  154.   Direction: DWORD; var Sdf: TScsiDefaults): TScsiError;
  155. function ASPIsend10(DeviceID: TCDBurnerInfo; OpCode: BYTE;
  156.   Byte1: BYTE; Lba: DWORD; Byte6: BYTE; Word7: WORD;
  157.   Pbuf: pointer; BufLen: DWORD;
  158.   Direction: DWORD; var Sdf: TScsiDefaults): TScsiError;
  159. function ASPIsend12(DeviceID: TCDBurnerInfo; OpCode: BYTE;
  160.   Byte1: BYTE; Lba: DWORD; TLength: DWORD; Byte10: BYTE;
  161.   Pbuf: pointer; BufLen: DWORD;
  162.   Direction: DWORD; var Sdf: TScsiDefaults): TScsiError;
  163. {With new TCDB command struct}
  164. function ASPIsend6CDB(DeviceID: TCDBurnerInfo; CDB: TCDB6; Pbuf: pointer;
  165.   BufLen: DWORD;
  166.   Direction: DWORD; var Sdf: TScsiDefaults): TScsiError;
  167. function ASPIsend10CDB(DeviceID: TCDBurnerInfo; CDB: TCDB10; Pbuf: pointer;
  168.   BufLen: DWORD;
  169.   Direction: DWORD; var Sdf: TScsiDefaults): TScsiError;
  170. function ASPIsend12CDB(DeviceID: TCDBurnerInfo; CDB: TCDB12; Pbuf: pointer;
  171.   BufLen: DWORD;
  172.   Direction: DWORD; var Sdf: TScsiDefaults): TScsiError;
  173. // ++++++++++++++base SPTI commands all new+++++++++++++++++++
  174. type
  175.   TSPTIWriter = record
  176.     HaId: Byte;
  177.     Target: Byte;
  178.     Lun: Byte;
  179.     Vendor: ShortString;
  180.     ProductId: ShortString;
  181.     Revision: ShortString;
  182.     VendorSpec: ShortString;
  183.     Description: ShortString;
  184.     DriveLetter: Char;
  185.     DriveHandle: Thandle;
  186.   end;
  187.   TSPTIWriters = record
  188.     ActiveCdRom: Byte;
  189.     CdRomCount: Byte;
  190.     CdRom: array[0..25] of TSPTIWriter;
  191.   end;
  192. function ScsiErrToString(Err: TScsiError): string;
  193. function ScsiErrToStr(Err: TScsiError): string;
  194. function ScsiDeviceIDtoStr(Device: TBurnerID): string;
  195. function GetDriveNumbers(var CDRoms: TSPTIWriters): integer;
  196. function GetSPTICdRomDrives(var CdRoms: TSPTIWriters): Boolean;
  197. procedure GetDriveInformation(i: byte; var CdRoms: TSPTIWriters);
  198. implementation
  199. uses Scsiunit;
  200. function AttachLUN(var Arg: BYTE; DeviceID: TBurnerID): BYTE;
  201. var
  202.   i, j, Lun: BYTE;
  203. begin
  204.   ScatterDeviceID(DeviceID, i, j, Lun);
  205.   Result := ((Lun and 7) shl 5) or (Arg and $1F);
  206. end;
  207. procedure FillWORD(Src: WORD; var Dst: BYTE);
  208. begin
  209.   BigEndian(Src, Dst, 2);
  210. end;
  211. procedure FillDWORD(Src: DWORD; var Dst: BYTE);
  212. begin
  213.   BigEndian(Src, Dst, 4);
  214. end;
  215. function ScsiErrToString(Err: TScsiError): string;
  216. begin
  217.   Result := EnumToStr(TypeInfo(TScsiError), Err);
  218. end;
  219. function ScsiErrToStr(Err: TScsiError): string;
  220. begin
  221.   Result := '() result is ' + ScsiErrToString(Err);
  222. end;
  223. function ScsiDeviceIDtoStr(Device: TBurnerID): string;
  224. var
  225.   Adapter, Target, Lun: byte;
  226.   Letter: Char;
  227. begin
  228.   Letter := ScatterDeviceID(Device, Adapter, Target, Lun);
  229.   if Letter < 'A' then
  230.     Letter := '?';
  231.   Result := IntToStr(Adapter) + ','
  232.     + IntToStr(Target) + ','
  233.     + IntToStr(Lun) + ','
  234.     + Letter + ': ';
  235. end;
  236. {*******************************************************************************
  237.                                                                     AspiIntalled
  238. *******************************************************************************}
  239. function AspiInstalled: Integer;
  240. var
  241.   AspiStatus: Cardinal;
  242. begin
  243.   if WNASPI_LOADED then
  244.   begin
  245.     AspiStatus := GetASPI32SupportInfo;
  246.     if HIBYTE(LOWORD(AspiStatus)) = SS_COMP then
  247.     begin
  248.       // get number of host installed on the system
  249.       Result := LOBYTE(LOWORD(AspiStatus));
  250.     end
  251.     else
  252.       Result := -1
  253.   end
  254.   else
  255.     Result := -1
  256. end;
  257. function CheckAspiLayer: Boolean;
  258. begin
  259.   Result := True;
  260.   if AspiInstalled = -1 then
  261.     Result := False;
  262. end;
  263. function GetDriveNumbers(var CDRoms: TSPTIWriters): integer;
  264. var
  265.   i: integer;
  266.   szDrives: array[0..105] of Char;
  267.   p: PChar;
  268. begin
  269.   GetLogicalDriveStrings(105, szDrives);
  270.   p := szDrives;
  271.   i := 0;
  272.   while p^ <> '' do
  273.   begin
  274.     if GetDriveType(p) = DRIVE_CDROM then
  275.     begin
  276.       CdRoms.CdRom[i].DriveLetter := p^; // + ':';
  277.       i := CdRoms.CdRomCount + 1;
  278.       CdRoms.CdRomCount := CdRoms.CdRomCount + 1;
  279.     end;
  280.     p := p + lstrlen(p) + 1;
  281.   end;
  282.   Result := CdRoms.CdRomCount;
  283. end;
  284. function GetAdaptorName(ID: Integer): string;
  285. begin
  286.   Result := EmptyStr;
  287. end;
  288. function GetSCSIID(ID: Integer): string;
  289. begin
  290.   Result := EmptyStr;
  291. end;
  292. function ISCDROM(ID, Target, LUN: Integer): Boolean;
  293. begin
  294.   Result := false;
  295. end;
  296. function GetCDRegName(ID, Target, LUN: Integer): string;
  297. var
  298.   DEVName: string;
  299.   Registry: TRegistry;
  300.   Root2000: string;
  301.   Root98: string;
  302.   FormatKey: string;
  303. begin
  304.   DEVName := 'Cannot Find Name';
  305.   Root2000 := 'HKEY_LOCAL_MACHINE';
  306.   Root98 := 'HKEY_LOCAL_MACHINEEnumScsi';
  307.   FormatKey := 'HARDWAREDEVICEMAPScsiScsi Port ' + inttostr(ID) +
  308.     'Scsi Bus 0Target Id ' + inttostr(Target) + 'Logical Unit Id ' +
  309.     inttostr(LUN);
  310.   Registry := TRegistry.Create;
  311.   Registry.RootKey := HKEY_LOCAL_MACHINE;
  312.   Registry.OpenKey(FormatKey, False);
  313.   DEVName := Registry.ReadString('Identifier');
  314.   Registry.Free;
  315.   Result := DEVName;
  316. end;
  317. function ResetAspi(ID, Target, LUN: Integer): Boolean;
  318. begin
  319.   Result := False;
  320. end;
  321. function BigEndianW(Arg: WORD): WORD;
  322. begin
  323.   result := ((Arg shl 8) and $FF00) or
  324.     ((Arg shr 8) and $00FF);
  325. end;
  326. function BigEndianD(Arg: DWORD): DWORD;
  327. begin
  328.   result := ((Arg shl 24) and $FF000000) or
  329.     ((Arg shl 8) and $00FF0000) or
  330.     ((Arg shr 8) and $0000FF00) or
  331.     ((Arg shr 24) and $000000FF);
  332. end;
  333. procedure BigEndian(const Source; var Dest; Count: integer);
  334. var
  335.   pSrc, pDst: PChar;
  336.   i: integer;
  337. begin
  338.   pSrc := @Source;
  339.   pDst := PChar(@Dest) + Count;
  340.   for i := 0 to Count - 1 do
  341.   begin
  342.     Dec(pDst);
  343.     pDst^ := pSrc^;
  344.     Inc(pSrc);
  345.   end;
  346. end;
  347. function GatherWORD(b1, b0: byte): WORD;
  348. begin
  349.   result := ((WORD(b1) shl 8) and $FF00) or
  350.     ((WORD(b0)) and $00FF);
  351. end;
  352. {$WARNINGS OFF}
  353. function GatherDWORD(b3, b2, b1, b0: byte): DWORD;
  354. begin
  355.   result := ((LongInt(b3) shl 24) and $FF000000) or
  356.     ((LongInt(b2) shl 16) and $00FF0000) or
  357.     ((LongInt(b1) shl 8) and $0000FF00) or
  358.     ((LongInt(b0)) and $000000FF);
  359. end;
  360. {$WARNINGS ON}
  361. procedure ScatterDWORD(Arg: DWORD; var b3, b2, b1, b0: byte);
  362. begin
  363.   b3 := (Arg shr 24) and $FF;
  364.   b2 := (Arg shr 16) and $FF;
  365.   b1 := (Arg shr 8) and $FF;
  366.   b0 := Arg and $FF;
  367. end;
  368. procedure ASPIstrCopy(Src: PChar; var Dst: ShortString; Leng: Integer);
  369. var
  370.   i: integer;
  371. begin
  372.   i := 0;
  373.   while (i < Leng) and (Src[i] >= ' ') do
  374.   begin
  375.     Dst[i + 1] := Src[i];
  376.     inc(i);
  377.   end;
  378.   while (i > 0) and (Dst[i] = ' ') do
  379.     Dec(i); // Trim it Right
  380.   Dst[0] := CHR(i);
  381. end;
  382. function GetAspiError(Status, HaStat, TargStat: BYTE): TScsiError;
  383. begin
  384.   result := Err_Unknown;
  385.   case Status of
  386.     0, 1: result := Err_None; // No error, all OK
  387.     2, 3: result := Err_Aborted;
  388.     $80: result := Err_InvalidRequest; // This command is
  389.     // not supported by ASPI manager
  390.     $81: result := Err_InvalidHostAdapter;
  391.     $82: result := Err_NoDevice;
  392.     $E0: result := Err_InvalidSrb;
  393.     $E1: result := Err_BufferAlign;
  394.     $E5: result := Err_AspiIsBusy;
  395.     $E6: result := Err_BufferTooBig;
  396.     4: case HaStat of
  397.         $09: result := Err_CommandTimeout;
  398.         $0B: result := Err_SrbTimeout;
  399.         $0D: result := Err_MessageReject;
  400.         $0E: result := Err_BusReset;
  401.         $0F: result := Err_ParityError;
  402.         $10: result := Err_RequestSenseFailed;
  403.         $11: result := Err_SelectionTimeout;
  404.         $12: result := Err_DataOverrun;
  405.         $13: result := Err_UnexpectedBusFree;
  406.         $14: result := Err_BusPhaseSequence;
  407.         $00: case TargStat of
  408.             0, 2: result := Err_CheckCondition;
  409.             $08: result := Err_TargetBusy;
  410.             $18: result := Err_TargetReservationConflict;
  411.             $28: result := Err_TargetQueueFull;
  412.           end;
  413.       end;
  414.   end;
  415. end;
  416. function GetAspiErrorSense(Status, HaStat, TargStat: BYTE;
  417.   Sense: PscsiSenseInfo): TScsiError;
  418. begin
  419.   Result := GetAspiError(Status, HaStat, TargStat);
  420.   if (Result = Err_CheckCondition) and Assigned(Sense) then
  421.     if Sense^[0] = 0 then
  422.       Result := Err_None
  423.     else if (Sense^[0] and $7E) <> $70 {// recognized values} then
  424.       Result := Err_SenseUnknown
  425.     else
  426.       case (Sense^[2] and $0F) of
  427.         0:
  428.           begin // Skey_NoSense
  429.             if (Sense^[2] and $80) <> 0 {// FileMark flag} then
  430.               Result := Err_SenseFileMark
  431.             else if (Sense^[2] and $40) <> 0 {// EndOfMedia flag} then
  432.               Result := Err_SenseEndOfMedia
  433.             else if (Sense^[2] and $20) <> 0 {// IllegalLength flag} then
  434.               Result := Err_SenseIllegalLength
  435.             else if (Sense^[3] and $80) <> 0 {// ResidualCount < 0} then
  436.               Result := Err_SenseIncorrectLength
  437.             else
  438.               Result := Err_SenseNoSense;
  439.           end;
  440.         1: Result := Err_SenseRecoveredError; //Skey_RecoveredError
  441.         2: Result := Err_SenseNotReady; //Skey_NotReady
  442.         3: Result := Err_SenseMediumError; //Skey_MediumError
  443.         4: Result := Err_SenseHardwareError; //Skey_HardwareError
  444.         5: Result := Err_SenseIllegalRequest; //Skey_IllegalRequest
  445.         6: Result := Err_SenseUnitAttention; //Skey_UnitAttention
  446.         7: Result := Err_SenseDataProtect; //Skey_DataProtect
  447.         8: Result := Err_SenseBlankCheck; //Skey_BlankCheck
  448.         9: Result := Err_SenseVendorSpecific; // Skey_VendorSpecific
  449.         10: Result := Err_SenseCopyAborted; // Skey_CopyAborted
  450.         11: Result := Err_SenseAbortedCommand; // Skey_AbortedCommand
  451.         12: Result := Err_SenseEqual; // Skey_Equal
  452.         13: Result := Err_SenseVolumeOverflow; // Skey_VolumeOverflow
  453.         14: Result := Err_SenseMiscompare; // Skey_Miscompare
  454.         15: Result := Err_SenseReserved; // Skey_Reserved
  455.       end;
  456. end;
  457. function AspiCheck(Err: TScsiError): boolean;
  458. begin
  459.   Result := Err in [Err_None, Err_DataOverrun, Err_SenseRecoveredError];
  460. end;
  461. function GatherDeviceID(Adapter, Target, Lun: byte; Letter: char): TBurnerID;
  462. begin
  463.   Result := GatherDWORD(Adapter, Target,
  464.     ((Lun and 7) shl 5) or (ORD(Letter) and $1F), 0);
  465. end;
  466. function ScatterDeviceID(DeviceID: TBurnerID;
  467.   var Adapter, Target, Lun: byte): char;
  468. var
  469.   Res: BYTE;
  470. begin
  471.   ScatterDWORD(DeviceID, Adapter, Target, Lun, Res);
  472.   Result := CHR((Lun and $1F) or $40);
  473.   Lun := (Lun shr 5) and 7;
  474. end;
  475. function DeviceIDtoLetter(DeviceID: TBurnerID): char;
  476. var
  477.   Adapter, Target, Lun: byte;
  478. begin
  479.   Result := ScatterDeviceID(DeviceID, Adapter, Target, Lun);
  480. end;
  481. function ASPIgetDeviceIDflag(DeviceID: TBurnerID;
  482.   Flag: TAspiDeviceIDflag): boolean;
  483. begin
  484.   Result := (DeviceID and (1 shl ORD(Flag))) <> 0;
  485. end;
  486. procedure ASPIsetDeviceIDflag(var DeviceID: TBurnerID;
  487.   Flag: TAspiDeviceIDflag; Value: boolean);
  488. begin
  489.   if Value then
  490.     DeviceID := DeviceID or (1 shl ORD(Flag))
  491.   else
  492.     DeviceID := DeviceID and not (1 shl ORD(Flag));
  493. end;
  494. function ASPIhaInquiry(HaId: BYTE; var sh: TScsiHAinfo): TScsiError;
  495. begin
  496.   Result := Err_None;
  497. end;
  498. {$WARNINGS OFF}
  499. function ASPIgetDeviceType(DeviceID: TBurnerID;
  500.   var DeviceType: TScsiDeviceType): TScsiError;
  501. type
  502.   SRB_GetDeviceType = packed record
  503.     SRB_Cmd: BYTE; // ASPI command code = 1 = SC_GET_DEV_TYPE
  504.     SRB_Status: BYTE; // ASPI command status byte
  505.     SRB_HaId: BYTE; // ASPI host adapter number
  506.     SRB_Flags: BYTE; // Reserved
  507.     SRB_Hdr_Rsvd: DWORD; // Reserved
  508.     SRB_Target: BYTE; // Target number for specified HA
  509.     SRB_Lun: BYTE; // Logical unit number of selected target
  510.     SRB_DeviceType: BYTE; // Selected HA/Target/Lun device type
  511.     SRB_Rsvd: BYTE; // Reserved for alignment
  512.   end;
  513. var
  514.   Gsrb: SRB_GetDeviceType;
  515. begin
  516.   FillChar(Gsrb, sizeof(Gsrb), 0);
  517.   Gsrb.SRB_Cmd := 1;
  518.   ScatterDeviceID(DeviceID, Gsrb.SRB_HaId, Gsrb.SRB_Target, Gsrb.SRB_Lun);
  519.   //   SendASPI32Command(@Gsrb);
  520.   Result := GetAspiError(Gsrb.SRB_Status, $FF, $FF);
  521.   if (Result = Err_None) and (Gsrb.SRB_DeviceType < ORD(TSDInvalid)) then
  522.     DeviceType := TScsiDeviceType(Gsrb.SRB_DeviceType)
  523.   else
  524.     DeviceType := TSDInvalid;
  525. end;
  526. {$WARNINGS ON}
  527. procedure GetDriveHandle(var DeviceID: TCDBurnerInfo);
  528. var
  529.   fh: THandle;
  530.   buf2: array[0..31] of Char;
  531.   DriveLetter: Char;
  532.   dwFlags: DWord;
  533. begin
  534.   dwFlags := GENERIC_READ;
  535.   if getOsVersion >= OS_WIN2K then
  536.     dwFlags := dwFlags or GENERIC_WRITE;
  537.   DriveLetter := DeviceIDtoLetter(DeviceID.DriveID);
  538.   StrPCopy(@buf2, Format('\.%s:', [DriveLetter]));
  539.   fh := CreateFile(buf2, dwFlags, FILE_SHARE_READ or FILE_SHARE_WRITE, nil,
  540.     OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
  541.   if fh = INVALID_HANDLE_VALUE then
  542.   begin
  543.     showmessage('cannot use need admin');
  544.     CloseHandle(fh);
  545.     Exit;
  546.   end;
  547. end;
  548. function GetDriveTempHandle(DeviceID: TCDBurnerInfo): Thandle;
  549. var
  550.   DriveLetter: Char;
  551. begin
  552.   DriveLetter := DeviceIDtoLetter(DeviceID.DriveID);
  553.   Result := CreateFile(PChar('\.' + DriveLetter + ':'),
  554.     GENERIC_READ or GENERIC_WRITE,
  555.     FILE_SHARE_READ or FILE_SHARE_WRITE,
  556.     nil,
  557.     OPEN_EXISTING,
  558.     FILE_ATTRIBUTE_NORMAL,
  559.     0);
  560. end;
  561. function CloseDriveHandle(DeviceID: TCDBurnerInfo): Boolean;
  562. begin
  563.   Result := CloseHandle(DeviceID.SptiHandle);
  564. end;
  565. {seperate test function}
  566. function ASPIsendScsiCommandInternal(DeviceID: TCDBurnerInfo;
  567.   Pcdb: pointer; CdbLen: DWORD;
  568.   Pbuf: pointer; BufLen: DWORD;
  569.   Direction: DWORD; var Sdf: TScsiDefaults): TScsiError;
  570. var
  571.   status: Byte;
  572.   dwFlags: Cardinal;
  573.   //  ErrorInt: Integer;
  574.   skSCSI: TskSCSI;
  575.   CDB: TCDB;
  576.   CDBSize: Cardinal;
  577. begin
  578.   status := 1;
  579.   Result := Err_None;
  580.   skSCSI := TskSCSI.Create;
  581.   if skSCSI.InitOK then
  582.   begin
  583.     CDBSize := CDBLen;
  584.     Move(TCDB(pcdb^), CDB, CDBSize);
  585.     dwFlags := Direction;
  586.     status := skSCSI.ExecCmd(Deviceid.HaId, DeviceID.Target, DeviceID.Lun, CDB,
  587.       CDBSize, dwFlags, pbuf, BufLen);
  588.     skSCSI.Destroy;
  589.   end;
  590.   // Move(TCDB12(Pcdb^), pswb^.spt.Cdb, pswb^.spt.CdbLength);
  591.   if not status = 0 then
  592.   begin
  593.     //    ErrorInt := GetLastError;
  594.     Result := Err_Unknown;
  595.     Exit;
  596.   end;
  597. end;
  598. function ASPIsendScsiCommand(DeviceID: TCDBurnerInfo;
  599.   Pcdb: pointer; CdbLen: DWORD;
  600.   Pbuf: pointer; BufLen: DWORD;
  601.   Direction: DWORD; var Sdf: TScsiDefaults): TScsiError;
  602. begin
  603.   Result := Err_None;
  604.   FillChar(Sdf.Sense, sizeof(TscsiSenseInfo), 0);
  605.   if Assigned(Sdf.fOnCommandSending) then
  606.     Sdf.fOnCommandSending(DeviceID, Pcdb, CdbLen, Pbuf, BufLen,
  607.       Direction, @Sdf, Result);
  608.   Result := ASPIsendScsiCommandInternal(DeviceID,
  609.     Pcdb, CdbLen, Pbuf, BufLen, Direction, Sdf);
  610.   if Assigned(Sdf.fOnCommandSent) then
  611.     Sdf.fOnCommandSent(DeviceID, Pcdb, CdbLen, Pbuf, BufLen,
  612.       Direction, @Sdf, Result);
  613. end;
  614. procedure ASPIabortCommand(HaId: BYTE; Psrb: pointer);
  615. type
  616.   SRB_Abort = packed record
  617.     SRB_Cmd: BYTE; // ASPI command code = 3 = SC_ABORT_SRB
  618.     SRB_Status: BYTE; // ASPI command status byte
  619.     SRB_HaId: BYTE; // ASPI host adapter number
  620.     SRB_Flags: BYTE; // Reserved
  621.     SRB_Hdr_Rsvd: DWORD; // Reserved
  622.     SRB_ToAbort: pointer; // Pointer to SRB to abort
  623.   end;
  624. var
  625.   Asrb: SRB_Abort;
  626. begin
  627.   FillChar(Asrb, sizeof(Asrb), 0);
  628.   Asrb.SRB_Cmd := 3;
  629.   Asrb.SRB_HaId := HaId;
  630.   Asrb.SRB_ToAbort := Psrb;
  631.   //   SendASPI32Command(@Asrb);
  632. end;
  633. function ASPIresetDevice(DeviceID: TCDBurnerInfo; Timeout: DWORD): TScsiError;
  634. type
  635.   SRB_ResetDevice = packed record
  636.     SRB_Cmd: BYTE; // ASPI command code = 4 = SC_RESET_DEV
  637.     SRB_Status: BYTE; // ASPI command status byte
  638.     SRB_HaId: BYTE; // ASPI host adapter number
  639.     SRB_Flags: BYTE; // Reserved
  640.     SRB_Hdr_Rsvd: DWORD; // Reserved
  641.     SRB_Target: BYTE; // Target's SCSI ID
  642.     SRB_Lun: BYTE; // Target's LUN number
  643.     SRB_Rsvd1: array[0..11] of BYTE; // Reserved for Alignment
  644.     SRB_HaStat: BYTE; // Host Adapter Status
  645.     SRB_TargStat: BYTE; // Target Status
  646.     SRB_PostProc: THandle; // Post routine
  647.     SRB_Rsvd2: POINTER; // Reserved
  648.     SRB_Rsvd3: array[0..31] of BYTE; // Reserved for alignment
  649.   end;
  650. var
  651.   Rsrb: SRB_ResetDevice;
  652.   hEvent: THandle;
  653. begin
  654.   Result := Err_None;
  655.   hEvent := CreateEvent(nil, true, false, nil); // event to notify completion
  656.   if hEvent = 0 then
  657.   begin
  658.     Result := Err_NoEvent;
  659.     exit;
  660.   end;
  661.   ResetEvent(hEvent);
  662.   FillChar(Rsrb, sizeof(Rsrb), 0);
  663.   with Rsrb do
  664.   begin
  665.     SRB_Cmd := 4; //  SC_RESET_DEV
  666.     ScatterDeviceID(DeviceID.DriveID, SRB_HaId, SRB_Target, SRB_Lun);
  667.     SRB_PostProc := hEvent;
  668.   end;
  669.   {   If SendASPI32Command(@Rsrb) = 0 Then Begin // SS_PENDING
  670.         If WaitForSingleObject(hEvent, Timeout) <> WAIT_OBJECT_0
  671.            Then Begin
  672.            Result := Err_NotifyTimeout;
  673.            ASPIabortCommand(Rsrb.SRB_HaId, @Rsrb);
  674.         End;
  675.      End Else Result := Err_NoDevice;
  676.      }
  677.   CloseHandle(hEvent);
  678.   if Result = Err_None then
  679.     with Rsrb do
  680.       Result := GetAspiError(SRB_Status, SRB_HaStat, SRB_TargStat);
  681. end;
  682. function ASPIgetDriveInt13info(DeviceID: TCDBurnerInfo;
  683.   var Info: TScsiInt13info): TScsiError;
  684. type
  685.   SRB_Int13info = packed record
  686.     SRB_Cmd: BYTE; // ASPI command code=6=SC_GET_DISK_INFO
  687.     SRB_Status: BYTE; // ASPI command status byte
  688.     SRB_HaId: BYTE; // ASPI host adapter number
  689.     SRB_Flags: BYTE; // Reserved
  690.     SRB_Hdr_Rsvd: DWORD; // Reserved
  691.     SRB_Target: BYTE; // Target's SCSI ID
  692.     SRB_Lun: BYTE; // Target's LUN number
  693.     SRB_DriveFlags: BYTE; // Driver flags
  694.     SRB_Int13Drive: BYTE; // Host Adapter Status
  695.     SRB_Heads: BYTE; // Preferred number of heads translation
  696.     SRB_Sectors: BYTE; // Preferred number of sectors translation
  697.     SRB_Rsvd: array[0..9] of BYTE; // Reserved
  698.   end;
  699. var
  700.   Isrb: SRB_Int13info;
  701. begin
  702.   FillChar(Isrb, sizeof(Isrb), 0);
  703.   with Isrb do
  704.   begin
  705.     SRB_Cmd := 6;
  706.     ScatterDeviceID(DeviceID.DriveID, SRB_HaId, SRB_Target, SRB_Lun);
  707.   end;
  708.   //   SendASPI32Command(@Isrb);
  709.   with Info, Isrb do
  710.   begin
  711.     Result := GetAspiError(SRB_Status, $FF, $FF);
  712.     Support := (Result = Err_None) and ((SRB_DriveFlags and 3) <> 0);
  713.     DosSupport := (Result = Err_None) and ((SRB_DriveFlags and 1) <> 0);
  714.     DriveNumber := SRB_Int13Drive;
  715.     Heads := SRB_Heads;
  716.     Sectors := SRB_Sectors;
  717.   end;
  718. end;
  719. function GetSPTICdRomDrives(var CdRoms: TSPTIWriters): Boolean;
  720. var
  721.   Index: integer;
  722. begin
  723.   Result := False;
  724.   if GetDriveNumbers(CdRoms) > 0 then
  725.   begin
  726.     for Index := 0 to CdRoms.CdRomCount - 1 do
  727.     begin
  728.       GetDriveInformation(Index, CdRoms);
  729.     end;
  730.     Result := True;
  731.   end;
  732. end;
  733. procedure GetDriveInformation(i: byte; var CdRoms: TSPTIWriters);
  734. var
  735.   fh: THandle;
  736.   buf: array[0..1023] of Char;
  737.   buf2: array[0..31] of Char;
  738.   status: Bool;
  739.   pswb: PSCSI_PASS_THROUGH_DIRECT_WITH_BUFFER;
  740.   pscsiAddr: PSCSI_ADDRESS;
  741.   length, returned: integer;
  742.   inqData: array[0..99] of Char; // was array[0..99] of Byte;
  743.   dwFlags: DWord;
  744.   DriveString: PChar;
  745. begin
  746.   dwFlags := GENERIC_READ;
  747.   if getOsVersion >= OS_WIN2K then
  748.     dwFlags := dwFlags or GENERIC_WRITE;
  749.   StrPCopy(@buf2, Format('\.%s:', [CdRoms.CdRom[i].DriveLetter]));
  750.   fh := CreateFile(buf2, dwFlags, FILE_SHARE_READ or FILE_SHARE_WRITE, nil,
  751.     OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
  752.   if fh = INVALID_HANDLE_VALUE then
  753.   begin
  754.     // It seems that with no Administrator privileges
  755.     // the handle value will be invalid
  756.     Exit;
  757.   end;
  758.   (*
  759.    * Get the drive inquiry data
  760.    *)
  761.   ZeroMemory(@buf, 1024);
  762.   ZeroMemory(@inqData, 100);
  763.   pswb := PSCSI_PASS_THROUGH_DIRECT_WITH_BUFFER(@buf);
  764.   pswb^.spt.Length := sizeof(SCSI_PASS_THROUGH);
  765.   pswb^.spt.CdbLength := 6;
  766.   pswb^.spt.SenseInfoLength := 24;
  767.   pswb^.spt.DataIn := SCSI_IOCTL_DATA_IN;
  768.   pswb^.spt.DataTransferLength := 100;
  769.   pswb^.spt.TimeOutValue := 2;
  770.   pswb^.spt.DataBuffer := @inqData;
  771.   pswb^.spt.SenseInfoOffset := SizeOf(pswb^.spt) + SizeOf(pswb^.Filler);
  772.   pswb^.spt.Cdb[0] := $12;
  773.   pswb^.spt.Cdb[4] := $64;
  774.   length := sizeof(SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER);
  775.   status := DeviceIoControl(fh,
  776.     IOCTL_SCSI_PASS_THROUGH_DIRECT,
  777.     pswb,
  778.     length,
  779.     pswb,
  780.     length,
  781.     Cardinal(returned),
  782.     nil);
  783.   if not status then
  784.   begin
  785.     // CloseHandle( fh );
  786.     Exit;
  787.   end;
  788.   DriveString := @inqData;
  789.   Inc(DriveString, 8);
  790.   CdRoms.CdRom[i].Vendor := Copy(DriveString, 1, 8); // Vendor
  791.   CdRoms.CdRom[i].ProductId := Copy(DriveString, 8 + 1, 16);
  792.   // Product ID
  793.   CdRoms.CdRom[i].Revision := Copy(DriveString, 24 + 1, 4);
  794.   // Revision
  795.   CdRoms.CdRom[i].VendorSpec := Copy(DriveString, 28 + 1, 20);
  796.   // Vendor Spec.
  797.   CdRoms.CdRom[i].Description := CdRoms.CdRom[i].Vendor +
  798.     CdRoms.CdRom[i].ProductId + CdRoms.CdRom[i].Revision;
  799.   CdRoms.CdRom[i].DriveHandle := fh;
  800.   (*
  801.    * get the address (path/tgt/lun) of the drive via IOCTL_SCSI_GET_ADDRESS
  802.    *)
  803.   ZeroMemory(@buf, 1024);
  804.   pscsiAddr := PSCSI_ADDRESS(@buf);
  805.   pscsiAddr^.Length := sizeof(SCSI_ADDRESS);
  806.   if (DeviceIoControl(fh, IOCTL_SCSI_GET_ADDRESS, nil, 0,
  807.     pscsiAddr, sizeof(SCSI_ADDRESS), Cardinal(returned),
  808.     nil)) then
  809.   begin
  810.     CDRoms.CdRom[i].HaId := pscsiAddr^.PortNumber;
  811.     CDRoms.CdRom[i].Target := pscsiAddr^.TargetId;
  812.     CDRoms.CdRom[i].Lun := pscsiAddr^.Lun;
  813.   end
  814.   else
  815.   begin
  816.     Exit;
  817.   end;
  818.   // CloseHandle( fh );
  819. end;
  820. function ASPIsend6(DeviceID: TCDBurnerInfo;
  821.   OpCode: BYTE; Lba: DWORD; Byte4: BYTE;
  822.   Pbuf: pointer; BufLen: DWORD;
  823.   Direction: DWORD; var Sdf: TScsiDefaults): TScsiError;
  824. var
  825.   cdb: array[0..5] of BYTE;
  826. begin
  827.   if Assigned(Pbuf) and (Direction = SRB_DIR_IN) then
  828.     FillChar(Pbuf^, BufLen, 0);
  829.   cdb[5] := 0;
  830.   cdb[4] := Byte4;
  831.   FillDWORD(LBA, cdb[0]);
  832.   cdb[1] := AttachLUN(cdb[1], DeviceID.DriveID);
  833.   cdb[0] := OpCode;
  834.   Result := ASPIsendScsiCommand(DeviceID, @cdb, 6,
  835.     Pbuf, BufLen, Direction, Sdf);
  836. end;
  837. function ASPIsend10(DeviceID: TCDBurnerInfo; OpCode: BYTE;
  838.   Byte1: BYTE; Lba: DWORD; Byte6: BYTE; Word7: WORD;
  839.   Pbuf: pointer; BufLen: DWORD;
  840.   Direction: DWORD; var Sdf: TScsiDefaults): TScsiError;
  841. var
  842.   cdb: array[0..9] of BYTE;
  843. begin
  844.   if Assigned(Pbuf) and (Direction = SRB_DIR_IN) then
  845.     FillChar(Pbuf^, BufLen, 0);
  846.   cdb[9] := 0;
  847.   FillWORD(Word7, cdb[7]);
  848.   cdb[6] := Byte6;
  849.   FillDWORD(LBA, cdb[2]);
  850.   cdb[1] := AttachLUN(Byte1, DeviceID.DriveID);
  851.   cdb[0] := OpCode;
  852.   Result := ASPIsendScsiCommand(DeviceID, @cdb, 10,
  853.     Pbuf, BufLen, Direction, Sdf);
  854. end;
  855. function ASPIsend12(DeviceID: TCDBurnerInfo; OpCode: BYTE;
  856.   Byte1: BYTE; Lba: DWORD; TLength: DWORD; Byte10: BYTE;
  857.   Pbuf: pointer; BufLen: DWORD;
  858.   Direction: DWORD; var Sdf: TScsiDefaults): TScsiError;
  859. var
  860.   cdb: array[0..11] of BYTE;
  861. begin
  862.   if Assigned(Pbuf) and (Direction = SRB_DIR_IN) then
  863.     FillChar(Pbuf^, BufLen, 0);
  864.   cdb[11] := 0;
  865.   cdb[10] := Byte10;
  866.   FillDWORD(TLength, cdb[6]);
  867.   FillDWORD(LBA, cdb[2]);
  868.   cdb[1] := AttachLUN(Byte1, DeviceID.DriveID);
  869.   cdb[0] := OpCode;
  870.   Result := ASPIsendScsiCommand(DeviceID, @cdb, 12,
  871.     Pbuf, BufLen, Direction, Sdf);
  872. end;
  873. function ASPIsend12CDB(DeviceID: TCDBurnerInfo; CDB: TCDB12; Pbuf: pointer;
  874.   BufLen: DWORD;
  875.   Direction: DWORD; var Sdf: TScsiDefaults): TScsiError;
  876. begin
  877.   if Assigned(Pbuf) and (Direction = SRB_DIR_IN) then
  878.     FillChar(Pbuf^, BufLen, 0);
  879.   Result := ASPIsendScsiCommand(DeviceID, @cdb, 12, Pbuf, BufLen, Direction,
  880.     Sdf);
  881. end;
  882. function ASPIsend10CDB(DeviceID: TCDBurnerInfo; CDB: TCDB10; Pbuf: pointer;
  883.   BufLen: DWORD;
  884.   Direction: DWORD; var Sdf: TScsiDefaults): TScsiError;
  885. begin
  886.   if Assigned(Pbuf) and (Direction = SRB_DIR_IN) then
  887.     FillChar(Pbuf^, BufLen, 0);
  888.   Result := ASPIsendScsiCommand(DeviceID, @cdb, 10, Pbuf, BufLen, Direction,
  889.     Sdf);
  890. end;
  891. function ASPIsend6CDB(DeviceID: TCDBurnerInfo; CDB: TCDB6; Pbuf: pointer;
  892.   BufLen: DWORD;
  893.   Direction: DWORD; var Sdf: TScsiDefaults): TScsiError;
  894. begin
  895.   if Assigned(Pbuf) and (Direction = SRB_DIR_IN) then
  896.     FillChar(Pbuf^, BufLen, 0);
  897.   Result := ASPIsendScsiCommand(DeviceID, @cdb, 6, Pbuf, BufLen, Direction,
  898.     Sdf);
  899. end;
  900. end.