; Hard disk I/O for MS-DOS 2.0 PAGE 60,132 INCLUDE IODEF.ASM IO GROUP CODE CODE SEGMENT BYTE PUBLIC 'IOSYS' ASSUME CS:IO, DS:IO ;---------------------------------------- IF INSTALL HDSKDEV: ;Header for hard disk DD -1 DW 2000H DW STRATEGY DW HDSK$IN DB ? ELSE PUBLIC HDSKTBL EXTRN EXIT:NEAR, CMDERR:NEAR, BUS$EXIT:NEAR, PTRSAV:DWORD ENDIF ;----------------------------------------- HDSKTBL: DW HDSK$INIT DW HARDCHG DW GET$HBPB DW CMDERR DW HARDREAD DW BUS$EXIT DW EXIT DW EXIT DW HARDWRITE DW HARDWRITE ;************************************************************* DIRENT EQU 96 ALLOCSIZ EQU 4 FATSIZ EQU 6 IF IMI NHEADS EQU 6 ; Number of heads NSECT EQU 8 ; Number of sectors per track NTRACKS EQU 306 ; Number of cylinders LOWCURTRK EQU 0 ; First track of low write current PRECOMTRK EQU 256 ; First track to set precomp bit ENDIF IF SCRIBE NHEADS EQU 4 ; Number of heads NSECT EQU 8 ; Number of sectors per track NTRACKS EQU 480 ; Number of cylinders LOWCURTRK EQU 0 ; First track of low write current PRECOMTRK EQU 0 ; First track to set precomp bit ENDIF RESETHDC EQU 54H STARTHDC EQU 55H HARDRDOP EQU 0 HARDWROP EQU 1 RETRY EQU 3 ; # of times to try disk command TIMEOUT EQU 10 ; 0.2 sec/loop--set 2 seconds for 10 MHZ CPU HDCPARAM: HDIR DB 0 ; Direction HSTEP DW 1 ; Amount to step HDRIVE DB 0DCH ; Drive/head select DMAAD DW 0 ; DMA address DMAHI DB 0 ARG1: HCYL DW -1 ; Current cylinder HHEAD DB 0 ; Current head HSECT DB 0 ; Current sector OPCODE DB 0 ; Read/write code HSTAT DB 0 ; Return status IF INSTALL NEXTAD DW HDCPARAM ELSE NEXTAD DW HDCPARAM+10H*BIOSSEG ENDIF NEXTADHI DB 0 ;--------------------------------------------- IF INSTALL PTRSAV DD 0 STRATP PROC FAR STRATEGY: MOV WORD PTR CS:[PTRSAV],BX MOV WORD PTR CS:[PTRSAV+2],ES RET STRATP ENDP HDSK$IN: PUSH SI MOV SI,OFFSET IO:HDSKTBL DISPATCH PROC FAR ENTRY: PUSH AX PUSH CX PUSH DX PUSH DI PUSH BP PUSH DS PUSH ES PUSH BX LDS BX,CS:[PTRSAV] ;GET POINTER TO I/O PACKET MOV AL,[BX.UNIT] ;AL = UNIT CODE MOV AH,[BX.MEDIA] ;AH = MEDIA DESCRIP MOV CX,[BX.COUNT] ;CX = COUNT MOV DX,[BX.START] ;DX = START SECTOR XCHG DI,AX MOV AL,[BX.CMD] XOR AH,AH ADD SI,AX ADD SI,AX CMP AL,11 JA CMDERR XCHG AX,DI LES DI,[BX.TRANS] PUSH CS POP DS CALL [SI] ;GO DO COMMAND LDS BX,CS:[PTRSAV] MOV [BX.STATUS],AX ;MARK OPERATION COMPLETE SUB [BX.COUNT],CX ;Subtract amount transfered POP BX POP ES POP DS POP BP POP DI POP DX POP CX POP AX POP SI RET ;RESTORE REGS AND RETURN DISPATCH ENDP ; Standard return types EXIT: XOR CX,CX ;Transfer complete MOV AH,00000001B ;All done RET BUS$EXIT: ;DEVICE BUSY EXIT MOV AH,00000011B RET CMDERR: MOV AL,3 ;UNKNOWN COMMAND ERROR MOV AH,10000001B ;MARK ERROR RETURN RET ENDIF ;--------------------------------------- HARDCHG: LDS BX,[PTRSAV] MOV BYTE PTR [BX.TRANS],1 ;Disk not changed JMP EXIT HARDREAD: MOV OPCODE,HARDRDOP JMP SHORT HARDIO HARDWRITE: MOV OPCODE,HARDWROP HARDIO: PUSH DS XOR SI,SI MOV BP,[NEXTAD] MOV AL,[NEXTADHI] MOV DS,SI MOV WORD PTR [SI+50H],BP MOV BYTE PTR [SI+52H],AL OUT RESETHDC,AL ; Reset hard disk controller POP DS MOV AX,ES SHL AX,1 RCL SI,1 SHL AX,1 RCL SI,1 SHL AX,1 RCL SI,1 SHL AX,1 RCL SI,1 ADD AX,DI MOV DMAAD,AX XCHG AX,SI ADC AL,0 MOV DMAHI,AL CMP HCYL,-1 ; Is current track invalid? JNZ COMPPOS CALL RESTORE ; Home disk head COMPPOS: PUSH DX MOV SI,NSECT ; Sector/track on hard disk XCHG AX,DX XOR DX,DX DIV SI ; AX=track, DX=sector INC DX ; Sector numbers start with 1 MOV HSECT,DL MOV SI,NHEADS XOR DX,DX DIV SI ; AX=cylinder, DX=head MOV HHEAD,DL SHL DL,1 SHL DL,1 NOT DL AND DL,9CH CMP AX,PRECOMTRK JB SAVHEAD1 OR DL,80H ; Turn on precomp SAVHEAD1: CMP AX,LOWCURTRK ; Need low write current? JAE SAVHEAD OR DL,40H ; Turn off low write current SAVHEAD: MOV HDRIVE,DL ; Drive/head select byte MOV DX,AX XCHG HCYL,AX ; Set current cyl, get previous SUB DX,AX ; Amount to move MOV AL,0 ; Assume movement IN JAE HAVSTEP NEG DX ; Get absolute value MOV AL,10H ; Set movement OUT HAVSTEP: MOV HDIR,AL MOV HSTEP,DX POP DX ; BX,CX,DX have orignal command parameters ; All set for hard disk operation! HARDREADWRITE: MOV AH,RETRY ; Retry count HCOM: CALL HDCCOM JNZ NOTNEXT ; If not successful, don't bump to next sector ADD DMAAD,1024 ADC DMAHI,0 INC DX MOV AL,HSECT INC AL CMP AL,NSECT+1 ; Stay on this track? MOV HSECT,AL LOOPNZ HARDREADWRITE JCXZ OKRET JMP COMPPOS ; Re-compute everything OKRET: MOV AH,1 ;No error RET NOTNEXT: CMP AL,1 ; Is drive not ready? JBE HARDERR ; Don't retry if not ready or time out DEC AH JNZ HCOM ; Hard disk error on hard disk. AL has the error code. Convert disk ; error code to MSDOS 2.0 error code HARDERR: MOV HCYL,-1 ; Force restore next time CMP AL,10 ; Is it a reasonable error code? JB NEXT1 MOV AL,0 ; General disk failure NEXT1: MOV BX,OFFSET IO:ERRTAB ; Set DOS error table XLAT MOV AH,81H ; ERROR RET ; CX = number of sectors to go ERRTAB: DB 12 ; General failure DB 2 ; Drive not ready DB 12 DB 12 DB 8 ; Sector not found DB 8 ; Data not found DB 12 ; Data overrun DB 4 ; Data CRC error DB 10 ; Write fault DB 4 ; Header CRC error ;Restore head on hard disk. RESTORE: MOV ARG1+1,30 ; 3 ms step time, no head settle delay MOV AX,7+100H*4 ; 1024 byte sector, LOAD CONSTANTS command XCHG AX,ARG1+3 ; Previous opcode in AH MOV BL,1 CALL QUICKCOM ; Execute command JNZ EXITREST ; Abort if controller failure MOV ARG1+1,0 ; Set to fast step (after restore) MOV HSTEP,0FFFH ; Maximum number of steps MOV HDIR,10H ; Step out CALL HDCCOM ; Restore and set fast seek MOV HCYL,0 ; Now on track zero EXITREST: MOV OPCODE,AH RET HDCCOM: MOV BL,TIMEOUT QUICKCOM: PUSH CX XOR CX,CX MOV HSTAT,0 OUT STARTHDC,AL HWAIT: MOV AL,HSTAT OR AL,AL LOOPZ HWAIT ; Try for 2 seconds JNZ HRET DEC BL JNZ HWAIT HRET: POP CX MOV HSTEP,0 CMP AL,-1 RET GET$HBPB: ; Set up BPB for Hard disk controller. Real simple isn't it? MOV SI,OFFSET IO:HARDDRIVE ; Hard disk Parm table SETBPB: LDS BX,[PTRSAV] MOV [BX.MEDIA],1 ;One hard disk MOV [BX.COUNT],SI MOV [BX.COUNT+2],CS JMP EXIT ; *************************************************************************** HINITTAB: DW HARDDRIVE HARDDRIVE: DW 1024 ; Sector size DB ALLOCSIZ ; Allocation unit DW 1 ; Reserved sectors DB 2 DW DIRENT ; Directory entries DW NSECT*NHEADS*NTRACKS DB 1 ; Media descriptor DW FATSIZ ; Number of sectors for 1 Fat BREAK LABEL BYTE ; Break address ;************************************************************** ; Code below this point is thrown away for installable versions HDSK$INIT: IF INSTALL MOV AX,CS MOV BX,AX MOV CL,4 SHL AX,CL ROL BX,CL AND BL,0FH ADD [NEXTAD],AX ADC [NEXTADHI],BL LDS BX,[PTRSAV] MOV WORD PTR [BX.TRANS],OFFSET IO:BREAK MOV WORD PTR [BX.TRANS+2],CS PUSH CS POP DS ENDIF MOV SI,OFFSET IO:HINITTAB JMP SETBPB CODE ENDS END