fdc driver doesn't work on a real pc

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.
Post Reply
Zioo

fdc driver doesn't work on a real pc

Post 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);
}
Zioo

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

Post 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(...)..
JoeKayzA

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

Post 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
Zioo

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

Post 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..
Zioo

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

Post 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?
Zioo

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

Post 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
JoeKayzA

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

Post 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
HanzZ

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

Post by HanzZ »

Can you atach your driver on internet? iam newbie and this driver looks pretty... thank you very much
Warrior

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

Post by Warrior »

He's provided most of it already. The rest should be easy to write.
Xardfir

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

Post 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
Slasher

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

Post by Slasher »

I use the same DMA transfer method (Single) in both boch and on real pc. Works fine.
Xardfir

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

Post 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.
Post Reply