floppy driver

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
User avatar
xyjamepa
Member
Member
Posts: 397
Joined: Fri Sep 29, 2006 8:59 am

floppy driver

Post by xyjamepa »

Hi...
I've been tring to write floppy disk driver for my os,
I'm using the DMA to transfer data from/to memory my floppy IRQ at 0x26 since I remapped the PIC.
Any way I've got these MSG from virtual pc not from bochs,unfortunately
bochs gave me nothing,no wrong messages no good working ,nothing at all it just went in a coma.

any try to read or write I get :

invalid command
end of cylinder
wanted 512B/sector got 128

and here's my whole floppy driver:



Thanx.
Attachments
fdc.txt
(6.53 KiB) Downloaded 110 times
Gizmo
Member
Member
Posts: 41
Joined: Fri Aug 03, 2007 3:41 am

Post by Gizmo »

Bochs has a text file that it creates where all errors are logged, so if boch's freezes that where you look.
User avatar
xyjamepa
Member
Member
Posts: 397
Joined: Fri Sep 29, 2006 8:59 am

Post by xyjamepa »

Hi...
for now I can use virtual pc so my problem not with bochs,
would you please take a look at my floppy driver and see what's
wrong with it,

Code: Select all

void write_cmd(int base,char cmd)
{ 
 outportb(base+FLOPPY_FIFO, cmd);
}

unsigned char read_data(int base)
{
 inportb(base + FLOPPY_FIFO);
}

void check_interrupt(int base,int *st0,int *cyl)
{
 write_cmd(base,CMD_SENSE_INTERRUPT);
 *st0=read_data(base);   //get the fdc status
 *cyl=read_data(base);
}

void motor(int base,int onoff)
{
 int i;
 if(onoff==1)	
  {
   outportb(base + FLOPPY_DOR, 0x1c); //turn motor on 
   delay(300); //sleep for 300 millie s
   motor_on=1;
  }  
 else if(onoff==0)
  {
   outportb(base + FLOPPY_DOR,0x0c);
   motor_on=0;
  }
}

Code: Select all

int calibrate(int base)
{
 int i,st0,cyl = -1;
 motor(base,1);		//turn motor on
 for(i=0;i<10;i++)
  {
   write_cmd(base,CMD_RECALIBRATE);
   write_cmd(base,0);
   irq_wait(floppy_irq);
   check_interrupt(base,&st0,&cyl);
   if(st0 & 0xC0)
     {
      printf("error\n");
      continue;
     }
   if(cyl==0)
    {
     motor(base,0);	//turn motor off
     return 0;
    }
  }
 motor(base,0);
 return -1;
}

void fdc_handler(struct regs *r)
{
 outportb(0x20,0x26);
}

int floppy_reset(int base)
{
 printf("floppy init...");

 irq_install_handler(0x26, fdc_handler);

 outportb(base + FLOPPY_DOR, 0x00);//disable controller
 outportb(base + FLOPPY_DOR, 0x0C);//enable controller
 irq_wait(floppy_irq);
 {
  int st0,cyl;
  check_interrupt(base,&st0,&cyl);
 }
 //set transfer speed 500kb/s
 outportb(base + FLOPPY_CCR, 0x00);

 write_cmd(base, CMD_SPECIFY);
 write_cmd(base, 0xDF);
 write_cmd(base,0x02);
 
 if(calibrate(base)==0)
  printf("[Done]\n");
}

int seek(int base,unsigned cyli,int head)
{
 int i;
 unsigned st0,cyl = -1;
 motor(base,1); 	//turn motor on
 for(i=0;i<10;i++)
  {
    write_cmd(base, CMD_SEEK);
    write_cmd(base,head << 2);
    write_cmd(base,cyli);
    
    irq_wait(floppy_irq);
    check_interrupt(base,&st0,&cyl);
    if(st0 & 0xC0)
     printf("error\n");
    if(cyl==cyli)	//does it match the right cylinder
      {
       motor(base,0);
       return 0;
      }
  }
 motor(base,0);
 return -1;
}

Code: Select all

void dma_init(floppy_dir dir)
{
 union
  {
   unsigned char b[4];
   unsigned long l;
  }a, c;  //address and length
 a.l=(unsigned) &floppy_dmabuf;
 c.l=(unsigned) floppy_dmalen - 1;
 if((a.l >> 24) || (c.l >> 16) || (((a.l&0xffff)+c.l)>>16)) 
  { 
    printf("floppy_dma_init: static buffer problem\n"); 
  } 
 
 unsigned char mode;
 switch(dir)
  {
    case floppy_dir_read: mode = 0x46;break;//read
    case floppy_dir_write: mode= 0x4A;break;//write
  }

 outportb(0x0A,0x06);   //mask channel 2
 outportb(0x0C,0xFF);   //reset flip-flop
 outportb(0x04,a.b[0]); //address low byte
 outportb(0x04,a.b[1]);	//        high
 outportb(0x81,a.b[2]); //externel page register
 
 outportb(0x0C,0xFF);	//reset flip-flop
 outportb(0x05,c.b[0]);	//count low byte
 outportb(0x05,c.b[1]); //      high
 outportb(0x0B,mode);	//set mode
 outportb(0x0A,0x02);	//unmask channel 2
}

