; =============================================================================
;
; Litos - Floppy disk
;
; =============================================================================
; This driver is only very simplified version of floppy driver due to the fact
; that floppy drive is obsolete device. Its alternative version is in files
; FLOP_OLD.* which contain unfinished version of the drive.
;
; This driver has following limitations:
; - it supports only one drive type, 3.5" floppy drive 1.44 MB
; - it supports only one controller and one drive
; - it supports only one media format - 1.44 MB (18 sectors per track,
; 80 tracks, 2 heads, HD data rate 500 kb/s)
;
; TODO: Media change detection, write-protect detection.
; =============================================================================
CODE_SECTION 32
; ------------- Driver setup
FD_IRQ EQU 6 ; IRQ number
FD_DMA EQU 2 ; DMA number
; ------------- Media parameters
FD_TRACKS EQU 80 ; number of tracks
FD_HEADS EQU 2 ; number of heads
FD_SECTORS EQU 18 ; sectors per track
FD_SECTSIZE EQU 512 ; sector size (in bytes)
FD_SECTSIZEBIT EQU 9 ; sector size (in bits)
FD_SECTSIZEFDC EQU 2 ; sector size (in FDC format)
FD_DATARATE EQU 0 ; data rate (in FDC format)
; ------------- Drive parameters
FD_SRTHUT EQU (16-6)*16+240/16 ; step rate (6)+head unload time (240)
FD_HLTNDMA EQU (2 & 0feh) + 0 ; head load time (2)+non DMA (0)
FD_SETTLE EQU 12 ; head settle time
FD_MOTONTIME EQU 1000 ; motor ON delay
FD_MOTOFFTIME EQU 1000 ; motor OFF delay
FD_DEVICE EQU 0 ; device index
FD_MOTMASK EQU B4 ; motor mask
FD_FORMGAP EQU 90 ; formatting inter-sector gap
FD_GPL EQU 3 ; gap 3 length (for write)
; ------------- Ports
FD_DORPORT EQU 3f2h ; digital output register (write)
FD_STATPORT EQU 3f4h ; diskette status port (read)
FD_RATEPORT EQU 3f4h ; data rate select port (write)
FD_DATAPORT EQU 3f5h ; command/data port (read/write)
FD_DIRPORT EQU 3f7h ; digital input register (read)
FD_DCRPORT EQU 3f7h ; diskette control register (write)
; -----------------------------------------------------------------------------
; Check if media is present
; -----------------------------------------------------------------------------
; INPUT: EBX = floppy disk device parameter block FLOPPY
; OUTPUT: CY = media is not present, diskette changed
; -----------------------------------------------------------------------------
; ------------- Push registers
FDPresent: push eax ; push EAX
push edx ; push EDX
; ------------- Check diskette change flag
mov dx,FD_DIRPORT ; DX <- digital input register
in al,dx ; read digital input register
cmp al,80h ; check media (B7 = diskette change)
cmc ; CY = diskette change
; ------------- Pop registers
pop edx ; pop EDX
pop eax ; pop EAX
ret
; -----------------------------------------------------------------------------
; Wait for controller ready
; -----------------------------------------------------------------------------
; INPUT: EBX = floppy disk device parameter block FLOPPY
; OUTPUT: CY = error (controller not ready)
; AL = diskette status register
; NOTES: It waits max. aprox. 100 ms for controller ready.
; -----------------------------------------------------------------------------
; ------------- Push registers
FDWaitReady: push ecx ; push ECX
push edx ; push EDX
; ------------- Check if driver is already in error state (reset required)
test byte [ebx+FLOPPY_Flags],FLOPPY_RESREQ ; reset required?
jnz FDWaitReady6 ; reset required
; ------------- Prepare registers
mov dx,FD_STATPORT ; EDX <- diskette status port
mov ecx,1000 ; ECX <- delay aprox. 1.5 ms
; ------------- Fast wait for data register ready (max. 1.5 ms)
FDWaitReady2: in al,dx ; AL <- read status port (1.5 us)
test al,FDS_READY ; is data register ready?
loopz FDWaitReady2 ; wait for data register ready
jnz FDWaitReady8 ; data register is ready
; ------------- Slow wait for data register ready (aprox. 105 ms)
mov cl,15 ; ECX <- delay 105 ms (=15*(15-1)/2 ms)
FDWaitReady4: mov al,15+1 ; AL <- 15+1, loop counter + 1 ms
sub al,cl ; AL <- delay, 1 to 15 ms
call SleepShort ; sleep for a while (1..15 ms)
in al,dx ; AL <- read status port
test al,FDS_READY ; is data register ready?
loopz FDWaitReady4 ; wait for data register ready
jnz FDWaitReady8 ; data register is ready
; ------------- Set reset request on error
mov byte [ebx+FLOPPY_LastErr],FDERR_FDCREADY ; time-out
or byte [ebx+FLOPPY_Flags],FLOPPY_RESREQ ; reset request
FDWaitReady6: stc ; set error flag
; ------------- Pop registers
FDWaitReady8: pop edx ; pop EDX
pop ecx ; pop ECX
ret
; -----------------------------------------------------------------------------
; Send data to floppy controller
; -----------------------------------------------------------------------------
; INPUT: AL = command byte
; EBX = floppy disk device parameter block FLOPPY
; OUTPUT: CY = error (controller not ready or it is in invalid state)
; NOTES: It waits max. aprox. 100 ms for data register ready.
; -----------------------------------------------------------------------------
; ------------- Push registers
FDSendData: push eax ; push EAX
push edx ; push EDX
; ------------- Wait for data register ready
mov ah,al ; AH <- push command byte
call FDWaitReady ; wait for data register ready
jc FDSendData4 ; error, data register is not ready
; ------------- Check status register
and al,FDS_READY+FDS_DIRREAD+FDS_NONDMA ; mask state
cmp al,FDS_READY ; check status (ready to CPU -> FDC)
jne FDSendData6 ; invalid state
; ------------- Output command byte (here is NC)
mov dx,FD_DATAPORT ; EDX <- command/data port
mov al,ah ; AL <- command byte
out dx,al ; output command byte
; ------------- Pop registers
FDSendData4: pop edx ; pop EDX
pop eax ; pop EAX
ret
; ------------- Set reset request on error
FDSendData6: mov byte [ebx+FLOPPY_LastErr],FDERR_FDCWRITE ; no data
or byte [ebx+FLOPPY_Flags],FLOPPY_RESREQ ; reset request
stc ; set error flag
; ------------- Pop registers
pop edx ; pop EDX
pop eax ; pop EAX
ret
; -----------------------------------------------------------------------------
; Get result from floppy controller
; -----------------------------------------------------------------------------
; INPUT: EBX = floppy disk device parameter block FLOPPY
; OUTPUT: CY = error (controller not ready or it is in invalid state)
; -----------------------------------------------------------------------------
; ------------- Push registers
FDGetResult: push eax ; push EAX
push ecx ; push ECX
push edx ; push EDX
; ------------- Clear reply buffer (only first 8 registers)
xor ecx,ecx ; ECX <- 0
mov [ebx+FLOPPY_Reply],ecx ; clear reply buffer
; ------------- Wait for data register ready (here is ECX = 0)
FDGetResult2: call FDWaitReady ; wait for data register ready
jc FDGetResult8 ; error, data register is not ready
; ------------- Check status register if controller has next data byte for CPU
test al,FDS_NONDMA ; check DMA state
jnz FDGetResult5 ; error, invalid state
test al,FDS_DIRREAD ; has controller next data for CPU?
jz FDGetResult8 ; controller has no other data for CPU
test al,FDS_BUSY ; is controller busy?
jz FDGetResult8 ; controller is not busy, no other data
; ------------- Check number of bytes
cmp cl,FLOP_REPMAX ; is reply buffer full?
jae FDGetResult4 ; reply buffer is full
; ------------- Get next status byte
mov dx,FD_DATAPORT ; EDX <- command/data port
in al,dx ; get status byte
mov [ebx+FLOPPY_Reply+ecx],al ; store byte
; ------------- Short delay (aprox. 20 us, to enable change busy flag)
mov al,20 ; AL <- 20 us
call UDelayByte ; short delay
; ------------- Next status byte
inc ecx ; ECX <- data counter
jmp short FDGetResult2 ; get next byte
; ------------- Error - buffer overrun
FDGetResult4: mov byte [ebx+FLOPPY_LastErr],FDERR_FDCOVER ; error
jmp short FDGetResult6
; ------------- Set reset request on error
FDGetResult5: mov byte [ebx+FLOPPY_LastErr],FDERR_FDCREAD ; error
FDGetResult6: or byte [ebx+FLOPPY_Flags],FLOPPY_RESREQ ; reset request
stc ; set error flag
; ------------- Pop registers
FDGetResult8: pop edx ; pop EDX
pop ecx ; pop ECX
pop eax ; pop EAX
ret
; -----------------------------------------------------------------------------
; Clear interrupt flag - callback function
; -----------------------------------------------------------------------------
; INPUT: EBX = floppy disk controller parameter block + FDC_IntLock
; OUTPUT: AL = 0 (return)
; -----------------------------------------------------------------------------
FDClearIntCB: and byte [ebx-FDC_IntLock+FDC_Flags],~FDC_INTOK; clear flag
mov al,0 ; AL <- 0, return
ret
; -----------------------------------------------------------------------------
; Clear interrupt flag
; -----------------------------------------------------------------------------
; INPUT: EBX = floppy disk device parameter block FLOPPY
; -----------------------------------------------------------------------------
; ------------- Push registers
FDClearInt: push ebx ; push EBX
push ecx ; push ECX
; ------------- Clear interrupt flag
mov ebx,[ebx+FLOPPY_FDC] ; EBX <- controller
add ebx,byte FDC_IntLock ; EBX <- task lock
mov ecx,FDClearIntCB ; ECX <- callback
call TaskWakeUpFnc ; clear bit
; ------------- Pop registers
pop ecx ; pop ECX
pop ebx ; pop EBX
ret
; -----------------------------------------------------------------------------
; Set interrupt flag - callback function
; -----------------------------------------------------------------------------
; INPUT: EBX = floppy disk controller parameter block + FDC_IntLock
; OUTPUT: AL = 1 (wake-up task)
; -----------------------------------------------------------------------------
FDSetIntCB: or byte [ebx-FDC_IntLock+FDC_Flags],FDC_INTOK ; set flag
mov al,1 ; AL <- 1, wake-up task
ret
; -----------------------------------------------------------------------------
; Floppy disk interrupt (fast handler)
; -----------------------------------------------------------------------------
; INPUT: EBX = floppy disk controller parameter block + FDC_IntLock
; OUTPUT: NC (interrupt is accepted)
; -----------------------------------------------------------------------------
; ------------- Push registers
FDInterrupt: push ecx ; push ECX
; ------------- Set interrupt flag
mov ecx,FDSetIntCB ; ECX <- callback
call TaskWakeUpFnc ; set bit
; ------------- Pop registers
pop ecx ; pop ECX
clc ; flag, interrupt accepted
ret
; -----------------------------------------------------------------------------
; Wait for interrupt flag - callback function
; -----------------------------------------------------------------------------
; INPUT: EBX = floppy disk controller parameter block + FDC_IntLock
; OUTPUT: AL = 0 sleep, 1 return
; -----------------------------------------------------------------------------
FDTestIntCB: test byte [ebx-FDC_IntLock+FDC_Flags],FDC_INTOK ; test flag
setnz al ; AL <- 1, flag is set
ret
; -----------------------------------------------------------------------------
; Wait for interrupt
; -----------------------------------------------------------------------------
; INPUT: EBX = floppy disk device parameter block FLOPPY
; OUTPUT: CY = error (time-out)
; -----------------------------------------------------------------------------
; ------------- Push registers
FDWaitInt: push eax ; push EAX
push ebx ; push EBX
push ecx ; push ECX
; ------------- Wait for interrupt (for 1 second)
mov eax,1000 ; EAX <- delay (1 second)
mov ebx,[ebx+FLOPPY_FDC] ; EBX <- controller
add ebx,byte FDC_IntLock ; EBX <- task lock
mov ecx,FDTestIntCB ; ECX <- callback
call TaskSleepFnc ; wait for interrupt
; ------------- Pop registers (here is CY = time-out)
pop ecx ; pop ECX
pop ebx ; pop EBX
pop eax ; pop EAX
; ------------- Set error code
jnc FDWaitInt8 ; operation OK
mov byte [ebx+FLOPPY_LastErr],FDERR_TIMEOUT ; time-out
FDWaitInt8: ret
; -----------------------------------------------------------------------------
; Check status of seek operation
; -----------------------------------------------------------------------------
; INPUT: EBX = floppy disk device parameter block FLOPPY
; OUTPUT: CY = error (time-out or seek error)
; NOTES: It is used after operations: seek, recalibrate, reset.
; -----------------------------------------------------------------------------
; ------------- Push registers
FDWaitSeek: push eax ; push EAX
; ------------- Wait for interrupt
call FDWaitInt ; wait for interrupt
jc FDWaitSeek8 ; time-out error
; ------------- Send "SENSE INTERRUPT STATUS" command
mov al,FD_SENSE ; AL <- sense interrupt status command
call FDSendData ; send command to controller
jc FDWaitSeek8 ; error
; ------------- Receive result
call FDGetResult ; get result
jc FDWaitSeek8 ; error
; ------------- Check result
mov al,[ebx+FLOPPY_ST0] ; AL <- ST0 register
and al,FDST0_SEEKEND+FDST0_INTMASK0 ; mask state bits
cmp al,FDST0_SEEKEND+FDST0_INTMASK0 ; abnormal termination?
clc ; clear error flag
jne FDWaitSeek8 ; seek OK
mov byte [ebx+FLOPPY_LastErr],FDERR_SEEKERR ; seek error
stc ; set error flag
; ------------- Pop registers
FDWaitSeek8: pop eax ; pop EAX
ret
; -----------------------------------------------------------------------------
; Seek to current track
; -----------------------------------------------------------------------------
; INPUT: EBX = floppy disk device parameter block FLOPPY
; OUTPUT: CY = error
; -----------------------------------------------------------------------------
; ------------- Push registers
FDSeek: push eax ; push EAX
; ------------- Clear interrupt flag
call FDClearInt ; clear interrupt flag
; ------------- Send SEEK command
mov al,FD_SEEK ; AL <- SEEK command
call FDSendData ; send SEEK command
jc FDSeek9 ; error
; ------------- Send disk number
mov al,FD_DEVICE ; AL <- device index
call FDSendData ; set drive to seek
jc FDSeek9 ; error
; ------------- Send track number
mov al,[ebx+FLOPPY_Track] ; AL <- current track
call FDSendData ; send track number
jc FDSeek9 ; error
; ------------- Check seek result
call FDWaitSeek ; check status
jc FDSeek9 ; error
; ------------- Delay to head settle
mov al,FD_SETTLE ; AL <- head settle time
call SleepShort ; sleep for head settle time
; ------------- Clear seek request (it clears CF)
and byte [ebx+FLOPPY_Flags],~FLOPPY_SEEKREQ
; ------------- Pop registers
FDSeek9: pop eax ; pop EAX
ret
; -----------------------------------------------------------------------------
; Send SPECIFY command
; -----------------------------------------------------------------------------
; INPUT: EBX = floppy disk device parameter block FLOPPY
; OUTPUT: CY = error
; -----------------------------------------------------------------------------
; ------------- Push registers
FDSpecify: push eax ; push EAX
push edx ; push EDX
; ------------- Send "SPECIFY" command
mov al,FD_SPECIFY ; AL <- specify command
call FDSendData ; send command to controller
jc FDSpecify8 ; error
; ------------- Set step rate time + head unload time
mov al,FD_SRTHUT ; AL <- step rate + head unload
call FDSendData ; send parameter to controller
jc FDSpecify8 ; error
; ------------- Set head load time
mov al,FD_HLTNDMA ; AL <- head load time
call FDSendData ; send parameter to controller
; ------------- Pop registers
FDSpecify8: pop edx ; pop EDX
pop eax ; pop EAX
ret
; -----------------------------------------------------------------------------
; Stop motor (without waiting and without lock)
; -----------------------------------------------------------------------------
; INPUT: EBX = floppy disk device parameter block FLOPPY
; NOTES: This function must be locked with FDC_MotorLock.
; -----------------------------------------------------------------------------
; ------------- Push registers
FDMotorOffNow: push eax ; push EAX
mov al,FDDOR_FDCENABLE+FDDOR_DMAENABLE+FD_DEVICE ; flags
and byte [ebx+FLOPPY_Flags],~FLOPPY_MOTORON ; OFF flag
jmp short FDMotorOnNow2
; -----------------------------------------------------------------------------
; Start motor (without waiting and without lock)
; -----------------------------------------------------------------------------
; INPUT: EBX = floppy disk device parameter block FLOPPY
; NOTES: This function must be locked with FDC_MotorLock.
; -----------------------------------------------------------------------------
; ------------- Push registers
FDMotorOnNow: push eax ; push EAX
mov al,FDDOR_FDCENABLE+FDDOR_DMAENABLE+FD_MOTMASK+FD_DEVICE
or byte [ebx+FLOPPY_Flags],FLOPPY_MOTORON ; ON flag
; ------------- Push registers 2
FDMotorOnNow2: push edx ; push EDX
; ------------- Set new digital output register
mov dx,FD_DORPORT ; DX <- digital output register
out dx,al ; output DOR register
; ------------- Pop registers
pop edx ; pop EDX
pop eax ; pop EAX
ret
; -----------------------------------------------------------------------------
; Start motor (and wait if it is not running)
; -----------------------------------------------------------------------------
; INPUT: EBX = floppy disk device parameter block FLOPPY
; -----------------------------------------------------------------------------
; ------------- Push registers
FDMotorOn: push eax ; push EAX
%ifdef SMP
push esi ; push ESI
%endif
; ------------- Lock motor and DOR
pushf ; push flags
cli ; disable interrupts
%ifdef SMP
mov esi,[ebx+FLOPPY_FDC] ; ESI <- controller
add esi,FDC_MotorLock ; ESI <- motor lock
call SpinLockESI ; lock motor and DOR
%endif
; ------------- Stop motor OFF timer
push ebx ; push EBX
add ebx,FLOPPY_Alarm ; EBX <- motor OFF timer
call AlarmStop ; stop alarm if it is running
pop ebx ; pop EBX
; ------------- Check if motor is already ON
test byte [ebx+FLOPPY_Flags],FLOPPY_MOTORON ; motor ON?
jnz FDMotorOn6 ; motor is already ON
; ------------- Start motor
call FDMotorOnNow ; start motor
; ------------- Unlock motor and DOR
%ifdef SMP
LOCK_Unlock esi ; unlock motor and DOR
%endif
popf ; pop flags (and enable interrupts)
; ------------- Delay
mov eax,FD_MOTONTIME ; EAX <- start time
call Sleep ; start motor
; ------------- Pop registers
%ifdef SMP
pop esi ; pop ESI
%endif
pop eax ; pop EAX
ret
; ------------- Unlock motor and DOR
FDMotorOn6:
%ifdef SMP
LOCK_Unlock esi ; unlock motor and DOR
%endif
popf ; pop flags (and enable interrupts)
; ------------- Pop registers
%ifdef SMP
pop esi ; pop ESI
%endif
pop eax ; pop EAX
ret
; -----------------------------------------------------------------------------
; Stop motor - callback function
; -----------------------------------------------------------------------------
; INPUT: EBX = alarm structure (FLOPPY + FLOPPY_Alarm)
; ECX = floppy disk device parameter block FLOPPY
; EDI:ESI = system time
; DESTROYS: EAX...EBP
; -----------------------------------------------------------------------------
; ------------- Lock motor and DOR
FDMotorOffCB: pushf ; push flags
cli ; disable interrupts
%ifdef SMP
mov esi,[ebx-FLOPPY_Alarm+FLOPPY_FDC] ; ESI <- controller
add esi,FDC_MotorLock ; ESI <- motor lock
call SpinLockESI ; lock motor and DOR
%endif
; ------------- Motor OFF
mov ebx,ecx ; EBX <- floppy disk driver
call FDMotorOffNow ; motor OFF
; ------------- Unlock motor and DOR
%ifdef SMP
LOCK_Unlock esi ; unlock motor and DOR
%endif
popf ; pop flags (and enable interrupts)
ret
; -----------------------------------------------------------------------------
; Stop motor (and start motor OFF timer if it was running)
; -----------------------------------------------------------------------------
; INPUT: EBX = floppy disk device parameter block FLOPPY
; NOTES: It saves flags.
; -----------------------------------------------------------------------------
; ------------- Push registers
FDMotorOff: push eax ; push EAX
push ebx ; push EBX
push ecx ; push ECX
%ifdef SMP
push esi ; push ESI
%endif
; ------------- Lock motor and DOR
pushf ; push flags
cli ; disable interrupts
%ifdef SMP
mov esi,[ebx+FLOPPY_FDC] ; ESI <- controller
add esi,FDC_MotorLock ; ESI <- motor lock
call SpinLockESI ; lock motor and DOR
%endif
; ------------- Stop motor OFF timer
add ebx,FLOPPY_Alarm ; EBX <- motor OFF timer
call AlarmStop ; stop alarm if it is running
; ------------- Check if motor is already OFF
test byte [ebx-FLOPPY_Alarm+FLOPPY_Flags],FLOPPY_MOTORON
jz FDMotorOff6 ; motor is already OFF
; ------------- Start timer
mov eax,FD_MOTOFFTIME ; EAX <- stop time
xor ecx,ecx ; ECX <- 0, no repeat
call AlarmSetInt ; set alarm interval
call AlarmStart ; start alarm
; ------------- Unlock motor and DOR
FDMotorOff6:
%ifdef SMP
LOCK_Unlock esi ; unlock motor and DOR
%endif
popf ; pop flags (and enable interrupts)
; ------------- Pop registers
%ifdef SMP
pop esi ; pop ESI
%endif
pop ecx ; pop ECX
pop ebx ; pop EBX
pop eax ; pop EAX
ret
; -----------------------------------------------------------------------------
; Set data transfer rate
; -----------------------------------------------------------------------------
; INPUT: EBX = floppy disk device parameter block FLOPPY
; -----------------------------------------------------------------------------
; ------------- Push registers
FDSetRate: push eax ; push EAX
push edx ; push EDX
; ------------- Set data transfer rate
mov dx,FD_DCRPORT ; EDX <- DCR register
mov al,FD_DATARATE ; AL <- data rate
out dx,al ; set current data rate
; ------------- Pop registers
pop edx ; pop EDX
pop eax ; pop EAX
ret
; -----------------------------------------------------------------------------
; Controller reset
; -----------------------------------------------------------------------------
; INPUT: EBX = floppy disk device parameter block FLOPPY
; -----------------------------------------------------------------------------
; ------------- Push registers
FDResetFDC: push eax ; push EAX
push edx ; push EDX
%ifdef SMP
push esi ; push ESI
%endif
; ------------- Lock motor and DOR
%ifdef SMP
mov esi,[ebx+FLOPPY_FDC] ; ESI <- controller
add esi,FDC_MotorLock ; ESI <- motor lock
call SpinLockESI ; lock motor and DOR
%endif
; ------------- Start reset signal
mov al,FDDOR_DMAENABLE+FD_MOTMASK+FD_DEVICE ; flags
mov dx,FD_DORPORT ; DX <- digital output register
out dx,al ; output DOR register
; ------------- Clear interrupt flag
call FDClearInt ; clear interrupt flag
; ------------- Short delay (20 us) to accept reset signal
mov al,20 ; AL <- delay [us]
call UDelayByte ; short delay
; ------------- Stop reset signal
mov al,FDDOR_DMAENABLE+FD_MOTMASK+FD_DEVICE+FDDOR_FDCENABLE
out dx,al ; output new DOR register
; ------------- Unlock motor and DOR
%ifdef SMP
LOCK_Unlock esi ; unlock motor and DOR
%endif
; ------------- Pop registers
%ifdef SMP
pop esi ; pop ESI
%endif
pop edx ; pop EDX
pop eax ; pop EAX
ret
; -----------------------------------------------------------------------------
; Reset disk (reset controller, start motor and seek to track 0)
; -----------------------------------------------------------------------------
; INPUT: EBX = floppy disk device parameter block FLOPPY
; OUTPUT: CY = error
; NOTES: Motor must be ON.
; -----------------------------------------------------------------------------
; ------------- Push regisers
FDReset: push eax ; push EAX
push ecx ; push ECX
; ------------- Clear reset request
and byte [ebx+FLOPPY_Flags],~FLOPPY_RESREQ ; reset request
; ------------- Send RESET signal to the controller
call FDResetFDC ; reset controller
; ------------- Wait for interrupt
call FDWaitInt ; wait for interrupt
jc short FDReset9 ; time-out error
; ------------- Send "SENSE INTERRUPT STATUS" command
mov cl,0c0h ; CL <- required state
FDReset2: mov al,FD_SENSE ; AL <- sense interrupt status command
call FDSendData ; send command to controller
jc short FDReset9 ; error
; ------------- Receive result
call FDGetResult ; get result
jc short FDReset9 ; error
; ------------- Check result (reset error)
cmp [ebx+FLOPPY_ST0],cl ; check return code
je short FDReset4 ; return code OK
mov byte [ebx+FLOPPY_LastErr],FDERR_FDCRESET
stc ; set error flag
jmp short FDReset9
; ------------- Initialize next interrupt register
FDReset4: inc ecx ; increase register number
cmp cl,0c4h ; all registers initialized?
jne FDReset2 ; initialize next register
; ------------- Specify disk parameters
call FDSpecify ; specify disk parameters
jc FDReset9 ; error
; ------------- Set data transfer rate
call FDSetRate ; set data transfer rate
; ------------- Recalibrate disk (seek to track 0) - 2 attempts
xor ecx,ecx ; ECX <- 0
mov cl,2 ; ECX <- 2, two attempts
FDReset6: call FDClearInt ; clear interrupt flag
; ------------- Send "RECALIBRATE" command
mov al,FD_RECALIB ; AL <- recalibrate command
call FDSendData ; send command
jc FDReset9 ; error
; ------------- Send disk number
mov al,FD_DEVICE ; AL <- device index
call FDSendData ; set drive to seek
jc FDReset9 ; error
; ------------- Check state
call FDWaitSeek ; check state
jnc FDReset8 ; operation OK
loop FDReset6 ; next attempt
jmp short FDReset9 ; error
; ------------- Re-seek to current track
FDReset8: and byte [ebx+FLOPPY_Flags],~FLOPPY_SEEKREQ ; clear request
cmp byte [ebx+FLOPPY_Track],0 ; track 0?
je FDReset9 ; track is already set
call FDSeek ; seek to current track
; ------------- Pop registers
FDReset9: pop ecx ; pop ECX
pop eax ; pop EAX
ret
; -----------------------------------------------------------------------------
; Parse error result from ST0, ST1, ST2 registers
; -----------------------------------------------------------------------------
; INPUT: EBX = floppy disk device parameter block FLOPPY
; OUTPUT: AL = error code (0 = no error)
; CY = error
; -----------------------------------------------------------------------------
; ------------- ST0: No error
FDSTError: mov al,FDERR_OK ; AL <- no error code
test byte [ebx+FLOPPY_ST0],FDST0_INTMASK ; error?
jz FDSTError8 ; no error
; ------------- ST0: Controller general error (code 01 = command not completed)
mov al,FDERR_FDCERR ; AL <- controller general error
test byte [ebx+FLOPPY_ST0],FDST0_INTMASK1 ; error?
jz FDSTError6 ; controller general error
; ------------- ST0: Drive not ready
mov al,FDERR_DRVREADY ; AL <- drive not ready error code
test byte [ebx+FLOPPY_ST0],FDST0_NREADY ; drive not ready?
jnz FDSTError6 ; drive not ready
; ------------- ST0: Track 0 not found
mov al,FDERR_ZEROTRACK ; AL <- track 0 not found error code
test byte [ebx+FLOPPY_ST0],FDST0_EQERR ; track 0 not found?
jnz FDSTError6 ; track 0 not found
; ------------- ST1: Missing sector address mark (sector head not found)
mov al,FDERR_ADDRFND ; AL <- address mark not found
test byte [ebx+FLOPPY_ST1],FDST1_MISADDR ; addr. not found?
jnz FDSTError6 ; address mark not found
; ------------- ST1: Disk write-protected
mov al,FDERR_WPROT ; AL <- disk write-protected
test byte [ebx+FLOPPY_ST1],FDST1_WP ; write protect?
jnz FDSTError6 ; disk write-protected
; ------------- ST1: Missing sector data
mov al,FDERR_DATAFND ; AL <- sector data not found error
test byte [ebx+FLOPPY_ST1],FDST1_NDATA ; data not found?
jnz FDSTError6 ; sector not found
; ------------- ST1: Data overrun (DMA error)
mov al,FDERR_OVERRUN ; AL <- data overrun error code
test byte [ebx+FLOPPY_ST1],FDST1_OVERRUN ; data overrun?
jnz FDSTError6 ; data overrun
; ------------- ST1: CRC error
mov al,FDERR_CRC ; AL <- CRC error code
test byte [ebx+FLOPPY_ST1],FDST1_CRC ; CRC error?
jnz FDSTError6 ; CRC error
; ------------- ST1: Sector not found
mov al,FDERR_SECTFND ; AL <- sector not found error code
test byte [ebx+FLOPPY_ST1],FDST1_EOC ; end of cylinder?
jnz FDSTError6 ; end of cylinder
; ------------- ST2: Sector head does not correspond
mov al,FDERR_BADHEAD ; AL <- sector head not correspond
test byte [ebx+FLOPPY_ST2],FDST2_BADCYL+FDST2_WRONGCYL
jnz FDSTError6 ; end of cylinder
; ------------- Unknown error
mov al,FDERR_UNKOWN ; AL <- unknown error code
; ------------- Set error code
FDSTError6: mov [ebx+FLOPPY_LastErr],al ; set error code
stc ; set error flag
FDSTError8: ret
; -----------------------------------------------------------------------------
; Wait for read/write/verify/format end
; -----------------------------------------------------------------------------
; INPUT: EBX = floppy disk device parameter block FLOPPY
; OUTPUT: CY = error (time-out or operation error)
; -----------------------------------------------------------------------------
; ------------- Push registers
FDWaitRW: push eax ; push EAX
; ------------- Wait of interrupt
call FDWaitInt ; wait for interrupt
jc FDWaitRW8 ; time-out error
; ------------- Receive result
call FDGetResult ; get result
jc FDWaitRW8 ; error
; ------------- Parse error code (return CY=error)
call FDSTError ; parse error code
; ------------- Pop registers
FDWaitRW8: pop eax ; pop EAX
ret
; -----------------------------------------------------------------------------
; Start DMA transfer
; -----------------------------------------------------------------------------
; INPUT: AL = DMA mode: 0=read from disk, 1=write, 2=verify
; EBX = floppy disk device parameter block FLOPPY
; CL = number of sectors (cannot be 0)
; NOTES: Data transfer uses DMA buffer FDC_Buffer of floppy disk device.
; -----------------------------------------------------------------------------
; ------------- Push registers
FDDMAStart: push eax ; push EAX
push ebx ; push EBX
push ecx ; push ECX
push edx ; push EDX
; ------------- Prepare transfer size (-> ECX)
movzx ecx,cl ; ECX <- number of sectors
shl ecx,FD_SECTSIZEBIT ; ECX <- data transfer size
; ------------- Prepare other DMA parameters (address, channel and mode)
mov edx,[ebx+FLOPPY_Buffer] ; EDX <- DMA buffer
mov bl,FD_DMA ; BL <- DMA channel number
xchg eax,ebx ; BL <- DMA mode, AL <- DMA channel
; ------------- Start DMA transfer
call DMAStart ; start DMA transfer
; ------------- Pop registers
pop edx ; pop EDX
pop ecx ; pop ECX
pop ebx ; pop EBX
pop eax ; pop EAX
ret
; -----------------------------------------------------------------------------
; Stop DMA transfer
; -----------------------------------------------------------------------------
; INPUT: EBX = floppy disk device parameter block FLOPPY
; NOTES: It saves flags.
; -----------------------------------------------------------------------------
; ------------- Push registers
FDDMAStop: push eax ; push EAX
; ------------- Stop DMA transfer
mov al,FD_DMA ; AL <- DMA channel number
call DMAStop ; stop DMA transfer
; ------------- Pop registers
pop eax ; pop EAX
ret
; -----------------------------------------------------------------------------
; Verify sectors (with DMA buffer, current track, current head)
; -----------------------------------------------------------------------------
; INPUT: AL = start sector number (1...)
; EBX = floppy disk device parameter block FLOPPY
; CL = number of sectors (cannot be 0)
; OUTPUT: CY = error
; NOTES: Function uses DMA buffer FDC_Buffer of floppy disk device.
; -----------------------------------------------------------------------------
; ------------- Push registers
FDVerifySect: push eax ; push EAX
push ecx ; push ECX
; ------------- Prepare verify mode
mov ch,al ; CH <- start sector
mov al,2 ; AL <- 2, DMA verify
jmp short FDReadSect2
; -----------------------------------------------------------------------------
; Read sectors (to DMA buffer, current track, current head)
; -----------------------------------------------------------------------------
; INPUT: AL = start sector number (1...)
; EBX = floppy disk device parameter block FLOPPY
; CL = number of sectors (cannot be 0)
; OUTPUT: CY = error
; NOTES: Function uses DMA buffer FDC_Buffer of floppy disk device.
; -----------------------------------------------------------------------------
; ------------- Push registers
FDReadSect: push eax ; push EAX
push ecx ; push ECX
; ------------- Prepare read mode
mov ch,al ; CH <- start sector
mov al,0 ; AL <- 0, DMA read from disk
FDReadSect2: mov ah,FD_READ ; AH <- read data command
jmp short FDWriteSect2
; -----------------------------------------------------------------------------
; Write sectors from buffer (current track, current head)
; -----------------------------------------------------------------------------
; INPUT: AL = start sector number (1...)
; EBX = floppy disk device parameter block FLOPPY
; CL = number of sectors (cannot be 0)
; EDX = buffer with data
; EBP = data length (in bytes) / 4
; OUTPUT: CY = error
; NOTES: Function uses DMA buffer FDC_Buffer of floppy disk device.
; -----------------------------------------------------------------------------
; ------------- Push registers
FDWriteBuf: push ecx ; push ECX
push esi ; push ESI
push edi ; push EDI
; ------------- Copy data to write
mov esi,edx ; ESI <- source buffer
mov edi,[ebx+FLOPPY_Buffer] ; EDI <- DMA buffer
mov ecx,ebp ; ECX <- data length/4
rep movsd ; copy data
; ------------- Pop registers
pop edi ; pop EDI
pop esi ; pop ESI
pop ecx ; pop ECX
; FDWriteSect must follow
; -----------------------------------------------------------------------------
; Write sector (from DMA buffer, current track, current head)
; -----------------------------------------------------------------------------
; INPUT: AL = start sector number (1...)
; EBX = floppy disk device parameter block FLOPPY
; CL = number of sectors (cannot be 0)
; OUTPUT: CY = error
; NOTES: Function uses DMA buffer FDC_Buffer of floppy disk device.
; -----------------------------------------------------------------------------
; ------------- Push registers
FDWriteSect: push eax ; push EAX
push ecx ; push ECX
; ------------- Prepare write mode
mov ch,al ; CH <- start sector
mov al,1 ; AL <- 1, DMA write to disk
mov ah,FD_WRITE ; AH <- write data command
; ------------- Start motor ON
FDWriteSect2: call FDMotorOn ; start motor ON
; ------------- Reset controller and drive
test byte [ebx+FLOPPY_Flags],FLOPPY_RESREQ ; reset request?
jz FDWriteSect4 ; reset not required
call FDReset ; reset controller and drive
jc FDWriteSect6 ; error
; ------------- Seek
FDWriteSect4: test byte [ebx+FLOPPY_Flags],FLOPPY_SEEKREQ ; seek request?
jz FDWriteSect5 ; no seek requesst
call FDSeek ; seek
; ------------- Set data transfer rate
FDWriteSect5: call FDSetRate ; set data transfer rate
; ------------- Start DMA transfer
call FDDMAStart ; start DMA transfer
; ------------- Clear interrupt flag
call FDClearInt ; clear interrupt flag
; ------------- Send command to controller
mov al,ah ; AL <- command
call FDSendData ; send command to controller
jc short FDWriteSect9 ; error
; ------------- Select head and drive
mov al,[ebx+FLOPPY_Head] ; AL <- current head number
shl al,2 ; rotate head to position
%if FD_DEVICE != 0
or al,FD_DEVICE ; add device index
%endif
call FDSendData ; send data to controller
jc short FDWriteSect9 ; error
; ------------- Set track number (for sector ID)
mov al,[ebx+FLOPPY_Track] ; AL <- current track number
call FDSendData ; send track to controller
FDWriteSect6: jc short FDWriteSect9 ; error
; ------------- Set head number (for sector ID)
mov al,[ebx+FLOPPY_Head] ; AL <- current head
call FDSendData ; send head to controller
jc short FDWriteSect9 ; error
; ------------- Set start sector number (for sector ID)
mov al,ch ; AL <- start sector number
call FDSendData ; send sector number to controller
jc short FDWriteSect9 ; error
; ------------- Set sector size (for sector ID)
mov al,FD_SECTSIZEFDC ; AL <- sector size
call FDSendData ; send sector size to controller
jc short FDWriteSect9 ; error
; ------------- Set maximal sector number
mov al,FD_SECTORS ; AL <- sectors per track
call FDSendData ; send sectors to controller
jc short FDWriteSect9 ; error
; ------------- Set gap 3 length (intersector gap)
mov al,FD_GPL ; AL <- gap 3 length
call FDSendData ; send gap 3 length to controller
jc short FDWriteSect9 ; error
; ------------- Set number of bytes
mov al,255 ; AL <- other unlimited length
call FDSendData ; send sectors to controller
jc short FDWriteSect9 ; error
; ------------- Wait for end of operation
call FDWaitRW ; wait for end of operation
; ------------- Motor OFF (it saves flags)
FDWriteSect9: call FDMotorOff ; motor OFF
; ------------- Stop DMA transfer (it saves flags)
call FDDMAStop ; stop DMA transfer
; ------------- Pop registers
pop ecx ; pop ECX
pop eax ; pop EAX
ret
; -----------------------------------------------------------------------------
; Compare sectors (to DMA buffer, current track, current head)
; -----------------------------------------------------------------------------
; INPUT: AL = start sector number (1...)
; EBX = floppy disk device parameter block FLOPPY
; CL = number of sectors (cannot be 0)
; EDX = compared data
; OUTPUT: CY = error
; NOTES: Function compares DMA buffers FDC_Buffer and FDC_Buffer2.
; -----------------------------------------------------------------------------
; ------------- Read sectors into buffer
FDCompSect: call FDReadSect ; read sectors into buffer
jc FDCompSect9 ; error
; ------------- Push registers
push ecx ; push ECX
push esi ; push ESI
push edi ; push EDI
; ------------- Prepare length of data (-> ECX)
movzx ecx,cl ; ECX <- number of sectors
shl ecx,FD_SECTSIZEBIT-2 ; ECX <- data transfer size / 4
; ------------- Compare data
mov esi,[ebx+FLOPPY_Buffer] ; ESI <- buffer 1
mov edi,edx ; EDI <- buffer 2
repe cmpsd ; compare buffers
je FDCompSect8 ; buffers are OK
; ------------- Pop registers
stc ; set error flag
FDCompSect8: pop edi ; pop EDI
pop esi ; pop ESI
pop ecx ; pop ECX
FDCompSect9: ret
; -----------------------------------------------------------------------------
; Write sectors to track with repeat on error
; -----------------------------------------------------------------------------
; INPUT: AL = start sector number (1...)
; EBX = floppy disk device parameter block FLOPPY
; CL = number of sectors (cannot be 0)
; EDX = buffer with data
; EBP = data length (in bytes) / 4
; OUTPUT: CY = error
; NOTES: Function uses DMA buffer FDC_Buffer of floppy disk device.
; -----------------------------------------------------------------------------
FDWriteRep: call FDWriteBuf ; write sectors
jnc FDWriteRep8 ; data written OK
call FDReset ; reset controller and drive
jc FDWriteRep8 ; error
call FDWriteBuf ; write sectors
jnc FDWriteRep8 ; data written OK
call FDReset ; reset controller and drive
jc FDWriteRep8 ; error
call FDWriteBuf ; write sectors
FDWriteRep8: ret
; -----------------------------------------------------------------------------
; Prepare parameters for read/write/... sectors from track, lock controller
; -----------------------------------------------------------------------------
; INPUT: EAX = start sector number (1...)
; EBX = floppy disk device parameter block FLOPPY
; ECX = number of sectors
; ESI = head
; EDI = cylinder
; OUTPUT: ECX = limited number of sectors (1...)
; EBP = data length (in bytes) / 4
; CY = error, invalid parameters
; -----------------------------------------------------------------------------
; ------------- Push registers
FDRWPrep: push edx ; push EDX
; ------------- Lock controller
call FDLock ; lock controller
; ------------- Check head number
cmp esi,byte FD_HEADS ; check head number
jae FDRWPrep8 ; invalid head number
; ------------- Check cylinder number
cmp edi,byte FD_TRACKS ; check cylinder number
jae FDRWPrep8 ; invalid cylinder number
; ------------- Check start sector
xor edx,edx ; EDX <- 0
mov dl,FD_SECTORS ; EDX <- sectors per track
sub edx,eax ; EDX <- remaining sectors - 1
jb FDRWPrep8 ; invalid sector number
; ------------- Limit number of sectors (-> ECX)
inc edx ; EDX <- remaining sectors
cmp edx,ecx ; check number of sectors
ja FDRWPrep2 ; number of sectors is OK
mov ecx,edx ; ECX <- limit number of sectors
; ------------- Length of data (-> EBP)
FDRWPrep2: mov ebp,ecx ; EBP <- number of sectors
shl ebp,FD_SECTSIZEBIT-2 ; EBP <- data transfer size / 4
; ------------- Set head
mov edx,esi ; EDX <- head
mov [ebx+FLOPPY_Head],dl ; set new current head
; ------------- Set cylinder
mov edx,edi ; EDX <- cylinder
cmp dl,[ebx+FLOPPY_Track] ; cylinder changed?
je FDRWPrep4 ; cylinder not changed
or byte [ebx+FLOPPY_Flags],FLOPPY_SEEKREQ ; seek request
mov [ebx+FLOPPY_Track],dl ; set new current track
; ------------- OK: Pop registers (here is NC)
FDRWPrep4: pop edx ; pop EDX
ret
; ------------- ERROR: Pop registers
FDRWPrep8: stc ; set error flag
FDRWPrep9: pop edx ; pop EDX
ret
; -----------------------------------------------------------------------------
; Compare sectors from track
; -----------------------------------------------------------------------------
; INPUT: EAX = start sector number (1...)
; EBX = floppy disk device parameter block FLOPPY
; ECX = number of sectors
; EDX = data buffer
; ESI = head
; EDI = cylinder
; OUTPUT: EAX = sectors OK compared
; CY = error
; -----------------------------------------------------------------------------
; ------------- Push registers (it must correspond with FDRead and FDWrite)
FDCompTrack: push ecx ; push ECX
push esi ; push ESI
push edi ; push EDI
push ebp ; push EBP
; ------------- Prepare parameters
call FDRWPrep ; prepare parameters
jc short FDReadTrack8 ; error
; ------------- Read sectors (with 2 attempts)
call FDReadSect ; read sectors
jnc short FDCompTrack6 ; data read OK
call FDReset ; reset controller and drive
jc short FDReadTrack8 ; error
call FDReadSect ; read sectors
jc short FDReadTrack8 ; error
; ------------- Compare data
FDCompTrack6: mov edi,edx ; EDI <- destination buffer
mov esi,[ebx+FLOPPY_Buffer] ; ESI <- DMA buffer
xchg eax,ebp ; EAX <- data length/4
xchg eax,ecx ; EAX <- sectors, ECX <- length/4
repe cmpsd ; compare data
je short FDReadTrack9 ; data OK
jmp short FDReadTrack8 ; error
; -----------------------------------------------------------------------------
; Read sectors from track
; -----------------------------------------------------------------------------
; INPUT: EAX = start sector number (1...)
; EBX = floppy disk device parameter block FLOPPY
; ECX = number of sectors
; EDX = data buffer
; ESI = head
; EDI = cylinder
; OUTPUT: EAX = sectors OK read
; CY = error
; -----------------------------------------------------------------------------
; ------------- Push registers (it must correspond with FDWrite and FDComp)
FDReadTrack: push ecx ; push ECX
push esi ; push ESI
push edi ; push EDI
push ebp ; push EBP
; ------------- Prepare parameters
call FDRWPrep ; prepare parameters
jc short FDReadTrack8 ; error
; ------------- Read sectors (with 3 attempts)
call FDReadSect ; read sectors
jnc short FDReadTrack6 ; data read OK
call FDReset ; reset controller and drive
jc short FDReadTrack8 ; error
call FDReadSect ; read sectors
jnc short FDReadTrack6 ; data read OK
call FDReset ; reset controller and drive
jc short FDReadTrack8 ; error
call FDReadSect ; read sectors
jc short FDReadTrack8 ; error
; ------------- Copy read data (here is NC)
FDReadTrack6: mov edi,edx ; EDI <- destination buffer
mov esi,[ebx+FLOPPY_Buffer] ; ESI <- DMA buffer
xchg eax,ebp ; EAX <- data length/4
xchg eax,ecx ; EAX <- sectors, ECX <- length/4
rep movsd ; copy data
jmp short FDReadTrack9
; ------------- Error
FDReadTrack8: xor eax,eax ; EAX <- no sectors OK read
stc ; set error flag
; ------------- Unlock controller (it saves flags)
FDReadTrack9: call FDUnlock ; unlock controller
; ------------- Pop registers
pop ebp ; pop EBP
pop edi ; pop EDI
pop esi ; pop ESI
pop ecx ; pop ECX
ret
; -----------------------------------------------------------------------------
; Write sectors to track
; -----------------------------------------------------------------------------
; INPUT: EAX = start sector number (1...)
; EBX = floppy disk device parameter block FLOPPY
; ECX = number of sectors
; EDX = data buffer
; ESI = head
; EDI = cylinder
; OUTPUT: EAX = sectors OK written
; CY = error
; -----------------------------------------------------------------------------
; ------------- Push registers (it must correspond with FDRead and FDComp)
FDWriteTrack: push ecx ; push ECX
push esi ; push ESI
push edi ; push EDI
push ebp ; push EBP
; ------------- Prepare parameters
call FDRWPrep ; prepare parameters
jc short FDReadTrack8 ; error
; ------------- Write sectors without verify (with 3 attempts)
test byte [ebx+DDEV_Flags],DDEV_WRITEVER; write with verify?
jnz FDWriteTrack4 ; write with verify
call FDWriteRep ; write sectors with repeat on error
jc short FDReadTrack8 ; error
FDWriteTrack2: xchg eax,ecx ; EAX <- number of sectors
jmp short FDReadTrack9 ; OK
; ------------- Write sectors with verify
FDWriteTrack4: test byte [ebx+DDEV_Flags],DDEV_USECOMP ; use compare?
jnz FDWriteTrack8 ; use compare
call FDWriteRep ; write sectors with repeat on error
jc short FDReadTrack8 ; error
call FDVerifySect ; verify sectors
jnc short FDWriteTrack2 ; ok
call FDReset ; reset controller and drive
jc short FDReadTrack8 ; error
call FDWriteBuf ; write sectors
jc short FDReadTrack8 ; error
call FDVerifySect ; verify sectors
jnc short FDWriteTrack2 ; ok
FDWriteTrack6: jmp short FDReadTrack8 ; error
; ------------- Write sectors with compare
FDWriteTrack8: call FDWriteRep ; write sectors with repeat on error
jc short FDReadTrack8 ; error
call FDCompSect ; compare sectors
jnc short FDWriteTrack2 ; ok
call FDReset ; reset controller and drive
jc short FDReadTrack8 ; error
call FDWriteBuf ; write sectors
jc short FDReadTrack8 ; error
call FDCompSect ; compare sectors
jnc short FDWriteTrack2 ; ok
jmp short FDWriteTrack6 ; error
; -----------------------------------------------------------------------------
; Verify sectors from track
; -----------------------------------------------------------------------------
; INPUT: EAX = start sector number (1...)
; EBX = floppy disk device parameter block FLOPPY
; ECX = number of sectors
; ESI = head
; EDI = cylinder
; OUTPUT: EAX = sectors OK verified
; CY = error
; -----------------------------------------------------------------------------
; ------------- Push registers
FDVerifyTrack: push ecx ; push ECX
push ebp ; push EBP
; ------------- Prepare parameters
call FDRWPrep ; prepare parameters
jc FDVerifyTrack8 ; error
; ------------- Verify sectors (with 2 attempts)
call FDVerifySect ; verify sectors
jnc FDVerifyTrack6 ; data verified OK
call FDReset ; reset controller and drive
jc FDVerifyTrack8 ; error
call FDVerifySect ; verify sectors
jc FDVerifyTrack8 ; error
FDVerifyTrack6: xchg eax,ecx ; EAX <- number of sectors
jmp short FDVerifyTrack9
; ------------- Error
FDVerifyTrack8: xor eax,eax ; EAX <- no sectors OK read
stc ; set error flag
; ------------- Unlock controller (it saves flags)
FDVerifyTrack9: call FDUnlock ; unlock controller
; ------------- Pop registers
pop ebp ; pop EBP
pop ecx ; pop ECX
ret
; -----------------------------------------------------------------------------
; Format track (without verify)
; -----------------------------------------------------------------------------
; INPUT: AL = formatting filler byte
; EBX = floppy disk device parameter block FLOPPY
; ESI = head
; EDI = cylinder
; OUTPUT: CY = error
; -----------------------------------------------------------------------------
; ------------- Push registers
FDFormatTrack: push eax ; push EAX
push ecx ; push ECX
push edx ; push EDX
push esi ; push ESI
push edi ; push EDI
; ------------- Lock controller
call FDLock ; lock controller
; ------------- Check parameters
cmp edi,byte FD_TRACKS ; check cylinder number
jae FDFormatTrack1 ; invalid cylinder number
cmp esi,byte FD_HEADS ; check head number
jb FDFormatTrack2 ; head number is OK
FDFormatTrack1: stc ; set error flag
jmp short FDFormatTrack7 ; error
; ------------- Start motor ON
FDFormatTrack2: call FDMotorOn ; start motor ON
; ------------- Reset controller and drive
test byte [ebx+FLOPPY_Flags],FLOPPY_RESREQ ; reset request?
jz FDFormatTrack3 ; reset not required
call FDReset ; reset controller and drive
jc FDFormatTrack9 ; error
; ------------- Set head (-> DL head)
FDFormatTrack3: mov edx,esi ; DL <- head number
mov [ebx+FLOPPY_Head],dl ; set current head
; ------------- Seek (-> CL cylinder)
mov ecx,edi ; CL <- cylinder
cmp cl,[ebx+FLOPPY_Track] ; cylinder changed?
jne FDFormatTrack4 ; cylinder changed
test byte [ebx+FLOPPY_Flags],FLOPPY_SEEKREQ ; seek request?
jz FDFormatTrack5 ; no seek requesst
FDFormatTrack4: mov [ebx+FLOPPY_Track],cl ; set new cylinder
call FDSeek ; seek
; ------------- Set data transfer rate
FDFormatTrack5: call FDSetRate ; set data transfer rate
; ------------- Initialize track layout (-> AH formatting filler byte)
mov edi,[ebx+FLOPPY_Buffer] ; EDI <- DMA buffer
push edi ; push EDI
mov ah,al ; DH <- formatting filler byte
mov ch,1 ; CH <- 1, sector number
FDFormatTrack6: mov al,cl ; AL <- cylinder
stosb ; store cylinder
mov al,dl ; AL <- head
stosb ; store head
mov al,ch ; AL <- sector number
stosb ; store sector number
mov al,FD_SECTSIZEFDC ; AL <- sector size
stosb ; store sector size
inc ch ; increase sector number
cmp ch,FD_SECTORS ; check sector number
jbe FDFormatTrack6 ; next sector
pop edx ; pop EDX (DMA address)
; ------------- Start DMA transfer
push ebx ; push EBX
mov al,FD_DMA ; AL <- DMA number
mov bl,1 ; BL <- write mode
mov ecx,FD_SECTORS*4 ; ECX <- DMA transfer size
call DMAStart ; start DMA transfer
pop ebx ; pop EBX
; ------------- Clear interrupt flag
call FDClearInt ; clear interrupt flag
; ------------- Send command to controller
mov al,FD_FORMAT ; AL <- command
call FDSendData ; send command to controller
FDFormatTrack7: jc short FDFormatTrack9 ; error
; ------------- Select head and drive
mov al,[ebx+FLOPPY_Head] ; AL <- current head number
shl al,2 ; rotate head to position
%if FD_DEVICE != 0
or al,FD_DEVICE ; add device index
%endif
call FDSendData ; send data to controller
jc short FDFormatTrack9 ; error
; ------------- Set sector size (for sector ID)
mov al,FD_SECTSIZEFDC ; AL <- sector size
call FDSendData ; send sector size to controller
jc short FDFormatTrack9 ; error
; ------------- Set number of sectors per track
mov al,FD_SECTORS ; AL <- sectors per track
call FDSendData ; send sectors to controller
jc short FDFormatTrack9 ; error
; ------------- Set gap length (intersector gap)
mov al,FD_FORMGAP ; AL <- intersector gap
call FDSendData ; send gap length to controller
jc short FDFormatTrack9 ; error
; ------------- Set filler byte
mov al,ah ; AL <- filler byte
call FDSendData ; send filler byte to controller
jc short FDFormatTrack9 ; error
; ------------- Wait for end of operation
call FDWaitRW ; wait for end of operation
; ------------- Motor OFF (it saves flags)
FDFormatTrack9: call FDMotorOff ; motor OFF
; ------------- Stop DMA transfer (it saves flags)
call FDDMAStop ; stop DMA transfer
; ------------- Unlock controller (it saves flags)
call FDUnlock ; unlock controller
; ------------- Pop registers
pop edi ; pop EDI
pop esi ; pop ESI
pop edx ; pop EDX
pop ecx ; pop ECX
pop eax ; pop EAX
ret
; -----------------------------------------------------------------------------
; Lock floppy controller
; -----------------------------------------------------------------------------
; INPUT: EBX = floppy disk device parameter block FLOPPY
; -----------------------------------------------------------------------------
FDLock: push ebx ; push EBX
mov ebx,[ebx+FLOPPY_FDC] ; EBX <- controller descriptor
add ebx,byte FDC_Mutex ; EBX <- mutex
call MutexLock ; lock mutex
pop ebx ; pop EBX
ret
; -----------------------------------------------------------------------------
; Unlock floppy controller
; -----------------------------------------------------------------------------
; INPUT: EBX = floppy disk device parameter block FLOPPY
; NOTES: It saves flags
; -----------------------------------------------------------------------------
FDUnlock: pushf ; push flags
push ebx ; push EBX
mov ebx,[ebx+FLOPPY_FDC] ; EBX <- controller descriptor
add ebx,byte FDC_Mutex ; EBX <- mutex
call MutexUnlock ; unlock mutex
pop ebx ; pop EBX
popf ; pop flags
ret
; -----------------------------------------------------------------------------
; Initialize floppy disk driver
; -----------------------------------------------------------------------------
; ------------- Lock controller
FDInit: mov ebx,FD0DrvDPB ; floppy disk drive 0
call FDLock ; lock controller
; ------------- Allocate DMA buffer
mov eax,FDBUFFSIZE ; EAX <- DMA buffer size
call DMAMemAlloc ; allocate DMA memory block
jc FDInit9 ; error? Cannot be at this time
mov [FDCDrvDPB+FDC_Buffer],edx ; store data buffer
mov [FD0DrvDPB+FLOPPY_Buffer],edx ; copy address for FD0
; ------------- Install DMA channel
mov al,FD_DMA ; AL <- DMA channel
call DMAAlloc ; install DMA channel
jc FDInit9 ; error
; ------------- Install floppy disk driver
mov ebx,FDCDrvDPB ; EBX <- driver parameter block
call DrvLstInsert ; insert driver into list
; ------------- Install floppy disk drives
mov ebx,FD0DrvDPB ; floppy disk drive 0
call DrvLstInsert ; insert drive into list
; ------------- Unlock controller
FDInit9: mov ebx,FD0DrvDPB ; floppy disk drive 0
call FDUnlock ; unlock controller
%ifdef KKKK
mov eax,32768
call SysMemAlloc
xchg eax,esi
mov ebx,FD0DrvDPB ; floppy disk drive 0
mov eax,512
xor edx,edx
mov ecx,1024
call DataDevRead
mov edx,esi
mov ecx,2
mov esi,0 ; head
mov edi,0 ; track
mov eax,1
; call FDReadTrack
jc FDInit8
mov esi,edx
mov edx,22
FDInit83: mov ecx,32
FDInit84: lodsb
call DebOutHexB
loop FDInit84
call DebNewLine
dec edx
jnz FDInit83
FDInit8:
%endif
ret
; -----------------------------------------------------------------------------
; Data
; -----------------------------------------------------------------------------
DATA_SECTION
; ------------- IRQ handler for floppy disk controller (IRQHAND)
align 8, db 0
FDIRQHandler: LISTHEAD ; link to next IRQ handler
dd 0 ; pointer to IRQ descriptor
dw IRQ_PRIVATE|IRQ_ACTIVE ; IRQ flags
db FD_IRQ ; current IRQ number
db FD_IRQ ; recomended best IRQ number
dd 1 << FD_IRQ ; mask of usable IRQs (1=enabled)
dd FDCDrvDPB+FDC_IntLock ; user data (NULL=disabled)
dd 0 ; counter for slow interrupts
dd FDInterrupt ; fast handler (NULL=none)
dd 0 ; slow handler (NULL=none)
dd 0 ; callback (NULL=none)
; ------------- Floppy disk controller parameter block (FDC)
align 8, db 0
; *** DPB
FDCDrvDPB: RBTREENODE ; red-black tree node
SPINLOCK ; driver lock
db 0,DRV_CTRL_FD ; index, class and subclass
db DPB_STATIC,0 ; flags and class flags
db 0,0,0,1 ; driver version
dd DrvVendorName ; pointer to vendor name
dd FDCDrvName ; pointer to driver name
dd FDCDrvModel ; pointer to model name
dd EmptySText ; modul path
dd FDCDrvDDFB ; pointer to function table
FDCDrvDPB1: LINKEDLIST FDCDrvDPB2,FDCDrvDPB5 ; resource list
; *** FDC
db FDC_DEFFLAG ; flags
db 0,0,0
dd NULL ; pointer to DMA buffer
TLOCK ; task lock for interrupt
SPINLOCK ; motor lock
MUTEX ; mutex to lock access to floppy
align 4, db 0
FDCDrvDPB2: LINKEDLIST FDCDrvDPB3,FDCDrvDPB1 ; resource list
dd FD_DMA ; start of resource
dw 1-1 ; size of resource-1
db RES_DMA ; resource type
db RES_STATIC+RES_AUTO ; flags
FDCDrvDPB3: LINKEDLIST FDCDrvDPB4,FDCDrvDPB2 ; resource list
dd FD_IRQ ; start of resource
dw 1-1 ; size of resource-1
db RES_IRQ ; resource type
db RES_STATIC+RES_AUTO ; flags
FDCDrvDPB4: LINKEDLIST FDCDrvDPB5,FDCDrvDPB3 ; resource list
dd 3f0h ; start of resource
dw 6-1 ; size of resource-1
db RES_PORT ; resource type
db RES_STATIC+RES_AUTO ; flags
FDCDrvDPB5: LINKEDLIST FDCDrvDPB1,FDCDrvDPB4 ; resource list
dd 3f7h ; start of resource
dw 1-1 ; size of resource-1
db RES_PORT ; resource type
db RES_STATIC+RES_AUTO ; flags
FDCDrvName: STEXT 'Floppy disk controller'
FDCDrvModel: STEXT '8272A'
; ------------- Floppy disk controller function block
align 4, db 0
; *** DFB
FDCDrvDDFB: dd DrvStdFuncOK ; device detection
dd DrvStdFuncOK ; device initialization
dd DrvStdFuncERR ; device deinitialization
dd DrvStdFuncERR ; enable device
dd DrvStdFuncERR ; disable device
; ------------- Floppy disk drive 0 (FLOPPY)
align 8, db 0
; *** DPB
FD0DrvDPB: RBTREENODE ; red-black tree node
SPINLOCK ; driver lock
db 0,DRV_DISK_FD ; index, class and subclass
db DPB_STATIC,0 ; flags and class flags
db 0,0,0,1 ; driver version
dd DrvVendorName ; pointer to vendor name
dd FD0DrvName ; pointer to driver name
dd FD0DrvModel ; pointer to model name
dd EmptySText ; modul path
dd FDDrvDDFB ; pointer to function table
FD0DrvDPB1: LINKEDLIST FD0DrvDPB1,FD0DrvDPB1 ; resource list
; *** DATADEV
dd DDEV_WRITEVER|DDEV_USECOMP ; flags
dd FLOPPY_CAP ; capabilities
db 0,0,0
db 9 ; granularity bits
dd 512 ; granularity size
dd ~(512-1) ; granularity inverse mask
dd FD0FileName ; device file name
dd 1474560,0 ; media size (bytes)
dd 0,0 ; current position
; *** DISK
dd 2880,0 ; total number of sectors
dd 18 ; number of sectors per track
dd 2 ; number of heads
dd 80 ; number of cylinders
; *** FLOPPY
dd FDCDrvDPB ; pointer to floppy disk controller
db FLOPPY_DEFFLAG ; flags
db 0 ; current track number
db 0 ; current head number
db FDERR_OK ; last error code
dd NULL ; pointer to DMA buffer
ALARMTIMER FDMotorOffCB,FD0DrvDPB ; motor OFF timer
times FLOP_REPMAX db 0 ; reply buffer
db 0
FD0DrvName: STEXT 'Floppy disk drive'
FD0DrvModel: STEXT '3.5" HD 1.44 MB'
FD0FileName: STEXT '\dev\fd'
; ------------- Floppy disk drive function block FLOPPYF
align 4, db 0
; *** DFB
FDDrvDDFB: dd DrvStdFuncOK ; device detection
dd DrvStdFuncOK ; device initialization
dd DrvStdFuncERR ; device deinitialization
dd DrvStdFuncERR ; enable device
dd DrvStdFuncERR ; disable device
; *** DATADEVF
dd DrvStdFuncOK ; open data device
dd DrvStdFuncOK ; clode data device
dd DiskRead ; read data from device
dd DiskWrite ; write data to device
dd DiskVerify ; verify data from device
dd DiskCompare ; compare data from device
dd DrvStdFuncERR ; lock door
dd DrvStdFuncERR ; get door open
dd DrvStdFuncERR ; set door open
dd DrvStdFuncERR ; test media change
; *** DISKF
dd FDReadTrack ; read sectors from track
dd FDWriteTrack ; write sectors to track
dd FDVerifyTrack ; verify sectors from track
dd FDCompTrack ; compare sectors from track
dd FDFormatTrack ; format track
|