Floppy driver headache
Posted: Thu Nov 25, 2010 4:00 pm
I'm currently coding my floppy driver, the first real device driver I'm building, and I have the problem that, although it works under bochs, it fails to reconfigure the controller under real hardware conditions. The recalibrate command fails to execute correctly and results in the MSR having a status of 0x90 (ie cmd busy, expecting input). I've been trying to debug it since this morning (its 10:57 PM now) but so far my conclusion is that something is going wrong so horribly that my debug code is interfering with reproducing results.
Here is the code i use:
The problem is probably obvious to someone with a more intimate knowledge of the floppy hardware, but it has eluded me so far.
Here is the code i use:
Code: Select all
#include <util.h>
#include <cmos.h>
#include <display.h>
#include <irq.h>
#include <idt.h>
#include <sched.h>
#include <proc.h>
#include <kcall_internal.h>
#define SRA 0x3F0
#define SRB 0x3F1
#define DOR 0x3F2
#define TDR 0x3F3
#define MSR 0x3F4
#define DSR 0x3F4
#define DATA_FIFO 0x3F5
#define DIR 0x3F7
#define CCR 0x3F7
unsigned int FTID;
unsigned int irq_waiting;
unsigned int timer_id=0;
unsigned long long timer_time=0;
void irq6()
{
irq_waiting = 1;
resume(FTID);
print("IRQ6\n");
}
void wait_timeout(int msec)
{
unsigned int ms, ls;
unsigned long long intime;
asm volatile("mov $0x32, %%eax\n"
"int $0x70" : "=a"(ms), "=b"(ls) : );
intime = (((long long)ms)<<32) | ((long long)ls);
intime += msec;
ms = (timer_time >> 32) & 0xFFFFFFFF;
ls = (timer_time) & 0xFFFFFFFF;
asm volatile("int $0x70" : : "a"(KC_TIMER_DESTROY), "b"(timer_id), "c"(ms), "d"(ls) );
timer_time = intime;
ms = (intime >> 32) & 0xFFFFFFFF;
ls = (intime) & 0xFFFFFFFF;
asm volatile("int $0x70" : "=a"(timer_id) : "a"(KC_TIMER_CREATE), "b"(FTID), "c"(ms), "d"(ls) );
}
void controller_reset()
{
unsigned char dor_orig;
unsigned char PIT_COUNT;
asm("cli");
dor_orig = inb(DOR);
outb(DOR, dor_orig & ~4);
PIT_COUNT = inb(0x40);
inb(0x40);
if (PIT_COUNT + 10 < PIT_COUNT)
{
while (((signed char)inb(0x40)) < ((signed char)PIT_COUNT + 10)) inb(0x40);
}
else
{
while (inb(0x40) < PIT_COUNT+10) inb(0x40);
}
inb(0x40);
outb(DOR, dor_orig);
wait_timeout(3000);
asm("sti");
}
int controller_command(unsigned char command, unsigned char *inbytes,
unsigned int inlen, unsigned char *outbytes, unsigned int outlen,
unsigned int wait_irq)
{
int i;
if (wait_irq)
irq_waiting = 0;
for (i=0; i<16 && (inb(MSR) & 0xd0) != 0x80; i++)
controller_reset();
if ((inb(MSR) & 0xd0) != 0x80)
return 1;
outb(DATA_FIFO, command);
while (inlen > 0)
{
for (i=0; i<128 && (inb(MSR) & 0x80) != 0x80; i++);
if ((inb(MSR) & 0x80) != 0x80)
return 2;
if ((inb(MSR) & 0x50) != 0x10)
return 3;
outb(DATA_FIFO, *inbytes);
inbytes++;
inlen--;
}
if ((inb(MSR) & 0x20) == 0x20)
PANIC("NDMA Set, no support for execution phase (yet).");
if (wait_irq)
{
asm("cli");
if (irq_waiting == 0)
wait_timeout(wait_irq);
if (idt_interruptable())
asm("sti");
}
for (i=0; i<2048 && (inb(MSR) & 0x80) != 0x80; i++);
if ((inb(MSR) & 0x80) != 0x80)
return 4;
while (outlen > 0)
{
for (i=0; i<128 && (inb(MSR) & 0x80) != 0x80; i++);
if ((inb(MSR) & 0x80) != 0x80)
return 5;
if ((inb(MSR) & 0x50) != 0x50)
return 6;
*outbytes = inb(DATA_FIFO);
outbytes++;
outlen--;
}
for (i=0; i<1024 && (inb(MSR) & 0x80) != 0x80; i++) wait_timeout(100);
if ((inb(MSR) & 0xD0) != 0x80)
return inb(MSR);
return 0;
}
void floppy_controller_init()
{
unsigned char floppy_res;
unsigned char floppy_in[3];
int i;
char succes;
if ((succes = controller_command(0x10, (unsigned char *)0, 0, &floppy_res, 1,0)))
{
print_num(succes);
print("\n");
PANIC("Unable to read out floppy state.");
}
if (floppy_res != 0x90)
PANIC("Unsuported floppy controller.");
outb(DOR, inb(DOR) | 0x08);
floppy_in[0] = 0;
floppy_in[1] = 0x47;
floppy_in[2] = 0;
if ((succes = controller_command(0x13, floppy_in, 3, (unsigned char *)0, 0,0)))
{
print_num(succes);
print("\n");
PANIC("Unable to reconfigure controller.");
}
if ((succes = controller_command(0x94, (unsigned char *)0, 0, floppy_in, 1,0)))
{
print_num(succes);
print("\n");
PANIC("Unable to lock config.");
}
if ((floppy_in[0] & 0x10) != 0x10)
PANIC("Unable to lock config.");
controller_reset();
outb(DOR, (inb(DOR) & ~0x3) | 0x10);
wait_timeout(500);
i=0;
do
{
floppy_in[0] = 0;
print("Start\n");
succes = controller_command(0x7, floppy_in, 1, (unsigned char*)0, 0, 10000);
print("End\n");
if (succes == 0)
{
succes = controller_command(0x8, (unsigned char*)0, 0, floppy_in, 2, 0);
if ((floppy_in[0] & 0x20) != 0x20)
succes = 1;
}
else
{
print_num(succes);
print("\n");
}
i++;
}
while (i<4 && succes != 0);
if (succes != 0)
PANIC("Unable to recalibrate drive 0.");
outb(DOR, (inb(DOR) & ~0x10));
print_hex(cmos_read_byte(0x10));
print("\nFinished.\n");
}
void floppy_task()
{
irq_set_handle(6, irq6);
floppy_controller_init();
while (1);
}
void floppy_init(int KPID)
{
FTID = process_spawn_task(KPID, (unsigned int)floppy_task);
}