Page 1 of 1

Floppy Disk Driver...

Posted: Fri Nov 24, 2006 9:57 am
by CorN_Sk8
hello progammers,

what the steps do make a floppy disk driver ?
what i need to know to make it ?
somebody have a tutorial step by step ?

thanks..

obs:
i was using C language and my kernel is in PMode...

Posted: Fri Nov 24, 2006 10:54 am
by CorN_Sk8
My initial code to the driver is...

Code: Select all

/* 
 * Sistema Operacional BrOS
 * CodeD by CorN_Sk8
 * Kernel em C
 */
 
#include "include\floppy.h"
#include "include\system.h"
#include "include\video.h"
#include "include\in_out.h"

int fdc_flag=0;

void reset_floppy(int device){
     char devs[] = {0x1C, 0x2D, 0x4E, 0x8F};
     
     irq_install_handler(6, fdc_handler());
     
     outportb(0x3f7, 0x00);
     outportb(0x3f2, 0x0c);     
     
     fdc_flag=1;
}

void init_floppy(int device){
     
     reset_floppy(device);
     while(fdc_flag);
     
         
}

void fdc_handler(struct regs *r){
     fdc_flag = 0;
}
thanks..

Posted: Fri Nov 24, 2006 11:26 am
by Dex
Maybe some of the doc's on bubach site, may help: http://bos.asmhackers.net/docs/floppy/

Posted: Fri Nov 24, 2006 12:11 pm
by CorN_Sk8
i read some tutorials, but i need help to understand...
my atual code is:

Code: Select all

/* 
 * Sistema Operacional BrOS
 * CodeD by CorN_Sk8
 * Kernel em C
 */
 
#include "include\floppy.h"
#include "include\system.h"
#include "include\video.h"
#include "include\in_out.h"

int fdc_flag=0;

void fdc_wait(){
     fdc_flag=1;
     while(fdc_flag) ;
}

void fdc_sendbyte(int b){
     outportb(FDC_DATA, b);   
}

int reset_floppy(int device){
     char devs[] = {0x1C, 0x2D, 0x4E, 0x8F};
     
     outportb(FDC_DOR, 0x00);
     
     outportb(FDC_CCR, 0x00);
     outportb(FDC_DOR, 0x0C);
     
     fdc_wait();
     
  return 1;
}

void fdc_handler(struct regs *r){
     fdc_flag = 0;
}

int init_floppy(int device){
    int flag;
    
     // Instal IRQ
     irq_install_handler(6, fdc_handler);
     
     // reset floppy driver          
     flag = reset_floppy(device);
     if(flag == 0){
         printf("\nError on init floppy driver in stage of [Reset].\n");
         return 0;
     }
         
}
what the next step ?

Posted: Fri Nov 24, 2006 1:05 pm
by Brynet-Inc

Code: Select all

int reset_floppy(int device){
     char devs[] = {0x1C, 0x2D, 0x4E, 0x8F};
     
     outportb(FDC_DOR, 0x00);
     
     outportb(FDC_CCR, 0x00);
     outportb(FDC_DOR, 0x0C);
     
     fdc_wait();
     
  return 1;
}

int init_floppy(int device){
    int flag;
    
     // Instal IRQ
     irq_install_handler(6, fdc_handler);
     
     // reset floppy driver          
     flag = reset_floppy(device);
     if(flag == 0){
         printf("\nError on init floppy driver in stage of [Reset].\n");
         return 0;
     }
         
}
I'm confused about that device variable, both init_floppy and reset_floppy seem to declare it, but apparently it's not used for anything.. :roll:

Posted: Fri Nov 24, 2006 1:19 pm
by CorN_Sk8

Code: Select all

/* 
 * Sistema Operacional BrOS
 * CodeD by CorN_Sk8
 * Kernel em C
 */
 
#include "include\floppy.h"
#include "include\system.h"
#include "include\video.h"
#include "include\in_out.h"

int fdc_flag            = 0;
int ST0                 = 0;
int fdc_status[7]       = { 0 };
int fdc_track           = 0xFF;
int fdc_motor           = 0;
int fdc_motor_countdown = 0;
int fdc_device          = 0;
int *fdc_buffer;

