Using floppy disc

Question about which tools to use, bugs, the best way to implement a function, etc should go here. Don't forget to see if your question is answered in the wiki first! When in doubt post here.
Brandon

Using floppy disc

Post by Brandon »

Does anyone know a good tutorial or page about using the floppy disc, writing and reading data(yes in PM).
DennisCGc

Re:Using floppy disc

Post by DennisCGc »

http://www.dbit.com/pub/ibmpc/floppy/fdcdemo.asm
http://debs.future.easyspace.com/Progra ... loppy.html

The first link is a program that uses it (not sure though), and the second one is a good reference....

HTH, DennisCGc.
User avatar
Neo
Member
Member
Posts: 842
Joined: Wed Oct 18, 2006 9:01 am

Re:Using floppy disc

Post by Neo »

Only Human
Brandon

Re:Using floppy disc

Post by Brandon »

Two things I wonder about.

The page u sent me said (in the table) that the data register is on port 3f5h.
But it also says that "All commands and status bytes are transferred via the data register, at port 37fh" This doesnt make sense, which port should I use to send the commands?

and one more thing. I dont understand the commands. What does "x7h" means (whats the x?)
bkilgore

Re:Using floppy disc

Post by bkilgore »

Brandon wrote: This doesnt make sense, which port should I use to send the commands?
The correct data port is the first one mentioned, 0x3f5

Brandon wrote: and one more thing. I dont understand the commands. What does "x7h" means (whats the x?)
The "X" means that other bits can come before, but it will always end in 0x7. This is because only the bottom 5 bits (except for in seek relative, also the top 1 bit) are used for the command, and a couple of the bits, depending on the command, are flags signalling more information about the command. See the second link in DennisCGc's post, around half-way down they start with images of the command-byte layouts. You'll see that in the first command byte sent, there are M or F or S bits in some of them, which they describe in more detail there. So a command won't just be 7h, it could be 57h or 17h or e7h, but it's always *something*7h
Brandon

Re:Using floppy disc

Post by Brandon »

Alright thank you. But I dont understand why this isnt working. I got a IRQ-handler that sets
fdc_flag = 1;
and the IRQ handler works so that?s not the problem

Here?s my code
reset_floppy();
start_floppy_motor(); // send motor command and set fdc_flag = 0
while(fdc_flag == 0) ; // Wait for interrupt
print("Floppy motor started\n", RED_TXT);

fdc_flag = 0;
while(in(0x3f4) & 0x80 == 0); // Read the main status
out(0x3f5 ,7); // Callibrate command
out(0x3f5 ,0); // Floppy 00
while(fdc_flag == 0) ; // Wait for interrupt, Stuck

print("Floppy callibrated\n", RED_TXT);

The program get?s stuck in the last while-statement. The callibration should generate an interrupt right? The thing I try to do is simply to start the motor and callibrate the floppy (starting the motor works)
Brandon

Re:Using floppy disc

Post by Brandon »

and, my IRQ handler (It fires, but dont know if I gotta do something else)

void int_38(void)
{
   out(0x20, 0x20);
   print("Floppy IRC\n", WHITE_TXT);
   fdc_flag = 1;
}
User avatar
Brendan
Member
Member
Posts: 8561
Joined: Sat Jan 15, 2005 12:00 am
Location: At his keyboard!
Contact:

Re:Using floppy disc

Post by Brendan »

Hi,

You'd need to wait before sending each byte of the command. It also might be a good idea to have some sort of time-outs (just in case)..

This lot was quickly converted from NASM code that does work:

Code: Select all

unsigned char fdc_flag = 0;
unsigned char statusBuffer[16];

int sendCommandByte(unsigned char c) {
    unsigned long time;

    time = getCurrentTimerTick() + 10mS;
    for(;;) {
        if(time <= getCurrentTimerTick()) return ERROR_TIMEOUT;
        if(in(0x3f4) & 0x80 != 0) {
            out(0x3f5, c);
            return OK;
        }
    }
}

int getStatusByte(unsigned char *c) {
    unsigned long time;

    time = getCurrentTimerTick() + 10mS;
    for(;;) {
        if(time <= getCurrentTimerTick()) return ERROR_TIMEOUT;
        if(in(0x3f4) & 0xC0 == 0xC0) {
            c = in(0x3f5);
            return OK;
        }
    }
}

int waitForIRQ(void) {
    unsigned long time;

    time = getCurrentTimerTick() + 10mS;
    for(;;) {
        if(time <= getCurrentTimerTick()) return ERROR_TIMEOUT;
        if(fdc_flag != 0) {
            fdc_flag = 0;
            return OK;
        }
    }
}

