;-----------------------------------------------------------------------
; Disketten I/O
; Input:
; (ah)=0 Reset Diskette System
; hard reset to nec, prepare command, recal rquired
; on all drives
; (ah)=1 read the status of the system into (al)
; diskette_status from last operation is used
;
; Registers for read/write/verify/format
; (dl) drive number (0-3 allowed, vlue checked)
; (dh) head number (0-1 allowed, not value checked)
; (ch) track number (0-39, not value checked)
; (cl) sektor number (1-8, not value checked,
; not used for format)
; (al) number of sektors ( max = 8, not value checked,
; not used for format
; (es:bx) address of buffer (not required for verify)
; (ah)=2 read the desired sektors into memory
; =3 write
; =4 verify
; =5 format
; for the format operation, the buffer pointer (es,bx)
; must point to the collektion of desired address fields
; for the track. Each field is composed of 4 Bytes,
; (c,h,r,n) where c = track number, h=head number,
; r = sektor number, n = number of bytes per sektor
; (00=128, 01=256, 02=512, 03=1024). There must be one
; entry for every sektor on the track. This information
; is used to find the requested sektor during read/write
; access.
;
; Data Variable -- disk_pointer
; double word pointer to the current set of diskette parameters
; Output
; ah = status of Operation
; Status bits are defined in the equates for
; Diskette_status variable in the data segment of this
; module.
; cy = 0 successful operation (ah = 0 on return)
; cy = 1 failed operation (ah has error reason)
; for read/write/verify
; ds,bx,dx,ch,cl reserved
; al = number of sektors actually read
; ***** al may not be correkt if time out error occurs
; note: if an error is reported by the diskette code, the
; appropriate action is to reset the diskette, then retry
; the operation, on read access, no motor start delay
; is taken, so that three retries are required on reads
; to ensure that the problem is not due to motor
; start-up.
;-----------------------------------------------------------------------
data segment at 40h
org 3eh
seek_status db ?
int_flag equ 80h
motor_status db ?
motor_count db ?
motor_wait equ 37
diskette_status db ?
nec_status db 7 dup(?)
data ends
assume ds:data
ife withhd
dma equ 0 ; dma address
dma_high equ 82h ; port for high 4 bits of dma
endif
diskette_io proc near
sti
push bx
push cx
push ds
push si
push di
push bp
push dx
mov bp,sp ; set up pointer to head parm
mov si,data
mov ds,si
call j1 ; call the rest to ensure ds restored
mov bx,4 ; get the motor wait parameter
call get_parm
mov motor_count,ah ; set the timer count for the motor
mov ah,diskette_status ; get status of operation
cmp ah,1 ; set the carry flag to indicate
cmc ; success or failure
pop dx
pop bp
pop di
pop si
pop ds
pop cx
pop bx
ret
diskette_io endp
j1 proc near
mov dh,al
and motor_status,07fh
or ah,ah
jz disk_reset
dec ah
jz fdisk_status
mov diskette_status,0
cmp dl,4
jae j3
dec ah
jz fdisk_read
dec ah
jnz j2
jmp fdisk_write
j2:
dec ah
jz disk_verf
dec ah
jz disk_format
j3:
mov diskette_status,bad_cmd
ret
j1 endp
;----- reset the diskette system
disk_reset proc near
mov dx,03f2h
cli
mov al,motor_status
mov cl,4
sal al,cl
test al,20h
jnz j5
test al,40h
jnz j4
test al,80h
jz j6
inc al
j4:
inc al
j5:
inc al
j6:
or al,8
out dx,al
mov seek_status,0
mov diskette_status,0
or al,4
out dx,al
sti
call chk_stat_2
mov al,nec_status
cmp al,0c0h
jz j7
or diskette_status,bad_cntlr
ret
;----- send specific command to nec
j7:
mov ah,3
call nec_output
mov bx,1
call get_parm
mov bx,3
call get_parm
j8:
ret
disk_reset endp
;-----diskette status routine
fdisk_status proc near
mov al,diskette_status
ret
fdisk_status endp
;-----diskette read
fdisk_read proc near
mov al,046h
j9:
call dma_setup
mov ah,0e6h
jmp short rw_opn
fdisk_read endp
;----- diskette verify
disk_verf proc near
mov al,042h
jmp j9
disk_verf endp
;----- diskette format
disk_format proc near
or motor_status,80h
mov al,04ah
call dma_setup
mov ah,04dh
jmp short rw_opn
j10:
mov bx,7
call get_parm
mov bx,9
call get_parm
mov bx,15
call get_parm
mov bx,17
jmp j16
disk_format endp
;-----diskette write routine
fdisk_write proc near
or motor_status,80h
mov al,04ah
call dma_setup
mov ah,0c5h
fdisk_write endp
;-----allow write routine to fall into rw_opn
;-----------------------------------------------------------------------
; rw_opn
; this routine performs the read/write/verify operation
;-----------------------------------------------------------------------
rw_opn proc near
jnc j11
mov diskette_status,dma_boundary
mov al,0
ret
j11:
push ax
;----- turn on the motor and select the drive
push cx
mov cl,dl
mov al,1
sal al,cl
cli
mov motor_count,0ffh
test al,motor_status
jnz j14
and motor_status,0f0h
or motor_status,al
sti
mov al,10h
sal al,cl
or al,dl
or al,0ch
push dx
mov dx,03f2h
out dx,al
pop dx
;----- wait for motor if write operation
test motor_status,80h
jz j14
clc
mov ax,090fdh
int 15h
jc j14
mov bx,20
call get_parm
or ah,ah
j12:
jz j14
sub cx,cx
j13:
loop j13
dec ah
jmp j12
j14:
sti
pop cx
;----- do the seek operation
call seek
pop ax
mov bh,ah
mov dh,0
jc j17
mov si,offset j17
push si
;----- send out the parameters to the controller
call nec_output
mov ah,[bp+1]
sal ah,1
sal ah,1
and ah,4
or ah,dl
call nec_output
;----- test for format command
cmp bh,04dh
jne j15
jmp j10
j15:
mov ah,ch
call nec_output
mov ah,[bp+1]
call nec_output
mov ah,cl
call nec_output
mov bx,7
call get_parm
mov bx,9
call get_parm
mov bx,11
call get_parm
mov bx,13
j16:
call get_parm
pop si
;----- let the operation happen
call wait_int
j17:
jc j21
call results
jc j20
;----- check the results returned by the controller
cld
mov si,offset nec_status
lods nec_status
and al,0c0h
jz j22
cmp al,040h
jnz j18
;----- abnormal termination, find out wy
lods nec_status
sal al,1
mov ah,record_not_fnd
jc j19
sal al,1
sal al,1
mov ah,bad_crc
jc j19
sal al,1
mov ah,bad_dma
jc j19
sal al,1
sal al,1
mov ah,record_not_fnd
jc j19
sal al,1
mov ah,write_protect
jc j19
sal al,1
mov ah,bad_addr_mark
jc j19
;----- nec must have failed
j18:
mov ah,bad_cntlr
j19:
or diskette_status,ah
call num_trans ; how many were really transferred
j20:
ret
j21:
call results
ret
;----- operation was successfull
j22:
call num_trans
xor ah,ah
ret
rw_opn endp
;-----------------------------------------------------------------------
; nec_output
; This routine sends a byte to the nec controller after testing
; for correct direction and controller ready. This routine will
; time out if the byte is not accepted within a reasonable
; amount of time, setting the diskette status on completion.
; Input
; (ah) byte to be output
; Output
; cy=0 success
; cy=1 failure -- diskette status updated
; If a failure has occured, the return is made one level
; higher than the caller of nec_output. (!Schweinkram)
; This removes the requirement of testing after every
; call of nec_output
; (al) destroyed
;-----------------------------------------------------------------------
nec_output proc near
push dx
push cx
mov dx,03f4h
xor cx,cx
j23:
in al,dx
test al,040h
jz j25
loop j23
j24:
or diskette_status,time_out
pop cx
pop dx
pop ax ; discard the return address
stc
ret
j25:
xor cx,cx
j26:
in al,dx
test al,080h
jnz j27
loop j26
jmp j24
j27:
mov al,ah
mov dl,0f5h
out dx,al
pop cx
pop dx
ret
nec_output endp
;-----------------------------------------------------------------------
; get_parm
; This routine fetches the indext pointer from the disk_bas
; block pointed at by the data variable disk_pointer. A byte from
; that table is then moved into ah, the index of that byte being
; the parm in bx
; Input:
; bx index of byte to be fetched *2
; if the low bit of bx is on, the byte is immediately output
; to the nec controller
; Exit
; am that byte from block
;-----------------------------------------------------------------------
disk_pointer equ 1eh * 4
get_parm proc near
push ds
push si
sub ax,ax
mov ds,ax
lds si,dword ptr ds:disk_pointer
shr bx,1
mov ah,[si+bx]
pop si
pop ds
jc nec_output
ret
get_parm endp
;-----------------------------------------------------------------------
; seek
; Thi routine will move the head on the named drive to the
; named track. If the drive has not been accessed since the
; drive reset command was issued, the drive will be recalibrated.
; Input:
; (dl) = Drive to seek on
; (ch) = track t seek to
; Output:
; cy = 0 success
; cy = 1 failure -- diskette_status set accordingly
; (ax) destroyed
;-----------------------------------------------------------------------
seek proc near
mov al,1
push cx
mov cl,dl
rol al,cl
pop cx
test al,seek_status
jnz j28
or seek_status,al
mov ah,07h
call nec_output
mov ah,dl
call nec_output
call chk_stat_2
jc j32
;----- drive is in synch with controller, seek to track
j28:
mov ah,0fh
call nec_output
mov ah,dl
call nec_output
mov ah,ch
call nec_output
call chk_stat_2
;----- wait for head settle
pushf
mov bx,18
call get_parm
push cx
j29:
mov cx,550
or ah,ah
jz j31
j30:
loop j30
dec ah
jmp j29
j31:
pop cx
popf
j32:
ret
seek endp
;-----------------------------------------------------------------------
; dma_setup
; this routine sets up the dma for read/write/verify operations
; input:
; (al) = mode byte for the dma
; (es:bx) - address to read/write the data
; output:
; (ax) destroyed
;-----------------------------------------------------------------------
dma_setup proc near
push cx
cli
out dma+12,al
push ax
pop ax
out dma+11,al
mov ax,es
mov cl,4
rol ax,cl
mov ch,al
and al,0f0h
add ax,bx
jnc jj33
inc ch
jj33:
push ax
out dma+4,al
mov al,ah
out dma+4,al
mov al,ch
and al,0fh
out 081h,al
;----- determine count
mov ah,dh
sub al,al
shr ax,1
push ax
mov bx,6
call get_parm
mov cl,ah
pop ax
shl ax,cl
dec ax
push ax
out dma+5,al
mov al,ah
out dma+5,al
sti
pop cx
pop ax
add ax,cx
pop cx
mov al,2
out dma+10,al
ret
dma_setup endp
;-----------------------------------------------------------------------
; chk_stat_2
; This routine handles the interrupt received after a
; recalibrate, seek, or reset to the adapter.
; The interrupt is waited for, the interrupt sensed,
; and the result returned to the caller.
; input:
; none
; output:
; cy = 0 success
; cy = 1 failure -- error is in diskette_status
; (ax) destroyed
;-----------------------------------------------------------------------
chk_stat_2 proc near
call wait_int
jc j34
mov ah,08h
call nec_output
call results
jc j34
mov al,nec_status
and al,060h
cmp al,060h
jz j35
clc
j34:
ret
j35:
or diskette_status,bad_seek
stc
ret
chk_stat_2 endp
;-----------------------------------------------------------------------
; wait_int
; This routine waits for an interrupt to occur. A time out
; routine takes place during the wait, so that an error may be
; returned if the drive is not ready.
; input:
; none
; output:
; cy = 0 success
; cy = 1 failure -- diskette_status is set accordingly
; (ax) destroyed
;-----------------------------------------------------------------------
wait_int proc near
sti
push ax
push bx
push cx
clc
mov ax,09001h
int 15h
sti
jc j36a
;
mov bl,2
xor cx,cx
j36:
test seek_status,int_flag
jnz j37
; push cx
; push bx
; push ds
; push es
; push ax
; push dx
; push si
; push di
; push bp
; call cs:warte
; pop bp
; pop di
; pop si
; pop dx
; pop ax
; pop es
; pop ds
; pop bx
; pop cx
loop j36
dec bl
jnz j36
j36a: or diskette_status, time_out
stc
j37:
pushf
and seek_status, not int_flag
popf
pop cx
pop bx
pop ax
ret
wait_int endp
;-----------------------------------------------------------------------
; disk_int
; This routine handles the diskette interrupt
; Input
; none
; output:
; The interrupt flag is set is seek_status
;-----------------------------------------------------------------------
;**************
;org 0ef57h
;**************
disk_int proc far
sti
push ds
push ax
push si
mov si,data
mov ds,si
or seek_status, int_flag
mov al,20h
out 20h,al
mov ax,09101h
int 15h
pop si
pop ax
pop ds
iret
disk_int endp
;-----------------------------------------------------------------------
; results
; This routine will read anything that the nec controller has
; to say following an interrupt.
; input:
; none
; output:
; cy = 0 successful transfer
; cy = 1 failure -- time out in waiting for status
; nec_status area has status byte loaded into it
; (ah) destroyed
;-----------------------------------------------------------------------
results proc near
cld
mov di,offset nec_status
push cx
push dx
push bx
mov bl,7
;-----wait for request for master
j38:
xor cx,cx
mov dx,03f4h
j39:
in al,dx
test al,80h
jnz j40a
loop j39
or diskette_status, time_out
j40:
stc
pop bx
pop dx
pop cx
ret
;----- test the direction bit
j40a:
in al,dx
test al,40h
jnz j42
j41:
or diskette_status,bad_cntlr
jmp j40
;-----read in the status
j42:
inc dx
in al,dx
mov [di],al
inc di
mov cx,10
j43: loop j43
dec dx
in al,dx
test al,10h
jz j44
dec bl
jnz j38
jmp j41
;----- result operation is done
j44:
pop bx
pop dx
pop cx
ret
;-----------------------------------------------------------------------
; num_trans
; This routine calculates the number of sectors that were
; actually transferred to/from the diskette
; input
; (ch) = cylinder of operation
; (cl) = start sector of operation
; output
; (al) = number actually transferred
; no other registers modified
;-----------------------------------------------------------------------
num_trans proc near
mov al,nec_status+3
cmp al,ch
mov al,nec_status+5
jz j45
mov bx,8
call get_parm
mov al,ah
inc al
j45:
sub al,cl
ret
num_trans endp
results endp
assume ds:shard