I know your frustration. I have been there, done that.
Okay, so first things first.
First check to see that there is actually a controller at that address.
Code: Select all
if (inpb(fdc->base+FDC_MSR) == 0xFF)
If that read returns 0xFF, you don't have a controller.
Next, reset the controller:
Code: Select all
outpb(fdc->base+FDC_DOR, 0x00); // reset
outpb(fdc->base+FDC_DOR, 0x00); // twice
You should send it twice. The reset should be no less than 500ns. As Brendan mentioned in another thread, an I/O from an ISA bus can take as long as 500ns to even more time, so writing it twice will ensure it is long enough.
Next, clear the reset.
Code: Select all
outpb(fdc->base+FDC_DOR, 0x04); // normal operation
Next, wait for the controller to be ready. Poll the MSR register from within a loop.
Code: Select all
if (inpb(fdc->base+FDC_MSR) == 0x80)
If bit 7 doesn't ever become set, you don't have a valid controller.
Ignoring that we haven't done a Sense Interrupt for the reset yet, this is were we can assume we have a valid FDC at this Port I/O address and can now detect the type of controller. i.e.: See what type of controller it is to see if it supports the DUMP command, etc. (left up to the reader to implement)
Now, let's do the reset/initialize sequence:
Code: Select all
// reset the controller
outpb(fdc->base+FDC_DOR, 0x00); // reset
udelay(100); // hold for 100 uS (unknown the amount of time we need to be in reset. (500ns on a 82078))
outpb(fdc->base+FDC_DOR, 0x0C); // release
mdelay(20); // wait 20 mS for controller to be ready (unknown the time we need to wait)
We know that we have to wait at least 500ns, but some controllers have been known to need more. I have found that 100uS is more than enough. After we release the reset, waiting 20 mS should be enough.
Now wait for the interrupt and then send the Sense Interrupt command receiving two bytes of response per command. If you do not receive two bytes in a fair amount of time, or the first byte does not show the drive number in the lower two bits *and* the second byte is not zero, you should assume that the controller is in error.
If this doesn't work, you can try again a number of times, but after two times, assume you have a faulting controller or drive(s).
Once you have successfully received all four command returns, send the specify command.
Code: Select all
// Specify command
buf[0] = FDC_CMD_SPECIFY;
buf[1] = 0xBB; // until we know what disk is in the drive, just use BBh
buf[2] = 0x04;
fdc_command(fdc, buf, 3);
You don't know what kind of disk is inserted, if any, so just send 0xBB.
If that does not fail, you have a valid controller. You can now assume all is well.
At this point, if you found an enhanced controller, done above while determining if the DUMP command is supported, you can configure the controller for implied_seek and disable_polling.
Code: Select all
// Try the configure command.
if (write_fdc(fdc, FDC_CMD_CONFIGURE) && fdc_want_more(fdc)) {
write_fdc(fdc, 0);
write_fdc(fdc, (flags & ~0x0F) | ((fifo_size - 1) & 0x0F));
write_fdc(fdc, 0); // pre-compensation from track 0 upwards
return TRUE;
}
The fdc_want_more() simply checks to see if the command is expecting parameters, i.e.: waiting for the "ready" bit to be set (MSR 7:6 = 10b).
Now, to read from the disk:
If the controller is not an enhanced controller, you can only read from one track at a time. i.e.: you can only read a count of sectors up to the end of the track. You must specify a new command to move to the next track. If the controller *is* an enhanced controller, you may read up to a cylinder of tracks at a time, ending at the last sector of the last track. i.e.: Some controllers will not increment the track field on the read. Some will, some will not. (I will have to verify that from my notes, but from the top of my head, I think that is correct).
Now for a few notes:
1) You ensure that the disk is turning before you read from it, yes?
2) You ensure that the disk has been turning for at least 2 seconds before you attempt to read from it, yes?
3) Do you send the Specify Command before the transfer? You now should have detected the type of disk in the drive and retrieved the step rate, head settle and unload times.
4) If not an enhanced controller, you must send the Seek command. The 82077AA wants a ReadID command after a seek to verify that you really are at that cylinder.
5) If a double density disk, you need to set the MFM bit on the transfer.
6) If an enhanced controller, you need to set the MT bit on the transfer.
7) If a read command, you need to set the SKIP bit.
8) You should wait no more than 1000mS per sector per read/write for the interrupt to fire. If the interrupt hasn't happened in (sectors * 1000ms), it was not successful.
Hope this helps,
Ben
-
http://www.fysnet.net/media_storage_devices.htm