int senseInterrupt(void) {
    int status;

    if((status = sendCommandByte(3)) != OK) return status;
    if((status = getStatus(2)) != OK) return status;
}


int getStatus(int count) {
    int status;
    int i = 0;
    unsigned char c;

    while(count > 0) {
        if((status = getStatusByte(&c)) != OK) return status;
        statusBuffer[i] = c;
        count--;
    }
    return OK;
}


int recalibrate(unsigned char device) {
    int status;
    unsigned char c;
    unsigned long time;

    for(;;) {
        if((status = sendCommandByte(7)) != OK) return status;
        if((status = sendCommandByte(device)) != OK) return status;
        if((status = waitForIRQ()) != OK) return status;
        if((status = senseInterrupt()) != OK) return status;
        c = statusBuffer[0] & 0xF0;
        c = c XOR 0x20   // How is XOR supposed to be coded in C????
        if(c = 0x50) return ERROR_NODEVICE;
        if((c & 0x10) == 0) {
            if((c & 0x40) != 0) return ERROR_NOMEDIA;
            time = getCurrentTimerTick() + HEAD_SETTLE_TIME;
            while(time > getCurrentTimerTick()) {};
            print("Floppy callibrated\n", RED_TXT);
            return OK;
        }
    }
}

Cheers,

Brendan
For all things; perfection is, and will always remain, impossible to achieve in practice. However; by striving for perfection we create things that are as perfect as practically possible. Let the pursuit of perfection be our guide.
bkilgore

Re:Using floppy disc

Post by bkilgore »

Brandon wrote: I got a IRQ-handler that sets
fdc_flag = 1;
and the IRQ handler works so that?s not the problem
. . .
fdc_flag = 0
while(fdc_flag == 0) ; // Wait for interrupt
Since I don't have your code I don't know if you already did this, but make sure you make fdc_flag volatile

Code: Select all

volatile int fdc_flag;
Otherwise the gcc optimizations might cache the value in a register and do something like:

Code: Select all

xor eax, eax   ;eax = 0
loop1:
cmp eax, 0
je loop1
And this loop will never exit. If you make it volatile you ensure it will keep checking the actual memory location.
User avatar
Neo
Member
Member
Posts: 842
Joined: Wed Oct 18, 2006 9:01 am

Re:Using floppy disc

Post by Neo »

i would recommend the intel manuals, they are better and more accurate than debs (which i found confusing) the flowcharts in the manual help you understand the ops better
Only Human
Brandon

Re:Using floppy disc

Post by Brandon »

hmm I changed the code but it still doesnt work.. is there something wrong with my ISR? Cause the IRQ is just firingen once..

   out(0xA0, 0x20);
   out(0x20, 0x20);
   print("Floppy IRC\n", WHITE_TXT);
   fdc_flag = 1;
Brandon

Re:Using floppy disc

Post by Brandon »

No the ISR is working. I just dont get an interrupt when Im done..
Brandon

Re:Using floppy disc

Post by Brandon »

Can it be something with bochs? Im gettin so confused cause I use the same code as u told me and the same code I saw in another thread, but still I?m not getting no interrupt after sending the two commands.
User avatar
Neo
Member
Member
Posts: 842
Joined: Wed Oct 18, 2006 9:01 am

Re:Using floppy disc

Post by Neo »

you remind me of the time i was writing my own floppy driver.
When the thing never used to work i used to think it was something with BOCHS. I ultimately got it working correctly and it works perfectly in BOCHS and a real computer now.
my only recommendation is as said before follow the intel manuals and trash deb's reference. I willing to bet you will be able to get ur code working. The first step (initialization) is the most important if that works correct almost all the others commands will start working.

what I did to do to init the FDC is
  • Read the BDA to get the floppy DPT (this is useful in the other commands such as "Park Head" which requires you to set the head settle time etc..
  • Reset the FDC (send 0 to the DOR of the FDC, followed by 0x0C which enables DMA)
  • Set the data rate by sending it to the CCR (value of 0 gives u a 500 kbps data rate which is the most common)
  • Wait for an interrupt (your loop here)
  • Issue the "Check Interrupt" command 4 times
    your almost done now after this
  • Issue the "Specify" command now to set up step rate time etc..
    Thats it you should be able to issue other commands and get them working now.
BTW this init function is called only once at the start of my kernel just after i re-enable interrupts. To read a sector i have to "Power-on" the FDC then set up the data rate (out 0 to CCR), "Recalibrate" the drive, setup DMA etc etc.. and after reading "Power it off". HTH
C & CW
Only Human
Brandon

Re:Using floppy disc

Post by Brandon »

DPT, CCR? What kinda ports is this, cant find them in the documents..
Post Reply