The making of my 32bit Floppy Driver..

Question about which tools to use, bugs, the best way to implement a function, etc should go here. Don't forget to see if your question is answered in the wiki first! When in doubt post here.
User avatar
Neo
Member
Member
Posts: 842
Joined: Wed Oct 18, 2006 9:01 am

The making of my 32bit Floppy Driver..

Post 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?
Only Human
Curufir

Re:The making of my 32bit Floppy Driver..

Post by Curufir »

Code: Select all

fdc_flag=1;

...

while(fdc_flag);
Is equivalent to:

Code: Select all

while(1);
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?
User avatar
Candy
Member
Member
Posts: 3882
Joined: Tue Oct 17, 2006 11:33 pm
Location: Eindhoven

Re:The making of my 32bit Floppy Driver..

Post by Candy »

Curufir wrote:

Code: Select all

fdc_flag=1;

...

while(fdc_flag);
Is equivalent to:

Code: Select all

while(1);
Only if fdc_flag is not volatile.
Curufir

Re:The making of my 32bit Floppy Driver..

Post 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.
User avatar
Neo
Member
Member
Posts: 842
Joined: Wed Oct 18, 2006 9:01 am

Re:The making of my 32bit Floppy Driver..

Post 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. :)
Only Human
User avatar
Neo
Member
Member
Posts: 842
Joined: Wed Oct 18, 2006 9:01 am

Re:The making of my 32bit Floppy Driver..

Post 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??
Only Human
mr. xsism

Re:The making of my 32bit Floppy Driver..

Post 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;)
User avatar
Neo
Member
Member
Posts: 842
Joined: Wed Oct 18, 2006 9:01 am

Re:The making of my 32bit Floppy Driver..

Post by Neo »

i sure the ints work as they get called with the other commands that ive implemented such as the 'calib_drive()' etc..
Only Human
User avatar
Neo
Member
Member
Posts: 842
Joined: Wed Oct 18, 2006 9:01 am

Re:The making of my 32bit Floppy Driver..

Post 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.
Only Human
User avatar
Neo
Member
Member
Posts: 842
Joined: Wed Oct 18, 2006 9:01 am

Re:The making of my 32bit Floppy Driver..

Post 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?
Only Human
User avatar
Solar
Member
Member
Posts: 7615
Joined: Thu Nov 16, 2006 12:01 pm
Location: Germany
Contact:

Re:The making of my 32bit Floppy Driver..

Post by Solar »

Hit me with a stick but I can't find the point where fdc_flag is declared volatile? ???
Every good solution is obvious once you've found it.
User avatar
Neo
Member
Member
Posts: 842
Joined: Wed Oct 18, 2006 9:01 am

Re:The making of my 32bit Floppy Driver..

Post 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>
Only Human
mr. xsism

Re:The making of my 32bit Floppy Driver..

Post 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.
mr. xsism

Re:The making of my 32bit Floppy Driver..

Post 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??
User avatar
Solar
Member
Member
Posts: 7615
Joined: Thu Nov 16, 2006 12:01 pm
Location: Germany
Contact:

Re:The making of my 32bit Floppy Driver..

Post 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?
Every good solution is obvious once you've found it.
Post Reply