Page 1 of 1

floppy driver problems.

Posted: Tue Sep 16, 2008 7:12 pm
by 01000101
I just started to implement a long-mode floppy driver as I've been stuck using interrupts for a while whist I focused on other things.

I have been following the wiki article about floppy drivers and also mystran's tutorial thread, but I keep getting errors when I calibrate the floppy drive.

I first do a reset by clearing and then setting bit 2 in the DOR reg.
Then I clear the CCR register to set the drive for 500kb/s operation.
The function floppy_fix_drive_data() sets up function 0x03 with appropriate (i think) timings for the drive.
Then when I get to the recalibration function, I get errors from the check_interrupt_status function. It fails all 4 times with the same issues.

Here's the code for the critical parts, if you want to see more just ask.

Code: Select all

#define base_address        0x03f0
#define DOR_register        0x03f2
#define status_register     0x03f4
#define data_register       0x03f5
#define CCR_register        0x03f7

/* -- DOR Register Bits -- */
#define DR0     0x01
#define DR1     0x02
#define REST    0x04
#define DMA     0x08
#define MOTA    0x10
#define MOTB    0x20
#define MOTC    0x40
#define MATD    0x80

/* -- Main Status Register Bits -- */
#define ACTA    0x01
#define ACTB    0x02
#define ACTC    0x04
#define ACTD    0x08
#define BUSY    0x10
#define NDMA    0x20
#define DIO     0x40
#define MRQ     0x80

void wait_for_data()
{
    int timeout = 1000;
    while((inportb(status_register) & BUSY) != 0)
    {if(timeout){timeout--;wait(5);}else{break;}}
    if(!timeout){printf("fdc - wait_for_data timeout! \n");}
}

unsigned short floppy_check_interrupt_status()
{
    unsigned short ret_val = 0;
    while(1)
    {
        floppy_write_cmd(0x08);
        wait_for_data();
        ret_val = ((read_controller() << 8) & 0xFF00);
        if((ret_val & 0xFF00) != 0x8000)
        {
            wait_for_data();
            ret_val |= (read_controller() & 0xFF);
            break;
        }
    }
    printf("fdc - interrupt_status: %x \n", ret_val);
    return ret_val;
}

void floppy_recalibrate()
{
    int timeout = 4;
    turn_floppy_motor_on();
    
    while(timeout--)
    {
        floppy_write_cmd(0x07); // recalibrate cmd
        floppy_write_cmd(0x00);
        if((floppy_check_interrupt_status() & 0x1000) == 0){break;} // check the UC bit in ST0
    }
    turn_floppy_motor_off();
}

void floppy_fix_drive_data()
{
    turn_floppy_motor_on();
    floppy_write_cmd(0x03); // fix drive data cmd
    floppy_write_cmd(0x8f); /* steprate = 8ms, unload time = 240ms */
    floppy_write_cmd(0x0B); /* load time = 10ms, no-DMA = 1 */
    
    int timeout = 1000;
    while((inportb(status_register) & BUSY) != 0 || (inportb(DOR_register) & REST) == 0)
    {if(timeout){timeout--;wait(1);}else{break;}}
    if(!timeout){printf("fdc - fix_drive_data timeout! \n");}
    turn_floppy_motor_off();
}

void floppy_reset()
{ 
    outportb(DOR_register, 0x00);
    outportb(DOR_register, REST);
    
    int timeout = 1000;
    while((inportb(status_register) & BUSY) != 0 || (inportb(DOR_register) & REST) == 0)
    {if(timeout){timeout--;wait(5);}else{break;}}
    if(!timeout){printf("fdc - reset timeout! \n");}
    
    outportb(CCR_register, 0x00);   // 500kbits/s transfer rate
    
    floppy_fix_drive_data();
    floppy_recalibrate();
    floppy_check_drive_status();
}
in the end I get a bunch of "fdc - interrupt_status: 0x7000 " (ST0 = 0x70, CYL = 0x00)

any help is appreciated.

Re: floppy driver problems.

Posted: Tue Sep 16, 2008 7:33 pm
by cr2
Please list your #defines.

Re: floppy driver problems.

Posted: Tue Sep 16, 2008 8:08 pm
by 01000101
ok, the orig post has been updated with the defines.

Re: floppy driver problems.

Posted: Tue Sep 16, 2008 8:33 pm
by cr2
try using interrupts instead of polling.

Re: floppy driver problems.

Posted: Tue Sep 16, 2008 10:16 pm
by 01000101
I could... except my entire OS is polling based, so that's not the best solution for me. Any actual ideas as to why the above code is failing the way it is?

Re: floppy driver problems.

Posted: Wed Sep 17, 2008 12:52 am
by Stevo14
The main thing that I see is that when you clear and reset the DOR, you are not setting the DMAGATE bit (bit 3). So it should look like:

Code: Select all

outportb(DOR_register, 0x00);
outportb(DOR_register, REST | DMA);//set bits 2 and 3
From the data sheet:
82077AA_FloppyControllerDatasheet wrote: If DMAGATE is set low the INT and DRQ outputs are tristated and the DACK and TC inputs are disabled. DMAGATE set high will enable INT DRQ TC and DACK to the system
This could be why you are getting errors.

Re: floppy driver problems.

Posted: Wed Sep 17, 2008 9:45 am
by 01000101
I will test that out in a bit. Thanks.

But what if I don't want to use a DMA channel to conduct transactions? Would I still need to enable that bit regardless?

Re: floppy driver problems.

Posted: Wed Sep 17, 2008 10:00 am
by Dex
You can take a look at my floppy driver, its well commented. http://dex4u.com/demos/FloppyDriver.zip

I use most poling in my OS, but for a floppy driver, its much better to use int and DMA.

