Tvùrce webu je i pro tebe! Postav tøeba web. Bez grafika. Bez kodéra. Hned.
wz

FLOPPY.ASM

Floppy Disk


; =============================================================================
;
;                             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

Back to source browser