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