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

FLOP_OLD.INC, FLOP_OLD.ASM

Unfinished version of universal floppy disk driver

FLOP_OLD.INC


; =============================================================================
;
;                           Litos - Floppy disk
;
; =============================================================================
; This floppy driver is unfinished due to the fact that floppy drive is
; obsolete device. It is replaced by simplified version of driver.
; =============================================================================

; ------------- Floppy disk controller function block

struc		FDCF

		resb	DFB_size	; 0: driver function block

endstruc				; size 14h = 20 bytes

; ------------- Floppy disk controller parameter block

FDBUFFSIZE	EQU	8000h		; DMA buffer size (42 sectors = 21K)

struc		FDC

		resb	DPB_size	; 0: driver parameter block
FDC_Flags:	resb	1		; 40h: flags (see below, DWORD aligned)
FDC_IRQ:	resb	1		; 41h: IRQ number (=6)
FDC_DMA:	resb	1		; 42h: DMA number (=2)
FDC_DevNum:	resb	1		; 43h: number of floppy devices
FDC_DevMask:	resb	1		; 44h: mask of detected drives
FDC_DORData1:	resb	1		; 45h: current DOR register of FDC #1
FDC_DORData2:	resb	1		; 46h: current DOR register of FDC #2
		resb	1
FDC_Buffer:	resd	1		; 48h: pointer to first DMA buffer
FDC_Buffer2:	resd	1		; 4Ch: pointer to second DMA buffer
FDC_IntLock:	resb	TASKLOCK_size	; 50h: task lock for interrupt
FDC_Task:	resd	1		; 5Ch: owning task (NULL=none)
FDC_DevList:	resb	LIST_size	; 60h: list of floppy drives
FDC_MotorLock:	resb	SPINLOCK_size	; 68h: motor and DOR lock

endstruc				; size 6Ch = 108 bytes

; ------------- Floppy disk controller flags

FDC_LOCK_BIT:	EQU	0		; floppy disk controller is locked
FDC_LOCK:	EQU	1 << FDC_LOCK_BIT
FDC_INTOK_BIT 	EQU	1		; interrupt occurs
FDC_INTOK	EQU	1 << FDC_INTOK_BIT

FDC_DEFFLAG	EQU	0		; default flags

; ------------- Floppy disk drive descriptor

struc		FDRIVE

FDRIVE_Flags:	resb	1		; 0: flags (see below)
FDRIVE_SRTHUT:	resb	1		; 1: Step rate time + head unload time
					;	B0..B3: head unload time / 16,
					;	 16 ms to 240 ms in 16 ms steps
					;	 (1=16 ms,2=32 ms...15=240 ms)
					;	 (0=256 ms on 82077 and more)
					;	B4..B7: 16 - step rate time,
					;	       15=1 ms,14=2 ms..0=15 ms
					;    Time intervals are multiplied
					;    dependently on data rate (82077+):
					;	250K ... x2
					;	300K ... x1.67
					;	500K ... x1
					;	1M ..... x0.5
FDRIVE_HLTNDMA:	resb	1		; 2: Head load time + non DMA
					;	B0: 1=non DMA, 0=use DMA
					;	B1..B7: head load time / 2,
					;	(1=2 ms, 2=4 ms,... 127=254 ms)
					;	(0=256 ms on 82077 and more)
					;    Time intervals are multiplied
					;    dependently on data rate (82077+):
					;	250K ... x2
					;	300K ... x1.67
					;	500K ... x1
					;	1M ..... x0.5
FDRIVE_Settle:	resb	1		; 3: head settle time (in [ms], = 15)
FDRIVE_MotorOn:	resd	1		; 4: motor on delay (in [ms])
FDRIVE_MotorOff:resd	1		; 8: motor off delay (in [ms])
FDRIVE_MaxSect:	resb	4		; 0Ch: maximum sectors for data rates
FDRIVE_RateSect:resb	3		; 10h: recomend. sectors for data rates
		resb	1
FDRIVE_Capacity:resd	1		; 14h: pointer to track capacity table
FDRIVE_Media:	resd	1		; 18h: pointer to media list FDMEDIA
FDRIVE_MediaNum:resb	1		; 1Ch: total number of media entries
FDRIVE_MediaStN:resb	1		; 1Dh: number of standard media
FDRIVE_MediaStd:resb	6		; 1Eh: indexes of standard media
					;      (first = default media)

endstruc				; size 24h = 36 bytes

; ------------- Macro - initialized entry "Step rate time + head unload time"
; %1 = step rate time 1 ms to 16 ms
; %2 = head unload time 16 ms to 240 ms (or 256 ms on 82077+) in 16 ms steps
;   Time intervals are multiplied dependently on data rate (on 82077 and more):
;	250K ... x2
;	300K ... x1.67
;	500K ... x1
;	1M ..... x0.5

%macro		SRTHUT	2
		db	((16-%1)*16) + ((%2/16)&0fh)
%endmacro

; ------------- Macro - initialized entry "Head load time + non DMA"
; %1 = head load time 2 ms to 254 ms (or 256 ms on 82077+) in 2 ms steps
; %2 = 1 don't use DMA, 0 use DMA
;   Time intervals are multiplied dependently on data rate (on 82077 and more):
;	250K ... x2
;	300K ... x1.67
;	500K ... x1
;	1M ..... x0.5

%macro		HLTNDMA	2
		db	%2 + (%1 & 0feh)
%endmacro

; ------------- Floppy disk drive flags

