Code: Select all
int first;
int second;
int current_track = -1;
short base_used;
volatile int irq6_state = 0;
int motor_on = 0;
int sr0=0;
int pcn=0;
int present = 1; //assume not present
// dma xfer for floppy
void set_dma(unsigned char *buff, short size, int read, int channel)
{
char page = 0;
char mode = 0;
short offset = 0;
if(read)
mode = 0x48 + (char)channel;
else
mode = 0x44 + (char)channel;
page = (char)((int)buff >> 16);
offset = (short)((int)buff & 0xFFFF);
size--;
cli();
outb(maskport[channel], (0x04 | channel)); // mask channel
outb(clearport[channel], 0x00); // stop trans
outb(modeport[channel], mode); // type of trans
outb(addrport[channel], LOW_BYTE(offset)); // send address
outb(addrport[channel], HI_BYTE(offset)); // send address
outb(pageport[channel], page); // send page
outb(countport[channel], LOW_BYTE(size)); // send size
outb(countport[channel], HI_BYTE(size)); // send size
outb(maskport[channel], channel); // unmask channel
sti();
}
void get_floppy_type()
{
unsigned char data;
outb(0x70, 0x10);
data = inb(0x71);
first = data >> 4;
second = data & 0xF;
}
void fdc_handler()
{
irq6_state = 1;
outb(0x20,0x20);
}
void start_motor()
{
outb((base_used + 0x2), 0x1C);
motor_on = 1;
}
void stop_motor()
{
outb((base_used + 0x2), 0x00);
motor_on = 0;
}
/* from intel manual */
void sendbyte(char byte)
{
volatile int msr;
int tmo;
for(tmo = 0; tmo < 128; tmo++)
{
msr = inb((base_used + 0x04));
if ((msr & 0xC0) == 0x80)
{
outb((base_used + 0x05), byte);
return;
}
inb(0x80);
}
}
/* from intel manual */
int getbyte()
{
volatile int msr;
int tmo;
for (tmo = 0; tmo < 128; tmo++)
{
msr = inb((base_used + 0x04));
if ((msr & 0xd0) == 0xd0)
return inb((base_used + 0x05));
inb(0x80);
}
return -1;
}
void wait_irq6()
{
while(irq6_state == 0);
irq6_state = 0;
}
int fdc_seek(char track)
{
if(current_track == track)
return 0;
//sendbyte(0x07); //calibrate
//sendbyte(0x00);
sendbyte(0x0F); //seek cmd
sendbyte(0x00);
sendbyte(track);
wait_irq6();
sendbyte(0x08); /* Send sense interrupt status command. */
sr0 = getbyte(); /* Read status register 0. */
pcn = getbyte(); /* Read present cylinder number. */
if (!FDC_SEEK_END(sr0))
printf(0x0f,1,10,"Seek Error");
return 1;
current_track = track;
printf(0x0f,1,10,"Seek OK");
return 0;
}
void fdc_reset()
{
outb((base_used + 0x02), 0); // stop everything
motor_on = 0;
outb((base_used + 0x04), 0); // data rate (500K/s)
outb((base_used + 0x02), 0x0C); // restart ints
wait_irq6();
unsigned char j;
for (j = 0; j < 4; j++)
{
sendbyte(0x08); /* Send sense intr status cmd. */
if (j == 0)
{
sr0 = getbyte(); /* Read status register 0. */
pcn = getbyte(); /* Read present cyl number. */
continue;
}
(void) getbyte(); /* Discard status register 0. */
(void) getbyte(); /* Discard present cylinder number. */
}
sendbyte(0x03); // timing
sendbyte(0xDF); // timing
sendbyte(0x02); // timing
timer_wait_ms(1);
inb(0x80);
fdc_seek(1);
sendbyte(0x07); //calibrate
sendbyte(0x00);
}
void init_floppy()
{
base_used = 0x3F0;
get_floppy_type();
fdc_reset();
}
void block2hts(int block,int *head,int *track,int *sector)
{
*head = (block % (18 * 2)) / (18);
*track = block / (18 * 2);
*sector = block % 18 + 1;
}
int floppy_read_sector(unsigned char *buf, int block)
{
int head, track, sector;
block2hts(block,&head,&track,§or);
start_motor();
outb((base_used + 0x7), 0);
set_dma(0x00000000, 512, 0, 2);
fdc_seek(track);
timer_wait_ms(1);
sendbyte(0xE6);
sendbyte((char)head << 2);
sendbyte((char)track);
sendbyte((char)head);
sendbyte((char)sector);
sendbyte(0x02); //sector size
sendbyte(0x12); //sectors per track
sendbyte(0x1B);
sendbyte(0xFF);
wait_irq6();
(void)getbyte();
(void)getbyte();
(void)getbyte();
(void)getbyte();
(void)getbyte();
(void)getbyte();
(void)getbyte();
if(!FDC_NORM_TERM(sr0))
{
printf(0x0f,1,6,"Read Error (0x%x)",sr0);
sendbyte(0x07); //re-calibrate
sendbyte(0x00);
} else {
memcpy((unsigned int *)buf, (unsigned int *)0x00000000, 128);
}
stop_motor();
return 0;
}
void fdc_install(void)
{
irq_install_handler(6,fdc_handler);
}