From eaa22af69c69dbc5224ba61a8330586011b96838 Mon Sep 17 00:00:00 2001 From: brandysb Date: Tue, 28 Jul 2009 13:18:51 +0000 Subject: [PATCH] add IDe serial reading support unit git-svn-id: https://svn.code.sf.net/p/lazarus-ccr/svn@922 8e941d3f-bd1b-0410-a28a-d453659cc2b4 --- components/onguard/source/IdeSN.pas | 235 ++++++++++++++++++++++++++++ 1 file changed, 235 insertions(+) create mode 100644 components/onguard/source/IdeSN.pas diff --git a/components/onguard/source/IdeSN.pas b/components/onguard/source/IdeSN.pas new file mode 100644 index 000000000..e0fd3fcfe --- /dev/null +++ b/components/onguard/source/IdeSN.pas @@ -0,0 +1,235 @@ +// Extracting IDE(ATA) disk serial number. + +// (c) 2000-2003 Alex Konshin +// mailto:akonshin@earthlink.net +// http://home.earthlink.net/~akonshin/index.htm +// +// 30 Jul 2000 created +// 22 Oct 2003 refactoring +// 24 Jun 2009 adapted for Lazarus OnGuard package by Bogusław Brandys +unit idesn; + +interface + +{$mode delphi}{$H+} + +//------------------------------------------------------------- +// Tries to extract the serial number from specified IDE disk. +// +// Parameters: +// ControllerNumber - SCSI port number of the controller. +// DriveNumber - Device index (0..4). +// +// +// Notes: +// 1. The parameter ControllerNumber is ignored on Windows 9x/ME platforms and should be 0. +// 2. This function CAN NOT extract SCSI disk serial number. +// + function GetIdeDiskSerialNumber( ControllerNumber, DriveNumber : Integer; var OutBuf : AnsiString ) : Boolean; + +//============================================================= +implementation + +uses + Windows, + SysUtils; // only for Win32Platform, SysErrorMessage and class Exception + + +//------------------------------------------------------------- +// Tries to extract the serial number from specified IDE disk. +// +// Parameters: +// ControllerNumber - SCSI port number of the controller. +// DriveNumber - SCSI port number of the controller. +// Notes: +// 1. The parameter ControllerNumber is ignored on Windows 9x/ME platforms and should be 0. +// 2. This function CAN NOT extract SCSI disk serial number. +// +function GetIdeDiskSerialNumber( ControllerNumber, DriveNumber : Integer; var OutBuf : AnsiString ) : Boolean; +type + TSrbIoControl = packed record + HeaderLength : ULONG; + Signature : Array[0..7] of Char; + Timeout : ULONG; + ControlCode : ULONG; + ReturnCode : ULONG; + Length : ULONG; + end; + SRB_IO_CONTROL = TSrbIoControl; + PSrbIoControl = ^TSrbIoControl; + + TIDERegs = packed record + bFeaturesReg : Byte; // Used for specifying SMART "commands". + bSectorCountReg : Byte; // IDE sector count register + bSectorNumberReg : Byte; // IDE sector number register + bCylLowReg : Byte; // IDE low order cylinder value + bCylHighReg : Byte; // IDE high order cylinder value + bDriveHeadReg : Byte; // IDE drive/head register + bCommandReg : Byte; // Actual IDE command. + bReserved : Byte; // reserved for future use. Must be zero. + end; + IDEREGS = TIDERegs; + PIDERegs = ^TIDERegs; + + TSendCmdInParams = packed record + cBufferSize : DWORD; // Buffer size in bytes + irDriveRegs : TIDERegs; // Structure with drive register values. + bDriveNumber : Byte; // Physical drive number to send command to (0,1,2,3). + bReserved : Array[0..2] of Byte; // Reserved for future expansion. + dwReserved : Array[0..3] of DWORD; // For future use. + bBuffer : Array[0..0] of Byte; // Input buffer. + end; + SENDCMDINPARAMS = TSendCmdInParams; + PSendCmdInParams = ^TSendCmdInParams; + + TIdSector = packed record + wGenConfig : Word; + wNumCyls : Word; + wReserved : Word; + wNumHeads : Word; + wBytesPerTrack : Word; + wBytesPerSector : Word; + wSectorsPerTrack : Word; + wVendorUnique : Array[0..2] of Word; + sSerialNumber : Array[0..19] of Char; + wBufferType : Word; + wBufferSize : Word; + wECCSize : Word; + sFirmwareRev : Array[0..7] of Char; + sModelNumber : Array[0..39] of Char; + wMoreVendorUnique : Word; + wDoubleWordIO : Word; + wCapabilities : Word; + wReserved1 : Word; + wPIOTiming : Word; + wDMATiming : Word; + wBS : Word; + wNumCurrentCyls : Word; + wNumCurrentHeads : Word; + wNumCurrentSectorsPerTrack : Word; + ulCurrentSectorCapacity : ULONG; + wMultSectorStuff : Word; + ulTotalAddressableSectors : ULONG; + wSingleWordDMA : Word; + wMultiWordDMA : Word; + bReserved : Array[0..127] of Byte; + end; + PIdSector = ^TIdSector; + +const + IDE_ID_FUNCTION = $EC; + IDENTIFY_BUFFER_SIZE = 512; + DFP_RECEIVE_DRIVE_DATA = $0007c088; + IOCTL_SCSI_MINIPORT = $0004d008; + IOCTL_SCSI_MINIPORT_IDENTIFY = $001b0501; + DataSize = sizeof(TSendCmdInParams)-1+IDENTIFY_BUFFER_SIZE; + BufferSize = SizeOf(SRB_IO_CONTROL)+DataSize; + W9xBufferSize = IDENTIFY_BUFFER_SIZE+16; +var + hDevice : THandle; + cbBytesReturned : DWORD; + s : String; + pInData : PSendCmdInParams; + pOutData : Pointer; // PSendCmdInParams; + Buffer : Array[0..BufferSize-1] of Byte; + srbControl : TSrbIoControl absolute Buffer; + + procedure ChangeByteOrder( var Data; Size : Integer ); + var ptr : PChar; + i : Integer; + c : Char; + begin + ptr := @Data; + for i := 0 to (Size shr 1)-1 do + begin + c := ptr^; + ptr^ := (ptr+1)^; + (ptr+1)^ := c; + Inc(ptr,2); + end; + end; + +begin + Result := false; + FillChar(Buffer,BufferSize,#0); + if Win32Platform=VER_PLATFORM_WIN32_NT then + begin // Windows NT, Windows 2000 + Str(ControllerNumber,s); + // Get SCSI port handle + hDevice := CreateFile( + PChar('\\.\Scsi'+s+':'), + GENERIC_READ or GENERIC_WRITE, + FILE_SHARE_READ or FILE_SHARE_WRITE, nil, OPEN_EXISTING, 0, 0 ); + if hDevice=INVALID_HANDLE_VALUE then Exit; + try + srbControl.HeaderLength := SizeOf(SRB_IO_CONTROL); + System.Move('SCSIDISK',srbControl.Signature,8); + srbControl.Timeout := 2; + srbControl.Length := DataSize; + srbControl.ControlCode := IOCTL_SCSI_MINIPORT_IDENTIFY; + pInData := PSendCmdInParams(PChar(@Buffer)+SizeOf(SRB_IO_CONTROL)); + pOutData := pInData; + with pInData^ do + begin + cBufferSize := IDENTIFY_BUFFER_SIZE; + bDriveNumber := DriveNumber; + with irDriveRegs do + begin + bFeaturesReg := 0; + bSectorCountReg := 1; + bSectorNumberReg := 1; + bCylLowReg := 0; + bCylHighReg := 0; + bDriveHeadReg := $A0 or ((DriveNumber and 1) shl 4); + bCommandReg := IDE_ID_FUNCTION; + end; + end; + if not DeviceIoControl( hDevice, IOCTL_SCSI_MINIPORT, @Buffer, BufferSize, @Buffer, BufferSize, cbBytesReturned, nil ) then Exit; + finally + CloseHandle(hDevice); + end; + end + else + begin // Windows 95 OSR2, Windows 98 + hDevice := CreateFile( '\\.\SMARTVSD', 0, 0, nil, CREATE_NEW, 0, 0 ); + if hDevice=INVALID_HANDLE_VALUE then Exit; + try + pInData := PSendCmdInParams(@Buffer); + pOutData := PChar(@pInData^.bBuffer); + with pInData^ do + begin + cBufferSize := IDENTIFY_BUFFER_SIZE; + bDriveNumber := DriveNumber; + with irDriveRegs do + begin + bFeaturesReg := 0; + bSectorCountReg := 1; + bSectorNumberReg := 1; + bCylLowReg := 0; + bCylHighReg := 0; + bDriveHeadReg := $A0 or ((DriveNumber and 1) shl 4); + bCommandReg := IDE_ID_FUNCTION; + end; + end; + if not DeviceIoControl( hDevice, DFP_RECEIVE_DRIVE_DATA, pInData, SizeOf(TSendCmdInParams)-1, pOutData, W9xBufferSize, cbBytesReturned, nil ) then Exit; + finally + CloseHandle(hDevice); + end; + end; + + with PIdSector(PChar(pOutData)+16)^ do + begin + ChangeByteOrder(sSerialNumber,SizeOf(sSerialNumber)); + SetString(s,sSerialNumber,SizeOf(sSerialNumber)); + end; + OutBuf := Trim(s); + Result := true; + +end; + + + +end. + + +