Floppy Seek Error
Posted: Sun Nov 23, 2008 2:01 pm
Myself and another member are having the same issues with this code:
The issue is that on real-hardware we receive a seek error then a read error. I have hardcoded my spt and heads count values which should be good to go for 1.44 MB disks which is what I am using and it works perfectly in MS VPC. In bochs it moves extremely slow to load and does nothing with no error. On real hardware it seeks then errors. The error is 0xFF when it should be 0x20. The read error returns 0x80, when it should be 0xC0. Can anyone see the problem with this code. I have compared it to many other codes, read countless guides, spent the wiki, spent datasheet, and still nothing could help, so it must be one of those minuet details I always overlook. If someone (with a working on real-hardware fdc driver preferably) could look at my logic and hopefully correct it or enlighten me that would be great. thanks in advance.
Code: Select all
int first;
int second;
int current_track = -1;
short base_used;
volatile int irq6_state = 0;
int motor_on = 0;
int sr0=0;
int pcn=0;
int present = 1; //assume not present
// dma xfer for floppy
void set_dma(unsigned char *buff, short size, int read, int channel)
{
char page = 0;
char mode = 0;
short offset = 0;
if(read)
mode = 0x48 + (char)channel;
else
mode = 0x44 + (char)channel;
page = (char)((int)buff >> 16);
offset = (short)((int)buff & 0xFFFF);
size--;
cli();
outb(maskport[channel], (0x04 | channel)); // mask channel
outb(clearport[channel], 0x00); // stop trans
outb(modeport[channel], mode); // type of trans
outb(addrport[channel], LOW_BYTE(offset)); // send address
outb(addrport[channel], HI_BYTE(offset)); // send address
outb(pageport[channel], page); // send page
outb(countport[channel], LOW_BYTE(size)); // send size
outb(countport[channel], HI_BYTE(size)); // send size
outb(maskport[channel], channel); // unmask channel
sti();
}
void get_floppy_type()
{
unsigned char data;
outb(0x70, 0x10);
data = inb(0x71);
first = data >> 4;
second = data & 0xF;
}
void fdc_handler()
{
irq6_state = 1;
outb(0x20,0x20);
}
void start_motor()
{
outb((base_used + 0x2), 0x1C);
motor_on = 1;
}
void stop_motor()
{
outb((base_used + 0x2), 0x00);
motor_on = 0;
}
/* from intel manual */
void sendbyte(char byte)
{
volatile int msr;
int tmo;
for(tmo = 0; tmo < 128; tmo++)
{
msr = inb((base_used + 0x04));
if ((msr & 0xC0) == 0x80)
{
outb((base_used + 0x05), byte);
return;
}
inb(0x80);
}
}
/* from intel manual */
int getbyte()
{
volatile int msr;
int tmo;
for (tmo = 0; tmo < 128; tmo++)
{
msr = inb((base_used + 0x04));
if ((msr & 0xd0) == 0xd0)
return inb((base_used + 0x05));
inb(0x80);
}
return -1;
}
void wait_irq6()
{
while(irq6_state == 0);
irq6_state = 0;
}
int fdc_seek(char track)
{
if(current_track == track)
return 0;
//sendbyte(0x07); //calibrate
//sendbyte(0x00);
sendbyte(0x0F); //seek cmd
sendbyte(0x00);
sendbyte(track);
wait_irq6();
sendbyte(0x08); /* Send sense interrupt status command. */
sr0 = getbyte(); /* Read status register 0. */
pcn = getbyte(); /* Read present cylinder number. */
if (!FDC_SEEK_END(sr0))
printf(0x0f,1,10,"Seek Error");
return 1;
current_track = track;
printf(0x0f,1,10,"Seek OK");
return 0;
}
void fdc_reset()
{
outb((base_used + 0x02), 0); // stop everything
motor_on = 0;
outb((base_used + 0x04), 0); // data rate (500K/s)
outb((base_used + 0x02), 0x0C); // restart ints
wait_irq6();
unsigned char j;
for (j = 0; j < 4; j++)
{
sendbyte(0x08); /* Send sense intr status cmd. */
if (j == 0)
{
sr0 = getbyte(); /* Read status register 0. */
pcn = getbyte(); /* Read present cyl number. */
continue;
}
(void) getbyte(); /* Discard status register 0. */
(void) getbyte(); /* Discard present cylinder number. */
}
sendbyte(0x03); // timing
sendbyte(0xDF); // timing
sendbyte(0x02); // timing
timer_wait_ms(1);
inb(0x80);
fdc_seek(1);
sendbyte(0x07); //calibrate
sendbyte(0x00);
}
void init_floppy()
{
base_used = 0x3F0;
get_floppy_type();
fdc_reset();
}
void block2hts(int block,int *head,int *track,int *sector)
{
*head = (block % (18 * 2)) / (18);
*track = block / (18 * 2);
*sector = block % 18 + 1;
}
int floppy_read_sector(unsigned char *buf, int block)
{
int head, track, sector;
block2hts(block,&head,&track,§or);
start_motor();
outb((base_used + 0x7), 0);
set_dma(0x00000000, 512, 0, 2);
fdc_seek(track);
timer_wait_ms(1);
sendbyte(0xE6);
sendbyte((char)head << 2);
sendbyte((char)track);
sendbyte((char)head);
sendbyte((char)sector);
sendbyte(0x02); //sector size
sendbyte(0x12); //sectors per track
sendbyte(0x1B);
sendbyte(0xFF);
wait_irq6();
(void)getbyte();
(void)getbyte();
(void)getbyte();
(void)getbyte();
(void)getbyte();
(void)getbyte();
(void)getbyte();
if(!FDC_NORM_TERM(sr0))
{
printf(0x0f,1,6,"Read Error (0x%x)",sr0);
sendbyte(0x07); //re-calibrate
sendbyte(0x00);
} else {
memcpy((unsigned int *)buf, (unsigned int *)0x00000000, 128);
}
stop_motor();
return 0;
}
void fdc_install(void)
{
irq_install_handler(6,fdc_handler);
}