Signed-off-by: Nikolay Nikolov nickysn@users.sourceforge.net --- src/hw/floppy.c | 2 ++ 1 file changed, 2 insertions(+)
diff --git a/src/hw/floppy.c b/src/hw/floppy.c index 3012b3a..16989c2 100644 --- a/src/hw/floppy.c +++ b/src/hw/floppy.c @@ -328,6 +328,8 @@ floppy_enable_controller(void) dprintf(2, "Floppy_enable_controller\n"); // Clear the reset bit (enter reset state), but set 'enable IRQ and DMA' floppy_dor_mask(FLOPPY_DOR_RESET, FLOPPY_DOR_IRQ); + // Real hardware needs a 4 microsecond delay + usleep(4); // Set the reset bit (normal operation) and keep 'enable IRQ and DMA' on floppy_dor_mask(0, FLOPPY_DOR_IRQ | FLOPPY_DOR_RESET); int ret = floppy_wait_irq();
The SPECIFY command sets the Step Rate Time, Head Load Time, Head Unload Time and the DMA enable/disable bit.
Signed-off-by: Nikolay Nikolov nickysn@users.sourceforge.net --- src/hw/floppy.c | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-)
diff --git a/src/hw/floppy.c b/src/hw/floppy.c index 16989c2..5a7e6b9 100644 --- a/src/hw/floppy.c +++ b/src/hw/floppy.c @@ -35,6 +35,8 @@ #define FLOPPY_FORMAT_GAPLEN 0x6c #define FLOPPY_PIO_TIMEOUT 1000 #define FLOPPY_IRQ_TIMEOUT 5000 +#define FLOPPY_SPECIFY1 0xAF // step rate 12ms, head unload 240ms +#define FLOPPY_SPECIFY2 0x02 // head load time 4ms, DMA used
#define FLOPPY_DOR_MOTOR_D 0x80 // Set to turn drive 3's motor ON #define FLOPPY_DOR_MOTOR_C 0x40 // Set to turn drive 2's motor ON @@ -51,8 +53,8 @@ // floppy here struct floppy_ext_dbt_s diskette_param_table2 VARFSEG = { .dbt = { - .specify1 = 0xAF, // step rate 12ms, head unload 240ms - .specify2 = 0x02, // head load time 4ms, DMA used + .specify1 = FLOPPY_SPECIFY1, + .specify2 = FLOPPY_SPECIFY2, .shutoff_ticks = FLOPPY_MOTOR_TICKS, // ~2 seconds .bps_code = FLOPPY_SIZE_CODE, .sectors = 18, @@ -250,6 +252,7 @@ floppy_wait_irq(void) #define FC_READ (0xe6 | (8<<8) | (7<<12) | FCF_WAITIRQ) #define FC_WRITE (0xc5 | (8<<8) | (7<<12) | FCF_WAITIRQ) #define FC_FORMAT (0x4d | (5<<8) | (7<<12) | FCF_WAITIRQ) +#define FC_SPECIFY (0x03 | (2<<8) | (0<<12))
// Send the specified command and it's parameters to the floppy controller. static int @@ -391,6 +394,15 @@ floppy_drive_recal(u8 floppyid) return DISK_RET_SUCCESS; }
+static int +floppy_drive_specify(void) +{ + u8 param[2]; + param[0] = FLOPPY_SPECIFY1; + param[1] = FLOPPY_SPECIFY2; + return floppy_pio(FC_SPECIFY, param); +} + static int floppy_drive_readid(u8 floppyid, u8 data_rate, u8 head) { @@ -468,6 +480,12 @@ floppy_prep(struct drive_s *drive_gf, u8 cylinder) ret = floppy_media_sense(drive_gf); if (ret) return ret; + + // Execute a SPECIFY command (sets the Step Rate Time, + // Head Load Time, Head Unload Time and the DMA enable/disable bit). + ret = floppy_drive_specify(); + if (ret) + return ret; }
// Seek to cylinder if needed.
The previous version allowed for only two floppies.
Signed-off-by: Nikolay Nikolov nickysn@users.sourceforge.net --- src/hw/floppy.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/hw/floppy.c b/src/hw/floppy.c index 5a7e6b9..730aadc 100644 --- a/src/hw/floppy.c +++ b/src/hw/floppy.c @@ -358,7 +358,7 @@ floppy_drive_pio(u8 floppyid, int command, u8 *param) SET_BDA(floppy_motor_counter, 255);
// Turn on motor of selected drive, DMA & int enabled, normal operation - floppy_dor_write((floppyid ? FLOPPY_DOR_MOTOR_B : FLOPPY_DOR_MOTOR_A) | FLOPPY_DOR_IRQ | FLOPPY_DOR_RESET | floppyid); + floppy_dor_write((FLOPPY_DOR_MOTOR_A << floppyid) | FLOPPY_DOR_IRQ | FLOPPY_DOR_RESET | floppyid);
// Send command. int ret = floppy_pio(command, param);
When starting up the floppy motor, wait for a certain amount of time, so that it can spin up and reach a stable speed. This delay is skipped, if the motor was already running (which can happen, since the floppy motor is intentionally kept spinning for 2 seconds after the previous floppy operation completes).
Signed-off-by: Nikolay Nikolov nickysn@users.sourceforge.net --- src/hw/floppy.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-)
diff --git a/src/hw/floppy.c b/src/hw/floppy.c index 730aadc..933e5c0 100644 --- a/src/hw/floppy.c +++ b/src/hw/floppy.c @@ -37,6 +37,7 @@ #define FLOPPY_IRQ_TIMEOUT 5000 #define FLOPPY_SPECIFY1 0xAF // step rate 12ms, head unload 240ms #define FLOPPY_SPECIFY2 0x02 // head load time 4ms, DMA used +#define FLOPPY_STARTUP_TIME 8 // 1 second
#define FLOPPY_DOR_MOTOR_D 0x80 // Set to turn drive 3's motor ON #define FLOPPY_DOR_MOTOR_C 0x40 // Set to turn drive 2's motor ON @@ -63,7 +64,7 @@ struct floppy_ext_dbt_s diskette_param_table2 VARFSEG = { .gap_len = FLOPPY_FORMAT_GAPLEN, .fill_byte = FLOPPY_FILLBYTE, .settle_time = 0x0F, // 15ms - .startup_time = 0x08, // 1 second + .startup_time = FLOPPY_STARTUP_TIME, }, .max_track = 79, // maximum track .data_rate = 0, // data transfer rate @@ -357,8 +358,16 @@ floppy_drive_pio(u8 floppyid, int command, u8 *param) // set the disk motor timeout value of INT 08 to the highest value SET_BDA(floppy_motor_counter, 255);
+ // Check if the motor is already running + u8 motor_mask = FLOPPY_DOR_MOTOR_A << floppyid; + int motor_already_running = floppy_dor_read() & motor_mask; + // Turn on motor of selected drive, DMA & int enabled, normal operation - floppy_dor_write((FLOPPY_DOR_MOTOR_A << floppyid) | FLOPPY_DOR_IRQ | FLOPPY_DOR_RESET | floppyid); + floppy_dor_write(motor_mask | FLOPPY_DOR_IRQ | FLOPPY_DOR_RESET | floppyid); + + // If the motor was just started, wait for it to get up to speed + if (!motor_already_running && !CONFIG_QEMU) + msleep(FLOPPY_STARTUP_TIME * 125);
// Send command. int ret = floppy_pio(command, param);
During initialization, real floppy controllers need 4 sense interrupt commands to clear the interrupt status (this represents the transition from "not ready" to "ready" for each of the four virtual floppy drives), instead of just one.
This is described in detail in section 7.4 - Drive Polling of the Intel 82077AA datasheet.
Signed-off-by: Nikolay Nikolov nickysn@users.sourceforge.net --- src/hw/floppy.c | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-)
diff --git a/src/hw/floppy.c b/src/hw/floppy.c index 933e5c0..9e6647d 100644 --- a/src/hw/floppy.c +++ b/src/hw/floppy.c @@ -340,8 +340,21 @@ floppy_enable_controller(void) if (ret) return ret;
+ // After the interrupt is received, send 4 SENSE INTERRUPT commands to + // clear the interrupt status for each of the four logical drives, + // supported by the controller. + // See section 7.4 - "Drive Polling" of the Intel 82077AA datasheet for + // a more detailed description of why this voodoo needs to be done. + // Without this, initialization fails on real controllers (but still works + // in QEMU) u8 param[2]; - return floppy_pio(FC_CHECKIRQ, param); + int i; + for (i=0; i<4; i++) { + ret = floppy_pio(FC_CHECKIRQ, param); + if (ret) + return ret; + } + return DISK_RET_SUCCESS; }
// Activate a drive and send a command to it.
On Sat, Feb 10, 2018 at 01:52:13PM +0200, Nikolay Nikolov wrote:
Signed-off-by: Nikolay Nikolov nickysn@users.sourceforge.net
Thanks. I committed this series.
-Kevin