Page 1 of 1

My FDC driver wont send me an interrupt

Posted: Tue Feb 26, 2008 2:28 pm
by lukem95
I have tried implementing a decent FDC driver using the resources on the wiki (mainly mystrans tutorial).

But i can't even reset the FDC as it wont send an interrupt, i even waited 10 minutes for one (whilst doing something else... im not THAT sad).

Code: Select all


static volatile int floppy_base = 0x03f0;
static volatile int floppy_number_drives;
static volatile int floppy_recieved_int = 1;
static volatile int floppy_motor_ticks = 0;
static volatile int floppy_motor_state = 0; 

//Floppy Registers
enum floppy_registers {
   FLOPPY_DOR  = 2,  // digital output register
   FLOPPY_MSR  = 4,  // master status register, read only
   FLOPPY_FIFO = 5,  // data FIFO, in DMA operation for commands
   FLOPPY_CCR  = 7   // configuration control register, write only
}; 

//Floppy Commands
enum floppy_commands {
   FLOPPY_CMD_SPECIFY = 3,            // SPECIFY
   FLOPPY_CMD_WRITE_DATA = 5,         // WRITE DATA
   FLOPPY_CMD_READ_DATA = 6,          // READ DATA
   FLOPPY_CMD_RECALIBRATE = 7,        // RECALIBRATE
   FLOPPY_CMD_SENSE_INTERRUPT = 8,    // SENSE INTERRUPT
   FLOPPY_CMD_SEEK = 15,              // SEEK
}; 

//Floppy Motor States
enum { floppy_motor_off = 0, floppy_motor_on, floppy_motor_wait }; 

int initialise_floppy_driver()
{
      outb(0x70, 0x10);
      unsigned char drives = inb(0x71);
      int a,b;
      a = drives >> 4;
      b = drives & 0xf;
      
      //Check how many floppy drives are installed
      if(a != 4)
      //None. dont waste our time
           return 1;
      if(b != 4)
           floppy_number_drives = 1;
      else
           floppy_number_drives = 2;
           
      kprintf("We got %d Floppy(s)!\n",floppy_number_drives);
      
      //Init to primary floppy
      floppy_base = 0x03f0;
      
      register_interrupt_handler(6, &floppy_handler);
      kprintf("IRQ6 set up\n");

      floppy_reset(floppy_base);
      
      return 0;
}

void floppy_wait_for_interrupt()
{
     floppy_recieved_int = 1;
     while(floppy_recieved_int);
     return;
}



int floppy_reset(int base) 
{
    outb((base + FLOPPY_DOR), 0x00); // disable controller
    timer_wait(2);                   // 20 microsecond wait
    outb((base + FLOPPY_DOR), 0x0C); // enable controller
    
    kprintf("waiting for interrupt..\n");
    floppy_wait_for_interrupt(); // sleep until interrupt occurs
    kprintf("we g0tz in interrupt from FDC.\n");
    
    int st0, cyl; // These value must be read, but can be ignored
    floppy_check_interrupt(base, &st0, &cyl);
    
    // set transfer speed 500kb/s
    outb((base + FLOPPY_CCR), 0x00);

    // These value are for 1.44mb floppy
    floppy_write_cmd(base, FLOPPY_CMD_SPECIFY);
    floppy_write_cmd(base, 0xdf); /* steprate = 3ms, unload time = 240ms */
    floppy_write_cmd(base, 0x02); /* load time = 16ms, no-DMA = 0 */

    // This is incase of failure
    kprintf("lets calibrate the FDC\n");
    if(floppy_calibrate(base)) return -1;
    kprintf("braaap\n");
    return 0;
}

... The rest of the code is the same
sorry about the length of that snippet, most of the code is the same as in the tutorial, but i thought it would be easier all in one place, rather than having to check back all the time.

the random kprintf's are to see where the code gets to.

it just waits for the interrupt and it never arrives =\

oh... i also get

Code: Select all

00017031251d[FDD  ] write access to port 03f2, value=00
00017031251d[FDD  ] DMA and interrupt capabilities disabled
00017031251d[FDD  ] io_write: digital output register
00017031251d[FDD  ]   motor on, drive1 = 0
00017031251d[FDD  ]   motor on, drive0 = 0
00017031251d[FDD  ]   dma_and_interrupt_enable=00
00017031251d[FDD  ]   normal_operation=00
00017031251d[FDD  ]   drive_select=00
00017507829d[FDD  ] write access to port 03f2, value=0c
00017507829d[FDD  ] io_write: digital output register
00017507829d[FDD  ]   motor on, drive1 = 0
00017507829d[FDD  ]   motor on, drive0 = 0
00017507829d[FDD  ]   dma_and_interrupt_enable=08
00017507829d[FDD  ]   normal_operation=04
00017507829d[FDD  ]   drive_select=00
00017508329i[FDD  ] controller reset in software
from bochs. This says that it has been successfully been reset, and the other data looks right, but i don't receive an interrupt.

Posted: Tue Feb 26, 2008 2:57 pm
by lukem95
^_^ i got it working, but there are no interrupts fired at all during my code, i just put a one second wait where an interrupt should be and it seems to work ok now.

im still curious as to why it didnt fire the int though...

Posted: Tue Feb 26, 2008 3:05 pm
by AJ
Hi,

I had this once in Bochs too but never really tried to figure it out. Thinking about it, though, I wonder if the interrupt is triggered instantly (with Bochs being an emulator rather than real hardware)?

In this case, the interrupt fires before you enter your wait loop and the FD driver thinks that an interrupt never came.

Cheers,
Adam

Posted: Wed Feb 27, 2008 12:00 pm
by lukem95
thats an interesting thought, ill try it on actual hardware.

i shouldv done it last night, but i have no floppy on my dev pc, so i have to make an .iso, burn to cd and then boot that into a pc with a floppy and try it there.

this is a lot of effort on a windows box lol. i really should get a linux dev box, but i dont have space for a desktop in my room, and i can't afford to buy a new pc.

Posted: Thu Feb 28, 2008 2:16 am
by JoeKayzA
As mentioned already, it is likely that bochs fires the interrupt immediately after you re-enable the fdc. A more reliable way to handle the interrupt would be to initialize floppy_received_int to zero, have your ISR increment the value each time it is called, and let your wait_for_interrupt() function loop until the value becomes non-zero (and decrement afterwards). This way, you would recognize the interrupt anyway.