294 lines
11 KiB
Plaintext
294 lines
11 KiB
Plaintext
/*
|
|
* File......: FLOPTST.PRG
|
|
* Author....: Gary Smith
|
|
* CIS ID....: 70714,3015
|
|
*
|
|
* This work is based on an original work by Joseph LaCour that
|
|
* was placed in the public domain. This work is placed in the
|
|
* public domain.
|
|
*
|
|
* ACKNOWLEDGEMENTS:
|
|
*
|
|
* PAOLO RAMOZZI FOR HIS WORK IN DBDCHECK FOR SHOWING HOW TO
|
|
* USE INT 13H.
|
|
*
|
|
*
|
|
* Modification history:
|
|
* ---------------------
|
|
*
|
|
* Rev 1.4 05 May 1995 03:05:00 TED
|
|
* Gary Smith ported ASM source to Clipper.
|
|
*
|
|
* Rev 1.3 23 Sep 1991 14:56:42 GLENN
|
|
* Bug reports from Craig Austin, James Finnal, and Ted Means. Line 128
|
|
* had MOV FDRIVE,AL which should have been MOV FDRIVE,BL. This caused the
|
|
* function to erroneously use the last drive available instead of the one
|
|
* specified by the calling process.
|
|
*
|
|
* Rev 1.2 15 Aug 1991 23:07:48 GLENN
|
|
* Forest Belt proofread/edited/cleaned up doc
|
|
*
|
|
* Rev 1.1 11 May 1991 00:21:42 GLENN
|
|
* File header changed to conform to Toolkit standard.
|
|
*
|
|
|
|
* $DOC$
|
|
* $FUNCNAME$
|
|
* FT_FLOPTST()
|
|
* $CATEGORY$
|
|
* DOS/BIOS
|
|
* $ONELINER$
|
|
* Test diskette drive status
|
|
* $SYNTAX$
|
|
* FT_FLOPTST( <nDrive> ) -> nStatus
|
|
* $ARGUMENTS$
|
|
* <nDrive> is the diskette drive number, 0 = A:, 1 = B:
|
|
* $RETURNS$
|
|
* -1 - Wrong Parameters
|
|
* 0 - Drive Loaded and ready to read or write
|
|
* 1 - Drive Door Open or Diskette inserted upside down
|
|
* 2 - Diskette is unformatted
|
|
* 3 - Write protected
|
|
* 4 - Undetermined
|
|
* $DESCRIPTION$
|
|
* FT_FLOPTST() is designed as a full replacement for ISDRIVE(). Where
|
|
* ISDRIVE() returns just .T. or .F. depending if the diskette drive is
|
|
* ready or not, FT_FLOPTST() returns a numeric code designating the
|
|
* diskette drive's status.
|
|
*
|
|
* FT_FLOPTST() is particularly useful in backup and restore programs
|
|
* that need to test the floppy drive before writing/reading from a
|
|
* floppy disk.
|
|
*
|
|
* No testing has been performed on systems with more than 2 floppy
|
|
* drives. If the third drive is "C" and the fourth "D" then there
|
|
* should be no problems.
|
|
*
|
|
* This function does not currently check subst'd drives. So if you
|
|
* have SUBST E: A:\ then FT_FLOPTST( ASC("E")-ASC("A") ) == 4
|
|
* Any suggestions to fix this limitation are appreciated.
|
|
*
|
|
* $EXAMPLES$
|
|
* iStatus := FT_FLOPTST( 0 )
|
|
* DO CASE
|
|
* CASE iStatus == 1
|
|
* Qout( "The door to drive A is open." )
|
|
* CASE iStatus == 2
|
|
* Qout( "The diskette in drive A is not formatted." )
|
|
* CASE iStatus == 3
|
|
* Qout( "The diskette in drive A is write-protected." )
|
|
* CASE iStatus == 4
|
|
* Qout( "Something is wrong with drive A, but I don't know what." )
|
|
* ENDCASE
|
|
* $END$
|
|
*
|
|
*/
|
|
|
|
#include "ftint86.ch"
|
|
|
|
#define TRUE .T.
|
|
#define FALSE .F.
|
|
|
|
#DEFINE ERR_WRONG_PARAMETERS -1
|
|
#DEFINE ERR_NO_ERROR 0
|
|
#DEFINE ERR_DRIVE_NOT_READY 1
|
|
#DEFINE ERR_UNFORMATTED 2
|
|
#DEFINE ERR_WRITE_PROTECTED 3
|
|
#DEFINE ERR_UNKNOWN 4
|
|
|
|
#IFDEF FT_TEST
|
|
#define CR_LF chr(13)+chr(10)
|
|
|
|
PROCEDURE MAIN( ;
|
|
cArg1 ;
|
|
)
|
|
LOCAL nErrCode
|
|
|
|
IF ValType( cArg1 ) == "C"
|
|
nErrCode := FT_FLOPTST( Asc( Upper(cArg1) ) - Asc( "A" ) )
|
|
OutStd( "Return Code is "+LTrim(Str(nErrCode)) +CR_LF )
|
|
ELSE
|
|
OutStd( "Usage: floptst cDrive"+CR_LF+" where cDrive is 'A' or 'B' etc..."+CR_LF )
|
|
ENDIF
|
|
|
|
RETURN
|
|
|
|
#ENDIF
|
|
|
|
|
|
FUNCTION FT_FLOPTST( ; // error code defined by ERR_*
|
|
nDriveNum_i ; // letter of floppy drive.
|
|
)
|
|
LOCAL cDrive
|
|
LOCAL cBuffer
|
|
LOCAL nErrorCode
|
|
LOCAL nRetCode
|
|
|
|
nRetCode := ERR_WRONG_PARAMETERS
|
|
IF ValType( nDriveNum_i ) == "N"
|
|
|
|
IF _GetDisketteNum( nDriveNum_i )
|
|
_ResetDisketteSystem()
|
|
_ReadBootSector( nDriveNum_i, @cBuffer, @nErrorCode )
|
|
|
|
IF nErrorCode == 0
|
|
_WriteBootSector( nDriveNum_i, cBuffer, @nErrorCode )
|
|
DO CASE
|
|
CASE nErrorCode == 0
|
|
nRetCode := ERR_NO_ERROR
|
|
CASE nErrorCode == 3
|
|
nRetCode := ERR_WRITE_PROTECTED
|
|
OTHERWISE
|
|
nRetCode := ERR_UNKNOWN
|
|
ENDCASE
|
|
ELSE
|
|
DO CASE
|
|
CASE nErrorCode == 128 // 80h
|
|
nRetCode := ERR_DRIVE_NOT_READY
|
|
CASE nErrorCode == 2
|
|
nRetCode := ERR_UNFORMATTED
|
|
OTHERWISE
|
|
nRetCode := ERR_UNKNOWN
|
|
END CASE
|
|
ENDIF
|
|
ENDIF
|
|
ENDIF
|
|
|
|
RETURN nRetCode
|
|
|
|
#define BITS_6AND7 192 // value of byte when bits 6&7 are high
|
|
|
|
STATIC FUNCTION _GetDisketteNum( ; // returns false if no floppy drive installed or nDrive_i is invalid
|
|
nDrive_i ; // drive number to query status
|
|
)
|
|
LOCAL aRegs[INT86_MAX_REGS]
|
|
LOCAL lRetCode
|
|
LOCAL nByte
|
|
LOCAL nDriveCount
|
|
|
|
// ASSERT 0 <= nDrive_i
|
|
|
|
lRetCode := FALSE
|
|
IF FT_INT86( 1*16+1, aRegs ) // INT for equipment determination
|
|
nByte := lowbyte( aRegs[AX] )
|
|
// bit 0 indicates floppy drive installed
|
|
IF Int( nByte / 2 ) * 2 != nByte // is it odd i.e. is bit 0 set??
|
|
// bits 6 & 7 indicate number of floppies installed upto 4.
|
|
nDriveCount := Asc( FT_BYTEAND( Chr(nByte), chr(BITS_6AND7) ) )
|
|
IF nDriveCount >= nDrive_i
|
|
lRetCode := TRUE
|
|
ENDIF
|
|
ENDIF
|
|
ENDIF
|
|
|
|
RETURN lRetCode
|
|
|
|
|
|
STATIC PROCEDURE _ResetDisketteSystem()
|
|
LOCAL aRegs[INT86_MAX_REGS]
|
|
|
|
aRegs[AX] := 0
|
|
|
|
FT_INT86( 1*16+3, aRegs )
|
|
|
|
RETURN
|
|
|
|
#define BUFFER_SIZEOF_SECTOR 512+1
|
|
|
|
STATIC FUNCTION _ReadBootSector( ;
|
|
nDriveNum, ;
|
|
cBuffer_o, ;
|
|
nErrCode_o ;
|
|
)
|
|
// call BIOS INT 13 for sector read
|
|
LOCAL aRegs[INT86_MAX_REGS]
|
|
LOCAL cBuffer := Space( BUFFER_SIZEOF_SECTOR )
|
|
LOCAL lSuccess
|
|
LOCAL nErrorCode
|
|
LOCAL lCarryFlag
|
|
|
|
aRegs[DX] := nDriveNum // DH = 0 Head 0, DL = drive number
|
|
aRegs[CX] := 1 // CH = 0 track 0, CL=1 sector 1
|
|
aRegs[BX] := REG_ES // buffer in ES:BX
|
|
aRegs[ES] := cBuffer
|
|
aRegs[AX] := makehi(2)+1 // AH = 02 read , AL=1 read one sector
|
|
|
|
lSuccess := _CallInt13hRetry( aRegs, @lCarryFlag, @nErrorCode )
|
|
|
|
cBuffer_o := aRegs[ES]
|
|
nErrCode_o := nErrorCode
|
|
|
|
RETURN lSuccess
|
|
|
|
|
|
STATIC FUNCTION _WriteBootSector( ;
|
|
nDriveNum, ;
|
|
cBuffer_i, ;
|
|
nErrCode_o ;
|
|
)
|
|
// call BIOS INT 13 for sector write
|
|
LOCAL aRegs[INT86_MAX_REGS]
|
|
LOCAL lSuccess
|
|
LOCAL nErrorCode
|
|
LOCAL lCarryFlag
|
|
|
|
aRegs[DX] := nDriveNum // DH = 0 Head 0 , DL = drive number
|
|
aRegs[CX] := 1 // CH = 0 track 0, CL=1 sector 1
|
|
aRegs[BX] := REG_ES // buffer in ES:BX
|
|
aRegs[ES] := cBuffer_i
|
|
aRegs[AX] := makehi(3)+1 // AH = 03 write , AL=1 read one sector
|
|
|
|
lSuccess := _CallInt13hRetry( aRegs, @lCarryFlag, @nErrorCode )
|
|
|
|
nErrCode_o := nErrorCode
|
|
|
|
RETURN lSuccess
|
|
|
|
|
|
STATIC FUNCTION _CallInt13hRetry( ; // logical: did the interrupt succeed?
|
|
aRegs_io, ; // registers values for INT 13h
|
|
lCarrySet_o, ; // status of carry flag if return code is true.
|
|
nDriveStatus_o ; // status of drive ( error code )
|
|
)
|
|
LOCAL lCarrySet
|
|
LOCAL aRegisters
|
|
LOCAL lSuccess
|
|
LOCAL nInterrupt_c := 1*16+3 // INT 13h
|
|
LOCAL i
|
|
|
|
lCarrySet := FALSE
|
|
aRegisters := AClone( aRegs_io )
|
|
lSuccess := FT_INT86( nInterrupt_c, aRegisters )
|
|
IF lSuccess
|
|
lCarrySet := carrySet( aRegisters[FLAGS] )
|
|
IF lCarrySet
|
|
_ResetDisketteSystem()
|
|
|
|
aRegisters := AClone( aRegs_io )
|
|
FT_INT86( nInterrupt_c, aRegisters )
|
|
lCarrySet := carrySet( aRegisters[FLAGS] )
|
|
IF lCarrySet
|
|
_ResetDisketteSystem()
|
|
|
|
aRegisters := AClone( aRegs_io )
|
|
FT_INT86( nInterrupt_c, aRegisters )
|
|
lCarrySet := carrySet( aRegisters[FLAGS] )
|
|
IF lCarrySet
|
|
_ResetDisketteSystem()
|
|
ENDIF
|
|
ENDIF
|
|
ENDIF
|
|
ENDIF
|
|
|
|
FOR i := 1 TO INT86_MAX_REGS
|
|
// pass altered register back up
|
|
aRegs_io[i] := aRegisters[i]
|
|
NEXT // i
|
|
lCarrySet_o := lCarrySet
|
|
nDriveStatus_o := highByte( aRegisters[AX] )
|
|
|
|
RETURN lSuccess
|
|
|
|
// EOF
|
|
|