A little while back I was trying to read floppies by dropping back to real mode and using BIOS; now I'm trying an FDC mini-driver.
Code: Select all
;Set up the DMA
mov al, #0x06
outb 0x0A, al ;Mask DMA channel 2 (FDC)
mov al, #0xFF
outb 0x0C, al ;Reset the flip-flop
mov ax, #0x6000
outb 0x04, al ;Set the base address
mov al, ah
outb 0x04, al
mov al, #0xFF
outb 0x0C, al ;Reset the flip-flop
mov ax, #0x23FF
outb 0x05, al ;Set the byte count (512 bytes = 1 sector)
mov al, ah
outb 0x05, al
mov al, #0x00
outb 0x81, al ;Highest byte of base address
mov al, #0x46
outb 0x0B, al ;Set mode for reading
mov al, #0x02
outb 0x0A, al ;Unmask DMA channel 2
;Set up the FDC
mov ax, #0x0008
mov ds, ax
mov [510], #0x41
mov [511], #0x71
call initmessage
mov al, #0x13
call sendcommand ;Send configure command (this one is required to confirm the state of drive polling mode)
mov al, #0x00
call sendcommand ;Send 0 parameter
mov al, #0x47
call sendcommand ;Send options (Implied Seek, FIFO Threshold = 8)
mov al, #0x00
call sendcommand ;Send precompensation (0 = Default)
call progressmessage
call preparewaitirq
mov al, #0x0C
mov dx, #0x03F2
outb dx, al ;Set DOR (Drive 0, Motor 0 off, use IRQ/DMA)
mov al, #0x80
mov dx, #0x03F4
outb dx, al ;Set DSR (1.44 MB, Reset)
call progressmessage
call waitirq
call progressmessage
mov al, #0x08
call sendcommand ;Send sense interrupt (required after reset)
call getresult ;Dump result byte 1
call getresult ;Dump result byte 2
call progressmessage
mov al, #0x08
call sendcommand ;Send sense interrupt (required after reset)
call getresult ;Dump result byte 1
call getresult ;Dump result byte 2
call progressmessage
mov al, #0x08
call sendcommand ;Send sense interrupt (required after reset)
call getresult ;Dump result byte 1
call getresult ;Dump result byte 2
call progressmessage
mov al, #0x08
call sendcommand ;Send sense interrupt (required after reset)
call getresult ;Dump result byte 1
call getresult ;Dump result byte 2
call progressmessage
mov al, #0x13
call sendcommand ;Send configure command (this is the one we actually want)
mov al, #0x00
call sendcommand ;Send parameter 1 (always 0)
mov al, #0x47
call sendcommand ;Send parameter 2 (Implied Seek, FIFO Threshold = 8)
mov al, #0x00
call sendcommand ;Send parameter 3 (precompensation; 0 = Default)
call progressmessage
mov al, #0x00
mov dx, #0x03F4
outb dx, al ;Set DSR (1.44 MB)
call progressmessage
mov al, #0x03
call sendcommand ;Send specify command
mov al, #0x8F
call sendcommand ;Send parameter 1 (SRT = 8ms, HUT = 240ms)
mov al, #0x0A
call sendcommand ;Send parameter 2 (HLT = 10ms, NDMA off = use DMA)
call progressmessage
mov al, #0x1C
mov dx, #0x03F2
outb dx, al ;Set DOR (Drive 0, Motor 0 on, use IRQ/DMA)
call progressmessage
;Read the sector
mov ax, #0x0050
mov ds, ax
mov al, #0x00
mov [1], al
waittimer:
mov al, [1]
cmp al, #0x0F ;0x0A
jnz waittimer
call progressmessage
;call preparewaitirq
;mov al, #0x0F
;call sendcommand ;Send seek command
;mov al, #0x00
;call sendcommand ;Send parameter 1 (H << 2 | D - must match current drive selection in DOR)
;mov al, #0x4F
;call sendcommand ;Send parameter 2 (Track)
;call progressmessage
;call waitirq
;call progressmessage
;mov al, #0x08
;call sendcommand ;Send sense interrupt (required after seek)
;call getresult ;Dump result byte 1
;call getresult ;Dump result byte 2
;call progressmessage
;call preparewaitirq
;mov al, #0x0F
;call sendcommand ;Send seek command
;mov al, #0x00
;call sendcommand ;Send parameter 1 (H << 2 | D - must match current drive selection in DOR)
;mov al, #0x00
;call sendcommand ;Send parameter 2 (Track)
;call progressmessage
;call waitirq
;call progressmessage
;mov al, #0x08
;call sendcommand ;Send sense interrupt (required after seek)
;call getresult ;Dump result byte 1
;call getresult ;Dump result byte 2
;call progressmessage
call preparewaitirq
mov al, #0x46
call sendcommand ;Send read command (with MFM bit)
mov al, #0x00
call sendcommand ;Send parameter 1 (H << 2 | D - must match current drive selection in DOR)
mov al, #0x00
call sendcommand ;Send parameter 2 (Track)
mov al, #0x00
call sendcommand ;Send parameter 3 (H - must match previous H)
mov al, #0x01
call sendcommand ;Send parameter 4 (Start Sector)
mov al, #0x02
call sendcommand ;Send parameter 5 (Bytes per sector; 2 = 512)
mov al, #0x12
call sendcommand ;Send parameter 6 (Number of sectors)
mov al, #0x1B
call sendcommand ;Send parameter 7 (Gap size; 1B = default for 3 1/2 inch drive)
mov al, #0xFF
call sendcommand ;Send parameter 8 (always FF)
call progressmessage
call waitirq
call progressmessage
call getresult ;Dump result byte 1
call getresult ;Dump result byte 2
call getresult ;Dump result byte 3
call getresult ;Dump result byte 4
call getresult ;Dump result byte 5
call getresult ;Dump result byte 6
call getresult ;Dump result byte 7
call progressmessage
;Turn the motor off
mov al, #0x0C
mov dx, #0x03F2
outb dx, al ;Set DOR (Drive 0, Motor 0 off, use IRQ/DMA)
call progressmessage
;Disable interrupts (the caller probably assumes that we will leave interrupts as we found them)
;cli
;Restore previous interrupt mask
pop ax
outb #0xA1, al
pop ax
outb #0x21, al
call progressmessage
;Pop registers
pop ax
mov gs, ax
pop ax
mov fs, ax
pop ax
mov es, ax
pop ax
mov ds, ax
pop edx
pop ecx
pop ebx
pop eax
ret
;Subroutine to prepare for waiting for an IRQ 6
preparewaitirq:
push ax
mov ax, ds
push ax
mov ax, #0x0050
mov ds, ax
mov al, #0x01
mov [0], al ;Set the IRQ 38 (FDC IRQ) flag
pop ax
mov ds, ax
pop ax
ret
;Subroutine to wait for an IRQ 6
waitirq:
push ax
mov ax, ds
push ax
mov ax, #0x0008
mov ds, ax
mov [600], #0x41
mov [601], #0x71
mov ax, #0x0050
mov ds, ax
waitloop:
mov al, [0]
cmp al, #0x00
jnz waitloop
pop ax
mov ds, ax
pop ax
ret
;Subroutine to send the byte in register al to the FDC (handles RQM and all that)
sendcommand:
push dx
push ax
mov ax, ds
push ax
mov ax, #0x0008
mov ds, ax
mov [600], #0x42
mov [601], #0x71
mov dx, #0x03F4
inb al, dx
and al, #0x80
cmp al, #0x00
pop ax
mov ds, ax
pop ax
pop dx
jz sendcommand
push dx
mov dx, #0x03F5
outb dx, al
pop dx
ret
;Subroutine to return a result byte from a command in register al (handles RQM and all that)
getresult:
push dx
push ax
mov dx, #0x03F4
inb al, dx
and al, #0x80
cmp al, #0x00
pop ax
pop dx
jz getresult
push dx
mov dx, #0x03F5
inb al, dx
pop dx
ret
initmessage:
push ax
mov ax, ds
push ax
mov ax, #0x0008
mov ds, ax
mov [500], #0x41
mov [501], #0x71
pop ax
mov ds, ax
pop ax
ret
progressmessage:
push ax
mov ax, ds
push ax
mov ax, #0x0008
mov ds, ax
mov al, [500]
inc al
mov [500], al
mov [501], #0x71
pop ax
mov ds, ax
pop ax
ret
Anyway, the problem is that when I run this on Bochs and Qemu it works, but on real hardware it runs without crashing but it doesn't return the data.
Any ideas? I've compared the code to a few tutorials and checked it against documentation but it's still not working.
Thanks,
onlyonemac