static int fdc_wait_until_ready( void )
{
	int counter, status;

	for( counter = 0; counter < 10000; counter++ )
	{
		status = inportb( FDC_MSR );
		if( status & MSR_READY )
		{
			return( status );
		}
	}
	return( -1 );
}

static int fdc_getbyte()
{
	int msr;

	msr = fdc_wait_until_ready();
	if( msr < 0 )
	{
		return( -1 );
	}
	msr &= MSR_DIR | MSR_READY | MSR_BUSY | MSR_DMA;
	if( msr == (MSR_DIR | MSR_READY | MSR_BUSY) )
	{
		return( inportb(FDC_DATA) );
	}
	return( -1 );
}

static int fdc_sendbyte( int b )
{
	int msr;

	msr = fdc_wait_until_ready();
	if( msr < 0 )
	{
		return( -1 );
	}
	if( (msr & (MSR_READY | MSR_DIR | MSR_DMA)) == MSR_READY )
	{
		outportb( FDC_DATA, b );
		return( 0 );
	}
	return( -1 );
}

int fdc_wait(int sensei){
     int i;
     
     fdc_flag=1;
     while(fdc_flag) ;
     
     i = 0;
     while( (i < 7) && (inportb(FDC_MSR) & MSR_BUSY) ){
         fdc_status[ i++ ] = fdc_getbyte();
     }
     
     if( sensei ){
         fdc_sendbyte( CMD_SENSEI );
         ST0 = fdc_getbyte();
         fdc_track = fdc_getbyte();
     } 
     return 1;    
}

void fdc_motor_on(){
     
     char devs[] = {0x1C, 0x2D, 0x4E, 0x8F};   
     
     if(!fdc_motor){
         outportb( FDC_DOR, devs[fdc_device] );
         timer_wait(100);
         fdc_motor = 1;                    
     }  
}

void fdc_motor_off(){
     
     if(fdc_motor){
     		outportb( FDC_DOR, 0x0C );
		    fdc_motor = 1;                   
     }
}

static void fdc_recalibrate()
{
	// Turn the motor on.
	fdc_motor_on();

	// Send recalibrate command.
	fdc_sendbyte( CMD_RECAL );
	fdc_sendbyte( 0 );

	// Wait until recalibrate command is finished.
	fdc_wait( 1 );

	// Turn the motor off.
	fdc_motor_off();
}

int __fdc_seek( int track ){

	// If already there return.
	if( fdc_track == track )
	{
		return( 0 );
	}

	// Turn the motor on.
	fdc_motor_on();

	// Send seek command.
	fdc_sendbyte( CMD_SEEK );
	fdc_sendbyte( 0 );
	fdc_sendbyte( track );

	// Wait until seek is finished.
	if( fdc_wait(1) == 0 )
	{
		// Timeout!
		fdc_motor_off();
		printf("ERRO");
		return 0;
	}

	// Let the head settle for 15msec.
	timer_wait(50);

	// Turn off the motor.
	fdc_motor_off();

	// Check if seek worked.
	if( (ST0 == 0x20) && (fdc_track == track) )
	{
		return( 0 );
	}
	return 0;
}

int reset_floppy(int device){
    
    fdc_device = device;        

    outportb(FDC_DOR, 0x00);
     
    outportb(FDC_CCR, 0x00);
    outportb(FDC_DOR, 0x0C);
     
    fdc_wait(1);
     
    fdc_sendbyte( CMD_SPECIFY );
    fdc_sendbyte( 0xdf );
    fdc_sendbyte( 0x02 );  
    
    __fdc_seek( 1 );   
    fdc_recalibrate();
     
    return 1;
}

void fdc_handler(struct regs *r){
     fdc_flag = 0;
}