Re: floppy driver problems.

Posted: Wed Sep 17, 2008 10:14 am
by 01000101
thanks, I'll check it out.
I guess it's not that hard to implement DMA anyway.

Re: floppy driver problems.

Posted: Wed Sep 17, 2008 10:51 am
by Stevo14
Yes, that was my first intention as well (to stay away from DMA) but I had trouble getting it to read/send me the right amount of data through the fifo. So, in the end I settled for DMA. Either way, I'm pretty sure that DMAGATE needs to be high for both modes (there is a different DMA bit somewhere else that actually makes a difference... can't remember what it is right now. Have a look in the data sheet if you are interested.).

Re: floppy driver problems.

Posted: Thu Sep 18, 2008 9:46 am
by Dex
I had the same idea when i started, i spent a week trying to get poling and nonDMA working.
In the end i changed to int and DMA and it worked fine.
Come to think about it i have not heard of anyone geting non-DMA floppy driver working, does anyone know of one ?.

Re: floppy driver problems.

Posted: Thu Sep 18, 2008 10:05 am
by bontanu
Come to think about it i have not heard of anyone geting non-DMA floppy driver working, does anyone know of one ?.
Yes, I did make it work without DMA but I do know that hardware chip very well.

Initial SOLAR OS floppy driver was non-DMA. However later on I have switched to using DMA.

So, yes it is possible...

Re: floppy driver problems.

Posted: Thu Sep 18, 2008 5:05 pm
by Dex
bontanu wrote:
Come to think about it i have not heard of anyone geting non-DMA floppy driver working, does anyone know of one ?.
Yes, I did make it work without DMA but I do know that hardware chip very well.

Initial SOLAR OS floppy driver was non-DMA. However later on I have switched to using DMA.

So, yes it is possible...
So it is possable, thanks for the info bontanu .

Re: floppy driver problems.

Posted: Thu Sep 18, 2008 5:25 pm
by 01000101
good to know (about the DMA issue).

as far as my floppy driver... I must be making a very stupid mistake as I am getting interrupt statuses of 0x08 (not ready) and timeouts.

Code: Select all

void wait_for_controller_to_send_byte()
{
    unsigned int timeout = 1000;
    while(timeout--)
    {
        if((inportb(status_register) & 0xC0) == 0x80){return;}
        else{wait(240);}
    }
    printf("fdc - wait_for_controller_to_send_byte timeout! \n");
}

void wait_for_controller_to_get_byte()
{
    unsigned int timeout = 1000;
    while(timeout--)
    {
        if((inportb(status_register) & 0xC0) == 0xC0){return;}
        else{wait(240);}
    }
    printf("fdc - wait_for_controller_to_get_byte timeout! \n");
}

void floppy_send_byte(unsigned char data)
{
    wait_for_controller_to_send_byte();
    outportb(data_register, data);
}

unsigned char floppy_get_byte()
{
    wait_for_controller_to_get_byte();
    return inportb(data_register);
}

void wait_for_interrupt()
{
    unsigned int timeout = 100;
    while(timeout--)
    {
        floppy_send_byte(0x08);
        st0 = floppy_get_byte();
        cyl = floppy_get_byte();
        if(!(st0 & 0x80))
        {
            printf("fdc - interrupt: %x | %x \n", st0, cyl);
            return;
        }
        wait(5);
    }
    printf("fdc - interrupt timeout! \n");
}

void floppy_reset()
{
    floppy_motor_status = 0;
    st0 = st3 = cyl = 0;
    
    printf("fdc - resetting. \n");
    outportb(DOR_register, 0x00);       // Start Reset, DMA
    wait(250);
    outportb(DOR_register, 0x0C);       // Finish Reset, DMA
    wait(250);
    wait_for_interrupt();
    
    outportb(CCR_register, 0x00);       // 500Kb/s mode
    wait(250);
    
    printf("fdc - specify cmd. \n");
    floppy_send_byte(0x03);             // specify cmd
    floppy_send_byte(0xDF);             // SRT = 8ms, HUT = 240ms
    floppy_send_byte(0x02);             // HLT = 10ms, ND = 0
}
here, I get wait_for_controller_to_send_byte timeouts and invalid interrupt status returns (0x08). should I be waiting longer/shorter inbetween reset commands?

Re: floppy driver problems.

Posted: Fri Sep 19, 2008 12:25 am
by Stevo14
Hmm... Well, I noticed several other things that are different between what you have and what my floppy driver has.

First,
I can see that you are not issuing 4 "sense interrupt" commands to the drive after you program the data rate and before the specify command. According to the data sheet, the are required. Here is how I do it:

Code: Select all

for(i = 0; i < 4; i++)
{
    fdc_send_command(fd, FDC_SENSE_INTERRUPT);
    fdc_get_data(fd, &st0);
    fdc_get_data(fd, &cyl);
}
You can then optionally send the configure command before the specify command in order to configure the fifo, enable polling (not sure what this does exactly), and turn on implied seeks.

Code: Select all

//configure the drive
fdc_send_command(fd,FDC_CONFIGURE);
fdc_send_data(fd, 0x00);//this parameter is defined as all zeros for some reason
unsigned char config_bits = 
//                    7      6         5                 4          3   2   1   0
//the bits here are:| 0 |   EIS   |  EFIFO          |   POLL     | FIFO threshold |
                         (0 << 6) | (0 << 5)        | (1 << 4)   | 15;
//               No Implied Seeks | Enable the FIFO | No Polling | Large FIFO buffer |
fdc_send_data(fd, config_bits);
fdc_send_data(fd, 0);//pretrk
Other than that, your "wait for data" routines seem fine.

And for the legally paranoid among us, I release the above bits of code into the public domain. Do as you please with them.