Page 1 of 1

fdc driver doesn't work on a real pc

Posted: Thu Oct 06, 2005 10:18 am
by Zioo
Hi..
Now I've manage to write a floppy driver. But it does not work on real computers. Only in emulators and thats not what I want. It does work in qemu and bochs.

If anyone can see whats wrong would I be happy ;) afaik is the error in the fdc_rw function but I cant figure out where. The driver is also not 100% finished.

Code: Select all

void fdc_wait_for_irq()
{
    while(fd_flag==0) ; // loop until interrupt is recived
    fd_flag = 0;  // disable so we are ready for a new interrupt
    fdc_sendbyte(CMD_SENSEI); // send sensi command
    sr0 = fdc_getbyte();  // get sr0
    fdc_track = fdc_getbyte();  // get track
}

void fdc_motoron()
{
    outportb(0x3f2,0x1C); // turn the motor on
    timer_wait(9);    // a 500 ms delay
}

void fdc_motoroff()
{
    outportb(0x3f2,0); // turn the motor off
}


void fdc_handler()
{
    fd_flag = 1; // indicate interrupt is recived
    //puts("IRQ6\n");
}

int fdc_seek(int track)
{
    if (fdc_track == track) return 1;

    fdc_sendbyte(CMD_SEEK); // send actual command bytes
    fdc_sendbyte(0); // send actual command bytes
    fdc_sendbyte(track); // send actual command bytes
    fdc_wait_for_irq(); // wait until seek finished
    timer_wait(1); // now let head settle for 1/18 sec

    if ((sr0 != 0x20) || (fdc_track != track))
       return 0;
    else
       return 1;
}

void fdc_reset()
{
    outportb(FDC_DOR,0); // stop the motor and disable IRQ/DMA
    outportb(FDC_DRS,0); // program data rate (500K/s)
    outportb(FDC_DOR,0x0c); // re-enable interrupts
    fdc_wait_for_irq(); // wait until interrupt is recived
    fdc_sendbyte(CMD_SPECIFY); // specify drive timings (got these off the BIOS)
    fdc_sendbyte(0xdf); // SRT = 3ms, HUT = 240ms
    fdc_sendbyte(0x02); // HLT = 16ms, ND = 0
}

void fdc_recalibrate()
{
    fdc_motoron(); // turn the motor on
    fdc_sendbyte(CMD_RECAL); // send actual command bytes
    fdc_sendbyte(0); // send actual command bytes
    fdc_wait_for_irq(); // wait until interrupt is recived
    fdc_motoroff(); // turn the motor off
}

void block2hts(int block,int *head,int *track,int *sector)
{
   *head = (block % (18 * 2)) / (18);
   *track = block / (18 * 2);
   *sector = block % 18 + 1;
}

int fdc_rw(int block,unsigned char *blockbuff,int read,unsigned long nosectors)
{
    int head,track,sector,tries, copycount = 0;
    unsigned char *p_tbaddr = (char *)0x80000;
    unsigned char *p_blockbuff = blockbuff;

    block2hts(block,&head,&track,&sector);

    fdc_motoron();

    if ((read == 0) && blockbuff) {
       for(copycount=0; copycount<(nosectors*512); copycount++) {
       *p_tbaddr = *p_blockbuff;
        p_blockbuff++;
        p_tbaddr++;
       }
    }

    for (tries = 0;tries < 3;tries++) {
     if (inportb(FDC_DIR) & 0x80) {
         fdc_seek(1);
         fdc_recalibrate();
         fdc_motoroff();
      }

    if (fdc_seek(track) == 0) {
        fdc_motoroff();
        puts("FDC: Error seeking to track\n");
        return 0;
    }

      outportb(FDC_CCR,0);

      if (read == 1) {
          init_dma(2,tbaddr,nosectors*512,0);
          fdc_sendbyte(CMD_READ);
      } else {
          init_dma(2,tbaddr,nosectors*512,1);
          fdc_sendbyte(CMD_WRITE);
      }

      fdc_sendbyte(head << 2);
      fdc_sendbyte(track);
      fdc_sendbyte(head);
      fdc_sendbyte(sector);
      fdc_sendbyte(2);
      fdc_sendbyte(18);
      fdc_sendbyte(0x1b);
      fdc_sendbyte(0xff);
      fdc_wait_for_irq();
      break; // missing check function
    }

    fdc_motoroff();

  if ((read == 1) && blockbuff) {
      p_blockbuff = blockbuff;
      p_tbaddr = (char *) 0x80000;
      for(copycount=0; copycount<(nosectors*512); copycount++) {
       *p_blockbuff = *p_tbaddr;
        p_blockbuff++;
        p_tbaddr++;
      }
   }

    return 0;
}

