diff options
| -rw-r--r-- | include/kernel/sched.h | 3 | ||||
| -rw-r--r-- | kernel/fd.c | 69 |
2 files changed, 50 insertions, 22 deletions
diff --git a/include/kernel/sched.h b/include/kernel/sched.h index 5429e8b..439da53 100644 --- a/include/kernel/sched.h +++ b/include/kernel/sched.h @@ -5,6 +5,9 @@ #include <stdint.h> #include <unistd.h> +/* TODO: change const 10 to tick rate */ +#define uptime() ((long) (ticks * 10)) + #define TSTATE_RUNNING 0 #define TSTATE_INTERRUPTIBLE 1 #define TSTATE_UNINTERRUPTIBLE 2 diff --git a/kernel/fd.c b/kernel/fd.c index 19068c4..f6563ea 100644 --- a/kernel/fd.c +++ b/kernel/fd.c @@ -28,6 +28,9 @@ #define NTYPES (sizeof(ftypes) / sizeof(struct ftype)) #define NFDS (sizeof(fd) / sizeof(struct fdrive)) +/* time (ms) to wait for the FDC to become ready (RQM set) */ +#define READ_TIMEOUT 2 + /* helper macros for converting LBA into CHS */ #define C(lba, ft) \ (lba / (ft->h * ft->s)) @@ -45,6 +48,9 @@ /* TODO: seek before reading */ /* TODO: check drive ready state in floppy driver (ensure the drive door is closed before any operation) */ /* TODO: cut back on printk() usage */ +/* TODO: implement retries for operations likely to fail */ +/* TODO: eliminate potential context switches in read_sect() */ +/* TODO: test that a drive actually exists before beginning an operation */ /* TODO: implement a timeout to prevent system hangs */ #define WAITIRQ(x) ({ \ @@ -61,6 +67,15 @@ struct sense_result { uint8_t cyl; } __attribute__((packed)); +struct req { + uint16_t c; + uint8_t h; + uint8_t s; + struct task_struct *wait; + struct req *nread; + struct req *nseek; +}; + struct ftype { uint16_t c; uint8_t h; @@ -72,7 +87,6 @@ struct ftype { struct fdrive { struct ftype *type; - struct task_struct *seek_wait; uint8_t cyl; uint8_t st0; }; @@ -93,9 +107,10 @@ static struct fdrive fd[4]; static char buffer[512] __attribute__((aligned (0x10000))); -static struct task_struct *read_wait; +static struct req *read_queue; static ssize_t read_data(void *buf, size_t len) { + long timeout; ssize_t c = 0; uint8_t *p = buf; @@ -105,17 +120,12 @@ static ssize_t read_data(void *buf, size_t len) { if(len > SSIZE_MAX) len = SSIZE_MAX; - /* - * TODO: fix this. - * This entire routine really is garbage. - * It doesn't use a timeout (potentially - * hanging the entire system) and doesn't - * handle the DIO flag properly. - */ while(len--) { - while(!(inb(FDMSR) & 0x80)); + timeout = uptime() + READ_TIMEOUT; + + while(!(inb(FDMSR) & 0x80) && uptime() < timeout); - if(!(inb(FDMSR) & 0x40)) + if(!(inb(FDMSR) & 0xC0)) break; *p++ = inb(FDDATA); @@ -129,9 +139,7 @@ static ssize_t read_data(void *buf, size_t len) { while((inb(FDMSR) & 0xC0) == 0xC0) inb(FDDATA); - if(!c) - return -1; - return c; + return !c ? -1 : c; } static void write_data(void *buf, size_t len) { @@ -237,7 +245,7 @@ static void reset(void) { while((inb(FDMSR) & wait)); } -int fd_read_sect(int sect) { +int fd_read_sect(int sect, struct req *r) { ssize_t in; struct { uint8_t st0; @@ -261,14 +269,30 @@ int fd_read_sect(int sect) { 0xFF }; - cli(); - if(read_wait) - sleep_on(&read_wait); - sti(); + /* prepare a read request */ + memset(r, 0, sizeof(struct req)); + r->c = C(sect, fd[0].type); + r->h = H(sect, fd[0].type); + r->s = S(sect, fd[0].type); + + if(read_queue) { + r->nread = read_queue->nread; + read_queue->nread = r; + sleep_on(&r->wait); + } else { + read_queue = r; + } printk("[fd] Reading sector 0x%01x (C: 0x%01x, H: 0x%01x, S: 0x%01x)\n", sect, cmd[2], cmd[3], cmd[4]); - WAITIRQ(write_data(cmd, sizeof(cmd))); + cli(); + write_data(cmd, sizeof(cmd)); + sti(); + sleep_on(&r->wait); + + read_queue = r->nread; + if(read_queue) + wake_up(&read_queue->wait); in = read_data(&res, sizeof(res)); if(in == sizeof(res) && !(res.st0 & 0xC0)) { @@ -285,7 +309,8 @@ void fd_interrupt(void) { struct sense_result sr; irq_fired = 1; - wake_up(&read_wait); + if(read_queue) + wake_up(&read_queue->wait); if((inb(FDMSR) & 0xC0) != 0x80) return; @@ -301,7 +326,7 @@ void fd_block_read(struct buffer *b) { void *p = b->b_data; for(i = SECTS(b->b_block); i < SECTS(b->b_block + 1); i++) { - if(fd_read_sect(i)) { + if(fd_read_sect(i, b->b_data)) { b->b_device = 0; return; } |
