Floppy Disk Controller: Difference between revisions
[unchecked revision] | [unchecked revision] |
Content deleted Content added
Auto motor off info, fixed a couple more errors |
Better info on "disk change" flag |
||
Line 10:
More detailed info can be found in the [[ATA in x86 RealMode (BIOS)]] article, because accessing a floppy is identical to accessing a hard disk
(using CHS) in Real Mode. The rest of this article deals with creating Protected Mode drivers for the floppy subsystem.
Note: the BIOS IRQ0 handler remembers a timeout for turning the motor off, from the last BIOS floppy access. The last access may have been
attempting to load your bootloader. So, in the distant future, if the BIOS ever receives 36 more IRQ0 ticks (if you ever return to Real Mode)
it may turn off your floppy motors for you, once.
=== Accessing USB Floppy Drives ===
Line 73 ⟶ 77:
If you are using PIO mode in a singletasking environment then the IRQ6s just waste CPU cycles, and you should be using polling instead.
You can usually shut the IRQs off by setting bit 3 (value = 8) of the Digital Ouptput Register (see below). If you want, you can even
toggle that bit on and off for specific commands, so that you receive some types of interrupts but not others.
To do PIO data transfers: init/reset the controller if needed (see below), select the drive if needed (see below),
Line 88 ⟶ 93:
There were several generations of floppy controller chips on several generations of 80286 (and prior) computers, before
the 82077AA chip existed. The 82077AA was built to emulate all of them, by setting various pins on the chip to 5 volts.
The three modes are: PC-AT mode, PS/2 mode, and Model 30 mode. The most likely mode you will see on any hardware that
In the documentation, you can ignore PC-AT mode. Or you can try to handle all three, by only using registers and commands that are identical
in all 3 modes.
Line 102 ⟶ 107:
On real hardware, there are definite timing issues. Seek delays and motor delays are just what any programmer would expect. It
would be nice if the drive would send an IRQ when the motor was up to speed, but it does not. Two things that you may not
expect are that quite new hardware
probably also need artificial delays between inputting "result" bytes. There is a bit in the MSR to test in order to know when the
Looping 20 times, and testing the value of the
you may want to put the driver to sleep for the shortest possible period (microsleep), instead.
== Registers ==
Line 146 ⟶ 151:
=== Bitflags and Registers that you can rely on ===
As said above, the most common controller chip has 3 modes, and many bitflags in the registers are different (or opposite!) depending on
the mode.
They are the following:
FIFO: The FIFO register may not have a 16byte buffer in all modes, but this is a minor difference that does not really affect its operation.
TDR: The Tape Drive Register is identical in all modes, but it is useless (you will never find functional equipment that requires it).
Line 260 ⟶ 265:
The two important bits are RQM and DIO. NDMA and BUSY are also useful in polling PIO mode.
Most important is RQM, which is set when it is OK (or necessary!) to read/write data from/to the FIFO port.
NDMA signals the end of the "execution phase" of a command, and the beginning of "result phase".
DIO and BUSY should be checked to verify proper command termination (the end of "result phase" and beginning of "command phase").
==== CCR and DSR ====
Line 275 ⟶ 280:
use different datarates, then you need to switch the datarate when you select the other drive. It also seems to be possible
to modify this register while the FDC is in "reset state".
Note2: some tutorials seem to claim that changing/setting the datarate causes an IRQ6. This is false.
Datarates used for setting either DSR or CCR:
Line 285 ⟶ 292:
Note: There is also a 300Kbps (value = 1), and a 250Kbps setting (value = 2) but they are only for utterly obsolete drives/media.
==== DIR register, Disk Change bit ====
This bit (bit 7, value = 0x80)
Do not trust your handling of this bit until you have tested the functionality on real hardware.
Note:
in Model 30 mode, the '''signal''' is also inverted, so it comes out the same. "False" always means the bit is cleared, and
"true" always means the bit is set.
Note2: You must turn on the drive motor bit before you access the DIR register for a selected drive (you do not have to wait
for the motor to spin up, though). It may also be necessary to read the register twice (and discard the first value), when
changing the selected drive -- because "selecting" sometimes takes a little time.
Basically, you want to keep a flag for whether there is media in each drive. If Disk Change is set and there was media,
the OS should get a signal that the previous media was ejected.
Once the Disk Change bit gets set (and you have "processed that message"), you need to try to clear the bit. The main way to
clear the bit is with a '''successful''' Seek to a '''new''' cylinder on the media. (Recalibrate or Reset do not work. And if the
controller thinks the heads are already on the correct cylinder, it will eat the Seek command without clearing the Disk
Change bit.) If the seek fails, you can be fairly certain that there is no media in the drive anymore. It is important to note that
this means you should check the value of Disk Change just prior to every Seek command that you do, because otherwise you
will lose any Disk Change information. This is also true for implied seeks, and relative seeks.
Apparently a small number of floppy drives also support one additional way to clear the bit -- something that
Linux calls a "twaddle". Simply toggle the drive motor bit on, off, and then on again. When your driver tries to clear the
Disk Change bit the first time, it can try a twaddle, and see if it works, and keep a flag if it does.
== Programming Details ==
Line 373 ⟶ 325:
accessed. To do that, you:
# Turn on the drive's motor and select the drive, using an "outb" command to the DOR IO port.
# Wait for awhile for the motor to get up to speed, using some waiting scheme (but don't wait too long).
# Issue your command byte plus some parameter bytes (the "command phase") to the FIFO IO port.
# Exchange data with the drive / "seek" the drive heads (the "execution phase"), on the FIFO IO port.
Line 386 ⟶ 338:
can completely lock up some systems. This claim seems unlikely?
When you turn a floppy drive motor on, it takes quite a few milliseconds to "spin up" -- to reach the (stabilized) speed
needed for data transfer. The controller has electronics to handle a large variation in rotation speed, but it has its limits.
If you start reading/writing immediately after the motor is turned on, "the PLL will fail to lock on to the data signal" and you will get an error.
After you are done reading (or writing), you should typically wait an additional
to seek the heads back to cylinder 0 just before turning the motor off.) You could leave the motor on longer,
but it might give the user the idea that the floppy is still transferring data and that it's taking an awfully long time
The reason to leave the motor on is that your driver may not know if there is a queue of sector reads or writes
that are going to be executed next. If there are going to be more drive accesses immediately, they won't need to wait
for the motor to spin up, if the motor is still on.
The suggested delays when turning the motor on are:
Line 461 ⟶ 411:
## Bit 2 (value = 4) in the DOR: Save the current/"original" value of the DOR, write a 0 to the DOR, wait 4 microseconds, then write the original value (bit 2 is always set) back to the DOR.
## '''or''' Bit 7 (value = 0x80) in the DSR: Precalculate a good value for the DSR (generally 0), and OR it with 0x80. Write that value to the DSR.
# Wait for the resulting IRQ6. HIHI!! only in polling mode?
# Send a Sense Interrupt command (required).
# If your OS/driver never turned off polling mode (see the Configure command), then you have to send 3 more Sense Interrupt commands. (Alternately, you can tell if you need the extra 3 by examining the top 2 bits of the st0 byte returned by the first Sense Interrupt. If both bits are set, you need to send 3 more.)
Line 488 ⟶ 438:
command fails -- this may be the reason why.
# Read DIR. If the "Disk Change" bitflag is set to "true", then the floppy drive door was opened, so the OS needs to test if a new disk is in the drive.
==== Waiting ====
Line 516 ⟶ 464:
## Loop on reading MSR until RQM = 1, verify that DIO = 1.
## In a loop: read the next result byte from the FIFO, loop on reading MSR until RQM = 1, verify CMD BSY = 1 and DIO = 1 ((Value & 0x50) == 0x50).
# After reading all the expected result bytes: check them for error conditions, verify that RQM = 1, CMD BSY = 0, and DIO = 0. '''If not''' retry the entire command again, several times, starting from step 2!
Note: implementing a failure timeout for each loop and the IRQ is pretty much required -- it is the only way to detect many command errors.
Line 572 ⟶ 519:
==== Status Registers ====
There are 3 registers that hold information about the last error encountered. The st0 register information
is passed back with the result bytes of most commands
bytes of read/write commands. They can also be retrieved with a Dumpreg command.
===== st0 =====
The top
time is an error indication.
Bit
===== st1 =====
The st1 register provides more detail about errors during read/write operations.
Line 586 ⟶ 533:
caused by '''not subtracting 1''' when setting the DMA byte count.
Bit 4 (value = 0x10) is set if your driver is too slow to get bytes in or out of the FIFO port in time.
Bit 1 (value = 2) is set if
The rest of the bits are for various types of data errors
===== st2 =====
The st2 register provides more (useless) detail about errors during read/write operations.
The bits all indicate various types of data errors
==== Configure ====
This command initializes controller-specific values: the data buffer "threshold" value, implied seek enable, FIFO
(And "Write Precompensation".) A good setting is: implied seek on, FIFO on, polling off, threshold = 8, precompensation 0.
Line 656 ⟶ 604:
===== SRT, HLT and HUT =====
These parameters sent with the Specify command to the controller are meant to optimize drive performance, and head lifetime.
controller were always meant
to be '''adaptive'''. That is, your driver is theoretically supposed to keep statistics of how often Seek commands fail with the current
setting of SRT. If they always work, and your driver wants to optimize performance, then it can send a new Specify command, with the SRT
value reduced by 1. Then begin keeping new statistics. Similarly for HLT
dirt, the driver would automatically compensate by seeing higher statistical error rates, and increase the values of SRT
Keeping statistics in that way only works when the drive in question is used often. Now that internal floppy drives are nearly obsolete,
Line 703 ⟶ 651:
Note: if you try to read the result bytes without waiting for RQM to set, then you are likely to always get an incorrect result value
of 0. This is also likely to get your driver out of sync with the FDC for input/output. The correct value of st0 after a reset should
be 0xC0 | drive number. After a Recalibrate/Seek it should be 0x20 | drive number.
==== Recalibrate ====
Line 742 ⟶ 691:
A Sense Interrupt command is required after this command completes, to clear it from being BUSY. (Multiple Sense Interrupts,
if you ran multiple Seeks.)
Note: the controller tries to remember what cylinder each drive's heads are currently on. If you try to seek to that same
cylinder, then the controller will silently ignore the command (and return a "success" value). One of the things this means
is that you can get a "success" return value on a seek '''even if there is no media in the drive''', if you happen to seek
to the wrong cylinder number.
===== Relative seek =====
Line 752 ⟶ 706:
==== Read/Write ====
Note: Remember that this is in CHS format, so the sector number starts at 1.
Line 778 ⟶ 731:
Note2: Floppy media and electronics are well known for being unreliable. Any read or write command that fails should be retried
at least twice, unless it was a write and failed on "write protect".
=== Perpendicular Mode and 2.88M floppies ===
If you are using an emulator and you need a floppy disk image that is bigger than 1440Kb, there is a 2880Kb image available.
In order to access it in Pmode, you need to modify your driver to handle Perpendicular Mode. Basically, it is an extra configuration
Line 794 ⟶ 746:
You also need to set CCR/DSR for the 1M datarate (value = 3) to access a 2.88M drive.
=== Additional Programming Notes ===
If you are doing a transfer between 2 floppy drives (so that both motors are on), and you are toggling "selection" between the two,
there may be a short delay required.
== Code Examples ==
|