floppy driver
floppy driver
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.
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.
- Attachments
-
- fdc.txt
- (6.53 KiB) Downloaded 110 times
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,
Thanx.
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;
}
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
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:
Thanx.
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);
}
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?
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?
-
- Member
- Posts: 2566
- Joined: Sun Jan 14, 2007 9:15 pm
- Libera.chat IRC: miselin
- Location: Sydney, Australia (I come from a land down under!)
- Contact:
By the way, all global variables or variables that could change unexpectedly should have the "volatile" keyword, eg.
Code: Select all
volatile int timer_ticks;
Have you seen this flowchart from the Intel manual? You can get the Intel manual from here
- Attachments
-
- flowchart.jpg (29.38 KiB) Viewed 1427 times