OSDev.org

The Place to Start for Operating System Developers
It is currently Thu Mar 23, 2017 12:25 pm

All times are UTC - 6 hours




Post new topic Reply to topic  [ 6 posts ] 
Author Message
 Post subject: Floppy Transfers Without DMA [solved]
PostPosted: Thu Jun 19, 2008 9:47 am 
Offline
Member
Member
User avatar

Joined: Fri Mar 07, 2008 3:40 am
Posts: 179
Location: Arad, Romania
I'm trying to avoid building DMA into my kernel. It can be loaded as a module later when my kernel implements multitasking. So for now all hard drive transfers are in PIO mode. I would also like to make this the case for my floppy driver. I've followed the floppy tutorial on this forum up to the point where it initializes DMA and starts the transfer. At this point I picked up the manual and started reading about non-DMA transfers. Supposedly (if I read correctly) you just have to send the CHS information after a read command and then read a byte (or two, I'm not sure) after each interrupt.

Here is the read function in it's entirety:
Code:
int fdc_read(fdc_drive_t *fd, unsigned char *data, unsigned int sector, unsigned int offset, unsigned int length)
{
   if(!fdc_motor_on(fd))
      return 0;

   //check if a disk is in the drive
   unsigned char disk_not_changed = inportb(fd->ports.digital_input) & 0x80;
   if(disk_not_changed)
   {
      write_string("DNC");
      //this is gaurenteed to change the disk if it exists
      if(!fdc_seek(fd, 79))
      {
         write_string(" failed seek! ");
         return 0;
      }
      if(!fdc_seek(fd, 0))
      {
         write_string(" failed seek! ");
         return 0;
      }
   }
   disk_not_changed = inportb(fd->ports.digital_input) & 0x80;
   if(disk_not_changed)
   {   
      write_string(" No disk in drive. ");
      //there is no disk in the drive
      return 0;
   }

   if(!fdc_seek(fd, sector))
   {
      write_string(" failed seek! ");
      return 0;
   }

   //send the read command
   fdc_send_command(fd, FDC_READ_DATA);
   //fdc_send_data(fd, fd->index | fd->current_head << 2);   //head and drive
   //fdc_send_data(fd, fd->current_cylinder);
   //fdc_send_data(fd, fd->current_head);
   //fdc_send_data(fd, fd->current_sector);
   //fdc_send_data(fd, 2);                  // bytes per sector (2 = 512)
   //fdc_send_data(fd, fd->current_sector + 1);   // "end of track" the final sector of this track
   //fdc_send_data(fd, 0x1B);               //GAP3 length
   //fdc_send_data(fd, 0xFF);               //data length (0xFF because bytes per sector != 0)

   // first read status information
   unsigned char st0, st1, st2, rcy, rhe, rse, bps;
   fdc_get_data(fd, &st0);
   write_hex(st0);
halt();
   fdc_get_data(fd, &st1);
   fdc_get_data(fd, &st2);
   /*
    * These are cylinder/head/sector values, updated with some
    * rather bizarre logic, that I would like to understand.
    *
    */
   fdc_get_data(fd, &rcy);
   fdc_get_data(fd, &rhe);
   fdc_get_data(fd, &rse);
   // bytes per sector, should be what we programmed in
   fdc_get_data(fd, &bps);

   //get the data
   int i = 0; unsigned char *tmp = data;
   for(i = 0; i < 512; i++)
   {
      fdc_wait_interrupt(fd);
      fdc_get_data(fd, tmp);
      write_hex(*tmp);
      tmp++;
   }
   
   if(!fdc_motor_off(fd))
      return 0;

   return 1;
}

The problem is that the controller returns 0x80 (Invalid Command) immediately after the read command is sent (it happens no matter if the CHS sending code is commented or not). Have I done something horribly wrong?

_________________
~[Fluidium]~


Last edited by Stevo14 on Sat Jun 21, 2008 2:54 am, edited 1 time in total.

Top
 Profile  
 
 Post subject: Re: Floppy Transfers Without DMA
PostPosted: Thu Jun 19, 2008 3:36 pm 
Offline
Member
Member
User avatar

Joined: Wed Feb 07, 2007 1:45 pm
Posts: 1401
Location: Eugene, OR, US
I have not done PIO floppy stuff yet, but my initial guess is that you cannot send the read command until AFTER you have set up the CHS address. The default sector is probably 0, which is illegal.

Also I'm worried about the way you calculate one CHS value: fd->index | fd->current_head << 2
-- are you sure the precedence of that calculation is right?


Top
 Profile  
 
 Post subject: Re: Floppy Transfers Without DMA
PostPosted: Fri Jun 20, 2008 12:25 am 
Offline
Member
Member
User avatar

Joined: Fri Mar 07, 2008 3:40 am
Posts: 179
Location: Arad, Romania
bewing wrote:
I have not done PIO floppy stuff yet, but my initial guess is that you cannot send the read command until AFTER you have set up the CHS address.

Well that would have been my intuitive guess also but both the manual and the tutorial say differently.

bewing wrote:
The default sector is probably 0, which is illegal.

I never though about this, I'll make sure that it's not zero.

bewing wrote:
Also I'm worried about the way you calculate one CHS value: fd->index | fd->current_head << 2
-- are you sure the precedence of that calculation is right?

No, I'm not sure if that calculation is correct, that is part of why I asked here. :) fd->index is just the drive number (0, 1, 2, or 3) and fd->current_head << 2 is supposed to correctly set the head bit. I'll be sure to check this also.

_________________
~[Fluidium]~


Top
 Profile  
 
 Post subject: Re: Floppy Transfers Without DMA
PostPosted: Fri Jun 20, 2008 5:07 am 
Offline
Member
Member
User avatar

Joined: Wed Feb 07, 2007 1:45 pm
Posts: 1401
Location: Eugene, OR, US
Guess I'm not much help then. :D -- But when you uncomment the CHS stuff, at least be sure to use parenthesis.

Quote:
d->index is just the drive number (0, 1, 2, or 3) and fd->current_head << 2 is supposed to correctly set the head bit.


Means: fd->index | (fd->current_head << 2)


Top
 Profile  
 
 Post subject: Re: Floppy Transfers Without DMA
PostPosted: Fri Jun 20, 2008 9:06 am 
Offline
Member
Member
User avatar

Joined: Fri Mar 07, 2008 3:40 am
Posts: 179
Location: Arad, Romania
bewing wrote:
Guess I'm not much help then. :D

Well, it's better than no help at all. :wink:

Stevo14 wrote:
bewing wrote:
The default sector is probably 0, which is illegal.

I never though about this, I'll make sure that it's not zero.

I've checked. fd->current_sector equals 1 just before it is sent to the floppy controller.

bewing wrote:
Means: fd->index | (fd->current_head << 2)

This doesn't help either. :(

I also checked to see if the controller has any error bits set before I send the read command and the controller reports no errors until I send the read command.

I suspect that this line is probably at fault:
Code:
fdc_send_data(fd, fd->current_sector + 1);   // "end of track" the final sector of this track

I have really no idea what is supposed to be sent, except that the manual calls it "end of track".

_________________
~[Fluidium]~


Top
 Profile  
 
 Post subject: Re: Floppy Transfers Without DMA
PostPosted: Sat Jun 21, 2008 12:43 am 
Offline
Member
Member
User avatar

Joined: Fri Mar 07, 2008 3:40 am
Posts: 179
Location: Arad, Romania
Ok, this is stupid... I forgot to set the "NO-DMA" bit in the specify command. #-o But I also needed to set the "MFM mode selector" bit in the read command in order for Qemu to accept it. Anyways, PIO mode works now. Yay! :D

EDIT: The final working read function:
Code:
int fdc_read(fdc_drive_t *fd, unsigned char *data, unsigned int sector, unsigned int offset, unsigned int length)
{
   unsigned char st0, st1, st2, rcy, rhe, rse, bps, cyl;

   if(!fdc_motor_on(fd))
      return 0;

   //check if a disk is in the drive
   unsigned char disk_not_changed = inportb(fd->ports.digital_input) & 0x80;
   if(disk_not_changed)
   {
      //write_string("DNC");
      //this is gaurenteed to change the disk if it exists
      if(!fdc_seek(fd, 79))
      {
         write_string(" failed seek! ");
         return 0;
      }
      if(!fdc_seek(fd, 0))
      {
         write_string(" failed seek! ");
         return 0;
      }
   }
   disk_not_changed = inportb(fd->ports.digital_input) & 0x80;
   if(disk_not_changed)
   {   
      write_string(" No disk in drive. ");
      //there is no disk in the drive
      return 0;
   }

   if(!fdc_seek(fd, sector))
   {
      write_string(" failed seek! ");
      return 0;
   }

   //send the read command
   fdc_send_command(fd, FDC_READ_DATA);
   fdc_send_data(fd, fd->index | (fd->current_head << 2));   //head and drive
   fdc_send_data(fd, fd->current_cylinder);
   fdc_send_data(fd, fd->current_head);
   fdc_send_data(fd, fd->current_sector);
   fdc_send_data(fd, 2);                  // bytes per sector (2 = 512)
   fdc_send_data(fd, 1);   // "end of track" the final sector of this track (I have no idea what it does)
   fdc_send_data(fd, 0x1B);               //GAP3 length
   fdc_send_data(fd, 0xFF);               //data length (0xFF because bytes per sector != 0)

   //get the data
   fdc_wait_interrupt(fd);//wait for it...
   //GO!
   int i = 0; unsigned char *tmp = data;
   for(i = 0; i < 512; i++)
   {   
      fdc_get_data(fd, tmp);
      write_hex(*tmp);
      tmp++;
   }

   // read status information
   fdc_get_data(fd, &st0);
   write_hex(st0);
   fdc_get_data(fd, &st1);
   fdc_get_data(fd, &st2);
   /*
    * These are cylinder/head/sector values, updated with some
    * rather bizarre logic, that I would like to understand.
    */
   fdc_get_data(fd, &rcy);
   fdc_get_data(fd, &rhe);
   fdc_get_data(fd, &rse);
   // bytes per sector, should be what we programmed in
   fdc_get_data(fd, &bps);

   if(!fdc_motor_off(fd))
      return 0;

   return 1;
}

_________________
~[Fluidium]~


Top
 Profile  
 
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 6 posts ] 

All times are UTC - 6 hours


Who is online

Users browsing this forum: Bing [Bot] and 7 guests


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Jump to:  
Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group