;; ; @(#) fddrv.asm - Bad-zero-track floppy disk driver (TSR). ; (c) 1997 Ivan Maidanski http://ivmai.chat.ru ; Freeware program source. All rights reserved. ;; ; Language: ASM8086 (for IBM PC/AT, MS-DOS v3.0+, COM file) ; Tested with: Turbo Assembler v3.1, Turbo Link v5.1 ; Last modified: 1997-06-28 15:45:00 GMT+04:00 ;; NAME Bad_Zero_Track_Floppy_Disk_Driver ; tasm fddrv.asm ; tlink /t fddrv.obj ; Comment: This driver enables You to use floppy disks with bad zero track. .MODEL SMALL .CODE .8086 Null LABEL NEAR ; Program constants DriverID= 0C184h FDDriveCnt= 4h RepeatCnt= 8h ; amount of cylinders to try ; PSP segment ORG 2Ch PSP@EnvSeg DW ? ; environment segment ORG 80h PSP@CmdLine DB 80h DUP(?) ; program command line ; RAM-resident part variables ORG 6Ch Int13hHandler@Old DD ? TrackMapTable DW FDDriveCnt DUP(?) ; RAM-resident part code shifted beginning TSRBegin= $ ; Program start point ORG 100h Start: cmp sp,OFFSET StackTop jae Start@CRef sub bp,bp ; abort program on no memory push es push bp retf Start@CRef: jmp Main EVEN ; RAM-resident part code ASSUME ds:NOTHING,es:NOTHING TSRShift= $-TSRBegin Int13hHandler PROC FAR ; Comment: BIOS disk i/o intercept handler ; Expects: ah - function number (2h,3h,4h,5h,27h), al - sector count, ; ch - cylinder number, cl - sector number, dl - drive, dh - head number, ; es:[bx] - buffer, bx - DriverID (if ah=27h) ; Returns: CF - error flag, ah - error code, ; al - number of sectors proceeded, ; bx=0 and es - TSR segment (if ah=27h and bx - DriverID) ; Uses: - (ax,CF)/(ax,bx,es) pushf cmp ah,1Ah ; service function ? jae Int13hHandler@Service cmp dl,FDDriveCnt ; check FDD number range jb Int13hHandler@CheckFunc Int13hHandler@FarJump: popf jmp cs:[Int13hHandler@Old] EVEN Int13hHandler@Service: cmp ah,27h ; Installation check ? jne Int13hHandler@FarJump cmp bx,DriverID jne Int13hHandler@FarJump popf mov ax,100h sub bx,bx push cs ; return TSR segment pop es push di jmp Int13hHandler@StoreErrRet EVEN Int13hHandler@CheckFunc: cmp ah,2h ; check for ReadSectors jb Int13hHandler@FarJump cmp ah,6h ; check for FormatTrack jae Int13hHandler@FarJump popf sti ; enable interrupts push di mov di,sp ; clear error flag and byte ptr ss:[di+6h],0FEh cmp ah,5h ; format zero track ? jne Int13hHandler@GetMapParam test cx,0FFC0h jne Int13hHandler@GetMapParam cmp dh,0 je Int13hHandler@QueryParams Int13hHandler@GetMapParam: mov di,dx ; get current track mapping parameters and di,0FFh shl di,1h add di,OFFSET TrackMapTable mov di,cs:[di] inc di ; no mapping yet ? jz Int13hHandler@AnalyzeDisk and di,0FFC0h push cx ; adjust values and cx,3Fh or di,cx pop cx test cx,0FFC0h ; zero cylinder ? xchg cx,di jz Int13hHandler@AccessDisk cmp cx,di ; work cylinder ? mov cx,di jne Int13hHandler@AccessDisk and cx,3Fh EVEN Int13hHandler@AccessDisk: cmp ah,5h ; prepare track layout for format operation ? jne Int13hHandler@AccessDiskCall push ax push di push cx mov di,bx mov cl,al mov ah,dh mov al,ch mov ch,0 cld EVEN Int13hHandler@AccessFillLoop: stosw inc di inc di loop Int13hHandler@AccessFillLoop pop cx pop di pop ax EVEN Int13hHandler@AccessDiskCall: pushf call cs:[Int13hHandler@Old] cmp ah,0 mov cx,di jne Int13hHandler@ErrRetCref jmp Int13hHandler@Ret EVEN Int13hHandler@ErrRetCref: jmp Int13hHandler@ErrRet EVEN Int13hHandler@AnalyzeDisk: cmp cx,1h ; read boot sector ? jne Int13hHandler@CannotAccess cmp dh,0 jne Int13hHandler@CannotAccess cmp ah,2h jne Int13hHandler@CannotAccess cmp al,0 ; nothing to do ? jne Int13hHandler@QueryParams mov ax,100h ; set "bad request" error flag jmp Int13hHandler@StoreErrRet EVEN Int13hHandler@CannotAccess: mov ax,600h ; cannot access if disk changed jmp Int13hHandler@StoreErrRet EVEN Int13hHandler@QueryParams: push ax push dx ; query drive parameters push es push bx mov ah,8h pushf call cs:[Int13hHandler@Old] pop bx pop es pop ax jnc Int13hHandler@SkipDefault mov cx,4F12h ; 18 sectors and 80 cylinders on DS disk by default mov dh,1h Int13hHandler@SkipDefault: mov dl,al mov ax,cx ; compute cylinder step rol al,1h rol al,1h xchg al,ah and ah,3h inc ax mov ch,RepeatCnt div ch xchg al,cl xchg ch,cl mov di,cx mov cl,dh mov ch,0 mov dh,0 EVEN Int13hHandler@TestTrack: pop ax cmp ah,5h ; format operation ? push ax jne Int13hHandler@ReadBoot push di ; prepare current track layout push cx mov di,bx mov cl,al mov ah,dh mov al,ch mov ch,0 cld EVEN Int13hHandler@FillLoop: stosw inc di inc di loop Int13hHandler@FillLoop pop cx pop di pop ax push ax pushf ; format track call cs:[Int13hHandler@Old] cmp ah,6h ; disk change line active ? je Int13hHandler@FailCrefDup pop ax push ax dec ah ; verify track EVEN Int13hHandler@ReadBoot: push cx mov cl,1h pushf call cs:[Int13hHandler@Old] cmp ah,0 pop cx je Int13hHandler@AccessOK cmp ah,3h ; write protected disk ? je Int13hHandler@FailCrefDup cmp ah,6h ; disk change line active ? je Int13hHandler@FailCrefDup cmp ah,9h ; DMA overrun ? je Int13hHandler@FailCrefDup sub ax,ax ; reset controller pushf call cs:[Int13hHandler@Old] pop ax cmp ah,5h ; format operation ? push ax jne Int13hHandler@ReadAgain pushf ; format track again call cs:[Int13hHandler@Old] cmp ah,6h ; disk change line active ? Int13hHandler@FailCrefDup: ; (ZF=1) je Int13hHandler@FailCref sub ax,ax ; reset controller pushf call cs:[Int13hHandler@Old] pop ax push ax dec ah ; verify track again EVEN Int13hHandler@ReadAgain: push cx mov cl,1h pushf call cs:[Int13hHandler@Old] cmp ah,0 pop cx jne Int13hHandler@CheckError EVEN Int13hHandler@AccessOK: pop ax cmp ah,5h ; go to next head ? push ax mov ah,0 jne Int13hHandler@CheckBoot cmp dh,cl ; last head ? jae Int13hHandler@StoreMapParam inc dh jmp Int13hHandler@TestTrack EVEN Int13hHandler@CheckBoot: cmp byte ptr es:[bx],0EBh ; check boot sector signature jne Int13hHandler@NextCylinder cmp byte ptr es:[bx+15h],0F0h jb Int13hHandler@NextCylinder test byte ptr es:[bx+0Bh],7Fh jnz Int13hHandler@NextCylinder EVEN Int13hHandler@StoreMapParam: add sp,2h mov di,dx ; store track mapping parameters push cx and di,3Fh and cl,0C0h shl di,1h add di,OFFSET TrackMapTable mov cs:[di],cx pop cx jmp short Int13hHandler@Ret EVEN Int13hHandler@CheckError: cmp ah,6h ; disk change line active ? Int13hHandler@FailCref: ; (ZF=1) je Int13hHandler@Fail cmp ah,20h ; permament error ? jae Int13hHandler@Fail cmp ah,8h ; DMA failure ? je Int13hHandler@Fail cmp ah,0Bh ; bad cylinder detected ? je Int13hHandler@NextCylinder test ah,1h ; permament error ? jnz Int13hHandler@Fail EVEN Int13hHandler@NextCylinder: dec di test di,03Fh ; continue ? jz Int13hHandler@BadDisk mov ax,di ; compute next cylinder number add ch,ah jnc Int13hHandler@TestTrackCref add cl,40h Int13hHandler@TestTrackCref: jmp Int13hHandler@TestTrack EVEN Int13hHandler@BadDisk: mov di,dx ; set "no mapping" flag shl di,1h add di,OFFSET TrackMapTable mov word ptr cs:[di],0 EVEN Int13hHandler@Fail: add sp,2h ; restore old values mov cx,1h EVEN Int13hHandler@ErrRet: cmp ah,6h ; disk change line active ? jne Int13hHandler@StoreErrRet mov di,dx ; reset zero track mapping parameters and di,0FFh shl di,1h add di,OFFSET TrackMapTable mov cs:[di],0FFFFh ; set "drive has not been accessed" flag EVEN Int13hHandler@StoreErrRet: mov di,sp ; store error flag or byte ptr ss:[di+6h],1h EVEN Int13hHandler@Ret: pop di iret Int13hHandler ENDP TSRLength= ($-Null)-TSRShift ; Non-resident part code ASSUME ds:@CODE,es:NOTHING Main PROC NEAR ; Comment: - ; Expects: ds=es=cs ; Returns: - (not applicable) ; Uses: - (all) mov sp,OFFSET StackTop mov ah,4Ah ; shrink memory block mov bx,(ProgramLength+0Fh)/10h ; size of program in paragraphs int 21h call TestDOSVer call DisableBreak mov ah,9h ; print introdation mov dx,OFFSET Main@MsgName int 21h mov si,OFFSET Main@Options ; get all program options call AnalyzeCMDLine test al,0Ch ; show help information ? jz Main@NoHelp mov ah,9h ; write help page to STDOUT mov dx,OFFSET Main@HelpPage int 21h jmp short Main@Exit Main@NoHelp: push ax ; preserve options presence byte call CheckPresence pop ax jnc Main@Already test al,1h ; -U ? jz Main@Inst mov ah,9h ; print error message mov dx,OFFSET Main@MsgNot int 21h mov ax,4C01h int 21h Main@Inst: test al,2h ; -I ? mov dx,OFFSET Main@MsgInfo jz Main@Print call FreeEnvSeg call SetUpTSR mov ah,9h ; print OK message mov dx,OFFSET Main@MsgOK int 21h mov ax,3100h ; terminate but stay resident mov dx,(TSRLength+0Fh)/10h int 21h Main@Already: test al,1h ; -U ? mov dx,OFFSET Main@MsgStatus jz Main@Print call ReleaseTSR mov ah,49h ; free RAM-resident part memory int 21h mov dx,OFFSET Main@MsgUn Main@Print: mov ah,9h ; print info int 21h Main@Exit: mov ax,4C00h int 21h Main@Options DB '?HIU',0 Main ENDP TestDOSVer PROC NEAR ; Comment: Tests for MS-DOS 3.0 or later ; Expects: ds=cs=PSP segment ; Returns: - (may not be applicable) ; Uses: ax,bx,cx mov ax,3000h ; get DOS version (al=0) int 21h cmp al,3h jae TestDOSVer@Ret mov ah,9h mov dx,OFFSET TestDOSVer@Msg int 21h int 20h ; CS must be the same as the PSP TestDOSVer@Ret: ret TestDOSVer ENDP DisableBreak PROC NEAR ; Comment: disable aborting program by 23h or 24h interrupts ; Expects: ds=cs ; Returns: - ; Uses: ax,dx mov ax,2523h ; set up empty int 23h handler ; Ignore CTRL+C (BREAK) mov dx,OFFSET DisableBreak@CtrlC int 21h mov ax,2524h ; set up new int 24h handler ; Fail operation mov dx,OFFSET DisableBreak@CritErr int 21h ret DisableBreak@CritErr: mov al,3h ; - fail DisableBreak@CtrlC: iret DisableBreak ENDP FreeEnvSeg PROC NEAR ; Comment: Free program environment segment ; Expects: - ; Returns: - ; Uses: ax,bx,es mov ah,51h ; get PSP segment int 21h mov es,bx sub ax,ax xchg ax,es:[PSP@EnvSeg] test ax,ax ; check for presence of PSP jz FreeEnvSeg@Ret mov es,ax mov ah,49h int 21h FreeEnvSeg@Ret: ret FreeEnvSeg ENDP AnalyzeCMDLine PROC NEAR ; Comment: get options presence word ; Expects: ds:[si] - options letters string (in upper case), es - PSP seg ; Returns: ax - options presence word, es:[di] - last option argument ; Uses: ax,bx,si,di cld sub bx,bx ; initialize flags lodsb AnalyzeCMDLine@Loop: mov ah,al call GetOption rcl bx,1h ; store presence flag lodsb test al,al ; end of string? jnz AnalyzeCMDLine@Loop mov ax,bx ret AnalyzeCMDLine ENDP GetOption PROC NEAR ; Comment: get option (/X or -X, case insensitive) ; Expects: ah - letter for which to scan (in upper case), es - PSP seg ; Returns: CF - "found" flag, es:[di] - found option argument ; Uses: al,di mov di,OFFSET PSP@CmdLine mov al,es:[di] ; get command line length test al,al ; clear "found" flag (CF=0) jz GetOption@Ret ; if none, return inc di GetOption@Loop: mov al,es:[di] inc di cmp al,' ' ; whitespace or end of command line? je GetOption@Loop cmc ; clear "found" flag if (al<' ') jnc GetOption@Ret cmp al,'/' je GetOption@Analyze cmp al,'-' jne GetOption@Skip GetOption@Analyze: mov al,es:[di] inc di cmp al,' ' ; whitespace or end of command line? je GetOption@Loop cmc ; clear "found" flag if (al<' ') jnc GetOption@Ret cmp al,'a' ; check for lower case jb GetOption@Upper cmp al,'z' ja GetOption@Upper sub al,'a'-'A' ; convert lower to upper case symbol GetOption@Upper: cmp al,ah stc ; set "found" flag je GetOption@Ret GetOption@Skip: mov al,es:[di] inc di cmp al,' ' ; whitespace or end of command line? je GetOption@Loop cmc ; clear "found" flag if (al<' ') jc GetOption@Skip GetOption@Ret: ret GetOption ENDP CheckPresence PROC NEAR ; Comment: Check whether Driver already installed ; Expects: - ; Returns: CF=1 - Driver not installed, es - TSR segment (if CF=0) ; Uses: ax,bx,es mov ah,27h ; installation check mov bx,DriverID int 13h dec ah jnz CheckPresence@Error test bx,bx ; ID accepted ? jz CheckPresence@Ret CheckPresence@Error: stc CheckPresence@Ret: ret CheckPresence ENDP SetUpTSR PROC NEAR ; Comment: initialize variables and set up new interrupt handlers ; Expects: ds=cs ; Returns: - (may not be applicable) ; Uses: ax,bx,cx,si,di,es cld ; reset TrackMapTable push ds pop es mov di,OFFSET TrackMapTable mov cx,FDDriveCnt mov ax,0FFFFh rep stosw mov si,OFFSET TSRBegin+TSRShift ; move resident part code mov di,OFFSET TSRBegin mov cx,(TSRLength-(TSRBegin-Null)+1h)/2h rep movsw mov ax,3513h ; store old int 13h handler addr int 21h mov word ptr [Int13hHandler@Old],bx mov word ptr [Int13hHandler@Old+2h],es mov ax,2513h ; set up new int 13h handler mov dx,OFFSET Int13hHandler-TSRShift int 21h ret SetUpTSR ENDP ReleaseTSR PROC NEAR ; Comment: check and restore old interrupt handlers ; Expects: ds=cs, es - TSR segment ; Returns: - (may not be applicable) ; Uses: ax,bx,dx mov dx,es mov ax,3513h ; check current int 13h handler int 21h mov ax,es cmp ax,dx jne ReleaseTSR@Err cmp bx,OFFSET Int13hHandler-TSRShift je ReleaseTSR@Restore ReleaseTSR@Err: mov ah,9h ; print error message mov dx,OFFSET ReleaseTSR@Msg int 21h mov ax,4C02h ; abort program int 21h ReleaseTSR@Restore: mov es,dx push ds mov ax,2513h ; restore old int 13h handler lds dx,es:[Int13hHandler@Old] int 21h pop ds ret ReleaseTSR ENDP ; Program messages Main@MsgName DB 'Bad-zero-track Floppy Disk Driver v1.4',0Dh,0Ah,'$' Main@MsgInfo DB 'For help, use option "/?".',0Dh,0Ah,'$' Main@MsgOK DB 'Driver installed successfully.',0Dh,0Ah,'$' Main@MsgUn DB 'Driver removed from memory successfully.',0Dh,0Ah,'$' Main@MsgStatus DB 'Driver installed.',0Dh,0Ah,'$' ReleaseTSR@Msg DB 'Driver cannot be uninstalled now.',0Dh,0Ah,'$' Main@MsgNot DB 'Error: Driver not installed.',0Dh,0Ah,'$' TestDOSVer@Msg DB 'Requires MS-DOS 3.0 or later.',0Dh,0Ah,'$' Main@HelpPage DB 0Dh,0Ah DB 'This driver enables you to format and use' DB ' floppy disks with bad zero track.',0Dh,0Ah DB 0Dh,0Ah DB 'Available options:',0Dh,0Ah DB ' -H ',' Display this help page',0Dh,0Ah DB ' -I ',' Install driver (as a TSR)',0Dh,0Ah DB ' -U ',' Uninstall driver',0Dh,0Ah DB 0Dh,0Ah,'$' ; Program stack EVEN DB 100h DUP(?) StackTop LABEL WORD ; End of program ProgramLength= $-Null END Start