int fdc_read_block(int block,unsigned char *blockbuff, unsigned long nosectors)
{
    int track=0, sector=0, head=0, track2=0, result=0, loop=0;

    block2hts(block, &head, &track, &sector);
    block2hts(block+nosectors, &head, &track2, &sector);

    if(track!=track2)
    {
        for(loop=0; loop<nosectors; loop++)
                result = fdc_rw(block+loop, blockbuff+(loop*512), 1, 1);
        return result;
    }

   return fdc_rw(block,blockbuff,1,nosectors);
}

void fdc_init()
{
    unsigned char i;
    unmask_irq(6);
    fdc_reset();
    fdc_seek(1);
    fdc_recalibrate();

   fdc_sendbyte(CMD_VERSION);
   i = fdc_getbyte();
   if (i == 0x80)
     puts("NEC765 controller found\n");
   else
     puts("Enhanced controller found\n");

    display_current_dir(1);

    mask_irq(6);
}

Re:fdc driver doesn't work on a real pc

Posted: Thu Oct 06, 2005 11:50 am
by Zioo
I forgot to say that is when i wants to read a sector it only works in a emulator... When i call fdc_read_block(...)..

Re:fdc driver doesn't work on a real pc

Posted: Thu Oct 06, 2005 11:58 am
by JoeKayzA
I had a short look at your code, but I can tell you about two common/typical reasons for this problem, when you go from emulators to real hardware:

Does you wait_for_irq() function work properly? On emulators, reading a sector works with virtually no delay (the data will be at disposal immediately after initiating the read, probably even before you reach 'wait_for_irq()'??), while on real hardware it takes _ages_ to load a floppy sector.

Do you check if a read succeeded? Again, emulators won't produce faulty reads, while real floppies can do. Check the manual for this.

I'll try to find some time to investigate more in your code :)

EDIT: On a sidenote, it would be helpful if you could state some more detail about what's going wrong. Does it triple fault, does it give you random/wrong data, does it freeze?

cheers Joe

Re:fdc driver doesn't work on a real pc

Posted: Thu Oct 06, 2005 12:05 pm
by Zioo
Thanks JoeKayzA :)

Yes your a right doesn't work isn't at good description.. When i read a sector on a real pc i simply don't get any data.. No errors..

Re:fdc driver doesn't work on a real pc

Posted: Sat Oct 08, 2005 8:03 am
by Zioo
When i try to read from the floppy on a real pc i get the "FDC: Error seeking to track" error... But why?

Re:fdc driver doesn't work on a real pc

Posted: Sat Oct 08, 2005 8:11 am
by Zioo
Now I've got it working.. My seek check was bad.. If just ignored the seek error and continued the floppy driver works :D

Re:fdc driver doesn't work on a real pc

Posted: Sat Oct 08, 2005 8:57 am
by JoeKayzA
Zioo wrote: Now I've got it working.. My seek check was bad.. If just ignored the seek error and continued the floppy driver works :D
Congrats! ;)

As I said: real floppies can produce errors, emulated ones don't.

cheers Joe

Re:fdc driver doesn't work on a real pc

Posted: Sat Oct 22, 2005 8:07 am
by HanzZ
Can you atach your driver on internet? iam newbie and this driver looks pretty... thank you very much

Re:fdc driver doesn't work on a real pc

Posted: Sat Oct 22, 2005 5:33 pm
by Warrior
He's provided most of it already. The rest should be easy to write.

Re:fdc driver doesn't work on a real pc

Posted: Mon Oct 24, 2005 7:30 pm
by Xardfir
You might want to check your DMA code.
In BOCHS use Single transfer, on a real PC use demand transfer. Never transfer any more than 64k, never transfer to anything higher than 16Mbytes in PHYSICAL memory.
There is a new DMA page in the OSFAQ, which explains what nasty problems may occur including the fact that 90% of the DMA chip doesn't function correctly in a standard PC (and has not done so in the last 20+ years due to IBM's initial implementation).

http://www.osdev.org/osfaq2/index.php/DMA

Re:fdc driver doesn't work on a real pc

Posted: Tue Oct 25, 2005 6:26 am
by Slasher
I use the same DMA transfer method (Single) in both boch and on real pc. Works fine.

Re:fdc driver doesn't work on a real pc

Posted: Tue Oct 25, 2005 9:57 pm
by Xardfir
Single mode is probably best as it maintains compatilibility with older hardware. Newer FDC controllers actually have buffers like the serial chip FIFO's so they can use demand mode for a bit of extra speed. Still, I doubt, apart from a little caching, the floppy drive is going to get any faster.