int do_track(int base,unsigned cyl,floppy_dir dir)
{
 unsigned char cmd;
 static const int flags = 0xC0;
 switch(dir)
  {
    case  floppy_dir_read:
      cmd = CMD_READ_DATA | flags ;
      break;
    case floppy_dir_write:
      cmd = CMD_WRITE_DATA | flags ;
      break;
  }
 if(seek(base,cyl,0)) return -1;
 if(seek(base,cyl,1)) return -1;
 int i;
 for(i=0;i<20;i++)
  {
   motor(base,1);
   dma_init(dir);
   delay(100); 		//sleep 100ms
   write_cmd(base, cmd);
   write_cmd(base, 0);
   write_cmd(base, cyl); //head and drive
   write_cmd(base, 0);   //first head 
   write_cmd(base, 1);   //first sector
   write_cmd(base, 2);	 //128*2^x=512
   write_cmd(base, 18);  //sector per track
   write_cmd(base, 0x1B);//length of GAP 3
   write_cmd(base, 0xFF);
   
   irq_wait(floppy_irq); 

   unsigned char st0, st1, st2, rcy, rhe, rse, bps; 
        st0 = read_data(base); 
        st1 = read_data(base); 
        st2 = read_data(base); 
        /* 
         * These are cylinder/head/sector values, updated with some 
         * rather bizarre logic, that I would like to understand. 
         * 
         */ 
        rcy = read_data(base); 
        rhe = read_data(base); 
        rse = read_data(base); 
        // bytes per sector, should be what we programmed in 
        bps = read_data(base); 

        int error = 0; 

        if(st0 & 0xC0) { 
            static const char * status[] = 
            { 0, "error", "invalid command", "drive not ready" }; 
            printf("floppy_do_sector: status = %s\n", status[st0 >> 6]); 
            error = 1; 
        } 
        if(st1 & 0x80) { 
            printf("floppy_do_sector: end of cylinder\n"); 
            error = 1; 
        } 
        if(st0 & 0x08) { 
            printf("floppy_do_sector: drive not ready\n"); 
            error = 1; 
        } 
        if(st1 & 0x20) { 
            printf("floppy_do_sector: CRC error\n"); 
            error = 1; 
        } 
        if(st1 & 0x10) { 
            printf("floppy_do_sector: controller timeout\n"); 
            error = 1; 
        } 
        if(st1 & 0x04) { 
            printf("floppy_do_sector: no data found\n"); 
            error = 1; 
        } 
        if((st1|st2) & 0x01) { 
            printf("floppy_do_sector: no address mark found\n"); 
            error = 1; 
        } 
        if(st2 & 0x40) { 
            printf("floppy_do_sector: deleted address mark\n"); 
            error = 1; 
        } 
        if(st2 & 0x20) { 
            printf("floppy_do_sector: CRC error in data\n"); 
            error = 1; 
        } 
        if(st2 & 0x10) { 
            printf("floppy_do_sector: wrong cylinder\n"); 
            error = 1; 
        } 
        if(st2 & 0x04) { 
            printf("floppy_do_sector: uPD765 sector not found\n"); 
            error = 1; 
        } 
        if(st2 & 0x02) { 
            printf("floppy_do_sector: bad cylinder\n"); 
            error = 1; 
        } 
        if(bps != 0x2) { 
            printf("floppy_do_sector: wanted 512B/sector, got %d\n", (1<<(bps+7))); 
            error = 1; 
        } 
        if(st1 & 0x02) { 
            printf("floppy_do_sector: not writable\n"); 
            error = 2; 
        } 

        if(!error) { 
            motor(base, 0); 
            return 0; 
        } 
        if(error > 1) { 
            printf("floppy_do_sector: not retrying..\n"); 
            motor(base, 0); 
            return -2; 
        } 

    printf("floppy_do_sector: 20 retries exhausted\n"); 
    motor(base, 0); 
    return -1; 

 
  }
 motor(base,0);
 return -1;
}
Thanx.
frank
Member
Member
Posts: 729
Joined: Sat Dec 30, 2006 2:31 pm
Location: East Coast, USA

Post by frank »

Maybe you should try functions like these for your send and receive byte functions. It has support for a timeout that you can remove.

Code: Select all

