Floppy Transfers Without DMA [solved]
Posted: Thu Jun 19, 2008 9:47 am
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:
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?
Here is the read function in it's entirety:
Code: Select all
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;
}