FDRIVE_5	EQU	B0		; 5.25" drive type (else 3.5")
FDRIVE_2HEADS	EQU	B1		; 2 heads (else 1 head)
FDRIVE_80TRACK	EQU	B2		; 80 tracks (else 40 tracks)
FDRIVE_250K	EQU	B4		; data rate DD 250 kb/s (3.5") enabled
FDRIVE_300K	EQU	B3		; data rate DD 300 kb/s (5.25") enabled
FDRIVE_500K	EQU	B5		; data rate HD 500 kb/s enabled
FDRIVE_1000K	EQU	B6		; data rate ED 1 Mb/s enabled
FDRIVE_CHDET	EQU	B7		; detect medium exchange

FDRIVE_DD	EQU	FDRIVE_250K+FDRIVE_300K ; data rates DD enabled
FDRIVE_DDHD	EQU	FDRIVE_DD+FDRIVE_500K ; data rates DD/HD enabled
FDRIVE_DDHDED	EQU	FDRIVE_DDHD+FDRIVE_1000K ; data rates DD/HD/ED enab.

FD_MAX80TRK	EQU	84		; maximum tracks for 80 track drive
FD_MAX40TRK	EQU	42		; maximum tracks for 40 track drive

; 5.25", 360 KB, DD, 5 t/sec (300 RPM)
;	DD (250 kb/s): 6250 B on track, max. 10 sectors, gap 49
;	DD (300 kb/s nonstandard): 7500 B on track, max. 13 sectors, gap 1
;
; 5.25" 1.2 MB, HD, 6 t/sec (360 RPM)
;	DD (250 kb/s nonstandard) 5208 B on track, max. 9 sectors, gap 2
;     	DD (300 kb/s): 6250 B on track, max. 10 sectors, gap 49
;	HD (500 kb/s): 10416 B on track, max. 18 sectors, gap 2
;
; 3.5" 720 KB, DD, 5 t/sec (300 RPM):
;	DD (250 kb/s): 6250 B on track, max. 10 sectors, gap 49
;	DD (300 kb/s nonstandard): 7500 B on track, max. 13 sectors, gap 1
;
; 3.5" 1.44 MB, HD, 5 t/sec=300 RPM):
;	DD (250 kb/s): 6250 B on track, max. 10 sectors, gap 49
;	DD (300 kb/s nonstandard): 7500 B on track, max. 13 sectors, gap 1
;	HD (500 kb/s): 12500 B on track, max. 21 sectors, gap 19
;
; 3.5" 2.88 MB, ED, 5 t/sec=300 RPM):
;	DD (250 kb/s): 6250 B on track, max. 10 sectors, gap 49
;	DD (300 kb/s nonstandard): 7500 B on track, max. 13 sectors, gap 1
;	HD (500 kb/s): 12500 B on track, max. 21 sectors, gap 19
;	ED (1 Mb/s): 25000 B on track, max. 42 sectors, gap 9
;
; Maximal intersector gaps for 1.44 MB drive (determined experimentally):
;  250K: 1..7 sectors/track=255, 8=236, 9=134, 10=56
;  300K: 1..9 sectors/track=255, 10=195, 11=117, 12=55, 13=2 interleaved
;  500K: 1..15=255, 16=221, 17=171, 18=127, 19=88, 20=53, 21=22 interleaved
;
; How to calculate maximal intersector gap (for 3.5" drive):
;  250K: gap = (6250/sectors_per_track - sector_size - 64)*1.149
;  300K: gap = (7500/sectors_per_track - sector_size - 63)*1.111
;  500K: gap = (12500/sectors_per_track - sector_size - 63)*1.067
;
; How to calculate optimal intersector gap:
;  track_capacity = data_transfer_rate / turns_per_second / 8
;  gap = (track_capacity/sectors_per_track - sector_size - 62)*3/4

; ------------- Floppy disk data rate
; Notes: Data rate identifiers are not identical to data rate of FDC.

FDRATE_250K	EQU	0		; 250 kb/s, DD on 3.5"
FDRATE_300K	EQU	1		; 300 kb/s, DD on 5.25"
FDRATE_500K	EQU	2		; 500 kb/s, HD on 5.25" and 3.5"
FDRATE_1M	EQU	3		; 1000 kb/s, ED on 3.5"

FDRATE_MAX	EQU	FDRATE_1M	; maximal data rate

; ------------- Floppy disk sector size

FDSIZE_128	EQU	0		; 128 B
FDSIZE_256	EQU	1		; 256 B
FDSIZE_512	EQU	2		; 512 B
FDSIZE_1K	EQU	3		; 1 KB
FDSIZE_2K	EQU	4		; 2 KB
FDSIZE_4K	EQU	5		; 4 KB
FDSIZE_8K	EQU	6		; 8 KB
FDSIZE_16K	EQU	7		; 16 KB

FDSIZE_MAX	EQU	FDSIZE_16K	; maximal sector size

; ------------- Floppy disk media descriptor

struc		FDMEDIA

FDMED_Flags:	resb	1		; 0: flags (see below, DWORD aligned)
FDMED_SectSize:	resb	1		; 1: sector size (0=128 B, ... 7=16 KB)
FDMED_TrackSect:resb	1		; 2: number of sectors per track
FDMED_Tracks:	resb	1		; 3: number of tracks
FDMED_Inter:	resb	1		; 4: interleaving (1 or 2)
FDMED_FormGap:	resb	1		; 5: formatting inter-sector gap
FDMED_HeadSlid:	resb	1		; 6: head sliding (DD 1, HD 2, ED 3)
FDMED_TrackSlid:resb	1		; 7: track sliding (DD 2, HD 3, ED 4)

endstruc				; size 8 bytes (hardcoded)

FDMEDIA_SIZEBIT	EQU	3		; size of FDMEDIA in bits

; ------------- Floppy disk media flags

FDMED_RATEMASK	EQU	B0+B1		; data rate mask
FDMED_5		EQU	B2		; 5.25" drive type (else 3.5")
FDMED_STD_BIT	EQU	3		; standard (compatible) media format
FDMED_STD	EQU	1 << FDMED_STD_BIT
FDMED_HEADS_BIT	EQU	4		; number of heads, 1=2 heads, 0=1 head
FDMED_HEADS	EQU	1 << FDMED_HEADS_BIT
FDMED_DBL_BIT	EQU	5		; use double-steps
FDMED_DBL	EQU	1 << FDMED_DBL_BIT

; ------------- Floppy disk media validity flags

FDMED_SIZE_OK	EQU	B0		; sector size is valid (hardcoded)
FDMED_SECT_OK	EQU	B1		; number of sectors per track is valid
FDMED_HEAD_OK	EQU	B2		; number of heads is valid
FDMED_TRK_OK	EQU	B3		; number of tracks is valid

FDMED_RATE_OK	EQU	B4		; data rate is valid
FDMED_DBL_OK	EQU	B5		; double-steps is valid

FDMED_INT_OK	EQU	B6		; interleaving is valid
FDMED_GAP_OK	EQU	B7		; formatting inter-sector gap is valid
FDMED_HSLID_OK	EQU	B8		; head sliding is valid
FDMED_TSLID_OK	EQU	B9		; track sliding is valid

; geometry flags
FDMED_GEOM_OK	EQU	FDMED_SIZE_OK+FDMED_SECT_OK+FDMED_HEAD_OK+FDMED_TRK_OK

; access flags
FDMED_ACC_OK	EQU	FDMED_RATE_OK+FDMED_DBL_OK

; formatting flags
FDMED_FORM_OK	EQU	FDMED_INT_OK+FDMED_GAP_OK+FDMED_HSLID_OK+FDMED_TSLID_OK

; all flags
FDMED_ALL_OK	EQU	FDMED_GEOM_OK+FDMED_ACC_OK+FDMED_FORM_OK

; ------------- Floppy disk device function block

struc		FLOPPYF

		resb	DISKF_size	; 0: block device function block

endstruc				; size 14h = 20 bytes

; ------------- Floppy disk data device capabilities

FLOPPY_CAP	EQU	DDEV_CANSEEK+DDEV_CANCHANGE+DDEV_CANALL+DDEV_CANHWWPROT

; ------------- Floppy disk device parameter block

FLOP_REPMAX	EQU	16		; maximal number of replies

struc		FLOPPY

		resb	DISK_size	; 0: block device parameter block

FLOPPY_FDC:	resd	1		; 74h: pointer to controller FDC
FLOPPY_Drive:	resd	1		; 78h: pointer to drive FDRIVE
FLOPPY_Flags:	resb	1		; 7Ch: flags (see below, DWORD aligned)
FLOPPY_Device:	resb	1		; 7Dh: device index (0 or 1)
FLOPPY_MotMask:	resb	1		; 7Eh: motor mask (B4 or B5)
FLOPPY_Track:	resb	1		; 7Fh: current track number
FLOPPY_Head:	resb	1		; 80h: current head number
FLOPPY_Rate:	resb	1		; 81h: current data rate
FLOPPY_SectSize:resb	1		; 82h: current sector size (0=128,...)
FLOPPY_Inter:	resb	1		; 83h: sector interleave
FLOPPY_FormGap:	resb	1		; 84h: formatting inter-sector gap
FLOPPY_HeadSlid:resb	1		; 85h: head sliding (DD 1, HD 2, ED 2)
FLOPPY_TrckSlid:resb	1		; 86h: track sliding (DD 2, HD 3, ED 4)
FLOPPY_FormFill:resb	1		; 87h: formatting filler byte
FLOPPY_ReplyNum:resb	1		; 88h: bytes in reply buffer
FLOPPY_GPL	resb	1		; 89h: gap 3 length (for write)
FLOPPY_LastErr:	resb	1		; 8Ah: last error code (see below)
FLOPPY_DMA:	resb	1		; 8Bh: DMA number (=2)
FLOPPY_DORData:	resd	1		; 8Ch: pointer to current DOR data
FLOPPY_DevList:	resb	LIST_size	; 90h: list of floppy drives
FLOPPY_DORPort:	resd	1		; 98h: digital output register (+2, W)
FLOPPY_StatPort:			;      diskette status port (+4, R)
FLOPPY_RatePort:resd	1		; 9Ch: data rate select register (+4,W)
FLOPPY_DataPort:resd	1		; 0A0h: command/data port (+5, RW)
FLOPPY_DIRPort:				;     digital input register (+7, R)
FLOPPY_DCRPort:	resd	1		; 0A4h: diskette control register (+7,W)
FLOPPY_Buffer:	resd	1		; 0A8h: pointer to first DMA buffer
FLOPPY_Buffer2:	resd	1		; 0ACh: pointer to second DMA buffer
FLOPPY_Alarm:	resb	ALARM_size	; 0B0h: motor OFF timer
FLOPPY_Reply:	resb	FLOP_REPMAX	; 0D0h: reply buffer

endstruc				; size 0E0h = 192 bytes

FLOPPY_TrckSect	EQU	DISK_TrackSect	; sectors per track

FLOPPY_ST0	EQU	FLOPPY_Reply + 0 ; reply register 0
FLOPPY_ST1	EQU	FLOPPY_Reply + 1 ; reply register 1
FLOPPY_ST2	EQU	FLOPPY_Reply + 2 ; reply register 2
FLOPPY_ST3	EQU	FLOPPY_Reply + 0 ; reply register 3 (=result)
FLOPPY_RES_CYL	EQU	FLOPPY_Reply + 3 ; reply register - cylinder
FLOPPY_RES_HEAD	EQU	FLOPPY_Reply + 4 ; reply register - head
FLOPPY_RES_SECT	EQU	FLOPPY_Reply + 5 ; reply register - sector number
FLOPPY_RES_SIZE	EQU	FLOPPY_Reply + 6 ; reply register - sector size

; ------------- Floppy disk device flags

FLOPPY_DOUBLE	EQU	B0		; use double steps
FLOPPY_RESREQ	EQU	B1		; reset request
FLOPPY_SEEKREQ	EQU	B2		; seek request

FLOPPY_DEFFLAG	EQU	FLOPPY_SEEKREQ	; floppy disk default flags

; ------------- Floppy disk error code

				; *** No error
FDERR_OK	EQU	00h		; no error
				; *** General errors
FDERR_UNKOWN	EQU	11h		; unknown error
				; *** FDC controller errors
FDERR_FDCERR	EQU	21h		; controller general error
FDERR_FDCRESET	EQU	22h		; controller reset error
FDERR_FDCREADY	EQU	23h		; controller not ready (FDC time-out)
FDERR_FDCWRITE	EQU	24h		; error writing command to controller
FDERR_FDCREAD	EQU	25h		; error receiving state from controller
FDERR_FDCOVER	EQU	26h		; result buffer overrun
FDERR_OVERRUN	EQU	27h		; data overrun (data lost, DMA error)
				; *** Drive error
FDERR_SEEKERR	EQU	31h		; seek error
FDERR_TIMEOUT	EQU	32h		; operation (interrupt) time-out
FDERR_DRVREADY	EQU	33h		; drive not ready
FDERR_ZEROTRACK	EQU	34h		; recalibrate error, track 0 not found
				; *** Media error
FDERR_ADDRFND	EQU	41h		; missing sector address mark
FDERR_WPROT	EQU	42h		; disk write-protected
FDERR_DATAFND	EQU	43h		; missing sector data
FDERR_CRC	EQU	44h		; bad CRC of sector
FDERR_SECTFND	EQU	45h		; sector not found
FDERR_BADHEAD	EQU	46h		; sector head does not correspomd

; ------------- Floppy disk track layout (one entry, used with format track)

struc		FTRACK

FTRACK_Cyl:	resb	1		; 0: cylinder number (0..79)
FTRACK_Head:	resb	1		; 1: head number (0..1)
FTRACK_Sect:	resb	1		; 2: sector number (1..)
FTRACK_Size:	resb	1		; 3: sector size (0=128,...)

endstruc				; size 4 bytes

; ------------- Main status register

FDS_BUSYMASK	EQU	B0+B1+B2+B3	; busy mask (drive 0..3 seeks)
FDS_BUSY	EQU	B4		; controller busy (command in progress)
FDS_NONDMA	EQU	B5		; non-DMA mode (SPECIFY is executed)
FDS_DIRREAD	EQU	B6		; data direction 1=FDC->CPU, 0=CPU->FDC
FDS_READY	EQU	B7		; data register ready (to transfer)

; ------------- Digital output register (DOR)

FDDOR_SELMASK	EQU	B0+B1		; drive select mask (0..3)
FDDOR_FDCENABLE	EQU	B2		; FDC enable (0=controller reset)
FDDOR_DMAENABLE	EQU	B3		; DMA enable
FDDOR_MOTOR0	EQU	B4		; drive 0 motor enable
FDDOR_MOTOR1	EQU	B5		; drive 1 motor enable
FDDOR_MOTOR2	EQU	B6		; drive 2 motor enable
FDDOR_MOTOR3	EQU	B7		; drive 3 motor enable

FDDOR_MOTMASK	EQU	B4+B5+B6+B7	; drive motors mask

; ------------- Status register ST0

FDST0_DRVMASK	EQU	B0+B1		; drive unit at interrupt
FDST0_HEAD	EQU	B2		; head state at interrupt
FDST0_NREADY	EQU	B3		; not ready (drive is not ready with
					; R/W command or access to side 1
					; required on single side drive)
FDST0_EQERR	EQU	B4		; equipment check error, fault signal
					; received or track 0 not found
FDST0_SEEKEND	EQU	B5		; seek completed
FDST0_INTMASK0	EQU	B6		; interrupt code mask (low bit)
FDST0_INTMASK1	EQU	B7		; interrupt code mask (high bit)
FDST0_INTMASK	EQU	B6+B7		; interrupt code mask
					;  00 = normal termination
					;  01 = abnormal termination, command
					;	was started but was not
					;	successfully completed
					;  10 = invalid command, command
					;	was never started
					;  11 = abnormal termination, ready
					;	signal changed state

; ------------- Status register ST1

FDST1_MISADDR	EQU	B0		; missing address mark
FDST1_WP	EQU	B1		; write protect (during write)
FDST1_NDATA	EQU	B2		; no data (sector not found)
FDST1_OVERRUN	EQU	B4		; overrun (FDC is not serviced by the
					; host system during data transfer)
FDST1_CRC	EQU	B5		; CRC error in data or head
FDST1_EOC	EQU	B7		; end of cylinder (FDC tries to access
					; sector after last sector of cylinder)

; ------------- Status register ST2

FDST2_MISADDR	EQU	B0		; missing address mark in data field
FDST2_BADCYL	EQU	B1		; bad cylinder (different cylinder)
FDST2_SCANERR	EQU	B2		; scan not satisfied (cannot find
					; sector during scan command)
FDST2_SCANEQU	EQU	B3		; scan equal hit
FDST2_WRONGCYL	EQU	B4		; wrong cylinder
FDST2_CRC	EQU	B5		; CRC error in data
FDST2_CTRLMARK	EQU	B6		; control mark

; ------------- Status register ST3

FDST3_HEAD	EQU	B2		; head
FDST3_DS	EQU	B3		; drive us double-sided
FDST3_TRACK0	EQU	B4		; track zero signal
FDST3_READY	EQU	B5		; drive is ready
FDST3_WP	EQU	B6		; write protect
FDST3_FAULT	EQU	B7		; drive fault

; ------------- Floppy disk commands
; Recalibrate:
;     W - DS drive select (B0+B1)

; Read/write data, read/write deleted data, read track, scan:
;     W - HDS+DS head select (B2) + drive select (B0+B1)
; 	- C cylinder (for sector ID information, starting 0)
; 	- H head (for sector ID information, 0 or 1)
;	- R sector number (for sector ID information. starting 1)
;	- N sector size (for sector ID information, 0=128 B...)
;	- EOT end of track (final sector number of a cylinder)
;	- GPL gap 3 length (spacing between sector excl. VCO sync field)
;	- DTL data length when N is 0
;     R	- ST0
;	- ST1
;	- ST2
; 	- C cylinder
; 	- H head
;	- R sector number
;	- N sector size

; Read ID:
;     W - HDS+DS head select (B2) + drive select (B0+B1)
;     R - ST0
;	- ST1
;	- ST2
; 	- C cylinder
; 	- H head
;	- R sector number
;	- N sector size

; Format a track:
;     W - HDS+DS head select (B2) + drive select (B0+B1)
;	- N sector size (for sector ID information, 0=128 B...)
;	- SC sectors/track
;	- GPL gap 3 length (spacing between sector excl. VCO sync field)
;	- D filler byte
;     R	- ST0
;	- ST1
;	- ST2
; 	- C cylinder
; 	- H head
;	- R sector number
;	- N sector size

; Sense interrupt status:
;     R	- ST0
;	- PCN present cylinder number

; Specify:
;     W - SRT+HUT step rate time (B4..B7) + head uload time (B0..B3)
;	- HLT+ND head load time (B1..B7) + non-DMA mode (B0)

; Semse drive status:
;     W - HDS+DS head select (B2) + drive select (B0+B1)
;     R	- ST3

; Seek:
;     W - HDS+DS head select (B2) + drive select (B0+B1)
;     W	- NCN new cylinder number

; Invalid command:
;     R - ST0 with 80h

; Get version:
;     R - ST0, 90h indicates 765B or more, 80h indicates 765A

FD_READ_TRK	EQU	2+B5+B6		; read track
					; (with MFM, without skip deleted data)

FD_SPECIFY	EQU	3		; specify

FD_STATUS	EQU	4		; sense drive status (read ST3)

FD_WRITE	EQU	5+B6		; write (without multi-track, with MFM)
FD_WRITE_MT	EQU	5+B6+B7		; write (with multi-track, with MFM)


FD_READ		EQU	6+B5+B6		; read (without multi-track, with MFM,
					;	with skip deleted data)
FD_READ_MT	EQU	6+B5+B6+B7	; read (with multi-track, with MFM,
					;	with skip deleted data)

FD_RECALIB	EQU	7		; recalibrate (move to track 0)

FD_SENSE	EQU	8		; sense interrupt status

FD_WRITE_DEL	EQU	9+B6		; write deleted data (without
					;	multi-track, with MFM)

FD_READ_ID	EQU	0ah+B6		; read sector header (with MFM)

RD_READ_DEL	EQU	0ch+B6		; read deleted data (without
					;	multi-track, with MFM)

FD_FORMAT	EQU	0dh+B6		; format track (with MFM)

FD_SEEK		EQU	0fh		; seek

FD_SCAN_EQU	EQU	11h+B6+B5	; scan equal (without multi-track,
					;	with MFM, with skip deleted)

FD_SCAN_LOW	EQU	19h+B6+B5	; scan low or equal (without
					;	multi-track, with MFM, with
					;	skip deleted data)

FD_SCAN_HIGH	EQU	1dh+B6+B5	; scan high or equal (without
					;	multi-track, with MFM, with
					;	skip deleted data)

FD_VERSION	EQU	10h		; get version

; ------------- Command extension (only 82077 controller)

FD_DUMPREG	EQU	0eh		; dump controller registers
FD_CONFIG	EQU	13h		; configure fifo
FD_PERPEND	EQU	12h		; perpendicular R/W mode
FD_UNLOCK	EQU	14h		; unlock fifo config
FD_SEEKLOW	EQU	8fh		; seek to lower tracks
FD_LOCK		EQU	94h		; lock fifo config
FD_SEEKHIGH	EQU	0cfh		; seek to higher tracks
FD_VERIFY	EQU	16h+B5+B6	; verify (with MFM,without multi-track)

; ------------- Command extension 2 (only 82078 controller)

FD_PARTID	EQU	18h		; part id
FD_POWERDOWN	EQU	27h		; configure powersave
FD_SAVE		EQU	2eh		; save controller registers
FD_OPTION	EQU	33h		; ISO format
FD_RESTORE	EQU	4eh		; restore controller registers
FD_DRIVESPEC	EQU	8eh		; drive specification: 2 Mpbs transfer
FD_FORMWRITE	EQU	0efh		; format and write

FLOP_OLD.ASM


; =============================================================================
;
;                             Litos - Floppy disk
;
; =============================================================================
; This floppy driver is unfinished due to the fact that floppy drive is
; obsolete device. It is replaced by simplified version of driver.
;
; Characteristic of this driver:
; - multiple sector sizes
; - multiple data rates 
; - multiple sectors per track
; - 2 controllers (4 drives)
; - non-standard disk formats (high-capacity disks)
; - formatting with head-sliding and track-sliding
; - automatic disk geometry
;
; TODO:
; - media format establishment
; - media change detection
; - formatting
; - correct calculations for other sectors than 512 B
; - detect write protection
; - device control
;
; Plan of media format establishment:
; - Try to detect sectors for all 4 data rates with READ_ID command. If just
;   ONE data rate is OK (found some sector and its parameters is OK), than use
;   it as established data rate. Take from it sector size. Else use default
;   data rate (500K) and default disk sector (512B).
; - Try to read maximum sectors from track - when it finish you can take last
;   found sector from its returned information and establish sectors per track.
; - Other determination of sectors per track is using READ_ID command: search
;   all sector heads to buffer until it will find some head again. Maximum
;   sector number uses as sectors per track. It can take more accurate - try
;   to read last sector and then all other following sectors.
; - Other determination is try to read sectors from start of track with one
;   sector reading. To enable fast reading read only every second sector. If
;   you find end of track try to read last sector more precise by one sector.
; - Determination of double step - try to read sectors from track 2 (not 1!).
; =============================================================================

		CODE_SECTION	32

; ------------- Macro - floppy disk media initialized descriptor
; %1 = data rate (FDRATE_500K,...)
; %2 = standard format (1=yes, 0=no)
; %3 = 2 heads (1=yes, 0=no)
; %4 = use double-steps (1=yes, 0=no)
; %5 = number of sectors per track (8, 9,..)
; %6 = number of tracks (40, 80)
; %7 = interleaving (1, 2)
; %8 = formatting inter-sector gap
; %9 = head sliding (DD 1, HD 2, ED 2)
; %10 = track sliding (DD 2, HD 3, ED 4)

%macro		FDMED5	10		; 5.25" drive

    db %1+FDMED_5+(%2<<FDMED_STD_BIT)+(%3<<FDMED_HEADS_BIT)+(%4<<FDMED_DBL_BIT)
		db	FDSIZE_512	; sector size
		db	%5		; number of sectors per track
		db	%6		; number of tracks
		db	%7		; interleaving
		db	%8		; formattin inter-sector gap
		db	%9		; head sliding (DD 1, HD 2, ED 2)
		db	%10		; track sliding (DD 2, HD 3, ED 4)

%endmacro

%macro		FDMED3	10		; 3.25" drive

    db %1+(%2<<FDMED_STD_BIT)+(%3<<FDMED_HEADS_BIT)+(%4<<FDMED_DBL_BIT)
		db	FDSIZE_512	; sector size
		db	%5		; number of sectors per track
		db	%6		; number of tracks
		db	%7		; interleaving
		db	%8		; formattin inter-sector gap
		db	%9		; head sliding (DD 1, HD 2, ED 2)
		db	%10		; track sliding (DD 2, HD 3, ED 4)

%endmacro

; -----------------------------------------------------------------------------
;                           Check if media is present
; -----------------------------------------------------------------------------
; INPUT:	EBX = floppy disk device parameter block FLOPPY
; OUTPUT:	CY = media is not present, diskette change
; -----------------------------------------------------------------------------

; ------------- Push registers

FDPresent:	push	eax		; push EAX
		push	edx		; push EDX

; ------------- Check if drive can detect media exchange (else medium present)

		mov	edx,[ebx+FLOPPY_Drive] ; EDX <- drive descriptor
		test	byte [edx+FDRIVE_Flags],FDRIVE_CHDET ; can detect?
		jz	FDPresent8	; cannot detect media change

; ------------- Check diskette change flag

		mov	edx,[ebx+FLOPPY_DIRPort] ; EDX<-digital input register
		in	al,dx		; read digital input register
		cmp	al,80h		; check media (B7 = diskette change)
		cmc			; CY = diskette change

; ------------- Pop registers

FDPresent8:	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	edx,[ebx+FLOPPY_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	edx,[ebx+FLOPPY_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
		mov	[ebx+FLOPPY_Reply+4],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	edx,[ebx+FLOPPY_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

; ------------- Store number of received bytes

FDGetResult8:	mov	[ebx+FLOPPY_ReplyNum],cl ; store number of bytes

; ------------- Pop registers

		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,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 2 seconds)

		mov	eax,2000	; EAX <- delay (2 seconds)
		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,[ebx+FLOPPY_Device] ; AL <- device index
		call	FDSendData	; set drive to seek
		jc	FDSeek9		; error

; ------------- Send track number

		mov	al,[ebx+FLOPPY_Track] ; AL <- current track
		test	byte [ebx+FLOPPY_Flags],FLOPPY_DOUBLE ; double steps?
		jz	FDSeek2		; no double steps
		shl	al,1		; AL <- physical track
FDSeek2:	call	FDSendData	; send track number
		jc	FDSeek9		; error

; ------------- Check seek result

		call	FDWaitSeek	; check status
		jc	FDSeek9		; error

; ------------- Delay to head settle

		mov	eax,[ebx+FLOPPY_Drive] ; EAX <- drive
		mov	al,[eax+FDRIVE_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	edx,[ebx+FLOPPY_Drive] ; EDX <- drive descriptor
		mov	al,[edx+FDRIVE_SRTHUT] ; AL <- step rate + head unload
		call	FDSendData	; send parameter to controller
		jc	FDSpecify8	; error

; ------------- Set head load time

		mov	al,[edx+FDRIVE_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	ah,FDDOR_FDCENABLE+FDDOR_DMAENABLE ; controller flags
		or	ah,[ebx+FLOPPY_MotMask] ; disable motor
		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	ah,FDDOR_FDCENABLE+FDDOR_DMAENABLE ; enable flags

; ------------- Push registers 2

FDMotorOnNow2:	push	edx		; push EDX

; ------------- Prepare new DOR register

		mov	edx,[ebx+FLOPPY_DORData] ; EDX <- pointer to DOR data
		mov	al,[edx] 	; AL <- current DOR data
		and	al,FDDOR_MOTMASK ; mask motor flags
		or	al,[ebx+FLOPPY_MotMask] ; enable motor
		xor	al,ah		; set flags and maybe disable motor
		or	al,[ebx+FLOPPY_Device] ; select drive

; ------------- Set new digital output register

		cmp	al,[edx]	; DOR register changed?
		je	FDMotorOnNow4	; DOR register not changed
		mov	[edx],al 	; store new DOR data
		mov	edx,[ebx+FLOPPY_DORPort] ; EDX <- digital output reg.
		out	dx,al		; output new DOR register

; ------------- Pop registers

FDMotorOnNow4:	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
		push	edx		; push EDX
%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

; ------------- Check if motor is already ON

		mov	edx,[ebx-FLOPPY_Alarm+FLOPPY_DORData] ; EDX <- DOR data
		mov	al,[ebx-FLOPPY_Alarm+FLOPPY_MotMask] ; AL <- motor mask
		test	[edx],al	; is motor already ON?
		pop	ebx		; pop EBX
		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	edx,[ebx+FLOPPY_Drive] ; EDX <- drive
		mov	eax,[edx+FDRIVE_MotorOn] ; EAX <- start time
		call	Sleep		; start motor

; ------------- Pop registers
%ifdef	SMP
		pop	esi		; pop ESI
%endif
		pop	edx		; pop EDX
		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	edx		; pop EDX
		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
		push	edx		; push EDX
%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

		mov	edx,[ebx-FLOPPY_Alarm+FLOPPY_DORData] ; EDX <- DOR data
		mov	al,[ebx-FLOPPY_Alarm+FLOPPY_MotMask] ; AL <- motor mask
		test	[edx],al	; is motor already OFF?
		jz	FDMotorOff6	; motor is already OFF

; ------------- Start timer

		mov	edx,[ebx-FLOPPY_Alarm+FLOPPY_Drive] ; EDX <- drive
		mov	eax,[edx+FDRIVE_MotorOff] ; 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	edx		; pop EDX
		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	edx,[ebx+FLOPPY_DCRPort] ; EDX <- DCR register
		movzx	eax,byte [ebx+FLOPPY_Rate] ; EAX <- current data rate
		mov	al,[FDDataRateTab+eax] ; AL <- translate 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	edx,[ebx+FLOPPY_DORData] ; EDX <- DOR data
		mov	al,[edx]	; AL <- current DOR register
		and	al,FDDOR_MOTMASK ; mask motor flags
		or	al,FDDOR_DMAENABLE ; FDC reset flags
		or	al,[ebx+FLOPPY_Device] ; select drive
		mov	edx,[ebx+FLOPPY_DORPort] ; EDX <- digital output reg.
		out	dx,al		; output new DOR register

; ------------- Clear interrupt flag

		call	FDClearInt	; clear interrupt flag

; ------------- Short delay (20 us) to accept reset signal

		push	eax		; push EAX
		mov	al,20		; AL <- delay [us]
		call	UDelayByte	; short delay
		pop	eax		; pop EAX

; ------------- Stop reset signal

		or	al,FDDOR_FDCENABLE ; FDC enable flag
		mov	edx,[ebx+FLOPPY_DORPort] ; EDX <- digital output reg.
		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,[ebx+FLOPPY_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, 3=compare
;		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	edx,cl		; EDX <- number of sectors
		mov	cl,[ebx+DDEV_GranBits] ; CL <- sector size (bits)
		shl	edx,cl		; EDX <- data transfer size
		mov	ecx,edx		; ECX <- transfer size

; ------------- Prepare DMA address (-> EDX)

		mov	edx,[ebx+FLOPPY_Buffer] ; EDX <- DMA buffer
		cmp	al,2		; verify?
		je	FDDMAStart2	; use rather buffer 2 on verify
		cmp	al,3		; compare mode?
		jb	FDDMAStart4	; no compare mode
		mov	al,0		; AL <- read mode
FDDMAStart2:	mov	edx,[ebx+FLOPPY_Buffer2] ; EDX <- DMA buffer 2

; ------------- Prepare other DMA parameters (address, channel and mode)

FDDMAStart4:	mov	bl,[ebx+FLOPPY_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

; -----------------------------------------------------------------------------
;                             Test DMA transfer
; -----------------------------------------------------------------------------
; INPUT:	EBX = floppy disk device parameter block FLOPPY
; OUTPUT:	CY = DMA transfer is still running
; -----------------------------------------------------------------------------

; ------------- Push registers

FDDMATest:	push	eax		; push EAX

; ------------- Test DMA transfer

		mov	al,[ebx+FLOPPY_DMA] ; AL <- DMA channel number
		call	DMATest		; test DMA transfer

; ------------- Pop registers

		pop	eax		; pop EAX
		ret

; -----------------------------------------------------------------------------
;                             Stop DMA transfer
; -----------------------------------------------------------------------------
; INPUT:	EBX = floppy disk device parameter block FLOPPY
; -----------------------------------------------------------------------------

; ------------- Push registers

FDDMAStop:	push	eax		; push EAX

; ------------- Stop DMA transfer

		mov	al,[ebx+FLOPPY_DMA] ; AL <- DMA channel number
		call	DMAStop		; stop DMA transfer

; ------------- Pop registers

		pop	eax		; pop EAX
		ret

; -----------------------------------------------------------------------------
;  Verify sectors from the disk (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

; -----------------------------------------------------------------------------
;  Compare sectors from the disk (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 compares DMA buffers FDC_Buffer and FDC_Buffer2.
; -----------------------------------------------------------------------------

; ------------- Read sectors into buffer 2

FDCompareSect:	call	FDCompareSect0	; read sectors into buffer 2
		jc	FDCompareSect9	; error

; ------------- Push registers

		push	ecx		; push ECX
		push	esi		; push ESI
		push	edi		; push EDI

; ------------- Prepare length of data (-> ECX)

		movzx	esi,cl		; ESI <- number of sectors
		mov	cl,[ebx+DDEV_GranBits] ; CL <- sector size (bits)
		sub	cl,2		; CL <- sector size in DWORDs
		shl	esi,cl		; ESI <- data transfer size / 4
		mov	ecx,esi		; ECX <- length of data / 4

; ------------- Compare data

		mov	esi,[ebx+FLOPPY_Buffer] ; ESI <- write buffer
		mov	edi,[ebx+FLOPPY_Buffer2] ; EDI <- read buffer
		repe	cmpsd		; compare buffers
		je	FDCompareSect8	; buffers are OK

; ------------- Pop registers

		stc			; set error flag
FDCompareSect8:	pop	edi		; pop EDI
		pop	esi		; pop ESI
		pop	ecx		; pop ECX
FDCompareSect9:	ret

; ------------- Push registers

FDCompareSect0:	push	eax		; push EAX
		push	ecx		; push ECX

; ------------- Prepare read mode

		mov	ch,al		; CH <- start sector
		mov	al,3		; AL <- 3, DMA compare
		jmp	short FDReadSect2

; -----------------------------------------------------------------------------
;    Read sectors from the disk (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 to the disk (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
		or	al,[ebx+FLOPPY_Device] ; add device index
		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,[ebx+FLOPPY_SectSize] ; AL <- sector size
		call	FDSendData	; send sector size to controller
		jc	short FDWriteSect9 ; error

; ------------- Set maximal sector number

		mov	al,[ebx+FLOPPY_TrckSect] ; AL <- sectors per track
		call	FDSendData	; send sectors to controller
		jc	short FDWriteSect9 ; error

; ------------- Set gap 3 length (intersector gap)

		mov	al,[ebx+FLOPPY_GPL] ; AL <- gap 3 length
		call	FDSendData	; send gap 3 length to controller
		jc	short FDWriteSect9 ; error

; ------------- Set number of bytes

		mov	al,128		; AL <- custom sector size
		cmp	byte [ebx+FLOPPY_SectSize],0 ; custom sector size?
		je	short FDWriteSect8 ; custom sector size
		mov	al,255		; AL <- other unlimited length
FDWriteSect8:	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

; ------------- Pop registers

		pop	ecx		; pop ECX
		pop	eax		; pop EAX
		ret

; -----------------------------------------------------------------------------
;              Write sectors to the disk with repeat on error
; -----------------------------------------------------------------------------
; 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.
; -----------------------------------------------------------------------------

FDWriteSectRep:	call	FDWriteSect	; write sectors
		jnc	FDWriteSectRep8	; data written OK
		call	FDReset		; reset controller and drive
		jc	FDWriteSectRep8	; error
		call	FDWriteSect	; write sectors
		jnc	FDWriteSectRep8	; data written OK
		call	FDReset		; reset controller and drive
		jc	FDWriteSectRep8	; error
		call	FDWriteSect	; write sectors
FDWriteSectRep8:ret

; -----------------------------------------------------------------------------
;            Prepare parameters for read/write/... 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:	ECX = limited number of sectors (1...)
;		EBP = data length (in bytes) / 4
;		CY = error, invalid parameters
; -----------------------------------------------------------------------------

; ------------- Push registers

FDRWPrep:	push	edx		; push EDX

; ------------- Check head number

		cmp	esi,[ebx+DISK_Heads] ; check head number
		jae	FDRWPrep8	; invalid head number

; ------------- Check cylinder number

		cmp	edi,[ebx+DISK_Tracks] ; check cylinder number
		jae	FDRWPrep8	; invalid cylinder number

; ------------- Check start sector

		mov	edx,[ebx+DISK_TrackSect] ; 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:	push	ecx		; push ECX
		mov	ebp,ecx		; EBP <- number of sectors
		mov	cl,[ebx+DDEV_GranBits] ; CL <- sector size (bits)
		sub	cl,2		; CL <- sector size in DWORDs
		shl	ebp,cl		; EBP <- data transfer size / 4
		pop	ecx		; pop ECX

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

FDComp:		push	ecx		; push ECX
		push	esi		; push ESI
		push	edi		; push EDI
		push	ebp		; push EBP

; ------------- Prepare parameters

		call	FDRWPrep	; prepare parameters
		jc	short FDRead8	; error

; ------------- Read sectors (with 2 attempts)

		call	FDReadSect	; read sectors
		jnc	short FDComp6	; data read OK
		call	FDReset		; reset controller and drive
		jc	short FDRead8	; error
		call	FDReadSect	; read sectors
		jc	short FDRead8	; error

; ------------- Compare data

FDComp6:	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 FDRead9	; data OK
		jmp	short FDRead8	; 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)

FDRead:		push	ecx		; push ECX
		push	esi		; push ESI
		push	edi		; push EDI
		push	ebp		; push EBP

; ------------- Prepare parameters

		call	FDRWPrep	; prepare parameters
		jc	short FDRead8	; error

; ------------- Read sectors (with 3 attempts)

		call	FDReadSect	; read sectors
		jnc	short FDRead6	; data read OK
		call	FDReset		; reset controller and drive
		jc	short FDRead8	; error
		call	FDReadSect	; read sectors
		jnc	short FDRead6	; data read OK
		call	FDReset		; reset controller and drive
		jc	short FDRead8	; error
		call	FDReadSect	; read sectors
		jc	short FDRead8	; error

; ------------- Copy read data (here is NC)

FDRead6:	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 FDRead9

; ------------- Error

FDRead8:	xor	eax,eax		; EAX <- no sectors OK read
		stc			; set error flag

; ------------- Pop registers

FDRead9:	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)

FDWrite:	push	ecx		; push ECX
		push	esi		; push ESI
		push	edi		; push EDI
		push	ebp		; push EBP

; ------------- Prepare parameters

		call	FDRWPrep	; prepare parameters
		jc	short FDRead8	; error

; ------------- Copy data to write

		push	ecx		; push ECX
		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	ecx		; pop ECX

; ------------- Write sectors without verify (with 3 attempts)

		test	byte [ebx+DDEV_Flags],DDEV_WRITEVER; write with verify?
		jnz	FDWrite4	; write with verify

		call	FDWriteSectRep	; write sectors with repeat on error
		jc	short FDRead8	; error
FDWrite2:	xchg	eax,ecx		; EAX <- number of sectors
		jmp	short FDRead9	; OK

; ------------- Write sectors with verify

FDWrite4:	test	byte [ebx+DDEV_Flags],DDEV_USECOMP ; use compare?
		jnz	FDWrite8	; use compare

		call	FDWriteSectRep	; write sectors with repeat on error
		jc	short FDRead8	; error

		call	FDVerifySect	; verify sectors
		jnc	short FDWrite2	; ok

		call	FDReset		; reset controller and drive
		jc	short FDRead8	; error
		call	FDWriteSect	; write sectors
		jc	short FDRead8	; error

		call	FDVerifySect	; verify sectors
		jnc	short FDWrite2	; ok
FDWrite6:	jmp	short FDRead8	; error

; ------------- Write sectors with compare

FDWrite8:	call	FDWriteSectRep	; write sectors with repeat on error
		jc	short FDRead8	; error

		call	FDCompareSect	; compare sectors
		jnc	short FDWrite2	; ok

		call	FDReset		; reset controller and drive
		jc	short FDRead8	; error
		call	FDWriteSect	; write sectors
		jc	short FDRead8	; error

		call	FDCompareSect	; compare sectors
		jnc	short FDWrite2	; ok
		jmp	short FDWrite6	; 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

FDVerify:	push	ecx		; push ECX
		push	ebp		; push EBP

; ------------- Prepare parameters

		call	FDRWPrep	; prepare parameters
		jc	FDVerify8	; error

; ------------- Verify sectors (with 2 attempts)

		call	FDVerifySect	; verify sectors
		jnc	FDVerify6	; data verified OK
		call	FDReset		; reset controller and drive
		jc	FDVerify8	; error
		call	FDVerifySect	; verify sectors
		jc	FDVerify8	; error
FDVerify6:	xchg	eax,ecx		; EAX <- number of sectors
		jmp	short FDVerify9

; ------------- Error

FDVerify8:	xor	eax,eax		; EAX <- no sectors OK read
		stc			; set error flag

; ------------- Pop registers

FDVerify9:	pop	ebp		; pop EBP
		pop	ecx		; pop ECX
		ret

; -----------------------------------------------------------------------------
;                      Recalculate media parameters
; -----------------------------------------------------------------------------
; INPUT:	EBX = floppy disk device parameter block FLOPPY
; -----------------------------------------------------------------------------

; ------------- Push registers

FDCalcMedia:	push	eax		; push EAX
		push	ecx		; push ECX
		push	edx		; push EDX

; ------------- Sector granularity bits

		mov	cl,[ebx+FLOPPY_SectSize] ; CL <- sector size
		add	cl,7		; correct sector size
		mov	[ebx+DDEV_GranBits],cl ; granularity bits

; ------------- Sector size

		xor	eax,eax		; EAX <- 0
		inc	eax		; EAX <- 1
		shl	eax,cl		; EAX <- sector size
		mov	[ebx+DDEV_GranSize],eax ; set granularity size

; ------------- Sector inverse mask

		dec	eax		; EAX <- sector size - 1
		not	eax		; EAX <- sector inverse mask
		mov	[ebx+DDEV_GranMask],eax ; set granularity inverse mask

; ------------- Calculate disk media parameters

		call	DiskCalcMedia	; calculate disk media parameters	

; ------------- Pop registers

		pop	edx		; pop EDX
		pop	ecx		; pop ECX
		pop	eax		; pop EAX
		ret

; -----------------------------------------------------------------------------
;                          Set table media type
; -----------------------------------------------------------------------------
; INPUT:	EBX = floppy disk device parameter block FLOPPY
;		EDX = media descriptor FDMEDIA
; NOTES:	Media type must be valid.
; -----------------------------------------------------------------------------

; ------------- Push registers

FDSetTabMedia:	push	eax		; push EAX

; ------------- Number of heads

		xor	eax,eax		; EAX <- 0
		inc	eax		; EAX <- 1 head
		test	byte [edx+FDMED_Flags],FDMED_HEADS ; 2 heads?
		jz	FDSetTabMedia2	; no, only 1 head
		inc	eax		; EAX <- 2 heads
FDSetTabMedia2:	mov	[ebx+DISK_Heads],eax ; set number of heads

; ------------- Double-steps

		and	byte [ebx+FLOPPY_Flags],~FLOPPY_DOUBLE ; clear flag
		mov	al,[edx+FDMED_Flags] ; AL <- flags
		test	al,FDMED_DBL	; use double-steps?
		jz	FDSetTabMedia4	; don't use double-steps
		or	byte [ebx+FLOPPY_Flags],FLOPPY_DOUBLE ; set flag

; ------------- Data rate

FDSetTabMedia4:	and	al,FDMED_RATEMASK ; mask data rate
		mov	[ebx+FLOPPY_Rate],al ; set data rate

; ------------- Sector size

		mov	al,[edx+FDMED_SectSize] ; AL <- sector size (0=128 B)
		mov	[ebx+FLOPPY_SectSize],al ; set sector size

; ------------- Number of cylinders

		movzx	eax,byte [edx+FDMED_Tracks]; EAX <- number of cylinders
		mov	[ebx+DISK_Tracks],eax ; set number of tracks

; ------------- Number of sectors per track

		movzx	eax,byte [edx+FDMED_TrackSect] ; EAX<-sectors per track
		mov	[ebx+DISK_TrackSect],eax ; set sectors per track

; ------------- Interleaving

		mov	al,[edx+FDMED_Inter] ; AL <- interleaving
		mov	[ebx+FLOPPY_Inter],al ; set interleaving

; ------------- Formatting inter-sector gap

		mov	al,[edx+FDMED_FormGap] ; AL <- formatting gap
		mov	[ebx+FLOPPY_FormGap],al ; set formatting gap

; ------------- Head sliding

		mov	al,[edx+FDMED_HeadSlid] ; AL <- head sliding
		mov	[ebx+FLOPPY_HeadSlid],al ; set head sliding

; ------------- Track sliding

		mov	al,[edx+FDMED_TrackSlid] ; AL <- track sliding
		mov	[ebx+FLOPPY_TrckSlid],al ; set track sliding

; ------------- Recalculate media parameters

		call	FDCalcMedia	; recalculate media parameters

; ------------- Pop registers

		pop	eax		; pop EAX
		ret

; -----------------------------------------------------------------------------
;                      Check if media type is supported
; -----------------------------------------------------------------------------
; INPUT:	EBX = floppy disk device parameter block FLOPPY
;		EDX = media descriptor FDMEDIA
; OUTPUT:	CY = media type is not supported
; -----------------------------------------------------------------------------

; ------------- Push registers

FDCheckMedia:	push	eax		; push EAX
		push	esi		; push ESI
		mov	esi,[ebx+FLOPPY_Drive] ; ESI <- drive

; ------------- Check sector size

		cmp	byte [edx+FDMED_SectSize],FDSIZE_MAX; check sector size
		ja	FDCheckMedia8	; invalid sector size

; ------------- Check number of sectors per track

		movzx	eax,byte [edx+FDMED_Flags] ; EAX <- flags
		and	al,FDMED_RATEMASK ; EAX <- data rate
		mov	al,[esi+FDRIVE_MaxSect+eax] ; AL <- maximum sectors
		mov	ah,[edx+FDMED_TrackSect] ; AH <- sectors per track
		cmp	ah,al		; check sectors per track
		ja	FDCheckMedia8	; invalid number of sectors per track
		or	ah,ah		; minimal number of sectors per track
		jz	FDCheckMedia8	; invalid number of sectors per track

; ------------- Check number of tracks and double-steps flag

		mov	al,FD_MAX80TRK	; AL <- maximum tracks for 80 trk drive
		test	byte [esi+FDRIVE_Flags],FDRIVE_80TRACK ; 80 tracks?
		jnz	FDCheckMedia2	; yes, 80 tracks
		mov	al,FD_MAX40TRK	; AL <- maximum tracks for 40 trk drive
FDCheckMedia2:	mov	ah,[edx+FDMED_Tracks] ; AH <- number of tracks
		or	ah,ah		; minimal number of tracks
		jz	FDCheckMedia8	; invalid number of tracks
		test	byte [edx+FDMED_Flags],FDMED_DBL ; double-steps?
		jz	FDCheckMedia4	; not double-steps
		shl	ah,1		; AH <- double-steps
		jc	FDCheckMedia9	; overflow
FDCheckMedia4:	cmp	ah,al		; check number of tracks
		ja	FDCheckMedia8	; invalid number of tracks

; ------------- Check interleaving

		cmp	byte [edx+FDMED_Inter],0 ; is interleaving valid?
		je	FDCheckMedia8	; invalid interleaving

; ------------- Check formatin inter-sector gap

		cmp	byte [edx+FDMED_FormGap],0 ; is formating gap valid?
		jne	FDCheckMedia9	; formating gap is OK

; ------------- Pop registers

FDCheckMedia8:	stc			; set error flag
FDCheckMedia9:	pop	esi		; pop ESI
		pop	eax		; pop EAX
		ret

; -----------------------------------------------------------------------------
;                            Compare media type
; -----------------------------------------------------------------------------
; INPUT:	EAX = media validity flags (see FDMEDIA)
;		EBX = floppy disk device parameter block FLOPPY
;		EDX = compared media descriptor FDMEDIA
;		ESI = table media descriptor FDMEDIA
; OUTPUT:	ZY = table media descriptor corresponds
; -----------------------------------------------------------------------------

; ------------- Push registers

FDCompMedia:	push	ecx		; push ECX
		push	esi		; push ESI

; ------------- Compare sector size

		test	al,FDMED_SIZE_OK ; is sector size valid?
		jz	FDCompMedia1	; sector size is not valid
		mov	cl,[edx+FDMED_SectSize] ; CL <- tested sector size
		cmp	cl,[esi+FDMED_SectSize] ; compare sector size
		jne	short FDCompMedia10 ; media is different

; ------------- Compare number of sectors per track

FDCompMedia1:	test	al,FDMED_SECT_OK; is number of sectors per track valid?
		jz	FDCompMedia2	; it is not valid
		mov	cl,[edx+FDMED_TrackSect] ; CL <- sectors per track
		cmp	cl,[esi+FDMED_TrackSect] ; compare sectors per track
		jne	short FDCompMedia10 ; media is different

; ------------- Compare number of tracks

FDCompMedia2:	test	al,FDMED_TRK_OK	; is number of tracks valid?
		jz	FDCompMedia3	; number of tracks is not valid
		mov	cl,[edx+FDMED_Tracks] ; CL <- number of tracks
		cmp	cl,[esi+FDMED_Tracks] ; compare number of tracks
		jne	short FDCompMedia10 ; media is different

; ------------- Prepare flags difference (-> CL)

FDCompMedia3:	mov	cl,[edx+FDMED_Flags] ; CL <- flags
		xor	cl,[esi+FDMED_Flags] ; compare flags

; ------------- Compare number of heads

		test	al,FDMED_HEAD_OK ; is number of heads valid?
		jz	FDCompMedia4	; number of heads is not valid
		test	cl,FDMED_HEADS	; check number of heads
		jnz	short FDCompMedia10 ; media is different

; ------------- Compare data rate

FDCompMedia4:	test	al,FDMED_RATE_OK ; is data rate valid?
		jz	FDCompMedia5	; data rate is not valid
		test	cl,FDMED_RATEMASK ; check data rate
		jnz	short FDCompMedia10 ; media is different

; ------------- Compare double-step flag

FDCompMedia5:	test	al,FDMED_DBL_OK	; is double-steps valid?
		jz	FDCompMedia6	; double-steps is not valid
		test	cl,FDMED_DBL	; check double-steps
		jnz	short FDCompMedia10 ; media is different

; ------------- Compare interleaving

FDCompMedia6:	test	al,FDMED_INT_OK ; is interleaving valid?
		jz	FDCompMedia7	; interleaving is not valid
		mov	cl,[edx+FDMED_Inter] ; CL <- interleaving
		cmp	cl,[esi+FDMED_Inter] ; compare interleaving
		jne	short FDCompMedia10 ; media is different

; ------------- Compare inter-sector gap

FDCompMedia7:	test	al,FDMED_GAP_OK ; is inter-sector gap valid?
		jz	FDCompMedia8	; inter-sector gap is not valid
		mov	cl,[edx+FDMED_FormGap] ; CL <- inter-sector gap
		cmp	cl,[esi+FDMED_FormGap] ; compare inter-sector gap
		jne	short FDCompMedia10 ; media is different

; ------------- Compare head sliding

FDCompMedia8:	test	ah,FDMED_HSLID_OK>>8 ; is head sliding valid?
		jz	FDCompMedia9	; head sliding is not valid
		mov	cl,[edx+FDMED_HeadSlid] ; CL <- head sliding
		cmp	cl,[esi+FDMED_HeadSlid] ; compare head sliding
		jne	short FDCompMedia10 ; media is different

; ------------- Compare track sliding

FDCompMedia9:	test	ah,FDMED_TSLID_OK>>8 ; is track sliding valid?
		jz	FDCompMedia10	; track sliding is not valid
		mov	cl,[edx+FDMED_TrackSlid] ; CL <- track sliding
		cmp	cl,[esi+FDMED_TrackSlid] ; compare track sliding

; ------------- Pop registers (here is ZY = OK)

FDCompMedia10:	pop	esi		; pop ESI
		pop	ecx		; pop ECX
		ret

; -----------------------------------------------------------------------------
;                             Set media type
; -----------------------------------------------------------------------------
; INPUT:	EAX = media validity flags (see FDMEDIA)
;		EBX = floppy disk device parameter block FLOPPY
;		EDX = media descriptor FDMEDIA
; OUTPUT:	CY = media type is not supported
; -----------------------------------------------------------------------------

; ------------- Push registers

FDSetMedia:	push	ecx		; push ECX
		push	esi		; push ESI
		push	edi		; push EDI

; ------------- Search standard media

		mov	edi,[ebx+FLOPPY_Drive] ; EDI <- drive FDRIVE
		xor	ecx,ecx		; ECX <- media index
FDSetMedia1:	movzx	esi,byte [edi+ecx+FDRIVE_MediaStd] ; ESI <- media index
		shl	esi,FDMEDIA_SIZEBIT ; ESI <- offset of media
		add	esi,[edi+FDRIVE_Media] ; ESI <- address of media
		call	FDCompMedia	; compare media
		jz	FDSetMedia3	; media is OK
		inc	ecx		; increase media index
		cmp	cl,[edi+FDRIVE_MediaStN] ; check media index
		jb	FDSetMedia1	; check next media

; ------------- Search all available media

		movzx	ecx,byte [edi+FDRIVE_MediaNum] ; ECX <- number of media
		mov	esi,[edi+FDRIVE_Media] ; ESI <- media list
		lea	esi,[esi+ecx*FDMEDIA_size-FDMEDIA_size] ; last entry
FDSetMedia2:	call	FDCompMedia	; compare media
		jz	FDSetMedia3	; media is OK
		sub	esi,FDMEDIA_size ; ESI <- next media
		loop	FDSetMedia2	; next media

; ------------- Prepare default media (-> ESI)

		movzx	esi,byte [edi+FDRIVE_MediaStd] ; ESI <- media index
		shl	esi,FDMEDIA_SIZEBIT ; ESI <- offset of media
		add	esi,[edi+FDRIVE_Media] ; ESI <- address of media

; ------------- Set sector size

FDSetMedia3:	test	al,FDMED_SIZE_OK ; is sector size valid?
		jnz	FDSetMedia4	; sector size is valid
		mov	byte [edx+FDMED_SectSize],FDSIZE_512 ; set sector size

; ------------- Set number of sectors per track

FDSetMedia4:	test	al,FDMED_SECT_OK; is number of sectors per track valid?
		jnz	FDSetMedia5	; it is valid
		mov	cl,[esi+FDMED_TrackSect] ; CL <- sectors per track
		mov	[edx+FDMED_TrackSect],cl ; set sectors per track

; ------------- Set number of tracks

FDSetMedia5:	test	al,FDMED_TRK_OK	; is number of tracks valid?
		jnz	FDSetMedia6	; number of tracks is valid

		mov	cl,40		; CL <- 40 tracks
		test	byte [edi+FDRIVE_Flags],FDRIVE_80TRACK ; 80 tracks?
		jz	FDSetMedia54	; no, always 40 tracks
		test	byte [edi+FDRIVE_Flags],FDRIVE_5 ; 5.25" drive?
		jz	FDSetMedia52	; no, always 80 tracks
		cmp	byte [edx+FDMED_TrackSect],10 ; check sectors
		jbe	FDSetMedia54	; it is DD format
FDSetMedia52:	mov	cl,80		; CL <- 80 tracks
FDSetMedia54:	mov	[edx+FDMED_Tracks],cl ; set number of tracks

; ------------- Set number of heads

FDSetMedia6:	mov	cl,[edx+FDMED_Flags] ; CL <- destination flags
		test	al,FDMED_HEAD_OK ; is number of heads valid?
		jnz	FDSetMedia7	; number of heads is valid
		and	cl,~FDMED_HEADS ; set 1 head
		test	byte [edi+FDRIVE_Flags],FDRIVE_2HEADS ; 2 heads?
		jz	FDSetMedia7	; only 1 head
		or	cl,FDMED_HEADS	; set 2 heads

; ------------- Set double-step flag

FDSetMedia7:	test	al,FDMED_DBL_OK	; is double-steps valid?
		jnz	FDSetMedia8	; double-steps is valid

		and	cl,~FDMED_DBL	; clear double-steps flag
		test	byte [edi+FDRIVE_Flags],FDRIVE_80TRACK ; 80 tracks?
		jz	FDSetMedia8	; only 40 tracks, no double-steps
		cmp	byte [edx+FDMED_Tracks],40 ; 40 tracks or less?
		ja	FDSetMedia8	; more than 40 tracks
		or	cl,FDMED_DBL	; set double-steps flag

; ------------- Set data rate

FDSetMedia8:    test	al,FDMED_RATE_OK ; is data rate valid?
		jnz	FDSetMedia9	; data rate is valid

		mov	ch,[edx+FDMED_TrackSect] ; CH <- sectors per track
		and	cl,~FDMED_RATEMASK ; set data rate to 250 kb/s
		cmp	ch,[edi+FDRIVE_RateSect+0] ; check sectors for 250 kb/s
		jbe	FDSetMedia9	; sectors are OK
		inc	ecx		; CL <- 300 kb/s
		cmp	ch,[edi+FDRIVE_RateSect+1] ; check sectors for 300 kb/s
		jbe	FDSetMedia9	; sectors are OK
		inc	ecx		; CL <- 500 kb/s
		cmp	ch,[edi+FDRIVE_RateSect+2] ; check sectors for 500 kb/s
		jbe	FDSetMedia9	; sectors are OK
		inc	ecx		; CL <- 1000 kb/s

FDSetMedia9:	mov	[edx+FDMED_Flags],cl ; set new flags

; ------------- Set inter-sector gap
; gap = (track_capacity/sectors_per_track - sector_size - 63)*3/4

		test	al,FDMED_GAP_OK ; is inter-sector gap valid?
		jnz	FDSetMedia10	; inter-sector gap is valid
		movzx	ecx,byte [edx+FDMED_TrackSect] ; ECX<-sectors per track
		jecxz	FDSetMedia10	; invalid number of sectors per track

		push	eax		; push EAX
		push	edx		; push EDX

		movzx	eax,byte [edx+FDMED_Flags] ; EAX <- flags
		and	al,FDMED_RATEMASK ; EAX <- data rate
		shl	eax,2		; EAX <- data rate * 4
		add	eax,[edi+FDRIVE_Capacity] ; EAX <- pointer
		mov	eax,[eax]	; EAX <- track capacity
		xor	edx,edx		; EDX <- 0
		div	ecx		; EAX<-track_capacity/sectors_per_track

		pop	edx		; pop EDX
		push	edx		; push EDX
		mov	cl,[edx+FDMED_SectSize] ; ECX <- sector size (0=128 B)
		xor	edx,edx		; EDX <- 0
		mov	dl,128		; EDX <- size 128 B
		shl	edx,cl		; EDX <- sector size

		sub	eax,edx		; subtract sectors size
		sub	eax,byte 63	; subtract sector head
		mov	edx,eax		; EDX <- store gap
		shl	eax,1		; EAX <- gap * 2
		add	eax,edx		; EAX <- gap * 3
		shr	eax,2		; EAX <- gap * 3 / 4

		jnz	FDSetMedia92	; gap is not 0
		inc	eax		; EAX <- 1, minimal gap
FDSetMedia92:	cmp	eax,255		; maximal gap
		jb	FDSetMedia94	; gap is OK
		mov	al,255		; AL <- limit gap

FDSetMedia94:	pop	edx		; pop EDX
		mov	[edx+FDMED_FormGap],al ; set inter-sector gap
		pop	eax		; pop EAX

; ------------- Set interleaving

FDSetMedia10:	test	al,FDMED_INT_OK ; is interleaving valid?
		jnz	FDSetMedia11	; interleaving is valid

		mov	cl,1		; CL <- 1, normal interleaving
		cmp	byte [edx+FDMED_FormGap],26 ; check gap
		jae	FDSetMedia102	; gap is big enough
		inc	ecx		; CL <- 2, use interleaving
FDSetMedia102:	mov	[edx+FDMED_Inter],cl ; set interleaving

; ------------- Set head sliding

FDSetMedia11:	test	ah,FDMED_HSLID_OK>>8 ; is head sliding valid?
		jnz	FDSetMedia12	; head sliding is valid

		movzx	ecx,byte [edx+FDMED_Flags] ; ECX <- flags
		and	cl,FDMED_RATEMASK ; ECX <- data rate
		mov	cl,[FDHeadSlidTab+ecx] ; CL <- head sliding
		mov	[edx+FDMED_HeadSlid],cl ; set head sliding

; ------------- Set track sliding

FDSetMedia12:	test	ah,FDMED_TSLID_OK>>8 ; is track sliding valid?
		jnz	FDSetMedia13	; track sliding is valid

		movzx	ecx,byte [edx+FDMED_Flags] ; ECX <- flags
		and	cl,FDMED_RATEMASK ; ECX <- data rate
		mov	cl,[FDTrackSlidTab+ecx] ; CL <- track sliding
		mov	[edx+FDMED_TrackSlid],cl ; set track sliding

; ------------- Check media

FDSetMedia13:	call	FDCheckMedia	; check media
		jc	FDSetMedia20	; error, media not supported

; ------------- Set media

		call	FDSetTabMedia	; set table media type
		clc			; clear error flag

; ------------- Pop registers

FDSetMedia20:	pop	edi		; pop EDI
		pop	esi		; pop ESI
		pop	ecx		; pop ECX
		ret

; -----------------------------------------------------------------------------
;                          Set media geometry
; -----------------------------------------------------------------------------
; INPUT:	AL = sector size (0=128,...7=16K, -1=default)
;		AH = number of sectors per track (1..42, 0=default)
;		EBX = floppy disk device parameter block FLOPPY
;		CL = number of heads (1 or 2, 0=default)
;		CH = number of tracks (1..80, 0=default)
;		DL = data transfer rate (0..3, -1=default)
; OUTPUT:	CY = media type is not supported
; -----------------------------------------------------------------------------

; ------------- Push registers

FDSetGeometry:	push	eax		; push EAX
		push	edx		; push EDX
		push	esi		; push ESI
		push	ebp		; push EBP
		mov	ebp,esp		; push ESP

; ------------- Prepare media descriptor (-> ESI)

		sub	esp,FDMEDIA_size ; reserve for media descriptor
		mov	esi,esp		; ESI <- media descriptor

; ------------- Store entries into media descriptor

		mov	[esi+FDMED_SectSize],al ; sector size
		mov	[esi+FDMED_TrackSect],ah ; sectors per track
		mov	[esi+FDMED_Tracks],ch ; number of tracks

; ------------- Sector size validity flag

		or	al,al		; default sector size?
		setns	al		; AL <- B0, sector size is valid

; ------------- Number of sectors per track validity flag

		or	ah,ah		; check sectors per track
		jle	FDSetGeometry2	; default sectors per track
		or	al,FDMED_SECT_OK ; number of sectors per track is valid
FDSetGeometry2:	movzx	eax,al		; EAX <- validity flags

; ------------- Data transfer rate validity flag

		or	dl,dl		; check data transfer rate
		jl	FDSetGeometry4	; default data transfer rate
		or	al,FDMED_RATE_OK ; data transfer rate is valid
FDSetGeometry4:	and	dl,FDMED_RATEMASK ; mask data transfer rate

; ------------- Number of heads validity flag

		cmp	cl,1		; check number of heads
		jl	FDSetGeometry6	; default number of heads
		je	FDSetGeometry5	; 1 head
		or	dl,FDMED_HEADS	; 2 heads
FDSetGeometry5:	or	al,FDMED_HEAD_OK ; number of heads is valid
FDSetGeometry6:	mov	[esi+FDMED_Flags],dl ; store flags

; ------------- Number of tracks

		or	ch,ch		; check number of tracks
		jle	FDSetGeometry7	; default number of tracks
		or	al,FDMED_TRK_OK	; number of tracks is valid

; ------------- Set media type

FDSetGeometry7:	mov	edx,esi		; EDX <- media descriptor
		call	FDSetMedia	; set media type

; ------------- Pop registers

		mov	esp,ebp		; pop ESP
		pop	ebp		; pop EBP
		pop	esi		; pop ESI
		pop	edx		; pop EDX
		pop	eax		; pop EAX
		ret

; -----------------------------------------------------------------------------
;                  Read sector ID (current track, current head)
; -----------------------------------------------------------------------------
; INPUT:	EBX = floppy disk device parameter block FLOPPY
; OUTPUT:	CY = error
; NOTES:	Function reads one sector ID into result buffer.
;		Motor must be turned on and head must be on right track.
; -----------------------------------------------------------------------------

; ------------- Push registers

FDReadID:	push	eax		; push EAX

; ------------- Set data transfer rate

		call	FDSetRate	; set data transfer rate

; ------------- Clear interrupt flag

		call	FDClearInt	; clear interrupt flag

; ------------- Send command to controller

		mov	al,FD_READ_ID	; AL <- command
		call	FDSendData	; send command to controller
		jc	FDReadID9	; error

; ------------- Select head and drive

		mov	al,[ebx+FLOPPY_Head] ; AL <- current head number
		shl	al,2		; rotate head to position
		or	al,[ebx+FLOPPY_Device] ; add device index
		call	FDSendData	; send data to controller
		jc	FDReadID9	; error

; ------------- Wait of interrupt

		call	FDWaitInt	; wait for interrupt
		jc	FDReadID9	; time-out error

; ------------- Receive result

		call	FDGetResult	; get result

; ------------- Pop registers

FDReadID9:	pop	eax		; pop EAX
		ret

; -----------------------------------------------------------------------------
;                        Detect media geometry
; -----------------------------------------------------------------------------
; INPUT:	EBX = floppy disk device parameter block FLOPPY
; OUTPUT:	CY = error
; -----------------------------------------------------------------------------

; ------------- Push registers

FDDetect:	push	eax		; push EAX

; ------------- Start motor ON

		call	FDMotorOn	; start motor ON

; ------------- Reset controller and drive, seek to track 0

		mov	byte [ebx+FLOPPY_Track],0 ; seek to zero track
		call	FDReset		; reset controller and drive
		jc	FDDetect9	; error

; ------------- Read ID of one (random) sector

		call	FDReadID	; read ID of one sector
		jc	FDDetect2	; error, use default sector size



FDDetect2:	mov	al,FDSIZE_512	; AL <- default sector size

FDDetect3:






; ------------- Motor OFF (it saves flags)

FDDetect9:	call	FDMotorOff	; motor OFF










		mov	byte [ebx+FLOPPY_Track],15h
		mov	byte [ebx+FLOPPY_Head],0
		mov	byte [ebx+FLOPPY_Rate],FDRATE_500K
		mov	byte [ebx+FLOPPY_SectSize],FDSIZE_512
		mov	byte [ebx+FLOPPY_TrckSect],30

		call	FDSeek


;		mov	edx,10

;FDInit841:	call	FDReadID	; read sector ID

		mov	al,FDSIZE_512

;		jc	FDInit9

;		lea	esi,[ebx+FLOPPY_Reply]
;		mov	ecx,7
;FDInit842:	lodsb
;		call	DebOutHexB
;		mov	al," "
;		call	DebOutChar
;		call	DebOutChar
;		loop	FDInit842
;		call	DebNewLine
;
;		dec	edx
;		jnz	FDInit841


;FDInit844:




		mov	al,1		; start sector
		mov	cl,30		; number of sectors
		call	FDReadSect
;		jc	FDInit9






; -----------------------------------------------------------------------------
;                             Format track
; -----------------------------------------------------------------------------
; INPUT:	AL = number of sectors
;		AH = head (0..1)
;		EBX = floppy disk device parameter block FLOPPY
;		EDX = track layout (array of FTRACK entries, DMA aligned)
;		CL = sector size (0=128,...)
;
; OUTPUT:	CY = error
; NOTES:	Current track and current head will be used.
; -----------------------------------------------------------------------------

FDFormCust:	



; ------------- Start DMA transfer

		push	eax		; push EAX
		push	ebx		; push EBX

		movzx	ecx,al		; ECX <- number of sectors
		shl	ecx,2		; ECX <- size of track layout
		mov	esi,[ebx+FLOPPY_FDC] ; ESI <- controller descriptor
		mov	al,[esi+FDC_DMA] ; AL <- DMA channel number
		mov	bl,1		; "write" DMA mode
		call	DMAStart	; start DMA transfer

		pop	ebx		; pop EBX
		pop	ecx		; pop ECX, number of sectors

; ------------- Send format command

		mov	al,FD_FORMAT	; AL <- format command
		call	FDSendData	; send command
		jc	FDFormCust8	; error

; ------------- Select drive and head

		mov	al,ah		; AL <- head
		shl	al,2		; rotate to position
		or	al,[ebx+FLOPPY_Device] ; add drive index
		call	FDSendData	; send drive and head
		jc	FDFormCust8	; error

; ------------- Set sector size

		xchg	eax,ecx		; AL <- sector size
		call	FDSendData	; send drive and head
		jc	FDFormCust8	; error
	
; ------------- Set number of sectors

;		mov	al,



; ------------- Pop registers

FDFormCust8:	
		ret

; -----------------------------------------------------------------------------
;                         Try to lock floppy controller
; -----------------------------------------------------------------------------
; INPUT:	EBX = floppy disk device parameter block FLOPPY
; OUTPUT:	NC = floppy controller successfully locked (CY = not locked)
; -----------------------------------------------------------------------------

; ------------- Push registers

FDTryLock:	push	edx

; ------------- Try to lock floppy controller

		mov	edx,[ebx+FLOPPY_FDC] ; EDX <- controller descriptor
%ifdef	SMP
		lock			; CPU instruction lock
%endif
		bts	dword [edx+FDC_Flags],FDC_LOCK_BIT ; try to lock
		jc	FDTryLock8	; controller already locked

; ------------- Set owning task

		push	eax		; push EAX
		CURRENT	eax		; EAX <- current task
		mov	[edx+FDC_Task],eax ; set owning task
		pop	eax		; pop EAX

; ------------- Pop registers

FDTryLock8:	pop	edx
FDLock9:	ret	

; -----------------------------------------------------------------------------
;                          Lock floppy controller
; -----------------------------------------------------------------------------
; INPUT:	EBX = floppy disk device parameter block FLOPPY
; -----------------------------------------------------------------------------

; ------------- Try to lock floppy controller

FDLock:		call	FDTryLock	; try to lock floppy controller
		jnc	FDLock9		; controller successfully locked

; ------------- Sleep for a while

		push	eax		; push EAX
		mov	al,20		; AL <- sleep time (20 ms)
		call	SleepShort	; wait for a while
		pop	eax		; pop EAX
		jmp	short FDLock	; next try to lock

; -----------------------------------------------------------------------------
;                           Unlock floppy controller
; -----------------------------------------------------------------------------
; INPUT:	EBX = floppy disk device parameter block FLOPPY
; -----------------------------------------------------------------------------

FDUnlock:	push	edx		; push EDX
		mov	edx,[ebx+FLOPPY_FDC] ; EDX <- controller descriptor
		and	dword [edx+FDC_Task],byte 0 ; no owning task
		and	byte [edx+FDC_Flags],~FDC_LOCK ; unlock
		pop	edx		; pop EDX
		ret

; -----------------------------------------------------------------------------
;                          Check controller
; -----------------------------------------------------------------------------
; INPUT:	EBX = first floppy disk device parameter block FLOPPY
;		EDX = second floppy disk device parameter block FLOPPY
; OUTPUT:	CY = error
; -----------------------------------------------------------------------------

; ------------- Push registers

FDCCheck:	push	eax		; push EAX

		mov	al,10
		call	SleepShort

		call	FDMotorOn

; ------------- Reset controller

		call	FDReset		; reset controller
		jc	FDCCheck9


;		mov	al,5
;		call	FDSeekAt
;		jc	FDCCheck9






; ------------- Send command to dump registers

;		mov	al,FD_DUMPREG	; command to dump registers
;		call	FDSendData	; send command
;		jc	FDCCheck9	; error

; ------------- Get result (CY = invalid controller)

;		call	FDGetResult	; get result
;		jc	FDCCheck9	; error
;		cmp	byte [ebx+FLOPPY_ReplyNum],1 ; check number of results


		clc

; ------------- Pop registers

FDCCheck9:	pop	eax		; pop EAX
		ret

; -----------------------------------------------------------------------------
;                      Initialize floppy disk driver
; -----------------------------------------------------------------------------

; ------------- Lock controller

FDInit:		mov	ebx,FD0DrvDPB	; floppy disk drive 0
		call	FDLock		; lock controller

; ------------- Check first controller

		mov	ebx,FD0DrvDPB	; floppy disk drive 0
		mov	edx,FD1DrvDPB	; floppy disk drive 1
		call	FDCCheck	; check first controller
		jc	FDInit9		; error





                mov	ebx,FDCDrvDPB	; EBX <- driver parameter block

; ------------- Allocate first DMA buffer

		mov	eax,FDBUFFSIZE	; EAX <- DMA buffer size
		call	DMAMemAlloc	; allocate DMA memory block
		jc	FDInit9		; error? Cannot be at this time
		mov	[ebx+FDC_Buffer],edx ; store data buffer
		mov	[FD0DrvDPB+FLOPPY_Buffer],edx ; copy address for FD0
		mov	[FD1DrvDPB+FLOPPY_Buffer],edx ; copy address for FD1
		mov	[FD2DrvDPB+FLOPPY_Buffer],edx ; copy address for FD2
		mov	[FD3DrvDPB+FLOPPY_Buffer],edx ; copy address for FD3

; ------------- Allocate second DMA buffer

		mov	eax,FDBUFFSIZE	; EAX <- DMA buffer size
		call	DMAMemAlloc	; allocate DMA memory block
		jc	FDInit9		; error? Cannot be at this time
		mov	[ebx+FDC_Buffer2],edx ; store data buffer
		mov	[FD0DrvDPB+FLOPPY_Buffer2],edx ; copy address for FD0
		mov	[FD1DrvDPB+FLOPPY_Buffer2],edx ; copy address for FD1
		mov	[FD2DrvDPB+FLOPPY_Buffer2],edx ; copy address for FD2
		mov	[FD3DrvDPB+FLOPPY_Buffer2],edx ; copy address for FD3

; ------------- Install DMA channel

		mov	al,[ebx+FDC_DMA] ; AL <- DMA channel
		call	DMAAlloc	; install DMA channel
		jc	FDInit9		; error

; ------------- Install floppy disk driver

		call	DrvLstInsert	; insert driver into list

; ------------- Install floppy disk drives

		lea	ecx,[ebx+FDC_DevList] ; ECX <- first drive
		mov	edx,ecx		; EDX <- first drive
FDInit8:	mov	edx,[edx+LIST_Next] ; EDX <- next drive
		cmp	edx,ecx		; next drive?
		je	FDInit82	; no next drive
		lea	ebx,[edx-FLOPPY_DevList] ; EBX <- floppy drive
		call	DrvLstInsert	; insert drive into list
		jmp	short FDInit8	; next drive

FDInit82:


		mov	ebx,FD0DrvDPB	; floppy disk drive 0


		mov	edi,[ebx+FLOPPY_Buffer]
		mov	al,5ah
		mov	ecx,32768
		rep	stosb


		mov	byte [ebx+FLOPPY_Track],15h
		mov	byte [ebx+FLOPPY_Head],0
		mov	byte [ebx+FLOPPY_Rate],FDRATE_250K
		mov	byte [ebx+FLOPPY_SectSize],FDSIZE_512
		mov	byte [ebx+FLOPPY_TrckSect],30

		call	FDSeek

;		mov	edx,10

;FDInit841:	call	FDReadID	; read sector ID

		mov	al,FDSIZE_512

;		jc	FDInit9

;		lea	esi,[ebx+FLOPPY_Reply]
;		mov	ecx,7
;FDInit842:	lodsb
;		call	DebOutHexB
;		mov	al," "
;		call	DebOutChar
;		call	DebOutChar
;		loop	FDInit842
;		call	DebNewLine
;
;		dec	edx
;		jnz	FDInit841


FDInit844:




		mov	al,1		; start sector
		mov	cl,20		; number of sectors
		call	FDReadSect
;		jc	FDInit9

		lea	esi,[ebx+FLOPPY_Reply]
		mov	ecx,7
FDInit846:	lodsb
		call	DebOutHexB
		mov	al," "
		call	DebOutChar
		call	DebOutChar
		loop	FDInit846
		call	DebNewLine



		mov	byte [ebx+FLOPPY_Rate],FDRATE_300K


		mov	al,1		; start sector
		mov	cl,10		; number of sectors
		call	FDReadSect
;		jc	FDInit9

		lea	esi,[ebx+FLOPPY_Reply]
		mov	ecx,7
FDInit847:	lodsb
		call	DebOutHexB
		mov	al," "
		call	DebOutChar
		call	DebOutChar
		loop	FDInit847
		call	DebNewLine


		mov	byte [ebx+FLOPPY_Rate],FDRATE_250K

		call	FDReadID
;		jc	FDInit9

		lea	esi,[ebx+FLOPPY_Reply]
		mov	ecx,7
FDInit848:	lodsb
		call	DebOutHexB
		mov	al," "
		call	DebOutChar
		call	DebOutChar
		loop	FDInit848
		call	DebNewLine


		mov	byte [ebx+FLOPPY_Rate],FDRATE_300K

		call	FDReadID
;		jc	FDInit9

		lea	esi,[ebx+FLOPPY_Reply]
		mov	ecx,7
FDInit849:	lodsb
		call	DebOutHexB
		mov	al," "
		call	DebOutChar
		call	DebOutChar
		loop	FDInit849
		call	DebNewLine


;		mov	eax,2
;		mov	ecx,6
;		mov	edx,800B8011h
;		mov	esi,0
;		mov	edi,0
;		call	FDWrite
;		jc	FDInit9

;		mov	eax,1
;		call	FDRead
;		jc	FDInit9


;		mov	eax,1

;
;		mov	edi,[ebx+FLOPPY_Buffer]
;		xor	eax,eax
;FDInit822:	stosb
;		inc	al
;		jnz	FDInit822

;		mov	al,1		; start sector
;		mov	cl,1		; number of sectors
;		call	FDWriteSect		
;		jc	FDInit9

;		mov	al,2		; start sector
;		mov	cl,1		; number of sectors
;		call	FDReadSect		
;		jc	FDInit9




;		mov	esi,[ebx+FLOPPY_Buffer]
;		mov	edx,22
;FDInit83:	mov	ecx,32
;FDInit84:	lodsb
;		call	DebOutHexB
;;		mov	al," "
;		call	DebOutChar
;		call	DebOutChar
;		loop	FDInit84
;		call	DebNewLine
;		dec	edx
;		jnz	FDInit83







; ------------- Unlock controller

FDInit9:	mov	ebx,FD0DrvDPB	; floppy disk drive 0
		call	FDMotorOff	; motor OFF
		call	FDUnlock	; unlock controller
		ret

; -----------------------------------------------------------------------------
;                                   Data
; -----------------------------------------------------------------------------

		DATA_SECTION

; ------------- Data rate translation table

FDDataRateTab:	db	2		; 250 kb/s, DD on 3.5"
		db	1		; 300 kb/s, DD on 5.25"
		db	0		; 500 kb/s, HD on 5.25" and 3.5"
		db	3		; 1000 kb/s, ED on 3.5"

; ------------- 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	6		; current IRQ number
		db	6		; recomended best IRQ number
		dd	B6		; 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
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,FDCDrvDPB7 ; resource list

		db	FDC_DEFFLAG	; flags
		db	6		; IRQ number
		db	2		; DMA number
		db	4		; number of floppy devices
		db	B0+B1+B2+B3	; mask of detected drives
FDCDrvDORData1:	db	0		; current DOR register of FDC #1
FDCDrvDORData2:	db	0		; current DOR register of FDC #2
		db	0
		dd	NULL		; pointer to first DMA buffer
		dd	NULL		; pointer to second DMA buffer
		TLOCK			; task lock for interrupt
		dd	NULL		; owning task (NULL=none)
FDCDrvDPB11:	LINKEDLIST FD0DrvDPB11, FD3DrvDPB11 ; list of floppy devices
		SPINLOCK		; motor and DOR lock

		align	4, db 0
FDCDrvDPB2:	LINKEDLIST FDCDrvDPB3,FDCDrvDPB1 ; resource list
		dd	2		; 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	6		; 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	370h		; start of resource
		dw	6-1		; size of resource-1
		db	RES_PORT	; resource type
		db	RES_STATIC+RES_AUTO ; flags

FDCDrvDPB5:	LINKEDLIST FDCDrvDPB6,FDCDrvDPB4 ; resource list
		dd	377h		; start of resource
		dw	1-1		; size of resource-1
		db	RES_PORT	; resource type
		db	RES_STATIC+RES_AUTO ; flags

FDCDrvDPB6:	LINKEDLIST FDCDrvDPB7,FDCDrvDPB5 ; 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

FDCDrvDPB7:	LINKEDLIST FDCDrvDPB1,FDCDrvDPB6 ; 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
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, #0 on first controller)

		align	8, db 0
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	EmptySText	; 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 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
		dd	FDrv3_1M44	; pointer to drive
		db	FLOPPY_DEFFLAG	; flags
		db	0		; device index
		db	B4		; motor mask
		db	0		; current track number
		db	0		; current head number
		db	FDRATE_500K	; current data rate
		db	FDSIZE_512	; current sector size
		db	1		; sector interleave
		db	150		; formatting inter-sector gap
		db	2		; head sliding
		db	3		; track sliding
		db	0efh		; formatting filler byte
		db	0		; bytes in reply buffer
		db	2		; gap 3 length
		db	FDERR_OK	; last error code
		db	2		; DMA number
		dd	FDCDrvDORData1	; pointer to current DOR data
FD0DrvDPB11:	LINKEDLIST FD1DrvDPB11, FDCDrvDPB11 ; list of floppy devices
		dd	3f2h		; digital output register
		dd	3f4h		; diskette status / data rate register
		dd	3f5h		; command / data port
		dd	3f7h		; digital input register / control
		dd	NULL		; pointer to first DMA buffer
		dd	NULL		; pointer to second DMA buffer
		ALARMTIMER FDMotorOffCB,FD0DrvDPB ; motor OFF timer
		times FLOP_REPMAX db 0	; reply buffer

FD0DrvName:	STEXT	'Floppy disk drive 0'
FD0FileName:	STEXT	'\dev\fd0'

; ------------- Floppy disk drive 1 (FLOPPY, #1 on first controller)

		align	8, db 0
FD1DrvDPB:	RBTREENODE		; red-black tree node
		SPINLOCK		; driver lock
		db	1,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	FD1DrvName	; pointer to driver name
		dd	EmptySText	; pointer to model name
		dd	EmptySText	; modul path
		dd	FDDrvDDFB	; pointer to function table
FD1DrvDPB1:	LINKEDLIST FD1DrvDPB1,FD1DrvDPB1 ; 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 mask
		dd	FD1FileName	; 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
		dd	FDrv3_1M44	; pointer to drive
		db	FLOPPY_DEFFLAG	; flags
		db	1		; device index
		db	B5		; motor mask
		db	0		; current track number
		db	0		; current head number
		db	FDRATE_500K	; current data rate
		db	FDSIZE_512	; current sector size
		db	1		; sector interleave
		db	150		; formatting inter-sector gap
		db	2		; head sliding
		db	3		; track sliding
		db	0efh		; formatting filler byte
		db	0		; bytes in reply buffer
		db	2		; gap 3 length
		db	FDERR_OK	; last error code
		db	2		; DMA number
		dd	FDCDrvDORData1	; pointer to current DOR data
FD1DrvDPB11:	LINKEDLIST FD2DrvDPB11, FD0DrvDPB11 ; list of floppy devices
		dd	3f2h		; digital output register
		dd	3f4h		; diskette status / data rate register
		dd	3f5h		; command / data port
		dd	3f7h		; digital input register / control
		dd	NULL		; pointer to first DMA buffer
		dd	NULL		; pointer to second DMA buffer
		ALARMTIMER FDMotorOffCB,FD1DrvDPB ; motor OFF timer
		times FLOP_REPMAX db 0	; reply buffer

FD1DrvName:	STEXT	'Floppy disk drive 1'
FD1FileName:	STEXT	'\dev\fd1'

; ------------- Floppy disk drive 2 (FLOPPY, #0 on second controller)

		align	8, db 0
FD2DrvDPB:	RBTREENODE		; red-black tree node
		SPINLOCK		; driver lock
		db	2,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	FD2DrvName	; pointer to driver name
		dd	EmptySText	; pointer to model name
		dd	EmptySText	; modul path
		dd	FDDrvDDFB	; pointer to function table
FD2DrvDPB1:	LINKEDLIST FD2DrvDPB1,FD2DrvDPB1 ; 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 mask
		dd	FD2FileName	; 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
		dd	FDrv3_1M44	; pointer to drive
		db	FLOPPY_DEFFLAG	; flags
		db	0		; device index
		db	B4		; motor mask
		db	0		; current track number
		db	0		; current head number
		db	FDRATE_500K	; current data rate
		db	FDSIZE_512	; current sector size
		db	1		; sector interleave
		db	150		; formatting inter-sector gap
		db	2		; head sliding
		db	3		; track sliding
		db	0efh		; formatting filler byte
		db	0		; bytes in reply buffer
		db	2		; gap 3 length
		db	FDERR_OK	; last error code
		db	2		; DMA number
		dd	FDCDrvDORData2	; pointer to current DOR data
FD2DrvDPB11:	LINKEDLIST FD3DrvDPB11, FD1DrvDPB11 ; list of floppy devices
		dd	372h		; digital output register
		dd	374h		; diskette status / data rate register
		dd	375h		; command / data port
		dd	377h		; digital input register / control
		dd	NULL		; pointer to first DMA buffer
		dd	NULL		; pointer to second DMA buffer
		ALARMTIMER FDMotorOffCB,FD2DrvDPB ; motor OFF timer
		times FLOP_REPMAX db 0	; reply buffer

FD2DrvName:	STEXT	'Floppy disk drive 2'
FD2FileName:	STEXT	'\dev\fd2'

; ------------- Floppy disk drive 3 (FLOPPY, #1 on second controller)

		align	8, db 0
FD3DrvDPB:	RBTREENODE		; red-black tree node
		SPINLOCK		; driver lock
		db	3,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	FD3DrvName	; pointer to driver name
		dd	EmptySText	; pointer to model name
		dd	EmptySText	; modul path
		dd	FDDrvDDFB	; pointer to function table
FD3DrvDPB1:	LINKEDLIST FD3DrvDPB1,FD3DrvDPB1 ; 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 mask
		dd	FD3FileName	; 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
		dd	FDrv3_1M44	; pointer to drive
		db	FLOPPY_DEFFLAG	; flags
		db	1		; device index
		db	B5		; motor mask
		db	0		; current track number
		db	0		; current head number
		db	FDRATE_500K	; current data rate
		db	FDSIZE_512	; current sector size
		db	1		; sector interleave
		db	150		; formatting inter-sector gap
		db	2		; head sliding
		db	3		; track sliding
		db	0efh		; formatting filler byte
		db	0		; bytes in reply buffer
		db	2		; gap 3 length
		db	FDERR_OK	; last error code
		db	2		; DMA number
		dd	FDCDrvDORData2	; pointer to current DOR data
FD3DrvDPB11:	LINKEDLIST FDCDrvDPB11, FD2DrvDPB11 ; list of floppy devices
		dd	372h		; digital output register
		dd	374h		; diskette status / data rate register
		dd	375h		; command / data port
		dd	377h		; digital input register / control
		dd	NULL		; pointer to first DMA buffer
		dd	NULL		; pointer to second DMA buffer
		ALARMTIMER FDMotorOffCB,FD3DrvDPB ; motor OFF timer
		times FLOP_REPMAX db 0	; reply buffer

FD3DrvName:	STEXT	'Floppy disk drive 3'
FD3FileName:	STEXT	'\dev\fd3'

; ------------- Floppy disk drive function block FLOPPYF

		align	4, db 0
FDDrvDDFB:	dd	DrvStdFuncOK	; device detection
		dd	DrvStdFuncOK	; device initialization
		dd	DrvStdFuncERR	; device deinitialization
		dd	DrvStdFuncERR	; enable device
		dd	DrvStdFuncERR	; disable device

		dd	DrvStdFuncERR	; open data device
		dd	DrvStdFuncERR	; clode data device
		dd	DrvStdFuncERR	; read data from device
		dd	DrvStdFuncERR	; write data to device
		dd	DrvStdFuncERR	; verify data from device
		dd	DrvStdFuncERR	; compare data from device
		dd	DrvStdFuncERR	; get current seek position
		dd	DrvStdFuncERR	; lock door
		dd	DrvStdFuncERR	; get door open
		dd	DrvStdFuncERR	; set door open
		dd	DrvStdFuncERR	; test media change

		dd	FDRead		; read sectors from track
		dd	FDWrite		; write sectors to track
		dd	FDVerify	; verify sectors from track
		dd	FDComp		; compare sectors from track

; ------------- Floppy disk 5.25" 360 KB drive descriptor FDRIVE

		align	4, db 0
FDrv5_360K:	db	FDRIVE_5+FDRIVE_2HEADS+FDRIVE_DD
		SRTHUT	3,240		; step rate time + head unload time
		HLTNDMA	2,0		; head load time + non DMA
		db	20		; head settle time
		dd	1000		; motor ON delay
		dd	1000		; motor OFF delay
		db	10,13,0,0	; maximum sectors for data rates
		db	10,13,0		; recomended sectors for data rates
		db	0
		dd	FDTrackCap3	; pointer to track capacity table
		dd	FDM5DD		; pointer to media list
		db	12		; total number of media entries
		db	4		; number of standard media
		db	7,6,1,0,0,0	; indexes of standard media

; ------------- Floppy disk 5.25" 1.2 MB drive descriptor FDRIVE

		align	4, db 0
FDrv5_1M2:    db FDRIVE_5+FDRIVE_2HEADS+FDRIVE_80TRACK+FDRIVE_DDHD+FDRIVE_CHDET
		SRTHUT	3,240		; step rate time + head unload time
		HLTNDMA	2,0		; head load time + non DMA
		db	15		; head settle time
		dd	1000		; motor ON delay
		dd	1000		; motor OFF delay
		db	9,10,18,0	; maximum sectors for data rates
		db	7,10,18		; recomended sectors for data rates
		db	0
		dd	FDTrackCap5	; pointer to track capacity table
		dd	FDM5HD		; pointer to media list
		db	16		; total number of media entries
		db	5		; number of standard media
		db	12,6,5,2,1,0	; indexes of standard media

; ------------- Floppy disk 3.5" 720 KB drive descriptor FDRIVE

		align	4, db 0
FDrv3_720K:	db	FDRIVE_2HEADS+FDRIVE_80TRACK+FDRIVE_DD+FDRIVE_CHDET
		SRTHUT	6,240		; step rate time + head unload time
		HLTNDMA	2,0		; head load time + non DMA
		db	12		; head settle time
		dd	1000		; motor ON delay
		dd	1000		; motor OFF delay
		db	10,13,0,0	; maximum sectors for data rates
		db	10,13,0		; recomended sectors for data rates
		db	0
		dd	FDTrackCap3	; pointer to track capacity table
		dd	FDM3		; pointer to media list
		db	18		; total number of media entries
		db	1		; number of standard media
		db	13,0,0,0,0,0	; indexes of standard media

; ------------- Floppy disk 3.5" 1.44 MB drive descriptor FDRIVE

		align	4, db 0
FDrv3_1M44:	db	FDRIVE_2HEADS+FDRIVE_80TRACK+FDRIVE_DDHD+FDRIVE_CHDET
		SRTHUT	6,240		; step rate time + head unload time
		HLTNDMA	2,0		; head load time + non DMA
		db	12		; head settle time
		dd	1000		; motor ON delay
		dd	1000		; motor OFF delay
		db	10,13,21,0	; maximum sectors for data rates
		db	10,13,21	; recomended sectors for data rates
		db	0
		dd	FDTrackCap3	; pointer to track capacity table
		dd	FDM3		; pointer to media list
		db	26		; total number of media entries
		db	2		; number of standard media
		db	22,13,0,0,0,0	; indexes of standard media

; ------------- Floppy disk 3.5" 2.88 MB drive descriptor FDRIVE

		align	4, db 0
FDrv3_2M88:	db	FDRIVE_2HEADS+FDRIVE_80TRACK+FDRIVE_DDHDED+FDRIVE_CHDET
		SRTHUT	6,240		; step rate time + head unload time
		HLTNDMA	2,0		; head load time + non DMA
		db	12		; head settle time
		dd	1000		; motor ON delay
		dd	1000		; motor OFF delay
		db	10,13,21,42	; maximum sectors for data rates
		db	10,13,21	; recomended sectors for data rates
		db	0
		dd	FDTrackCap3	; pointer to track capacity table
		dd	FDM3		; pointer to media list
		db	33		; total number of media entries
		db	3		; number of standard media
		db	26,22,13,0,0,0	; indexes of standard media

; ------------- Track capacity for drive 5.25" 1.2 MB, 360 RPM (6 turns/sec)

FDTrackCap5:	dd	250000/6/8	; 250 kb/s (5208 B)
		dd	300000/6/8	; 300 kb/s (6250 B)
		dd	500000/6/8	; 500 kb/s (10416 B)
		dd	1000000/6/8	; 1000 kb/s (20833 B)

; ------------- Track capacity for other driver, 300 RPM (5 turns/sec)

FDTrackCap3:	dd	250000/5/8	; 250 kb/s (6250 B)
		dd	300000/5/8	; 300 kb/s (7500 B)
		dd	500000/5/8	; 500 kb/s (12500 B)
		dd	1000000/5/8	; 1000 kb/s (25000 B)

; ------------- Table of head sliding

FDHeadSlidTab:	db	1		; 250 kb/s
		db	1		; 300 kb/s
		db	2		; 500 kb/s
		db	3		; 1000 kb/s

; ------------- Table of track sliding

FDTrackSlidTab:	db	2		; 250 kb/s
		db	2		; 300 kb/s
		db	3		; 500 kb/s
		db	4		; 1000 kb/s

; ------------- Floppy disk CMOS types

FDCMOSType:	dd	FDrv3_1M44	; 0: default or unknown
		dd	FDrv5_360K	; 1: 5.25" DD
		dd	FDrv5_1M2	; 2: 5.25" HD
		dd	FDrv3_720K	; 3: 3.5" DD
		dd	FDrv3_1M44	; 4: 3.5" HD
		dd	FDrv3_2M88	; 5: 3.5" ED (AMI PC Bios)
		dd	FDrv3_2M88	; 6: 3.5" ED

; ------------- Media descriptors - 5.25" 360K drive, 300 RPM

		align	4, db 0
FDM5DD:		FDMED5	FDRATE_250K,1,0,0, 8,40,1,155,1,3 ; 0  160K
		FDMED5	FDRATE_250K,1,0,0, 9,40,1, 90,1,3 ; 1  180K
		FDMED5	FDRATE_250K,0,0,0,10,40,1, 38,1,3 ; 2  200K
		FDMED5	FDRATE_300K,0,0,0,11,40,1, 80,1,3 ; 3  220K
		FDMED5	FDRATE_300K,0,0,0,12,40,1, 39,1,3 ; 4  240K
		FDMED5	FDRATE_300K,0,0,0,13,40,2,  1,1,3 ; 5  260K
		FDMED5	FDRATE_250K,1,1,0, 8,40,1,155,1,3 ; 6  320K
		FDMED5	FDRATE_250K,1,1,0, 9,40,1, 90,1,3 ; 7  360K
		FDMED5	FDRATE_250K,0,1,0,10,40,1, 38,1,3 ; 8  400K
		FDMED5	FDRATE_300K,0,1,0,11,40,1, 80,1,3 ; 9  440K
		FDMED5	FDRATE_300K,0,1,0,12,40,1, 39,1,3 ; 10 480K
		FDMED5	FDRATE_300K,0,1,0,13,40,2,  1,1,3 ; 11 520K

; ------------- Media descriptors - 5.25" 1.2 MB drive, 360 RPM

		align	4, db 0
FDM5HD:		FDMED5	FDRATE_250K,0,0,1, 7,40,1,126,1,3 ; 0  140K
		FDMED5	FDRATE_300K,1,0,1, 8,40,1,155,1,3 ; 1  160K
		FDMED5	FDRATE_300K,1,0,1, 9,40,1, 90,1,3 ; 2  180K
		FDMED5	FDRATE_300K,0,0,1,10,40,1, 38,1,3 ; 3  200K
		FDMED5	FDRATE_250K,0,1,1, 7,40,1,126,1,3 ; 4  280K
		FDMED5	FDRATE_300K,1,1,1, 8,40,1,155,1,3 ; 5  320K
		FDMED5	FDRATE_300K,1,1,1, 9,40,1, 90,1,3 ; 6  360K
		FDMED5	FDRATE_300K,0,1,1,10,40,1, 38,1,3 ; 7  400K
		FDMED5	FDRATE_250K,0,1,0, 7,80,1,126,1,2 ; 8  560K
		FDMED5	FDRATE_300K,0,1,0, 8,80,1,155,1,2 ; 9  640K
		FDMED5	FDRATE_300K,0,1,0, 9,80,1, 90,1,2 ; 10 720K
		FDMED5	FDRATE_300K,0,1,0,10,80,1, 38,1,2 ; 11 800K
		FDMED5	FDRATE_500K,1,1,0,15,80,1, 80,2,3 ; 12 1.2M 
		FDMED5	FDRATE_500K,0,1,0,16,80,1, 58,2,3 ; 13 1.28M
		FDMED5	FDRATE_500K,0,1,0,17,80,1, 38,2,3 ; 14 1.36M
		FDMED5	FDRATE_500K,0,1,0,18,80,2,  2,2,3 ; 15 1.44M

; ------------- Media descriptors - 3.5" 720K drive, 300 RPM

		align	4, db 0
FDM3:		FDMED3	FDRATE_250K,0,0,1, 8,40,1,155,1,3 ; 0  160K
		FDMED3	FDRATE_250K,0,0,1, 9,40,1, 90,1,3 ; 1  180K
		FDMED3	FDRATE_250K,0,0,1,10,40,1, 38,1,3 ; 2  200K
		FDMED3	FDRATE_300K,0,0,1,11,40,1, 80,1,3 ; 3  220K
		FDMED3	FDRATE_300K,0,0,1,12,40,1, 39,1,3 ; 4  240K
		FDMED3	FDRATE_300K,0,0,1,13,40,2,  1,1,3 ; 5  260K
		FDMED3	FDRATE_250K,0,1,1, 8,40,1,155,1,3 ; 6  320K
		FDMED3	FDRATE_250K,0,1,1, 9,40,1, 90,1,3 ; 7  360K
		FDMED3	FDRATE_250K,0,1,1,10,40,1, 38,1,3 ; 8  400K
		FDMED3	FDRATE_300K,0,1,1,11,40,1, 80,1,3 ; 9  440K
		FDMED3	FDRATE_300K,0,1,1,12,40,1, 39,1,3 ; 10 480K
		FDMED3	FDRATE_300K,0,1,1,13,40,2,  1,1,3 ; 11 520K
		FDMED3	FDRATE_250K,0,1,0, 8,80,1,155,1,2 ; 12 640K
		FDMED3	FDRATE_250K,1,1,0, 9,80,1, 90,1,2 ; 13 720K
		FDMED3	FDRATE_250K,0,1,0,10,80,1, 38,1,2 ; 14 800K
		FDMED3	FDRATE_300K,0,1,0,11,80,1, 80,1,2 ; 15 880K
		FDMED3	FDRATE_300K,0,1,0,12,80,1, 39,1,2 ; 16 960K
		FDMED3	FDRATE_300K,0,1,0,13,80,2,  1,1,2 ; 17 1.04M

; ------------- Media descriptors - 3.5" 1.44 MB drive, 300 RPM

		FDMED3	FDRATE_500K,0,1,0,14,80,1,238,2,3 ; 18 1.12M
		FDMED3	FDRATE_500K,0,1,0,15,80,1,194,2,3 ; 19 1.2M
		FDMED3	FDRATE_500K,0,1,0,16,80,1,155,2,3 ; 20 1.28M
		FDMED3	FDRATE_500K,0,1,0,17,80,1,120,2,3 ; 21 1.36M
		FDMED3	FDRATE_500K,1,1,0,18,80,1, 90,2,3 ; 22 1.44M
		FDMED3	FDRATE_500K,0,1,0,19,80,1, 62,2,3 ; 23 1.52M
		FDMED3	FDRATE_500K,0,1,0,20,80,1, 38,2,3 ; 24 1.6M
		FDMED3	FDRATE_500K,0,1,0,21,80,2, 15,2,3 ; 25 1.68M

; ------------- Media descriptors - 3.5" 2.88 MB drive, 300 RPM

		FDMED3	FDRATE_1M,1,1,0,36,80,1, 90,3,4 ; 26 2.88M
		FDMED3	FDRATE_1M,0,1,0,37,80,1, 76,3,4 ; 27 2.96M
		FDMED3	FDRATE_1M,0,1,0,38,80,1, 62,3,4 ; 28 3.04M
		FDMED3	FDRATE_1M,0,1,0,39,80,1, 50,3,4 ; 29 3.12M
		FDMED3	FDRATE_1M,0,1,0,40,80,1, 38,3,4 ; 30 3.2M
		FDMED3	FDRATE_1M,0,1,0,41,80,1, 26,3,4 ; 31 3.28M
		FDMED3	FDRATE_1M,0,1,0,42,80,2, 15,3,4 ; 32 3.36M

Back to source browser