Floppy Disk Controller: Difference between revisions

Jump to navigation Jump to search
[unchecked revision][unchecked revision]
Content deleted Content added
m →‎Controller Reset: - 2nd formatting error
Added some notes, fixed one error
Line 1: Line 1:
== Overview and Documentation ==
== Overview and Documentation ==
The Floppy Disk Controller (FDC) is a (legacy) device that controls hardware for access to 3.5/5.25 inch floppy disks. There are a range of chips that have
The Floppy Disk Controller (FDC) is a (legacy) device that controls internal 3.5/5.25 inch floppy disk drive devices on desktop x86 systems.
been produced for this function and include: 8272A, 82078, 82077SL & 82077AA. The 82077AA is the most advanced, and has been produced since 1991. For more
There are a range of chips that have been produced for this function which include: 8272A, 82078, 82077SL & 82077AA. The 82077AA is the most
recent systems, a model of that chip has been embedded in the motherboard chipset. (So pay close attention to that datasheet, below.)
advanced, and has been produced since 1991. For more recent systems, a model of that chip has been embedded in the motherboard chipset.
(So pay close attention to that datasheet, below.)


=== Accessing Floppies in Real Mode ===
=== Accessing Floppies in Real Mode ===
For bootloaders or OSes that run with the CPU remaining in [[Real Mode]], use [[BIOS (PC)#BIOS functions|BIOS Function]] INT13h AH=2 (read) or AH=3 (write) to access
Use BIOS function INT13h AH=2 (read) or AH=3 (write). You need to know the "drive number" (typically 0 or 1), and put that value in DL.
floppy drives. You need to know the "drive number" (typically 0 or 1), and put that value in DL.
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
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.
(using CHS) in Real Mode. The rest of this article deals with creating Protected Mode drivers for the floppy subsystem.


=== Accessing USB Floppy Drives ===
=== Accessing USB Floppy Drives ===
Line 33: Line 35:
In the olden days, there used to be 5.25 inch low-density, high-density, and single-sided drives. There used to be media
In the olden days, there used to be 5.25 inch low-density, high-density, and single-sided drives. There used to be media
for each of these drive types. There also used to be 3.5 inch low density media. None of this really exists anymore. The only
for each of these drive types. There also used to be 3.5 inch low density media. None of this really exists anymore. The only
actual hardware you will typically run into anymore is 3.5 inch, 1.44MB drives.
actual hardware you will typically run into now is 3.5 inch, 1.44MB drives.


A 1.44MB floppy disk has 80 cylinders, 2 sides, and 18 sectors per track. The drive records the two sides with two "heads" that
A 1.44MB floppy disk is usually formatted with 80 cylinders, 2 sides, and 18 sectors per track. The drive records the two sides
are bolted together. They cannot seek independently. The "track" on one side of a disk is always exactly opposite the
with two "heads" that are bolted together. They cannot seek independently. The "track" on one side of a disk is always exactly
track on the other side of the disk. (There is a misconception about this in many floppy driver code examples.) You only
opposite the track on the other side of the disk. (There is a misconception about this in many floppy driver code examples.)
need to seek one head to find a particular cylinder, so that both heads may read/write that cylinder.
You only need to seek one head to find a particular cylinder, so that both heads may read/write that cylinder.


=== CHS ===
=== CHS ===
Line 86: Line 88:
There were several generations of floppy controller chips on several generations of 80286 computers, before
There were several generations of floppy controller chips on several generations of 80286 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 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 mode you will typically see on emulators is Model 30 Mode.
The three modes are: PC-AT mode, PS/2 mode, and Model 30 mode.
The only mode you will ever see on any hardware that still runs is PS/2 mode. It is unfortunate that emulators get this wrong,
The only mode you will ever see on any hardware that still runs is PS/2 mode. In the documentation, you
can ignore the Model 30 and PC-AT modes. Or you can try to handle all three, by only using registers and commands that are identical
but the only real effect from it is in the logic for testing "Disk Change" (see below). In the documentation, you
can ignore PC-AT modes. Or you can try to handle all three, by only using registers and commands that are identical
in all 3 modes.
in all 3 modes.


=== Most commands run "silently" ===
=== Most commands run "silently" ===
There are only a few commands/conditions that produce interrupts: a reset, Seek, Recalibrate, or one of the (several kinds of)
There are only a few commands/conditions that produce interrupts: a reset (in polling mode only), Seek, Recalibrate, or one of the many
read/write/verify/format commands. Many commands do not produce any result bytes, either. If you want to verify that a silent
read/write/verify/format commands. Several commands do not produce any result bytes, either. If you want to verify that a silent
command actually worked, just about the only thing you can do is use the Dumpreg command to check the current state of the
command actually worked, just about the only thing you can do is use the Dumpreg command to check the current state of the
controller.
controller.
Line 100: Line 101:
=== Timing Issues ===
=== Timing Issues ===
On real hardware, there are definite timing issues. Seek delays and motor delays are just what any programmer would expect. It
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 doesn't. The thing that you '''don't'''
would be nice if the drive would send an IRQ when the motor was up to speed, but it does not. The thing that you may not
expect is that you need a microsecond delay between each command/parameter byte that you output to the FDC, even on machines as recent as Pentium
expect is that quite new hardware may still need artificial delays between "command/parameter" bytes. There is a bit in the MSR
to test, to know when the next byte can be sent. It is not a good idea to simply hardcode specific delays between output bytes.
166 systems. This can be done by, for example, reading port 0x3F6 (the ATA alternate status port) 10 times. Or, you can just decide
If you really feel you must do that, though, then a 400ns delay (consisting of reading the MSR port 4 times and discarding the
that the floppy is a low priority device, and swap out the driver between each output byte. Wasting an entire microsecond of CPU
results) is probably adequate. Looping 20 times, and testing the value of the RMQ bit in the MSR each time, should always be
time just to make FDC commands run as quickly as possible seems unreasonable.
a sufficient "timeout".


== Registers ==
== Registers ==
Line 264: Line 266:
Alternately, you can always set both of them, for maximum compatibility with ancient chipsets.
Alternately, you can always set both of them, for maximum compatibility with ancient chipsets.


The bottom 2 bits specify the data transfer rate to/from the drive. You want both bits set to zero for a 1.44MB floppy drive.
The bottom 2 bits specify the data transfer rate to/from the drive. You want both bits set to zero for a 1.44MB or 1.2M floppy drive.
So generally, you want to set CCR to zero just once, after bootup (because the BIOS may not have done it).
So generally, you want to set CCR to zero just once, after bootup (because the BIOS may not have done it, unless it booted a floppy disk).


Note: a reset procedure does not affect this register. However, if you have drives of different types on the bus which
Note: a reset procedure does not affect this register. However, if you have drives of different types on the bus which
use different datarates, then you need to switch the datarate when you select the other drive.
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".


Datarates used for setting either DSR or CCR:
Datarates used for setting either DSR or CCR:


<pre>
<pre>
Datarate value
Datarate value Drive Type
1Mbps 3
1Mbps 3 2.88M
500Kbps 0
500Kbps 0 1.44M, 1.2M
250Kbps 2
</pre>
</pre>


Note: There is also a 300Kbps setting (value = 1), but you should never use it; 250Kbps is powerup default.
Note: There is also a 300Kbps (value = 1), and a 250Kbps setting (value = 2) but they are only used for utterly obsolete drives/media.


=== Important Bitflags that depend on the Mode ===
=== Important Bitflags that depend on the Mode ===


==== DIR register, Disk Change bit ====
==== DIR register, Disk Change bit ====
Note: many sources say that you must turn on the drive motor bit before you access the DIR register for a selected drive.
This claim needs further testing.


This bit (bit 7, value = 0x80) could be very useful, if it actually works for you. It is supposed to tell you if the floppy door was
This bit (bit 7, value = 0x80) could be very useful, if it actually works for you. It is supposed to tell you if the floppy door was
Line 289: Line 293:
bit until you have tested the functionality on real hardware.
bit until you have tested the functionality on real hardware.


Basically, you want to keep a flag for whether there is media in the drive. if Disk Change is "true" and there was media,
Basically, you want to keep a flag for whether there is media in each drive. if Disk Change is "true" and there was media,
the OS should get a signal that the previous media was ejected.
the OS should get a signal that the previous media was ejected, and the driver should automatically recalibrate the drive
for the new media. The recalibration serves two purposes. The heads may have moved when the new media was inserted, and the
recalibrate will correct for this. Also, the recalibrate will clear the Disk Change flag to "false" if there is '''new''' media
in the drive. You find out initially whether there is media in the drives by issuing Recalibrate commands to all the drives
(see the [[#Reinitialization|reinitialization]] procedure below).


If the driver wants to automatically check for new media, it can periodically do a Reset procedure on the drive/controller.
If a drive has no media in it, and the driver wants to automatically check for new media, it can periodically do a Seek command
If Disk Change remains "true", then the drive is still empty. If it goes "false", it means that a new floppy has been inserted,
on the drive. If Disk Change remains "true", then the drive is still empty. If it goes "false", it means that a new
and the OS should get a "media inserted" signal.
floppy has been inserted, and the OS should get a "media inserted" signal. On some/most hardware, it is possible to
simply toggle the drive motor bit off and then on again, to achieve the same result as doing a Seek (Linux calls this a "twaddle").


But there is a problem. As the section title says, the problem is that the value of the Disk Change bitflag depends
But there is a problem. As the section title says, the problem is that the '''value''' of the Disk Change bitflag depends
on the mode. And there are 3 possible modes.
on the mode. And there are 3 possible modes.
And the idiots at Intel who made this chip failed utterly in giving you a definitive way of figuring out the mode.
And the idiots at Intel who made this chip failed utterly in giving you a definitive way of figuring out the mode.
Line 308: Line 317:


If you ignore PC-AT mode, then you can tell whether Disk Change is true or false by looking at the other bits in upper DIR.
If you ignore PC-AT mode, then you can tell whether Disk Change is true or false by looking at the other bits in upper DIR.
Bits 4, 5, and 6 of DIR tell you what value of Disk Change is "true". Usually "true" = 0.
Bits 4, 5, and 6 of DIR tell you what value of Disk Change is "true". Usually "true" = 1 on real hardware.


The workaround (to do ONCE): Read DIR. Assume that the current value of Disk Change means "true". Send a Recalibrate command.
The workaround (to do ONCE): Read DIR. Assume that the current value of Disk Change means "true". Send a Recalibrate command.
Line 353: Line 362:
If you really want to try using non-essential bitflags that are mode-dependent, you will need to look in the
If you really want to try using non-essential bitflags that are mode-dependent, you will need to look in the
datasheet linked below for their locations and meanings. Including them would add too much extraneous info to
datasheet linked below for their locations and meanings. Including them would add too much extraneous info to
this article. As mentioned in the case of the Disk Change bit, it is not logically possible to completely
this article.
determine what mode the controller chip is in, so it is not really possible to know the meaning of any bitflag,
if there is any ambiguity between modes.


== Programming Details ==
== Programming Details ==
Line 364: Line 375:
# Get an IRQ6 at the end of the execution phase, but '''only if the command HAS an execution phase'''.
# Get an IRQ6 at the end of the execution phase, but '''only if the command HAS an execution phase'''.
# Read any "result bytes" produced by the command (the "result phase").
# Read any "result bytes" produced by the command (the "result phase").
# The commands "Recalibrate", "Seek", and "Seek Relative" require an additional "Sense Interrupt" command to be sent.
# The commands "Recalibrate", "Seek", and "Seek Relative" do not have a result phase, and require an additional "Sense Interrupt" command to be sent.


And then you are ready for the next command. See below for more detail on how to issue a command.
And then you are ready for the next command. See below for more detail on how to issue a command.


=== Motor Delays ===
=== Motor Delays ===
Note: the Linux floppy driver sourcecode has a comment that claims that turning on the motor for drive 2 or drive 3
When you turn the motor on, it takes quite a few milliseconds to "spinup" -- to reach the (stabilized) speed needed for data transfer.
on a floppy bus can completely lock up some systems. This claim seems unlikely?
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'll get an error.


Note2: modern floppy drives ignore the motor bits, and only spin the disk when they think they need to.
After you're done reading (or writing), you should typically wait an additional 2 seconds to turn the motor off. (It may also be smart

When you turn a floppy drive motor on, it takes quite a few milliseconds to "spinup" -- 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 2 seconds to turn the motor off. (It may also be smart
to seek the heads back to cylinder 0 just before turning the motor off.) You could leave the motor on longer,
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.
but it might give the user the idea that the floppy is still transferring data and that it's taking an awfully long time.
Line 581: Line 597:
* Configure command = 0x13
* Configure command = 0x13
* First parameter byte = 0
* First parameter byte = 0
* Second parameter byte = (implied seek enable << 6) | (fifo enable << 5) | (polling enable << 4) | thresh_val (= threshold - 1)
* Second parameter byte = (implied seek enable << 6) | (fifo '''DIS'''able << 5) | (polling enable << 4) | thresh_val (= threshold - 1)
* Third parameter byte = precomp_val = 0
* Third parameter byte = precomp_val = 0
* No result bytes.
* No result bytes.
Line 841: Line 857:
* [http://bos.asmhackers.net/docs/floppy/snippet_9/fdc.c GazOS] (C,GPL)
* [http://bos.asmhackers.net/docs/floppy/snippet_9/fdc.c GazOS] (C,GPL)
* [http://bos.asmhackers.net/docs/floppy/snippet_5/FLOPPY.ASM RDOS] (ASM, GPL)
* [http://bos.asmhackers.net/docs/floppy/snippet_5/FLOPPY.ASM RDOS] (ASM, GPL)
* [http://www.gelato.unsw.edu.au/lxr/source/drivers/block/floppy.c Linux] (C,GPL)


[[Category:Storage]]
[[Category:Storage]]