int init_floppy(int device){
    int flag;
    int ret;
    int v;
    
    // Instal IRQ
    irq_install_handler(6, fdc_handler);
     
    // reset floppy driver          
    flag = reset_floppy(device);
    if(flag == 0){
        printf("\nError on init floppy driver in stage of [Reset].\n");
        return 0;
    }
     
     fdc_sendbyte( CMD_VERSION );
     v = fdc_getbyte();

     switch ( v ) {
         case 0xFF: printf(" [ controller not found ]");
         ret = 0;
         break;

		     case 0x80: printf(" [ NEC controller ]");
         ret = 1;		     
         break;

		     case 0x81: printf(" [ VMware controller ]");
         ret = 1;		     
         break;

         case 0x90: printf(" [ enhanced controller ]");
         ret = 1;         
         break;

		     default: printf(" [ unknown controller [%d] ]", v);
         ret = 1;		     
         break;
    }    

    return 1; 
         
}
now i need write FDC_READ ...

Posted: Sat Feb 24, 2007 5:58 am
by pcmattman
Hmmm... dunno if this is the right place to post but hey, who cares? It's only 3 months old...

I came across this in looking up how to control the floppy drive without DMA... now I can actually reset the drive (and stop it from spinning out of control). This is good. But I still have a problem: how do I actually read sectors? I don't care about writing (yet) but I would like to know how to read them...

Please, no DMA!

Posted: Sat Feb 24, 2007 1:34 pm
by bubach
I think this has code to read a sector without DMA:
http://bos.asmhackers.net/docs/floppy/s ... 6/fdc1.txt

Posted: Sat Feb 24, 2007 5:03 pm
by pcmattman
I'm really confused right now... This is my current floppy driver code:

Code: Select all

#include "mattise.h"

/**** revision 2 ****/

int floppy_flag = 1;

// ports
#define DOR 0x3F2
#define CCR 0x3F7

char* drive_types[6] =	{ "No floppy drive.",
				"360KB 5.25in floppy",
				"1.2MB 5.25in floppy",
				"720KB 3.5in floppy",
				"1.44MB 3.5in floppy",
				"2.88MB 3.5in floppy"
			};

void DetectFloppyDrives()
{
	unsigned char c;
	outportb( 0x70, 0x10 );
	c = inportb( 0x71 );

	unsigned char drive1;
	unsigned char drive2;
	drive1 = c >> 4;
	drive2 = c & 0xF;

	kputs( "Floppy 1: " ); kputs( drive_types[ drive1 ] );
	kputs( "\n" );
	kputs( "Floppy 2: " ); kputs( drive_types[ drive2 ] );
	kputs( "\n" );
}

// floppy acessory functions

void SendByte_FDC( char b )
{
	// byte storage
	unsigned char a = 0;

	// wait for ready
	while( true )
	{
		// wait a little while
		sleep( 100 );

		// get a byte from the controller
		a = inportb( 0x3F4 );

		// bitwise and
		a &= 0x80;

		// check
		if( a == 0x80 )
			break;
	}

	// wait a bit more
	sleep( 100 );

	// send the byte
	outportb( 0x3F5, b );
}

unsigned char RecByte_FDC()
{
	// two byte length storage areas
	unsigned char a;
	unsigned char b;

	// wait for ready
	while( true )
	{
		// wait a little while
		sleep( 100 );

		// get a byte from the controller
		a = inportb( 0x3F4 );

		// bitwise and
		a &= 0x80;

		// check
		if( a == 0x80 )
			break;
	}

	// get the byte and return it
	b = inportb( 0x3F5 );

	// return to caller
	return b;
}

void Recal()
{
	// recalibrate the floppy drive
	unsigned char res = 0;
	unsigned char cres = 0;

	// main loop - may have to keep recalibrating numerous times
	while( true )
	{
		// send the recalibrate command
		SendByte_FDC( 7 );

		// send 'drive a' indicator
		SendByte_FDC( 0 ); // replace 0 with 1 for b

		// send 'sense interrupt'
		SendByte_FDC( 0x08 );

		// wait for data from controller
		res = RecByte_FDC();

		// play with the byte
		cres = res & 0x80;

		// equal?
		if( cres == 0x80 )
			continue;

		// get another byte
		res = RecByte_FDC();

		// result byte got nothing?
		if( res == 0 )
			break;
	}
}

