Page 1 of 1
floppy driver
Posted: Sun Aug 12, 2007 1:11 pm
by xyjamepa
Hi...
I've been tring to write floppy disk driver for my os,
I'm using the DMA to transfer data from/to memory my floppy IRQ at 0x26 since I remapped the PIC.
Any way I've got these MSG from virtual pc not from bochs,unfortunately
bochs gave me nothing,no wrong messages no good working ,nothing at all it just went in a coma.
any try to read or write I get :
invalid command
end of cylinder
wanted 512B/sector got 128
and here's my whole floppy driver:
Thanx.
Posted: Sun Aug 12, 2007 1:17 pm
by Gizmo
Bochs has a text file that it creates where all errors are logged, so if boch's freezes that where you look.
Posted: Mon Aug 13, 2007 2:14 am
by xyjamepa
Hi...
for now I can use virtual pc so my problem not with bochs,
would you please take a look at my floppy driver and see what's
wrong with it,
Code: Select all
void write_cmd(int base,char cmd)
{
outportb(base+FLOPPY_FIFO, cmd);
}
unsigned char read_data(int base)
{
inportb(base + FLOPPY_FIFO);
}
void check_interrupt(int base,int *st0,int *cyl)
{
write_cmd(base,CMD_SENSE_INTERRUPT);
*st0=read_data(base); //get the fdc status
*cyl=read_data(base);
}
void motor(int base,int onoff)
{
int i;
if(onoff==1)
{
outportb(base + FLOPPY_DOR, 0x1c); //turn motor on
delay(300); //sleep for 300 millie s
motor_on=1;
}
else if(onoff==0)
{
outportb(base + FLOPPY_DOR,0x0c);
motor_on=0;
}
}
Code: Select all
int calibrate(int base)
{
int i,st0,cyl = -1;
motor(base,1); //turn motor on
for(i=0;i<10;i++)
{
write_cmd(base,CMD_RECALIBRATE);
write_cmd(base,0);
irq_wait(floppy_irq);
check_interrupt(base,&st0,&cyl);
if(st0 & 0xC0)
{
printf("error\n");
continue;
}
if(cyl==0)
{
motor(base,0); //turn motor off
return 0;
}
}
motor(base,0);
return -1;
}
void fdc_handler(struct regs *r)
{
outportb(0x20,0x26);
}
int floppy_reset(int base)
{
printf("floppy init...");
irq_install_handler(0x26, fdc_handler);
outportb(base + FLOPPY_DOR, 0x00);//disable controller
outportb(base + FLOPPY_DOR, 0x0C);//enable controller
irq_wait(floppy_irq);
{
int st0,cyl;
check_interrupt(base,&st0,&cyl);
}
//set transfer speed 500kb/s
outportb(base + FLOPPY_CCR, 0x00);
write_cmd(base, CMD_SPECIFY);
write_cmd(base, 0xDF);
write_cmd(base,0x02);
if(calibrate(base)==0)
printf("[Done]\n");
}
int seek(int base,unsigned cyli,int head)
{
int i;
unsigned st0,cyl = -1;
motor(base,1); //turn motor on
for(i=0;i<10;i++)
{
write_cmd(base, CMD_SEEK);
write_cmd(base,head << 2);
write_cmd(base,cyli);
irq_wait(floppy_irq);
check_interrupt(base,&st0,&cyl);
if(st0 & 0xC0)
printf("error\n");
if(cyl==cyli) //does it match the right cylinder
{
motor(base,0);
return 0;
}
}
motor(base,0);
return -1;
}
Code: Select all
void dma_init(floppy_dir dir)
{
union
{
unsigned char b[4];
unsigned long l;
}a, c; //address and length
a.l=(unsigned) &floppy_dmabuf;
c.l=(unsigned) floppy_dmalen - 1;
if((a.l >> 24) || (c.l >> 16) || (((a.l&0xffff)+c.l)>>16))
{
printf("floppy_dma_init: static buffer problem\n");
}
unsigned char mode;
switch(dir)
{
case floppy_dir_read: mode = 0x46;break;//read
case floppy_dir_write: mode= 0x4A;break;//write
}
outportb(0x0A,0x06); //mask channel 2
outportb(0x0C,0xFF); //reset flip-flop
outportb(0x04,a.b[0]); //address low byte
outportb(0x04,a.b[1]); // high
outportb(0x81,a.b[2]); //externel page register
outportb(0x0C,0xFF); //reset flip-flop
outportb(0x05,c.b[0]); //count low byte
outportb(0x05,c.b[1]); // high
outportb(0x0B,mode); //set mode
outportb(0x0A,0x02); //unmask channel 2
}
int do_track(int base,unsigned cyl,floppy_dir dir)
{
unsigned char cmd;
static const int flags = 0xC0;
switch(dir)
{
case floppy_dir_read:
cmd = CMD_READ_DATA | flags ;
break;
case floppy_dir_write:
cmd = CMD_WRITE_DATA | flags ;
break;
}
if(seek(base,cyl,0)) return -1;
if(seek(base,cyl,1)) return -1;
int i;
for(i=0;i<20;i++)
{
motor(base,1);
dma_init(dir);
delay(100); //sleep 100ms
write_cmd(base, cmd);
write_cmd(base, 0);
write_cmd(base, cyl); //head and drive
write_cmd(base, 0); //first head
write_cmd(base, 1); //first sector
write_cmd(base, 2); //128*2^x=512
write_cmd(base, 18); //sector per track
write_cmd(base, 0x1B);//length of GAP 3
write_cmd(base, 0xFF);
irq_wait(floppy_irq);
unsigned char st0, st1, st2, rcy, rhe, rse, bps;
st0 = read_data(base);
st1 = read_data(base);
st2 = read_data(base);
/*
* These are cylinder/head/sector values, updated with some
* rather bizarre logic, that I would like to understand.
*
*/
rcy = read_data(base);
rhe = read_data(base);
rse = read_data(base);
// bytes per sector, should be what we programmed in
bps = read_data(base);
int error = 0;
if(st0 & 0xC0) {
static const char * status[] =
{ 0, "error", "invalid command", "drive not ready" };
printf("floppy_do_sector: status = %s\n", status[st0 >> 6]);
error = 1;
}
if(st1 & 0x80) {
printf("floppy_do_sector: end of cylinder\n");
error = 1;
}
if(st0 & 0x08) {
printf("floppy_do_sector: drive not ready\n");
error = 1;
}
if(st1 & 0x20) {
printf("floppy_do_sector: CRC error\n");
error = 1;
}
if(st1 & 0x10) {
printf("floppy_do_sector: controller timeout\n");
error = 1;
}
if(st1 & 0x04) {
printf("floppy_do_sector: no data found\n");
error = 1;
}
if((st1|st2) & 0x01) {
printf("floppy_do_sector: no address mark found\n");
error = 1;
}
if(st2 & 0x40) {
printf("floppy_do_sector: deleted address mark\n");
error = 1;
}
if(st2 & 0x20) {
printf("floppy_do_sector: CRC error in data\n");
error = 1;
}
if(st2 & 0x10) {
printf("floppy_do_sector: wrong cylinder\n");
error = 1;
}
if(st2 & 0x04) {
printf("floppy_do_sector: uPD765 sector not found\n");
error = 1;
}
if(st2 & 0x02) {
printf("floppy_do_sector: bad cylinder\n");
error = 1;
}
if(bps != 0x2) {
printf("floppy_do_sector: wanted 512B/sector, got %d\n", (1<<(bps+7)));
error = 1;
}
if(st1 & 0x02) {
printf("floppy_do_sector: not writable\n");
error = 2;
}
if(!error) {
motor(base, 0);
return 0;
}
if(error > 1) {
printf("floppy_do_sector: not retrying..\n");
motor(base, 0);
return -2;
}
printf("floppy_do_sector: 20 retries exhausted\n");
motor(base, 0);
return -1;
}
motor(base,0);
return -1;
}
Thanx.
Posted: Mon Aug 13, 2007 4:14 pm
by frank
Maybe you should try functions like these for your send and receive byte functions. It has support for a timeout that you can remove.
Code: Select all
BYTE Floppy_Drive::Get_Byte( void )
{
BYTE msr = 0;
// reset the timer
timer1 = 0;
// reset the error
error = DISK_OK;
while( timer1 < 5000 )
{
// get the MSR
msr = inportb( 0x3F4 );
// get the 2 msb bits
msr = msr & 0xC0;
// check to see if data is ready
if ( msr == 0xC0 )
{
// return the data
return( inportb( 0x3F5 ) );
} // end if
} // end while
// timeout error
error = DISK_TIMEOUT_ERROR;
// return error
return( 0xFF );
} // end Get_Byte
////////////////////////////////////////////////////////////////////////////////
void Floppy_Drive::Send_Byte( BYTE data )
{
BYTE msr = 0;
// reset the timer
timer1 = 0;
// reset the error
error = DISK_OK;
while( timer1 < 5000 )
{
// get the MSR
msr = inportb( 0x3F4 );
// get the 2 msb bits
msr = msr & 0xC0;
// check to see if the drive is ready to accept data
if ( msr == 0x80 )
{
// send the data to the floppy controller
outportb( 0x3F5, data );
// end control
return;
} // end if
} // end while
// timeout error
error = DISK_TIMEOUT_ERROR;
} // end Send_Byte
Posted: Tue Aug 14, 2007 5:12 am
by xyjamepa
Hi...
First of all now bochs is interactive with me again,
Now I know there's wrong with sendbyte and/or getbyte and/or check_interrupt
sendbyte and getbyte work fine witout any error but when I use check_interrupt I get read byte: time out
so here are this functions,would you guys take a look at it:
Code: Select all
int sendbyte(int base,char cmd)
{
byte msr=0;int tmo=0;
for(tmo=0;tmo<128;tmo++)
{
msr=inportb(base + FLOPPY_MSR);
if((msr & 0xC0)==0x80)
{
outportb(base + FLOPPY_FIFO);
return 1;
}
inportb(0x80); //delay
}
printf("write cmd :time out\n");
return -1;
}
unsigned char getbyte(int base)
{
byte msr=0;int tmo;
for(tmo=0;tmo<128;tmo++)
{
msr=inportb(base + FLOPPY_MSR);
if((msr & 0xD0)==0xD0)
{
return inportb(base + FLOPPY_FIFO);
}
inportb(0x80);//delay
}
printf("read byte time out\n");
return -1;
}
void check_interrupt(int base,int *st0,int *cyl)
{
sendbyte(base,CMD_SENSE_INTERRUPT);
*st0=getbyte(base);
*cyl=getbyte(base);
}
Thanx.
Posted: Tue Aug 14, 2007 5:31 am
by JamesM
This does seem like you're abusing the forum as a sort of remote, many-headed debugging tool...
Not that I mind helping, but you just seem to be working it out on your own just fine, I don't see why you need any help. Debugging practice is good.
Posted: Tue Aug 14, 2007 5:52 am
by xyjamepa
One more note:
In function check_interrupt if I didn't read st0 or I didn't read cyl
everything works fine this mean I can only read on of them st0 or cyl
when I read them both I get read time out.
Posted: Tue Aug 14, 2007 9:32 am
by xyjamepa
When we want to reset the controller we disable it
and then enable it this will generate an interrupt from the controller
which in my case 0x26 (after remapping PIC) after that we send
CMD_SENSE_INTERRUPT=0x8 which will reset the interrupt.
We can determine the source of the interrupt via ST0 regs,if it's value
was 0x80 this means no interrupt pending,but my irq_wait gives me
0x26 was fired!!!!!!,doesn't this mean irq 0x26 pending?
Posted: Tue Aug 14, 2007 6:18 pm
by pcmattman
By the way, all global variables or variables that could change unexpectedly should have the "volatile" keyword, eg.
Posted: Wed Aug 15, 2007 10:45 am
by frank
Have you seen this flowchart from the Intel manual? You can get the Intel manual from
here