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();
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.
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..21389bc 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) + msleep(FLOPPY_STARTUP_TIME * 125);
// Send command. int ret = floppy_pio(command, param);
On Fri, Feb 09, 2018 at 02:31:02AM +0200, Nikolay Nikolov wrote:
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..21389bc 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
}, .max_track = 79, // maximum track .data_rate = 0, // data transfer rate.startup_time = FLOPPY_STARTUP_TIME,
@@ -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)
msleep(FLOPPY_STARTUP_TIME * 125);
Thanks. This delay is quite large and I fear it could adversely impact existing qemu users running old software on emulated floppies. I think the above might be better as:
if (!motor_already_running && !runnongOnQEMU()) msleep(FLOPPY_STARTUP_TIME * 125);
I would not normally advocate making a special case for QEMU emulation, but a full second delay seems excessive.
The rest of the series looks good to me!
Going forward, could you format the first line of the patch so that it does not exceed 80 characters - long first line descriptions do not interact well with "git shortlog".
-Kevin
On Fri, 2018-02-09 at 23:35 -0500, Kevin O'Connor wrote:
On Fri, Feb 09, 2018 at 02:31:02AM +0200, Nikolay Nikolov wrote:
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..21389bc 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
}, .max_track = 79, // maximum track .data_rate = 0, // data transfer rate.startup_time = FLOPPY_STARTUP_TIME,
@@ -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)
msleep(FLOPPY_STARTUP_TIME * 125);
Thanks. This delay is quite large and I fear it could adversely impact existing qemu users running old software on emulated floppies. I think the above might be better as:
if (!motor_already_running && !runnongOnQEMU()) msleep(FLOPPY_STARTUP_TIME * 125);
I would not normally advocate making a special case for QEMU emulation, but a full second delay seems excessive.
Ok.
The rest of the series looks good to me!
Going forward, could you format the first line of the patch so that it does not exceed 80 characters - long first line descriptions do not interact well with "git shortlog".
Ok, I will edit all my commit messages in this series, so that they fit.
Nikolay
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 21389bc..d80851b 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.
This patch series makes SeaBIOS work with a real floppy controller. Only a single 1.44 MB floppy drive with a 1.44 MB diskette was tested. Both reading and writing works. Formatting was not tested. I also tested QEMU - seems to work fine.
Nikolay
On Fri, 2018-02-09 at 02:30 +0200, Nikolay Nikolov wrote:
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();