void SeekTrackSide( unsigned char track, unsigned char side )
{
	// bytes, lots of bytes
	unsigned char a,b,c;

	// do something cool
	while( true ) /* go_and_seek_it_again: */
	{
		// seek command
		SendByte_FDC( 0x0F );

		// send the side
		SendByte_FDC( side * 4 );

		// send the track
		SendByte_FDC( track );

		// sense interrupt
		SendByte_FDC( 0x08 );

		// recieve a byte
		a = RecByte_FDC();

		// bitwise fun
		a &= 0x80;

		// checks
		if( a != 0x80 )
			break;

		// recieve another byte
		a = RecByte_FDC();

		// check
		if( a == track )
			break;
	}
}

void MotorOn()
{
	// turn on the motor
	outportb( DOR, 0x1C );
}

void MotorOff()
{
	// turn off the motor
	outportb( DOR, 0x0 );
}

// floppy IRQ handler
void FloppyHandler( struct regs* r )
{
	// reset the flag, say that we
	// have handled the interrupt
	// lets the initialization return
	floppy_flag = 0;
}

// reset the floppy disk
void ResetFloppy()
{
	// reset the drive
	outportb( DOR, 0x00 );
	outportb( DOR, 0x0C );
	outportb( CCR, 0x00 );

	// set the flag
	floppy_flag = 1;

	// wait for the interrupt...
	while( floppy_flag == 1 );
}

// initializes the floppy
void InitFloppy()
{
	// install the handler
	irq_install_handler( 6, FloppyHandler );
}
How can I read the sectors I want from the disk?

General timer

Posted: Fri Jul 27, 2007 3:32 am
by enrico_granata
While looking at Teemu Voipio's floppy disk driver, I incurred into a call:

Code: Select all

timer_sleep(1); // sleep 10 ms 
How does he do it? I mean, the timer interrupt has a granularity of around 1/18th second. How can he sleep for 1/100th second?

Is there a way to calibrate the clock to trigger at a different interval, or is there some other time-measuring device with a higher precision :?:

Posted: Fri Jul 27, 2007 3:58 am
by JamesM
bran wrote:The timer will divide it's input clock of 1.19MHz (1193180Hz) by the number you give it in the data register to figure out how many times per second to fire the signal for that channel
The default is for the divisor register to be set so it fires at 18.222Hz. If you set it to 1, you should be able to get interrupts up to 1.19MHz.

Impressive bumping, btw :P

JamesM

Posted: Fri Jul 27, 2007 4:01 am
by enrico_granata
:P I guess this is all detailed in the Wiki about the pit (which I should probably have looked at before posting), right?
I'm gonna give a look at that before bothering again :oops:

Posted: Sat Jul 28, 2007 5:58 am
by enrico_granata
I am trying to understand the floppy disk driver by comparing the tutorial at http://debs.future.easyspace.com/Progra ... loppy.html with Teemu Voipio's driver..but I can't seem to figure out this piece of code (commands being sent to the controller for actual read/write):

Code: Select all

        floppy_write_cmd(base, cmd);  // set above for current direction 
        floppy_write_cmd(base, 0);    // 0:0:0:0:0:HD:US1:US0 = head and drive
        floppy_write_cmd(base, cyl);  // cylinder 
        floppy_write_cmd(base, 0);    // first head (should match with above) 
        floppy_write_cmd(base, 1);    // first sector, strangely counts from 1 
        floppy_write_cmd(base, 2);    // bytes/sector, 128*2^x (x=2 -> 512) 
Shouldn't this be 512? Why is it just 2? :shock:

Code: Select all

        floppy_write_cmd(base, 18);   // number of tracks to operate on 
If I write 1 in here, will it just read or write 1 sector?

Code: Select all

        floppy_write_cmd(base, 0x1b); // GAP3 length, 27 is default for 3.5" 
        floppy_write_cmd(base, 0xff); // data length (0xff if B/S != 0) 
Thanks for any hints!

Posted: Sat Jul 28, 2007 8:01 am
by jnc100
enrico granata wrote:Shouldn't this be 512? Why is it just 2?
82077aa datasheet
See table 5-2, page 24.

Regards,
John