Skip to content

Commit

Permalink
Merge pull request #1741 from ghaerr/df7
Browse files Browse the repository at this point in the history
[direct df] Replace QEMU kluge with implied seek option for 360k/1.2M floppies
  • Loading branch information
ghaerr authored Oct 4, 2023
2 parents 01595b2 + cde4232 commit 56d3bb7
Showing 1 changed file with 49 additions and 49 deletions.
98 changes: 49 additions & 49 deletions elks/arch/i86/drivers/block/directfd.c
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,7 @@
* 82077AA IBM PS/2 (gen 3) DOR,DIR,CCR PERPENDICULAR,LOCK
*/

#define QEMU_STRETCH_FIX 0 /* =1 to ignore floppy stretch for QEMU 360k/AT */
#define USE_IMPLIED_SEEK 0 /* =1 for QEMU with 360k/AT stretch floppies (not real hw) */
#define CHECK_DISK_CHANGE 0 /* =1 to add driver media changed code */
#define CLEAR_DIR_REG 0 /* =1 to clear DIR DSKCHG when set (for media change) */

Expand All @@ -125,10 +125,10 @@
static void (*do_floppy)(); /* interrupt routine to call */
static int initial_reset_flag;
static int need_configure = 1; /* for 82077 */
static int recalibrate;
static int reset;
static int recover; /* recalibrate immediately after resetting */
static int seek;
static int reset; /* something went wrong, reset FDC, start over */
static int recalibrate; /* seek errors, etc, eventually triggers recalibrate_floppy */
static int recover; /* recovering from hang, awakened by watchdog timer */
static int seek; /* set if current op needs a track change (seek) */

/* BIOS floppy motor timeout counter - FIXME leave this while BIOS driver present */
static unsigned char __far *fl_timeout = (void __far *)0x440L;
Expand Down Expand Up @@ -158,7 +158,7 @@ static unsigned char running = 0; /* keep track of motors already running */
* 2nd DMA controller transfers words only, not bytes and thus up to 128k bytes
* in one 'swoop'.
*/
#define LAST_DMA_ADDR (0x100000L - BLOCK_SIZE) /* stick to the 1M limit */
#define LAST_DMA_ADDR (0x100000L - BLOCK_SIZE) /* enforce the 1M limit */

#define _MK_LINADDR(seg, offs) ((unsigned long)((((unsigned long)(seg)) << 4) + (unsigned)(offs)))

Expand Down Expand Up @@ -444,8 +444,8 @@ void request_done(int uptodate)
* assuming the user is smart enough to umount before media changes - or
* ready for the consequences.
*
* floppy-change is never called from an interrupt, so we can relax a bit
* here, sleep etc. Note that floppy-on tries to set current_DOR to point
* floppy_change is never called from an interrupt, so we can relax a bit
* here, sleep etc. Note that floppy_on tries to set current_DOR to point
* to the desired drive, but it will probably not survive the sleep if
* several floppies are used at the same time: thus the loop.
*/
Expand Down Expand Up @@ -594,7 +594,7 @@ static int DFPROC result(void)
}
reset = 1;
current_track = NO_TRACK;
printk("df: getstatus timeout\n");
printk("df: result timeout\n");
return -1;
}

Expand Down Expand Up @@ -654,14 +654,20 @@ static void DFPROC perpendicular_mode(unsigned char rate)

