Page 1 of 3
The making of my 32bit Floppy Driver..
Posted: Sat Feb 28, 2004 12:41 pm
by Neo
I've decided to start work on my 32bit floppy dirver from today and so have started this thread to discuss how I should implement this (I use GCC and NASM under Windows). I just want to have a working driver that can read and write disks(multitasking etc can come later)
I have the documents at
debs.future.easyspace.com/Programming/Hardware/FDC/floppy.html as well as some from
www.osdever.net
After reading i've decided that the first function to write would be the power_on of the FDC (obviously) so i implemented this with a simple
Code: Select all
void power_on()
{
outb(FDCA_BASE+DOR,0x1C);
delay(500); // a 500 ms delay
calib_drive(); // read on
}
i then wrote a FDC IRQ handler which does nothing more than change a 'flag' variable.(INTs are working)
Code: Select all
void FDCHandler(void)
{
kprintf("\nFloppy IRQ ");
fdc_flag=!fdc_flag;???// fdc_flag is a volatile BYTE
}
The next function i wanted to implement was the calibrate_drive because every FDC has to be calibrated as soon as powered on.
this however needed some other small routines such as waiting for the FDC etc.. So i wrote the following(in NASM)
Code: Select all
_FDC_cmd_ready:
.cont:
mov???dx,FDCA_BASE+MSR
in???al,dx
and???al,0xC0
cmp???al,0x80
jne???.cont
retn
The calibrate function was then
Code: Select all
void calib_drive(void)
{
BYTE st0=-1,cyl=-1;
do{
fdc_flag=1;
kprintf("\nCalibrating Drive..");
FDC_cmd_ready();
outb(FDCA_BASE+DR,CALIBRATE_DRIVE);
outb(FDCA_BASE+DR,0);
while(fdc_flag);
chk_int_status(&st0,&cyl);??????// this is below
kprintf("\nst0=%d,cyl=%d",st0,cyl);
}while((st0 & 0x10)); // until UC bit is reset
}
on reading i saw that the calibrate_drive generates an interrupt and this can be checked with the 'check_int_status' command, so i wrote this as shown
Code: Select all
void chk_int_status(BYTE *st0,BYTE *cyl)
{
kprintf("\nChecking int status..");
FDC_cmd_ready();
outb(FDCA_BASE+DR,CHK_INT_STATUS);
*st0=inb(FDCA_BASE+DR);???
*cyl=inb(FDCA_BASE+DR);
}
I then called the power_on() function from the kernel, it printed its message as well as the calib_drive() message but thats it. It got into an infinte loop after this. So what is wrong here?
Re:The making of my 32bit Floppy Driver..
Posted: Sat Feb 28, 2004 2:04 pm
by Curufir
Is equivalent to:
Which would be where the infinite loop comes in. I guess this means that your interrupt is never being called. You did unmask the fdc IRQ didn't you?
Re:The making of my 32bit Floppy Driver..
Posted: Sat Feb 28, 2004 2:10 pm
by Candy
Curufir wrote:
Is equivalent to:
Only if fdc_flag is not volatile.
Re:The making of my 32bit Floppy Driver..
Posted: Sat Feb 28, 2004 2:36 pm
by Curufir
Hehe, I was just working through things. I doubt there was any need to point out the loop, was just getting it clear in my head.
Since he says that the message from the calib_drive routine is printed, but doesn't mention the one for the IRQ my guess is this is where the infinite loop occurs.
Re:The making of my 32bit Floppy Driver..
Posted: Sun Feb 29, 2004 2:37 am
by Neo
I finally got this intial stuff working. I didnt know that we had to wait before
each byte was sent to the FDC anyway i did this and the thing worked but gave me the same results it was only then thta irealised that we had to also wait before reading each byte from the FDC. Anyway i have these functions working now. The wait functions are
Code: Select all
_FDC_cmd_ready:
push dx
.cont:
mov dx,FDCA_BASE+MSR
in al,dx
and al,0xC0
cmp al,0x80
jne .cont
pop dx
retn
_FDC_data_ready:
push dx
.cont:
mov dx,FDCA_BASE+MSR
in al,dx
and al,0xD0
cmp al,0xD0
jne .cont
pop dx
retn
The rest of the corrected code is here
Code: Select all
void FDCHandler(void)
{
kprintf("\nFloppy IRQ ");
fdc_flag=!fdc_flag;
}
void powerup_floppy(void)
{
kprintf("\nPowering FDC..");
outb(FDCA_BASE+DOR,0x1C);
delay(500);
calib_drive();
}
void calib_drive(void)
{
BYTE st0=-1,cyl=-1;
do{
fdc_flag=1;
kprintf("\nCalibrating Drive..");
send_cmd(CALIBRATE_DRIVE);
send_cmd(0);
while(fdc_flag); // wait for an interrupt
chk_int_status(&st0,&cyl);
kprintf("\nst0=%x,cyl=%x",st0,cyl);
}while((st0 & 0x10));
}
void chk_int_status(BYTE *st0,BYTE *cyl)
{
send_cmd(CHK_INT_STATUS);
FDC_data_ready();
*st0=inb(FDCA_BASE+DR);
FDC_data_ready();
*cyl=inb(FDCA_BASE+DR);
}
void chk_drive_status(void)
{
BYTE st3=0;
kprintf("\nChecking Drive Status..");
send_cmd(CHK_DRIVE_STATUS);
send_cmd(0);
FDC_data_ready();
st3=inb(FDCA_BASE+DR);
kprintf("\nST3=%x",st3);
}
I've also added a chk_drive_status() which also works fine now.
I next tried adding a seek/park_head function as shown
Code: Select all
void park_head(BYTE cylinder)
{
BYTE st0=-1,cyl=-1;
kprintf("\nParking head to 0x%x",cylinder);
fdc_flag=1;
send_cmd(PARK_HEAD);
send_cmd(0);
send_cmd(cylinder);
while(fdc_flag==1);
chk_int_status(&st0,&cyl);
kprintf("\nst0=%x,cyl=%x",st0,cyl);
}
This just prints the message given and then stalls. No IRQ fires. do we have to wait for an IRQ or just read the DR?
And thanks for your replies.
Re:The making of my 32bit Floppy Driver..
Posted: Sun Feb 29, 2004 11:17 am
by Neo
i just realised that the thing works when i dont try waiting for an interrupt. But I tried positiong the head over cylinder 1 (as my code above shows) but the check_int_status() gives me a cylinder value of 0 on a real PC and 1(the correct answer) in BOCHS.
Do i have to delay for a while before reading i tried with 10ms but this too stalled.
What is the real procedure to seek/park a FDC head?
This command has no result phase. To verify successful completion of the command, it is necessary to check the head position immediately after completion of the command, using the check interrupt status command.
the doc says this about the see/park head command. does this mean that a int is fired after completion of the command? how else do i know that the command is completed? Is there any other doc for this floppy stuff??
Re:The making of my 32bit Floppy Driver..
Posted: Sun Feb 29, 2004 3:29 pm
by mr. xsism
make sure that your floppyy IRQ is set to fire(IRQ2 IIRC) and that you install the interrupt handler to the correct corresponding interrupt descriptor.
I assume you already sti enabled interrupts(but just in case;)
Re:The making of my 32bit Floppy Driver..
Posted: Sun Feb 29, 2004 7:16 pm
by Neo
i sure the ints work as they get called with the other commands that ive implemented such as the 'calib_drive()' etc..
Re:The making of my 32bit Floppy Driver..
Posted: Mon Mar 01, 2004 2:43 am
by Neo
Crumbs! I must be one of the dumb'est guys out here. Do ya know what was wrong with my code?
"I WAS'NT ACKNOWLEDGING THE INT ( outb(0x20,0x20) )". I can't stop kicking myself for this <neo kicks himself a few more times..>. Anyway as i wanted this thread to be more of a sort of helper to the others like me who are starting out on floppy drivers, i've (swallowed my pride and) posted the corrected handler up here.
Thanks xsism (you made me go check my handler code and find this).
Code: Select all
_FDCHandler:
ISR_HEAD
???call???_FDC_CHandler
???mov???al,0x20
???out???0x20,al
ISR_TAIL
iret
As you can see the handler is an ASM stub that calls the C function now.
Re:The making of my 32bit Floppy Driver..
Posted: Mon Mar 01, 2004 11:13 am
by Neo
To reset the primary floppy controller,(in C)
1. write 0x00 to the DIGITAL_OUTPUT_REG of the desired controller
2. write 0x0C to the DIGITAL_OUTPUT_REG of the desired controller
3. wait for an interrupt from the controller
4. check interrupt status (this is function 0x08 of controllers)
5. write 0x00 to the CONFIG_CONTROL_REG
6. configure the drive desired on the controller (function 0x03 of controller)
7. calibrate the drive (function 0x07 of controller)
This comes from "Code Slashers" floppy tutorial. I want to know if this is the correct way to reset a floppy controller when powering-on? right now i use the code shown in my previous posts (i.e just sending 0x1C to the FDC_DOR). It works for now but I still wanted to be sure?
Re:The making of my 32bit Floppy Driver..
Posted: Mon Mar 01, 2004 11:49 am
by Solar
Hit me with a stick but I can't find the point where fdc_flag is declared volatile? ???
Re:The making of my 32bit Floppy Driver..
Posted: Mon Mar 01, 2004 11:53 am
by Neo
in the header file floppy.h along with the constants, #defines etc..
<edit>
I cant seem to wrap my head around the fix-drive-data command. What exactly are the time values i should use for step-rate,head load & unload times. i also cant understand the table for these like what the different columns (1M,500k,300k,250k) and the entries (0-f) mean?? and how they relate to each other.
Also what are the default values.(in hex) and does anyone have some good links to floppy programming. I tried googling but did not come up with good links.
</edit>
Re:The making of my 32bit Floppy Driver..
Posted: Mon Mar 01, 2004 8:56 pm
by mr. xsism
i'm having some probs with my floppy dirver too. It reads FAT and prints correct info out but when i list the FAT dir it doesn't do it. But that's on a real PC, whereas vmware does it fine. What could cause that??
Another really important question: for ISRs, i save and restore all registers, does this even matter? I noticed neo's code just calls the C handler and iret's.
Re:The making of my 32bit Floppy Driver..
Posted: Tue Mar 02, 2004 12:38 am
by mr. xsism
note:
i found that the 1st fdc_read works perfectly but 2nd returns a 'command execution started but terminated abnormally' in ST0 and a 'FDC cannot find sector ID' in ST1. What is the sector ID it cannot find exactly??
Re:The making of my 32bit Floppy Driver..
Posted: Tue Mar 02, 2004 2:38 am
by Solar
On a different tangent... I've been considering to omit floppy drive support alltogether. It's a pain to implement, the last time I used a real floppy for anything meaningful is quite some time since, and even if you do everything right it kills your multitasking due to the brain-dead BIOS-hacking way you have to do it on IA32 architectures.
Is there any good reason to continue supporting floppy drives?