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 |
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 |
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. |
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 |
|||
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 |
(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 |
actual hardware you will typically run into now is 3.5 inch, 1.44MB drives. |
||
A 1.44MB floppy disk |
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 |
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.) |
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 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. |
The only mode you will ever see on any hardware that still runs is PS/2 mode. In the documentation, you |
||
⚫ | |||
but the only real effect from it is in the logic for testing "Disk Change" (see below). In the documentation, you |
|||
⚫ | |||
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 |
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. |
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 |
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 |
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 |
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 |
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 |
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 |
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" = |
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 |
|||
⚫ | |||
on a floppy bus can completely lock up some systems. This claim seems unlikely? |
|||
⚫ | |||
⚫ | |||
Note2: modern floppy drives ignore the motor bits, and only spin the disk when they think they need to. |
|||
⚫ | |||
⚫ | |||
⚫ | |||
⚫ | |||
⚫ | |||
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 |
* 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]] |