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,§or);
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, §or);
block2hts(block+nosectors, &head, &track2, §or);
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);
}