BYTE Floppy_Drive::Get_Byte( void )
{
    BYTE msr = 0;

    // reset the timer
    timer1 = 0;

    // reset the error
    error = DISK_OK;

    while( timer1 < 5000 )
    {
        // get the MSR
        msr = inportb( 0x3F4 );

        // get the 2 msb bits
        msr = msr & 0xC0;

        // check to see if data is ready
        if ( msr == 0xC0 )
        {
            // return the data
            return( inportb( 0x3F5 ) );

        } // end if

    } // end while

    // timeout error
    error = DISK_TIMEOUT_ERROR;

    // return error
    return( 0xFF );

} // end Get_Byte

////////////////////////////////////////////////////////////////////////////////

void Floppy_Drive::Send_Byte( BYTE data )
{
    BYTE msr = 0;

    // reset the timer
    timer1 = 0;

    // reset the error
    error = DISK_OK;

    while( timer1 < 5000 )
    {
        // get the MSR
        msr = inportb( 0x3F4 );

        // get the 2 msb bits
        msr = msr & 0xC0;

        // check to see if the drive is ready to accept data
        if ( msr == 0x80 )
        {
            // send the data to the floppy controller
            outportb( 0x3F5, data );

            // end control
            return;

        } // end if

    } // end while

    // timeout error
    error = DISK_TIMEOUT_ERROR;

} // end Send_Byte
User avatar
xyjamepa
Member
Member
Posts: 397
Joined: Fri Sep 29, 2006 8:59 am

Post by xyjamepa »

Hi...
First of all now bochs is interactive with me again,
Now I know there's wrong with sendbyte and/or getbyte and/or check_interrupt
sendbyte and getbyte work fine witout any error but when I use check_interrupt I get read byte: time out

so here are this functions,would you guys take a look at it:

Code: Select all

int sendbyte(int base,char cmd)
{
 byte msr=0;int tmo=0;
 for(tmo=0;tmo<128;tmo++)
  {
   msr=inportb(base + FLOPPY_MSR);
   if((msr & 0xC0)==0x80)
     { 
       outportb(base + FLOPPY_FIFO);
       return 1;
     }
    inportb(0x80);  //delay
  }
 printf("write cmd :time out\n");
 return -1;
}

unsigned char getbyte(int base)
{
 byte msr=0;int tmo;
 for(tmo=0;tmo<128;tmo++)
  {
    msr=inportb(base + FLOPPY_MSR);
    if((msr & 0xD0)==0xD0)
     {
      return inportb(base + FLOPPY_FIFO);
     }
    inportb(0x80);//delay
  }
 printf("read byte time out\n");
 return -1;
}

void check_interrupt(int base,int *st0,int *cyl)
{
 sendbyte(base,CMD_SENSE_INTERRUPT);
 *st0=getbyte(base);
 *cyl=getbyte(base);
}
Thanx.
User avatar
JamesM
Member
Member
Posts: 2935
Joined: Tue Jul 10, 2007 5:27 am
Location: York, United Kingdom
Contact:

Post by JamesM »

This does seem like you're abusing the forum as a sort of remote, many-headed debugging tool...

Not that I mind helping, but you just seem to be working it out on your own just fine, I don't see why you need any help. Debugging practice is good.
User avatar
xyjamepa
Member
Member
Posts: 397
Joined: Fri Sep 29, 2006 8:59 am

Post by xyjamepa »

One more note:
In function check_interrupt if I didn't read st0 or I didn't read cyl
everything works fine this mean I can only read on of them st0 or cyl
when I read them both I get read time out.
User avatar
xyjamepa
Member
Member
Posts: 397
Joined: Fri Sep 29, 2006 8:59 am

Post by xyjamepa »

When we want to reset the controller we disable it
and then enable it this will generate an interrupt from the controller
which in my case 0x26 (after remapping PIC) after that we send
CMD_SENSE_INTERRUPT=0x8 which will reset the interrupt.
We can determine the source of the interrupt via ST0 regs,if it's value
was 0x80 this means no interrupt pending,but my irq_wait gives me
0x26 was fired!!!!!!,doesn't this mean irq 0x26 pending?
pcmattman
Member
Member
Posts: 2566
Joined: Sun Jan 14, 2007 9:15 pm
Libera.chat IRC: miselin
Location: Sydney, Australia (I come from a land down under!)
Contact:

Post by pcmattman »

By the way, all global variables or variables that could change unexpectedly should have the "volatile" keyword, eg.

Code: Select all

volatile int timer_ticks;
frank
Member
Member
Posts: 729
Joined: Sat Dec 30, 2006 2:31 pm
Location: East Coast, USA

Post by frank »

Have you seen this flowchart from the Intel manual? You can get the Intel manual from here
Attachments
flowchart.jpg
flowchart.jpg (29.38 KiB) Viewed 1429 times
Post Reply