mirror of
https://github.com/stevenhowes/wbios.git
synced 2026-05-26 15:53:34 +01:00
d410ad0acb
Original source https://www.pcengines.ch/file/wbios111s.zip
753 lines
17 KiB
Plaintext
753 lines
17 KiB
Plaintext
;
|
|
; Floppy BIOS
|
|
;
|
|
; (C)1997-2001 Pascal Dornier / PC Engines; All rights reserved.
|
|
; This file is licensed pursuant to the COMMON PUBLIC LICENSE 0.5.
|
|
;
|
|
; Limitations:
|
|
;
|
|
; - Only 3.5" floppy drives supported.
|
|
; - Only 1.44 MB mode supported.
|
|
; - Only one drive supported.
|
|
;
|
|
#if def DEBUG
|
|
FD_DEBUG: ;& enable debug code, comment out for
|
|
;production code
|
|
#endif
|
|
;
|
|
; INT 13 entry
|
|
;
|
|
int13: sti
|
|
push ds ;save registers
|
|
push es
|
|
pusha
|
|
mov bp,sp ;access to stack frame
|
|
#if def FD_DEBUG
|
|
call v_dump ;& dump registers
|
|
#endif
|
|
xor di,di ;access BIOS segment
|
|
mov ds,di
|
|
cmp ah,0 ;reset doesn't care about drive #
|
|
jz int13_1
|
|
cmp dl,0 ;valid drive ?
|
|
jnz fd_badcmd ;:bail out
|
|
int13_1: cmp byte [m_fdmed0],0 ;drive doesn't exist ?
|
|
jz fd_badcmd ;:bail out
|
|
mov di,ax ;command -> index
|
|
shr di,8
|
|
add di,di
|
|
and byte [bp+18h],0feh ;clear return carry
|
|
cmp di,19h*2 ;limit command vector
|
|
jae fd_badcmd
|
|
jmp [cs:di.fd_vectab] ;jump to command
|
|
;
|
|
; floppy vector table
|
|
;
|
|
fd_vectab: dw fd_rst ;AH=00: recalibrate drive
|
|
dw fd_status ;AH=01: get status
|
|
dw fd_read ;AH=02: read
|
|
dw fd_write ;AH=03: write
|
|
dw fd_verify ;AH=04: verify
|
|
dw fd_format ;AH=05: format track
|
|
dw fd_badcmd ;AH=06: bad
|
|
dw fd_badcmd ;AH=07: bad
|
|
dw fd_drvprm ;AH=08: read drive parameters
|
|
dw fd_badcmd ;AH=09: bad
|
|
dw fd_badcmd ;AH=0A: bad
|
|
dw fd_badcmd ;AH=0B: bad
|
|
dw fd_badcmd ;AH=0C: bad
|
|
dw fd_badcmd ;AH=0D: bad
|
|
dw fd_badcmd ;AH=0E: bad
|
|
dw fd_badcmd ;AH=0F: bad
|
|
dw fd_badcmd ;AH=10: bad
|
|
dw fd_badcmd ;AH=11: bad
|
|
dw fd_badcmd ;AH=12: bad
|
|
dw fd_badcmd ;AH=13: bad
|
|
dw fd_badcmd ;AH=14: bad
|
|
dw fd_gettyp ;AH=15: get drive type
|
|
dw fd_dskchg ;AH=16: get disk change status
|
|
dw fd_fmttyp ;AH=17: set drive type for format
|
|
dw fd_medtyp ;AH=18: set media type for format
|
|
;
|
|
; Illegal command
|
|
;
|
|
fd_badcmd: mov byte [m_fdstat],1 ;illegal command
|
|
;
|
|
; AH=01: get status
|
|
;
|
|
fd_status:
|
|
fd_exit: mov al,[m_fdstat] ;get error code
|
|
fd_exit1: mov [bp._ah],al ;return in AH
|
|
and al,al ;error ?
|
|
jz fd_exit2
|
|
or byte [bp+18h],1 ;yes: set carry
|
|
fd_exit2:
|
|
#if def FD_DEBUG
|
|
call v_dump2 ;& dump registers
|
|
#endif
|
|
popa ;restore registers
|
|
pop es
|
|
pop ds
|
|
iret ;return from interrupt
|
|
;
|
|
; AH=00: recalibrate floppy drives
|
|
;
|
|
fd_rst: les si,[m_fdbase]
|
|
|
|
in al,pic0+1 ;enable floppy interrupt
|
|
and al,0bfh
|
|
out iowait,al
|
|
out pic0+1,al
|
|
|
|
mov dx,fdc_rate ;set 500 kb/s data rate
|
|
mov al,0
|
|
out dx,al
|
|
|
|
mov dx,fdc_ctrl
|
|
mov word [m_fdstat],0 ;clear error status
|
|
mov byte [m_fdcnt],0ffh ;prevent motor off event
|
|
mov al,[m_fdmot] ;digital output register
|
|
rol al,4
|
|
and al,11110011b
|
|
or al,8 ;enable interrupts
|
|
out dx,al ;reset FDC
|
|
and byte [m_fdrecal],70h ;clear interrupt and recal flags
|
|
mov cx,100 ;wait a bit
|
|
fd_rstw: out iowait,ax
|
|
loop fd_rstw
|
|
xor al,4 ;end reset pulse
|
|
out dx,al
|
|
call fd_wait ;wait for interrupt
|
|
jb fd_rst1 ;:bad controller
|
|
|
|
mov bl,0c0h ;expected result
|
|
fd_rst0: mov al,8 ;sense interrupt
|
|
call fd_cmd ;send command
|
|
jb fd_rst1 ;:error
|
|
call fd_res ;get results
|
|
jb fd_rst1 ;:error
|
|
cmp byte [m_fdfile],bl ;drive ready changed state ?
|
|
jnz fd_rst1 ;no: error
|
|
inc bl
|
|
cmp bl,0c4h ;done all drives ?
|
|
jb fd_rst0
|
|
;
|
|
; FDC specify command
|
|
;
|
|
mov al,3 ;specify command
|
|
call fd_cmd ;send to FDC
|
|
jb fd_spec9
|
|
mov al,[es:si] ;m_fdbase -> step rate, head unload
|
|
call fd_cmd ;send to FDC
|
|
jb fd_spec9
|
|
mov al,[es:si+1] ;m_fdbase -> motor on time, DMA mode
|
|
call fd_cmd
|
|
|
|
#if def FDC_FIFO ;NSC PC87306
|
|
jb fd_spec9
|
|
mov al,13h ;configure command
|
|
call fd_cmd
|
|
jb fd_spec9
|
|
mov al,0
|
|
call fd_cmd
|
|
jb fd_spec9
|
|
mov al,00001000xb ;enable FIFO
|
|
call fd_cmd
|
|
jb fd_spec9
|
|
mov al,0 ;precompensation track
|
|
call fd_cmd
|
|
#endif
|
|
|
|
fd_spec9: mov al,[es:si+2] ;m_fdbase -> motor count
|
|
mov [m_fdcnt],al ;restore motor timer
|
|
jmp fd_exit
|
|
|
|
fd_rst1: or byte [m_fdstat],20h ;bad controller
|
|
fd_rst2: jmp fd_exit
|
|
;
|
|
; AH=05: format track
|
|
;
|
|
fd_format: call fd_dma ;convert address ES:BX -> CH:DX
|
|
mov ax,0200h+4ah ;sectors * 4 shift, DMA mode write
|
|
call fd_dma2 ;complete DMA initialization
|
|
jb fd_rw90 ;:error
|
|
call fd_seek ;turn on motor, seek to track
|
|
jb fd_rw90 ;:error
|
|
call cs_waitbx ;wait BX milliseconds
|
|
|
|
mov al,3 ;specify command
|
|
call fd_cmd ;send to FDC
|
|
jb fd_rw90
|
|
mov al,[es:si] ;m_fdbase -> step rate, head unload
|
|
call fd_cmd ;send to FDC
|
|
jb fd_rw90
|
|
mov al,[es:si+1] ;m_fdbase -> motor on time, DMA mode
|
|
call fd_cmd
|
|
jb fd_rw90
|
|
|
|
mov al,4dh ;format command
|
|
call fd_cmd
|
|
jb fd_rw90
|
|
mov al,[bp._dh] ;head
|
|
shl al,2
|
|
call fd_cmd
|
|
jb fd_rw90
|
|
mov al,[es:si+3] ;bytes per sector
|
|
call fd_cmd
|
|
jb fd_rw90
|
|
mov al,[es:si+4] ;sectors per track
|
|
call fd_cmd
|
|
jb fd_rw90
|
|
mov al,[es:si+7] ;gap length
|
|
call fd_cmd
|
|
jb fd_rw90
|
|
mov al,[es:si+8] ;fill byte
|
|
jmp fd_rw3 ;continue as read / write
|
|
;
|
|
; AH=03: write sectors
|
|
;
|
|
fd_write: call fd_dma ;convert address ES:BX -> CH:DX
|
|
mov al,4ah ;DMA mode: write
|
|
call fd_dma2 ;complete DMA initialization
|
|
jb fd_rw90 ;:error
|
|
call fd_seek ;turn on motor, seek to track
|
|
jb fd_rw90 ;:error
|
|
call cs_waitbx ;wait BX milliseconds
|
|
mov al,0c5h ;write command
|
|
jmp short fd_rw1
|
|
|
|
fd_rw90: jmp fd_rw9
|
|
;
|
|
; AH=04: verify
|
|
;
|
|
fd_verify:
|
|
#if def FD_VERF000 ;STPC patch: read to F000 segment
|
|
mov bx,0f000h
|
|
mov es,bx
|
|
xor bx,bx
|
|
#endif
|
|
call fd_dma ;convert address ES:BX -> CH:DX
|
|
xor dx,dx ;clear offset -> no DMA errors
|
|
#if def FD_VERF000
|
|
mov al,46h ;DMA mode: read
|
|
#else
|
|
mov al,42h ;DMA mode: verify
|
|
#endif
|
|
jmp short fd_read2 ;rest like read
|
|
;
|
|
; AH=02: read
|
|
;
|
|
fd_read: call fd_dma ;convert address ES:BX -> CH:DX
|
|
mov al,46h ;DMA mode: read
|
|
fd_read2: call fd_dma2 ;complete DMA initialization
|
|
jb fd_rw90 ;:error
|
|
call fd_seek ;turn on motor, seek to track
|
|
jb fd_rw90 ;:error
|
|
fd_read3: mov al,0e6h ;FDC read command
|
|
;
|
|
; execute read / write command
|
|
;
|
|
fd_rw1: call fd_cmd ;command
|
|
jb fd_rw9 ;:error
|
|
mov al,0 ;drive 0
|
|
test byte [bp._dh],1 ;other head ?
|
|
jz fd_rw2
|
|
or al,4 ;set head bit
|
|
fd_rw2: call fd_cmd
|
|
jb fd_rw9
|
|
mov al,[bp._ch] ;track number
|
|
call fd_cmd
|
|
jb fd_rw9
|
|
mov al,[bp._dh] ;head number
|
|
call fd_cmd
|
|
jb fd_rw9
|
|
mov al,[bp._cl] ;sector number
|
|
call fd_cmd
|
|
jb fd_rw9
|
|
mov al,[es:si+3] ;m_fdbase -> bytes / sector
|
|
call fd_cmd
|
|
jb fd_rw9
|
|
mov al,[es:si+4] ;m_fdbase -> end of track sector
|
|
call fd_cmd
|
|
jb fd_rw9
|
|
mov al,[es:si+5] ;m_fdbase -> gap length
|
|
call fd_cmd
|
|
jb fd_rw9
|
|
mov al,[es:si+6] ;m_fdbase -> data length
|
|
fd_rw3: call fd_cmd
|
|
jb fd_rw9
|
|
call fd_wait ;wait for interrupt
|
|
jb fd_rw9
|
|
call fd_res ;get results
|
|
jb fd_rw9
|
|
cmp byte [bp._al],3 ;write ?
|
|
jz fd_rw4
|
|
cmp byte [bp._al],5 ;format ?
|
|
jnz fd_rw5
|
|
fd_rw4: mov bx,1 ;wait 1 ms after write -> write gate
|
|
call cs_waitbx ;delay (prevent immediate step away)
|
|
fd_rw5: test byte [m_fdfile],0c0h ;any error ?
|
|
jz fd_rw99 ;:no
|
|
call fd_error ;translate error
|
|
fd_rw9: cmp byte [bp._ah],5 ;format ?
|
|
jz fd_rw99
|
|
mov byte [bp._al],0 ;clear sector count
|
|
fd_rw99: mov al,[es:si+2] ;m_fdbase -> motor count
|
|
mov [m_fdcnt],al
|
|
jmp fd_exit
|
|
;
|
|
; translate error code
|
|
;
|
|
fd_error: mov al,20h ;(FDC error)
|
|
test byte [m_fdfile],80h ;invalid command ?
|
|
jnz fd_err9 ;:yes
|
|
mov al,[m_fdfile+1] ;ST1 status
|
|
and al,10110111b ;mask off unused status bits
|
|
mov bx,fd_errtab+9 ;^error table
|
|
stc ;ensure termination
|
|
fd_err1: dec bx
|
|
rcr al,1 ;test bit
|
|
jnb fd_err1 ;try next
|
|
mov al,[cs:bx] ;get correct error code
|
|
fd_err9: or [m_fdstat],al
|
|
ret
|
|
;
|
|
; error codes
|
|
;
|
|
fd_errtab: db 20h ;(bit overflow)
|
|
db 4 ;sector not found
|
|
db 20h ;(not used)
|
|
db 10h ;CRC error
|
|
db 8 ;DMA overrun
|
|
db 20h ;(not used)
|
|
db 4 ;sector not found
|
|
db 3 ;write protect
|
|
db 2 ;address mark not found
|
|
;
|
|
; Floppy parameters
|
|
;
|
|
fd_ptab: db 0dfh ;step rate, head unload
|
|
db 02 ;head load, DMA mode
|
|
db 25h ;motor wait
|
|
db 02 ;512 bytes per sector
|
|
db 18 ;end of track
|
|
db 24h ;normal gap
|
|
db 0ffh ;DTL
|
|
db 54h ;gap length for format
|
|
db 0f6h ;fill byte for format
|
|
db 15 ;head settle time (x 1 ms)
|
|
db 8 ;motor start time (x 125 ms)
|
|
;
|
|
; turn on motor
|
|
;
|
|
; out: BX = turn-on delay in ms
|
|
;
|
|
fd_motor: xor bx,bx ;no settling time required
|
|
|
|
; turn on motor if required
|
|
|
|
mov byte [m_fdcnt],255 ;prevent motor shutdown
|
|
mov byte [m_fdstat],0 ;clear error code
|
|
test byte [m_fdmot],1 ;motor running ?
|
|
jnz fd_mot1 ;:yes
|
|
or byte [m_fdmot],1 ;set motor flag
|
|
mov dx,fdc_ctrl ;turn on motor
|
|
mov al,00011100xb ;drive 0, DMA enable, not reset
|
|
out dx,al
|
|
mov bl,[es:si+10] ;m_fdbase -> motor start time
|
|
shl bx,7 ;x 128 -> value in ms
|
|
fd_mot1: ret
|
|
;
|
|
; turn on motor, seek to track if needed
|
|
;
|
|
; -> settling time in ms in BX
|
|
;
|
|
fd_seek: call fd_motor ;turn on motor
|
|
|
|
; check and reset disk change
|
|
|
|
mov dx,fdc_chg ;disk change line active ?
|
|
in al,dx
|
|
and al,80h
|
|
jz fd_seek1x ;:no
|
|
#if def FD_DEBUG
|
|
pusha ;& write a message on disk change
|
|
mov si,deb_dskch ;&
|
|
call v_msg ;&
|
|
popa ;&
|
|
#endif
|
|
call fd_seek1z ;recalibrate
|
|
cmp byte [bp._ch],0 ;destination = track 0 ?
|
|
jnz fd_seek1b
|
|
inc byte [bp._ch]
|
|
call fd_seek2 ;seek to track 1
|
|
dec byte [bp._ch]
|
|
fd_seek1b: call fd_seek2 ;seek to track 0 / wanted track
|
|
mov dx,fdc_chg ;disk change line still active ?
|
|
in al,dx
|
|
and al,80h
|
|
jz fd_seek1c ;no: ok
|
|
mov byte [m_fdstat],80h ;set time-out error
|
|
fd_seek1c: ret
|
|
|
|
; recalibrate if required
|
|
|
|
fd_seek1x: test byte [m_fdrecal],1 ;need recalibration ?
|
|
jnz fd_seek2 ;:no
|
|
fd_seek1z: mov al,7 ;recalibrate
|
|
call fd_cmd
|
|
jb fd_seek9
|
|
mov al,0 ;drive 0
|
|
call fd_cmd
|
|
jb fd_seek9
|
|
call fd_wsk ;wait for seek complete
|
|
jb fd_seek9
|
|
or byte [m_fdrecal],1 ;set bit - done
|
|
mov byte [m_fdtrk0],0 ;set current track
|
|
or bx,bx ;motor settling time ?
|
|
jnz fd_seek2 ;yes, bigger than head settling time
|
|
mov bl,[es:si+9] ;m_fdbase -> head settling time
|
|
|
|
; seek to track if required
|
|
|
|
fd_seek2: mov al,[bp._ch] ;destination track
|
|
cmp al,[m_fdtrk0] ;= current track ?
|
|
jz fd_seek9 ;:done (implied clc)
|
|
|
|
mov al,0fh ;seek command
|
|
call fd_cmd
|
|
jb fd_seek9
|
|
mov al,0 ;drive number
|
|
call fd_cmd
|
|
jb fd_seek9
|
|
mov al,[bp._ch] ;destination track
|
|
call fd_cmd
|
|
jb fd_seek9
|
|
mov [m_fdtrk0],al ;set new position
|
|
call fd_wsk ;wait for seek complete
|
|
|
|
or bx,bx ;motor settling time ?
|
|
jnz fd_seek9 ;yes, bigger than head settling time
|
|
mov bl,[es:si+9] ;m_fdbase -> head settling time
|
|
|
|
fd_seek9: ret
|
|
;
|
|
; wait for seek to complete, get status
|
|
;
|
|
fd_wsk: call fd_wait ;wait for interrupt
|
|
jb fd_wsk8 ;:error
|
|
fd_wsk2: mov al,8 ;sense interrupt
|
|
call fd_cmd
|
|
jb fd_wsk8
|
|
call fd_res ;get results
|
|
jb fd_wsk8
|
|
mov al,[m_fdfile]
|
|
and al,01100000xb ;error, seek end bits
|
|
cmp al,00100000xb ;no error, seek end ?
|
|
jz fd_wsk9 ;:ok
|
|
fd_wsk8: or byte [m_fdstat],40h ;set seek error bit
|
|
stc
|
|
fd_wsk9: ret
|
|
;
|
|
; initialize DMA controller
|
|
;
|
|
; ES = buffer segment
|
|
; BX = buffer offset
|
|
;
|
|
fd_dma: ; ES:BX -> physical address CH:DX, init ES:SI, AH
|
|
|
|
mov dx,es ;buffer segment
|
|
rol dx,4
|
|
mov ch,dl ;high 4 bits
|
|
and dl,0f0h ;mask off low bits
|
|
add dx,bx ;add buffer offset
|
|
adc ch,0
|
|
les si,[m_fdbase] ;load ^ floppy parameters
|
|
mov ah,[es:si+3] ;get shift count
|
|
add ah,7 ;shift count + 7 (128 byte base)
|
|
ret
|
|
;
|
|
; second half of DMA setup
|
|
;
|
|
; AL = DMA mode
|
|
; AH = shift count (for sector -> byte calculation)
|
|
; DX = address (low 16 bits)
|
|
; CH = address (high 4 bits)
|
|
;
|
|
fd_dma2: mov cl,ah ;shift count
|
|
mov bl,[bp._al] ;number of sectors
|
|
mov bh,0
|
|
shl bx,cl ;-> byte count
|
|
dec bx ;-1 for DMA
|
|
add bx,dx ;test for DMA overflow
|
|
jb fd_dma9 ;:error
|
|
sub bx,dx ;restore count
|
|
|
|
fd_dma3: cli ;critical section
|
|
push ax
|
|
mov al,6 ;disable DRQ2
|
|
out dma0+10,al
|
|
out iowait,ax
|
|
pop ax
|
|
out dma0+12,al ;dummy access -> reset hi/lo FF
|
|
out iowait,ax
|
|
out dma0+11,al ;write DMA mode
|
|
out iowait,ax
|
|
mov al,dl ;low address
|
|
out dma0+4,al
|
|
out iowait,ax
|
|
mov al,dh ;high address
|
|
out dma0+4,al
|
|
mov al,ch ;DMA page register
|
|
and al,15
|
|
out fd_page,al
|
|
|
|
#if def GX_FDFIX
|
|
push dx
|
|
mov al,0 ;clear high page register !!!
|
|
mov dx,fd_page+0400h
|
|
out dx,al
|
|
pop dx
|
|
#endif
|
|
|
|
mov al,bl ;low count
|
|
out dma0+5,al
|
|
out iowait,ax
|
|
mov al,bh ;high count
|
|
out dma0+5,al
|
|
out iowait,ax
|
|
mov al,2 ;enable DRQ2
|
|
out dma0+10,al
|
|
|
|
sti ;end of critical section
|
|
clc
|
|
ret
|
|
|
|
fd_dma9: mov byte [m_fdstat],9 ;DMA overflow error
|
|
ret
|
|
;
|
|
; write command byte AL to FDC
|
|
;
|
|
fd_cmd: mov ah,al ;save data
|
|
mov dx,fdc_stat
|
|
xor cx,cx
|
|
fd_cmd1: in al,dx ;read status
|
|
and al,0c0h ;RQM / DIO
|
|
xor al,80h ;RQM set, DIO clear = write to FDC
|
|
jz fd_cmd2 ;:ok
|
|
loop fd_cmd1 ;keep trying
|
|
or byte [m_fdstat],80h ;time out
|
|
stc
|
|
ret
|
|
|
|
fd_cmd2: mov al,ah ;restore data
|
|
inc dx
|
|
out dx,al ;write data to fdc_data
|
|
ret ;(carry clear)
|
|
;
|
|
; get results from FDC
|
|
;
|
|
fd_res: mov dx,fdc_stat
|
|
xor cx,cx
|
|
mov di,m_fdfile ;destination pointer
|
|
fd_res1: xor cx,cx ;clear time-out
|
|
fd_res2: out iowait,ax
|
|
in al,dx ;read status
|
|
cmp al,0c0h ;FDC ready for data read ?
|
|
jnb fd_res3 ;:yes
|
|
loop fd_res2
|
|
fd_res8: or byte [m_fdstat],80h ;time out
|
|
stc
|
|
ret
|
|
|
|
fd_res3: out iowait,ax
|
|
inc dx
|
|
in al,dx ;read fdc_data
|
|
dec dx
|
|
mov [di],al ;store result
|
|
inc di
|
|
out iowait,ax ;give FDC some time to update status
|
|
out iowait,ax
|
|
out iowait,ax
|
|
out iowait,ax
|
|
cmp di,m_fdfile+7 ;max bytes ?
|
|
jz fd_res9 ;:done
|
|
;
|
|
; wait for next byte
|
|
;
|
|
fd_res4: in al,dx ;get controller status
|
|
cmp al,0c0h
|
|
jae fd_res3 ;:ready with data
|
|
and al,0f0h ;ready for next command ?
|
|
cmp al,80h
|
|
jz fd_res9 ;:yes, done
|
|
loop fd_res4 ;keep trying
|
|
jmp fd_res8 ;time-out
|
|
|
|
fd_res9: clc
|
|
ret
|
|
;
|
|
; Floppy interrupt
|
|
;
|
|
irq6: push ax
|
|
push ds
|
|
xor ax,ax
|
|
mov ds,ax
|
|
or byte [m_fdrecal],80h ;set interrupt flag
|
|
mov al,eoi ;end of interrupt
|
|
out pic0,al
|
|
pop ds
|
|
pop ax
|
|
iret
|
|
;
|
|
; Did we get interrupt ? CY set if time-out
|
|
;
|
|
fd_wait: mov byte [m_fdcnt],0ffh ;keep motor running
|
|
push cx
|
|
mov cx,[m_timer] ;start time
|
|
add cx,19 ;time-out 1 second
|
|
fd_wait2: test byte [m_fdrecal],80h ;did we get interrupt ?
|
|
jnz fd_wait3 ;:yes
|
|
cmp cx,[m_timer]
|
|
js fd_wait4 ;:time-out
|
|
hlt ;wait for next interrupt
|
|
jmp fd_wait2 ;look again
|
|
fd_wait3: pop cx
|
|
and byte [m_fdrecal],7Fh ;clear interrupt flag
|
|
ret
|
|
|
|
fd_wait4: or byte [m_fdstat],80h ;set time-out status
|
|
stc
|
|
pop cx
|
|
ret
|
|
;
|
|
; AH=08: read drive parameters
|
|
;
|
|
fd_drvprm: xor bx,bx ;for non-existent drive
|
|
xor cx,cx
|
|
xor dx,dx
|
|
xor si,si
|
|
xor di,di
|
|
mov [m_fdstat],bl ;clear status
|
|
mov [bp._ax],bx ;clear AX
|
|
|
|
cmp byte [m_fdmed0],0 ;drive present ?
|
|
jz fd_drvp9 ;:no
|
|
|
|
mov si,cs ;segment -> ES
|
|
mov di,fd_ptab
|
|
mov bx,4 ;drive type = 1.44 MB
|
|
mov cx,79*256+18 ;80 tracks, 18 sectors per track
|
|
mov dx,1*256+1 ;1 head, 1 drive
|
|
|
|
fd_drvp9: mov [bp._bx],bx
|
|
mov [bp._cx],cx
|
|
mov [bp._dx],dx
|
|
mov [bp._es],si
|
|
mov [bp._di],di
|
|
jmp fd_exit ;return ok status
|
|
;
|
|
; AH=15: get drive type
|
|
;
|
|
fd_gettyp: mov al,0 ;drive not present
|
|
mov byte [m_fdstat],al ;clear status
|
|
cmp dl,0 ;drive 0 ?
|
|
jnz fd_gett2
|
|
cmp byte [m_fdmed0],0 ;drive present ?
|
|
jz fd_gett2 ;:no
|
|
mov al,2 ;change line available
|
|
fd_gett2: mov [bp._ah],al ;return in AH
|
|
jmp fd_exit2 ;don't set CY
|
|
;
|
|
; AH=17: set drive type for format
|
|
;
|
|
; since we only support 1.44 MB, basically a no-op
|
|
;
|
|
fd_fmttyp: cmp al,5
|
|
jae fd_fmtt2
|
|
cmp al,0
|
|
jnz fd_dskchg
|
|
fd_fmtt2: jmp fd_badcmd
|
|
;
|
|
; AH=16: get disk change status
|
|
;
|
|
fd_dskchg: les si,[m_fdbase] ;^disk parameters
|
|
mov al,80h ;drive not ready (no drive)
|
|
cmp dl,0 ;drive 0 ?
|
|
jnz fd_dsk2
|
|
cmp byte [m_fdmed0],0 ;drive present ?
|
|
jz fd_dsk2 ;:no
|
|
call fd_motor ;turn on motor
|
|
call cs_waitbx ;wait for motor startup time
|
|
mov byte [m_fdcnt],36 ;restore motor timer
|
|
mov dx,fdc_chg ;read disk change line
|
|
in al,dx
|
|
and al,80h
|
|
jz fd_dsk2 ;:not active, AL = 0
|
|
mov al,6 ;disk change active
|
|
fd_dsk2: mov [m_fdstat],al
|
|
jmp fd_exit1 ;set CY if not 0
|
|
;
|
|
; AH=18: set media type for format
|
|
;
|
|
fd_medtyp: mov al,80h ;drive not ready (no drive)
|
|
cmp dl,0 ;drive 0 ?
|
|
jnz fd_medt9
|
|
cmp byte [m_fdmed0],0 ;drive present ?
|
|
jz fd_medt9 ;:no
|
|
mov al,0ch ;invalid format
|
|
cmp ch,79 ;80 tracks ?
|
|
jnz fd_medt9 ;:no, error
|
|
cmp cl,18 ;18 sectors ?
|
|
jnz fd_medt9 ;:no, error
|
|
mov [bp._es],cs ;return ^disk parameters
|
|
mov word [bp._di],fd_ptab
|
|
mov al,0 ;ok status
|
|
fd_medt9: mov [m_fdstat],al ;set status
|
|
jmp fd_exit1 ;set CY if not 0
|
|
;
|
|
; Initialize floppy drive: detect FDC presence,
|
|
; reset FDC, turn on floppy motor, recalibrate
|
|
;
|
|
fd_init: mov dx,fdc_ctrl ;make sure FDC is present - control
|
|
mov al,0 ;register should read / write
|
|
out dx,al
|
|
dec ax
|
|
out iowait,al
|
|
in al,dx ;read back
|
|
cmp al,0ffh
|
|
jz fd_init9 ;:doesn't exist
|
|
|
|
or byte [m_devflg],1 ;floppy drive present
|
|
mov byte [m_fdmed0],17h ;drive A: present
|
|
mov ah,0 ;reset drive
|
|
int 13h
|
|
call fd_motor ;turn on floppy motor
|
|
mov al,7 ;recalibrate
|
|
call fd_cmd
|
|
jb fd_init9
|
|
mov al,0 ;drive 0
|
|
call fd_cmd
|
|
fd_init9: ret
|
|
;
|
|
; secondary floppy init
|
|
;
|
|
fd_inb: cmp byte [m_fdmed0],0
|
|
jz fd_inb9 ;:no FDC
|
|
or byte [m_fdrecal],1 ;set bit - done
|
|
mov byte [m_fdtrk0],0 ;set current track
|
|
mov byte [m_fdstat],0 ;clear errors
|
|
call fd_wsk ;wait for seek complete
|
|
jb fd_inb7 ;:error
|
|
jmp short fd_inb9 ;ok
|
|
|
|
; error: drive not present
|
|
|
|
fd_inb7: mov al,[m_devflg] ;decrement drive count
|
|
sub al,40h
|
|
jnb fd_inb8 ;there is another "floppy" (e.g. flash)
|
|
and al,00111110xb ;no floppy drives present
|
|
fd_inb8: mov [m_devflg],al
|
|
mov byte [m_fdmed0],0 ;disable drive
|
|
fd_inb9: ret
|