static void DFPROC configure_fdc_mode(void)
{
if (need_configure && (fdc_version >= FDC_TYPE_82072)) {
/* Enhanced version with FIFO & write precompensation */
/* check for enhanced chip with FIFO, vertical recording and implied seeks */
if (fdc_version >= FDC_TYPE_82072 && (need_configure || USE_IMPLIED_SEEK)) {
/* implied seek required for QEMU to work with 360k floppies in 1.2M drives */
int implied_seek = USE_IMPLIED_SEEK && floppy->stretch;
output_byte(FD_CONFIGURE);
output_byte(0);
output_byte(0x1A); /* FIFO on, polling off, 10 byte threshold */
output_byte(0); /* precompensation from track 0 upwards */
if (implied_seek)
output_byte(0x4A); /* FIFO on, polling on, 10 byte threshold, implied seek */
else
output_byte(0x0A); /* FIFO on, polling on, 10 byte threshold */
output_byte(0); /* precompensation from track 0 upwards */
if (need_configure)
printk("df: implied seek %s\n", implied_seek? "enabled": "disabled");
need_configure = 0;
printk("df: FIFO enabled\n");
}
if (cur_spec1 != floppy->spec1) {
cur_spec1 = floppy->spec1;
Expand Down Expand Up @@ -818,8 +824,8 @@ static void DFPROC setup_rw_floppy(void)
output_byte(2); /* sector size = 512 */
output_byte(floppy->sect);
output_byte(floppy->gap);
output_byte(0xFF); /* sector size, 0xff unless sector size==0 (128b) */
if (reset)
output_byte(0xFF); /* sector size, 0xff unless sector size==0 (128b) */
if (reset) /* if output_byte timed out */
redo_fd_request();
}

Expand Down Expand Up @@ -857,14 +863,13 @@ static void DFPROC transfer(void)
#endif
DEBUG("trns%d-", read_track);

configure_fdc_mode(); /* FIXME: Why are we doing this here???
* should be done once per media change ... */

if (reset) {
configure_fdc_mode(); /* ensure controller is in the right mode per transaction */
if (reset) { /* if output_byte timed out */
redo_fd_request();
return;
}
if (!seek) {
if (!seek || (USE_IMPLIED_SEEK && floppy->stretch && fdc_version >= FDC_TYPE_82072)) {
current_track = seek_track;
setup_rw_floppy();
return;
}
Expand All @@ -875,7 +880,7 @@ static void DFPROC transfer(void)
output_byte(FD_SEEK);
output_byte((head << 2) | current_drive);
output_byte(seek_track);
if (reset) /* error in output_byte() */
if (reset) /* if output_byte timed out */
redo_fd_request();
}

Expand All @@ -888,11 +893,13 @@ static void DFPROC recalibrate_floppy(void)
output_byte(FD_RECALIBRATE);
output_byte(current_drive);

#if 0
/* FIXME this may not make sense: We're waiting for recal_interrupt
* why redo_fd_request here when recal_interrupt is doing it ???
* 'reset' gets set in recal_interrupt, maybe that's it ??? */
if (reset)
redo_fd_request();
#endif
}

/*
Expand Down Expand Up @@ -957,6 +964,7 @@ static void reset_interrupt(void)

/*
* reset is done by pulling bit 2 of DOR low for a while.
* As the FDC recovers from reset, it pulls the IRQ, and reset_interrupt is called.
*/
static void DFPROC reset_floppy(void)
{
Expand All @@ -967,16 +975,21 @@ static void DFPROC reset_floppy(void)
cur_spec1 = -1;
cur_rate = -1;
recalibrate = 1;
need_configure = 1;
need_configure = 1; /* not required if LOCK set on 82077 */
if (!initial_reset_flag)
printk("df: reset_floppy\n");
clr_irq(); /* FIXME don't busyloop with interrupts off, use timer */
DEBUG("df: reset_floppy\n");
clr_irq(); /* FIXME don't busyloop with interrupts off, use timer */
outb_p(current_DOR & ~0x04, FD_DOR);
delay_loop(1000);
outb(current_DOR, FD_DOR);
set_irq();
}

/*
* shutdown is called by the 'main' watchdog timer (typically 6 secs of idle time)
* and sets the 'recover' flag to enable a full restart of the adapter: Reset FDC,
* re-configure, recalibrate, essentially start from scratch.
*/
static void floppy_shutdown(void)
{
DEBUG("[%u]shtdwn0x%x|%x-", (unsigned int)jiffies, current_DOR, running);
Expand All @@ -991,10 +1004,9 @@ static void floppy_shutdown(void)
#if CLEAR_DIR_REG
static void shake_done(void)
{
/* Need SENSEI to clear the interrupt per spec, required by QEMU, not by
* real hardware */
output_byte(FD_SENSEI); /* TESTING FIXME */
result();
/* Need SENSEI to clear the interrupt */
output_byte(FD_SENSEI);
(void) result();
DEBUG("shD0x%x-", ST0);
current_track = NO_TRACK;
if (inb(FD_DIR) & 0x80) {
Expand All @@ -1008,16 +1020,13 @@ static void shake_done(void)
redo_fd_request();
}

/*
* The result byte after the SENSEI cmd is ST3, not ST0
*/
static int DFPROC retry_recal(void (*proc)())
{
DEBUG("rrecal-");
output_byte(FD_SENSEI);
if (result() == 2 && (ST0 & 0x10) != 0x10) /* track 0 test */
return 0; /* No 'unit check': We're OK */
do_floppy = proc; /* otherwise recalibrate */
do_floppy = proc; /* otherwise repeat recalibrate */
output_byte(FD_RECALIBRATE);
output_byte(current_drive);
return 1;
Expand All @@ -1038,7 +1047,7 @@ static void shake_one(void)
do_floppy = shake_done;
output_byte(FD_SEEK);
output_byte(head << 2 | current_drive);
output_byte(1);
output_byte(1); /* resetting media change bit requires head movement */
}

/*
Expand All @@ -1065,17 +1074,14 @@ static void DFPROC floppy_ready(void)
if (keep_data[current_drive] > 0)
keep_data[current_drive]--;
} else {
/* FIXME: this is non sensical: Need to assume that a medium change
/* FIXME: this is nonsensical: Should assume that a medium change
* means a new medium of the same format as the prev until it fails.
*/
if (current_type[current_drive] != NULL)
printk("df%d: Disk type undefined after disk change\n", current_drive);
current_type[current_drive] = NULL;
}
/* Forcing the drive to seek makes the "media changed" condition go
* away. There should be a cleaner solution for that ...
* FIXME: This is way too slow and recal is not seek ...
*/

if (!reset && !recalibrate) {
if (current_track && current_track != NO_TRACK)
do_floppy = shake_zero;
Expand Down Expand Up @@ -1154,17 +1160,13 @@ static void DFPROC redo_fd_request(void)
tmp = start / floppy->sect;
head = tmp % floppy->head;
track = tmp / floppy->head;
#if QEMU_STRETCH_FIX
seek_track = track; /* QEMU doesn't seem to support track doubling */
#else
seek_track = track << floppy->stretch;
#endif
command = (req->rq_cmd == READ)? FD_READ: FD_WRITE;
DEBUG("df%d: %s sector %d CHS %d/%d/%d max %d stretch %d seek %d\n",
DEVICE_NR(req->rq_dev), req->rq_cmd==READ? "read": "write",
start, track, head, sector, floppy->sect, floppy->stretch, seek_track);

/* timer for hung operations, 6 secs probably too long ... */
/* restart timer for hung operations, 6 secs probably too long ... */
del_timer(&fd_timeout);
fd_timeout.tl_expires = jiffies + 6 * HZ;
add_timer(&fd_timeout);
Expand Down Expand Up @@ -1488,11 +1490,9 @@ static int DFPROC get_fdc_version(void)
* properly, so force a reset for the standard FDC clones,
* to avoid interrupt garbage.
*/
/* testing FIXME -- the FDC has just been reset by the BIOS, do we need this? */
if (type < FDC_TYPE_82077) {
initial_reset_flag = 1;
reset_floppy();
}
initial_reset_flag = 1;
reset_floppy();

return type;
}

Expand Down

0 comments on commit 56d3bb7

Please sign in to comment.