diff options
author | Kevin O'Connor <kevin@koconnor.net> | 2013-03-03 11:05:19 -0500 |
---|---|---|
committer | Kevin O'Connor <kevin@koconnor.net> | 2013-03-03 15:45:01 -0500 |
commit | 068cb4f3511747fb03e16b37980dd3d1eefda910 (patch) | |
tree | 04ef4afaa3a7f3ab434deda1d4798b590f54946e | |
parent | c8494055d2e5e64280dbc385cc001c1230472474 (diff) | |
download | seabios-068cb4f3511747fb03e16b37980dd3d1eefda910.tar.gz |
floppy: Improve floppy_pio() error checking.
The controller can be busy on a response without it being an error.
Don't spin infinitely if status isn't what is expected.
Signed-off-by: Kevin O'Connor <kevin@koconnor.net>
-rw-r--r-- | src/floppy.c | 60 |
1 files changed, 42 insertions, 18 deletions
diff --git a/src/floppy.c b/src/floppy.c index 58fc7dd..91d3565 100644 --- a/src/floppy.c +++ b/src/floppy.c @@ -23,6 +23,7 @@ #define FLOPPY_FILLBYTE 0xf6 #define FLOPPY_GAPLEN 0x1B #define FLOPPY_FORMAT_GAPLEN 0x6c +#define FLOPPY_PIO_TIMEOUT 1000 // New diskette parameter table adding 3 parameters from IBM // Since no provisions are made for multiple drive types, most @@ -201,31 +202,54 @@ struct floppy_pio_s { static int floppy_pio(struct floppy_pio_s *pio) { - // wait for drive readiness - while ((inb(PORT_FD_STATUS) & 0xc0) != 0x80) - ; - - // send command to controller - int i; - for (i=0; i<pio->cmdlen; i++) - outb(pio->data[i], PORT_FD_DATA); + // Send command to controller. + u64 end = calc_future_tsc(FLOPPY_PIO_TIMEOUT); + int i = 0; + for (;;) { + u8 sts = inb(PORT_FD_STATUS); + if (!(sts & 0x80)) { + if (check_tsc(end)) { + floppy_disable_controller(); + return DISK_RET_ETIMEOUT; + } + continue; + } + if (sts & 0x40) { + floppy_disable_controller(); + return DISK_RET_ECONTROLLER; + } + outb(pio->data[i++], PORT_FD_DATA); + if (i >= pio->cmdlen) + break; + } + // Wait for command to complete. if (pio->waitirq) { int ret = floppy_wait_irq(); if (ret) return ret; } - if (!pio->resplen) - return DISK_RET_SUCCESS; - - // check port 3f4 for accessibility to status bytes - if ((inb(PORT_FD_STATUS) & 0xc0) != 0xc0) - return DISK_RET_ECONTROLLER; - - // read return status bytes from controller - for (i=0; i<pio->resplen; i++) - pio->data[i] = inb(PORT_FD_DATA); + // Read response from controller. + end = calc_future_tsc(FLOPPY_PIO_TIMEOUT); + i = 0; + for (;;) { + u8 sts = inb(PORT_FD_STATUS); + if (!(sts & 0x80)) { + if (check_tsc(end)) { + floppy_disable_controller(); + return DISK_RET_ETIMEOUT; + } + continue; + } + if (i >= pio->resplen) + break; + if (!(sts & 0x40)) { + floppy_disable_controller(); + return DISK_RET_ECONTROLLER; + } + pio->data[i++] = inb(PORT_FD_DATA); + } return DISK_RET_SUCCESS; } |