Using floppy disc

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.
Brandon

Re:Using floppy disc

Post by Brandon »

ok, I?ve tried and tried.. I cant find the DBA or the "specify command". this is how far I?ve got

void reset_floppy() {
???out(0x3f2, 0);
???out(0x3f2, 0x0C);
???out(0x3f7, 0);

???wait_for_floppy_irq();
???send_floppy_command(8);

but I cant send the command 4 times (even though I check the MRQ in between). And I cant find the specify command either. The error I get in Bochs when trying to send more than one "check interrupt" command is:
io: 3f5: receiving new comm, old one (08) pending
User avatar
Neo
Member
Member
Posts: 842
Joined: Wed Oct 18, 2006 9:01 am

Re:Using floppy disc

Post by Neo »

Brandon wrote: DPT, CCR? What kinda ports is this, cant find them in the documents..
BDA= Bios Data Area
DPT= disk parameter table
CCR == DIR =digital input register
read the intel manuals
Only Human
User avatar
Neo
Member
Member
Posts: 842
Joined: Wed Oct 18, 2006 9:01 am

Re:Using floppy disc

Post by Neo »

Brandon wrote: The error I get in Bochs when trying to send more than one "check interrupt" command is:
io: 3f5: receiving new comm, old one (08) pending
Are you sending the EOI (End of Interrupt) signal?

your code should look something like this

Code: Select all

void reset_floppy() {
   out(0x3f2, 0);
   out(0x3f2, 0x0C);
   fdc_flag=1;
}

void init_floppy()
{
  int i;
  reset_floppy();
  out(0x3f7,0);

  while(fdc_flag);???// wait till it changes to 0

  for(i=0;i<4;i++) {
    check_int_status();
  }
  specify_FDC();
}
BTW the "Specify command= 0x03".
Only Human
Brandon

Re:Using floppy disc

Post by Brandon »

how should the check_int_status() look like?

And in the code you just wrote, I didnt see the using of the specify command?

and yes, this is my irq handler

void int_38(void)
{
   out(0xA0, 0x20);
   out(0x20, 0x20);
   print("Floppy IRC\n", WHITE_TXT);
   fdc_flag = 1;
}
User avatar
Neo
Member
Member
Posts: 842
Joined: Wed Oct 18, 2006 9:01 am

Re:Using floppy disc

Post by Neo »

are u sure the EOI can be sent that way at the beginning in a C function? anybody knows?
Only Human
beyondsociety

Re:Using floppy disc

Post by beyondsociety »

It can as I have seen chris greise do it in his code. Just to be on the safe side, I use an asm wrapper for my IRQS that sends the End of interrupt (EOI). This way I know the c compiler isnt going to possibly crash my irq_handler code.

I suggest taking a look on the OS faq on how to do this. Hope this helps.
User avatar
Brendan
Member
Member
Posts: 8561
Joined: Sat Jan 15, 2005 12:00 am
Location: At his keyboard!
Contact:

Re:Using floppy disc

Post by Brendan »

Hi,
Neo wrote: are u sure the EOI can be sent that way at the beginning in a C function? anybody knows?
If the device is capable of generating IRQ's with extremely short amounts of time inbetween, then the interrupt handler could interrupt itself and would need to be re-entrant (unless interrupts are completely disabled anyway - e.g. interrupt gate used).

While most devices are slow compared to the CPU, you'd also need to be careful with IRQs that are shared by more than one device - PCI IRQs and serial ports for instance.


Cheers,

Brendan
For all things; perfection is, and will always remain, impossible to achieve in practice. However; by striving for perfection we create things that are as perfect as practically possible. Let the pursuit of perfection be our guide.
Brandon

Re:Using floppy disc

Post by Brandon »

Im pretty sure the IRQ handler works...

Bu the way. How do I read the status registers ST0, ST1 and so on.. cant find them..
User avatar
Neo
Member
Member
Posts: 842
Joined: Wed Oct 18, 2006 9:01 am

Re:Using floppy disc

Post by Neo »

Brandon wrote: and yes, this is my irq handler

void int_38(void)
{
???out(0xA0, 0x20);
???out(0x20, 0x20);
???print("Floppy IRC\n", WHITE_TXT);
???fdc_flag = 1;
}
why the

Code: Select all

out(0xA0,0x20);
I think you need to write a ASM stub that only calls the FDC handler and then sends the EOI, something like this

Code: Select all

FDCHandler:
 ISR_HEAD
   call   FDC_CHandler
   mov   al,0x20
   out   0x20,al
 ISR_TAIL
 iretd
where ISR_HEAD and ISR_TAIL are macros I wrote which expanded are

Code: Select all

%macro ISR_HEAD 0
 cli
 pusha
 push   fs
 push   gs
 push   es
 push   ds
%endmacro

%macro ISR_TAIL 0
 pop   ds
 pop   es
 pop   gs
 pop   fs
 popa
 sti
%endmacro
Actualy i'm not too sure you should send the EOI at the start of the function as you have shown.
Only Human
Brandon

Re:Using floppy disc

Post by Brandon »

Oh thought number 6 was on the slave, silly me..

anyways, I know that the ISR works.. what my problem is to do this things you told me about

"Issue the "Check Interrupt" command 4 times
your almost done now after this"

"Issue the "Specify" command now to set up step rate time etc.."

What is the Check interrupt sposed to do? and how do I do it.. I havent really understood how to use the data register. Do I have to, before sending a command, send how many bytes I will send? and how do I read the data registers.
User avatar
Neo
Member
Member
Posts: 842
Joined: Wed Oct 18, 2006 9:01 am

Re:Using floppy disc

Post by Neo »

Brandon wrote: What is the Check interrupt sposed to do? and how do I do it.. I havent really understood how to use the data register. Do I have to, before sending a command, send how many bytes I will send? and how do I read the data registers.
Yeah i guess i forgot the "Specify" command in that demo code above (I've changed it now)

how have you been sending out commands to the FDC and reading the results so far?
I suggest you read some tutorials on this first (if you haven't so far) because I don't have the time for a detailed explanation.
You have to check that the FDC's DR (Data Reg) is ready to receive your commands before issuing one. This is done by checking the MSR to see if the appropriate bits are set/reset.
Similarly you need to check to see if it is ready to receive data before reading from the DR.

The "Check Interrupt Status" IIRC is also known as the "Sense Interrupt Status" command . Look them up in your manual.
Only Human
Brandon

Re:Using floppy disc

Post by Brandon »

Alright.. this is how I?ve done. When trying to write to the data reg, I read the MRQ and all that. But I havent written anything (dont know if I have to specify how many bytes I will send). The thing I wonder about:

Before I send a command, do I have to send a line with the number of bytes to be sent? Spose I want to send command 3 and 1 argument (if we spose the command requires this). Should I then write
send(2) // Number of bytes comming
send(3)
send(1)

I also use if((in(0x3f4) & 0xC0) == 0xC0) ... to see if Im able to read from the data register. But How do I read the different status registers like ST0 and ST1 from the DR? And, when I issue the "sense command", do I have to read any of those registers in between (except for the MSR)?

Ive tried to find tutorials but the one I?ve found didnt make sense. I know the data register uses a stack, but I dont know how to "pop" the different status registers from it.
distantvoices
Member
Member
Posts: 1600
Joined: Wed Oct 18, 2006 11:59 am
Location: Vienna/Austria
Contact:

Re:Using floppy disc

Post by distantvoices »

@brendan: XOR in c is a '^', iirc.

@brandon: the chip does this as soon as you have performed the read operation on the data register: after in(port) it puts the next value in its internal buffer on the port.

so, you issue a series of in(port) commands, and check for each iteration: is there a value to be fetched? some flag in some status register tells this. If nothing is there to be fetched: exit the loop.
... the osdever formerly known as beyond infinity ...
BlueillusionOS iso image
User avatar
Neo
Member
Member
Posts: 842
Joined: Wed Oct 18, 2006 9:01 am

Re:Using floppy disc

Post by Neo »

Brandon wrote: Before I send a command, do I have to send a line with the number of bytes to be sent? Spose I want to send command 3 and 1 argument (if we spose the command requires this). Should I then write
send(2) // Number of bytes comming
send(3)
send(1)

I also use if((in(0x3f4) & 0xC0) == 0xC0) ... to see if Im able to read from the data register. But How do I read the different status registers like ST0 and ST1 from the DR? And, when I issue the "sense command", do I have to read any of those registers in between (except for the MSR)?

Ive tried to find tutorials but the one I?ve found didnt make sense. I know the data register uses a stack, but I dont know how to "pop" the different status registers from it.
no nothing of that sort, the command itself tells the FDC how manybytes are expected and you need to give it the correct number only, no need to specify how many bytes.
The DR is the only register you need to read bytes from and write commands to. The MSR register should be read before each read/write to the DR to see that the DR is ready to accept or give data.
To check if the FDC is ready to receive commands the code in C is something like this

Code: Select all

void FDC_cmd_ready()
{
  while( (in(0x3F4)&0xC0)!=0x80 );
}
add in a delay if you need. My own code is in asm and is shown below (the above was translated from it).

Code: Select all

FDC_cmd_ready:
 push???dx
.cont:
???mov???dx,FDCA_BASE+MSR ; // 0x3F4
???in???al,dx
???and???al,0xC0
???cmp???al,0x80
???je??? .end
???in???al,0x80 ???; delay
???jne??? .cont
.end:
 pop???dx ; should probably push & pop ax too
 retn
To check if the FDC is ready to be read just replace the 0x80 with 0xC0 in the 'cmp' statement above.

You dont need to pop anything from anywhere to get the resultant bytes. just read the DR consecutively for each byte you expect to receive.
For e.g. consider the "Check Interrupt Status" command it is represented by 0x08 and results in 2 bytes as output which are ST0 and Physical Cylinder Number (PCN).
The steps to be followed in executing this command are
  • Check if the FDC is ready to receive commands and loop while its not (or sleep or something if you have multi-processing working)
  • Write out the byte 0x08 (check int status) to the DR
  • Check if the FDC is ready to be read and loop etc until its not.
  • Now read the DR to get ST0
  • Repeat the previous 2 steps to read in the PCN
HTH
Only Human
Brandon

Re:Using floppy disc

Post by Brandon »

Thank you very much =) I?ll play around with it :) Much clearer now

Edit: This is the code I got right now:

void FDC_cmd_ready(unsigned char code) {
   while((in(0x3F4) & code) == 0);
}

void send_floppy_command(unsigned char command) {
   FDC_cmd_ready(0x80);
   out(0x3f5, command);
}

unsigned char get_floppy_command() {
   FDC_cmd_ready(0xC0);
   return in(0x3f5);
}

void reset_floppy() {
   // Reset the floppy
   out(0x3f2, 0);
   out(0x3f2, 0x0C);

   // Set the data rate = 500 kbps
   out(0x3f7, 0);

   wait_for_floppy_irq();   // Wait for IRC

   int i;
   for(i = 0;i<4;i++) {
   send_floppy_command(0x8); // Send the check interrupt cmd
   get_floppy_command(); // Read the data reg
   get_floppy_command(); // Read the data reg
}

send_floppy_command(3);      // The specify command
send_floppy_command(0); // And the arguments
send_floppy_command(0);
}

I run the function reset_floppy(). Then I send
out(0x3f2, 0x1C);
to start the motor. Then I wait for an IRQ. But that IRQ never occurs. So I suppose there?s something wrong with my reset-code
Post Reply