fdc: rewrite seek and DSKCHG bit handling

This bit is cleared on every successful seek to a different track (cylinder).
The seek is also called on revalidate or on read/write/format commands which
also clear the DSKCHG bit.

Signed-off-by: Pavel Hrdina <phrdina@redhat.com>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
This commit is contained in:
Pavel Hrdina 2012-06-22 12:33:54 +02:00 committed by Kevin Wolf
parent 4ddc07cac2
commit 6be01b1e0b

View file

@ -153,8 +153,12 @@ static int fd_seek(FDrive *drv, uint8_t head, uint8_t track, uint8_t sect,
} }
#endif #endif
drv->head = head; drv->head = head;
if (drv->track != track) if (drv->track != track) {
if (drv->bs != NULL && bdrv_is_inserted(drv->bs)) {
drv->media_changed = 0;
}
ret = 1; ret = 1;
}
drv->track = track; drv->track = track;
drv->sect = sect; drv->sect = sect;
} }
@ -170,9 +174,7 @@ static int fd_seek(FDrive *drv, uint8_t head, uint8_t track, uint8_t sect,
static void fd_recalibrate(FDrive *drv) static void fd_recalibrate(FDrive *drv)
{ {
FLOPPY_DPRINTF("recalibrate\n"); FLOPPY_DPRINTF("recalibrate\n");
drv->head = 0; fd_seek(drv, 0, 0, 1, 1);
drv->track = 0;
drv->sect = 1;
} }
/* Revalidate a disk drive after a disk change */ /* Revalidate a disk drive after a disk change */
@ -711,14 +713,6 @@ static void fdctrl_raise_irq(FDCtrl *fdctrl, uint8_t status0)
qemu_set_irq(fdctrl->irq, 1); qemu_set_irq(fdctrl->irq, 1);
fdctrl->sra |= FD_SRA_INTPEND; fdctrl->sra |= FD_SRA_INTPEND;
} }
if (status0 & FD_SR0_SEEK) {
FDrive *cur_drv;
/* A seek clears the disk change line (if a disk is inserted) */
cur_drv = get_cur_drv(fdctrl);
if (cur_drv->bs != NULL && bdrv_is_inserted(cur_drv->bs)) {
cur_drv->media_changed = 0;
}
}
fdctrl->reset_sensei = 0; fdctrl->reset_sensei = 0;
fdctrl->status0 = status0; fdctrl->status0 = status0;
@ -997,7 +991,10 @@ static void fdctrl_unimplemented(FDCtrl *fdctrl, int direction)
fdctrl_set_fifo(fdctrl, 1, 0); fdctrl_set_fifo(fdctrl, 1, 0);
} }
/* Seek to next sector */ /* Seek to next sector
* returns 0 when end of track reached (for DBL_SIDES on head 1)
* otherwise returns 1
*/
static int fdctrl_seek_to_next_sect(FDCtrl *fdctrl, FDrive *cur_drv) static int fdctrl_seek_to_next_sect(FDCtrl *fdctrl, FDrive *cur_drv)
{ {
FLOPPY_DPRINTF("seek to next sector (%d %02x %02x => %d)\n", FLOPPY_DPRINTF("seek to next sector (%d %02x %02x => %d)\n",
@ -1005,30 +1002,39 @@ static int fdctrl_seek_to_next_sect(FDCtrl *fdctrl, FDrive *cur_drv)
fd_sector(cur_drv)); fd_sector(cur_drv));
/* XXX: cur_drv->sect >= cur_drv->last_sect should be an /* XXX: cur_drv->sect >= cur_drv->last_sect should be an
error in fact */ error in fact */
if (cur_drv->sect >= cur_drv->last_sect || uint8_t new_head = cur_drv->head;
cur_drv->sect == fdctrl->eot) { uint8_t new_track = cur_drv->track;
cur_drv->sect = 1; uint8_t new_sect = cur_drv->sect;
int ret = 1;
if (new_sect >= cur_drv->last_sect ||
new_sect == fdctrl->eot) {
new_sect = 1;
if (FD_MULTI_TRACK(fdctrl->data_state)) { if (FD_MULTI_TRACK(fdctrl->data_state)) {
if (cur_drv->head == 0 && if (new_head == 0 &&
(cur_drv->flags & FDISK_DBL_SIDES) != 0) { (cur_drv->flags & FDISK_DBL_SIDES) != 0) {
cur_drv->head = 1; new_head = 1;
} else { } else {
cur_drv->head = 0; new_head = 0;
cur_drv->track++; new_track++;
if ((cur_drv->flags & FDISK_DBL_SIDES) == 0) if ((cur_drv->flags & FDISK_DBL_SIDES) == 0) {
return 0; ret = 0;
}
} }
} else { } else {
cur_drv->track++; new_track++;
return 0; ret = 0;
} }
if (ret == 1) {
FLOPPY_DPRINTF("seek to next track (%d %02x %02x => %d)\n", FLOPPY_DPRINTF("seek to next track (%d %02x %02x => %d)\n",
cur_drv->head, cur_drv->track, new_head, new_track, new_sect, fd_sector(cur_drv));
cur_drv->sect, fd_sector(cur_drv));
} else {
cur_drv->sect++;
} }
return 1; } else {
new_sect++;
}
fd_seek(cur_drv, new_head, new_track, new_sect, 1);
return ret;
} }
/* Callback for transfer end (stop or abort) */ /* Callback for transfer end (stop or abort) */
@ -1626,11 +1632,7 @@ static void fdctrl_handle_seek(FDCtrl *fdctrl, int direction)
/* The seek command just sends step pulses to the drive and doesn't care if /* The seek command just sends step pulses to the drive and doesn't care if
* there is a medium inserted of if it's banging the head against the drive. * there is a medium inserted of if it's banging the head against the drive.
*/ */
if (fdctrl->fifo[2] > cur_drv->max_track) { fd_seek(cur_drv, cur_drv->head, fdctrl->fifo[2], cur_drv->sect, 1);
cur_drv->track = cur_drv->max_track;
} else {
cur_drv->track = fdctrl->fifo[2];
}
/* Raise Interrupt */ /* Raise Interrupt */
fdctrl_raise_irq(fdctrl, FD_SR0_SEEK); fdctrl_raise_irq(fdctrl, FD_SR0_SEEK);
} }
@ -1695,9 +1697,10 @@ static void fdctrl_handle_relative_seek_out(FDCtrl *fdctrl, int direction)
SET_CUR_DRV(fdctrl, fdctrl->fifo[1] & FD_DOR_SELMASK); SET_CUR_DRV(fdctrl, fdctrl->fifo[1] & FD_DOR_SELMASK);
cur_drv = get_cur_drv(fdctrl); cur_drv = get_cur_drv(fdctrl);
if (fdctrl->fifo[2] + cur_drv->track >= cur_drv->max_track) { if (fdctrl->fifo[2] + cur_drv->track >= cur_drv->max_track) {
cur_drv->track = cur_drv->max_track - 1; fd_seek(cur_drv, cur_drv->head, cur_drv->max_track - 1,
cur_drv->sect, 1);
} else { } else {
cur_drv->track += fdctrl->fifo[2]; fd_seek(cur_drv, cur_drv->head, fdctrl->fifo[2], cur_drv->sect, 1);
} }
fdctrl_reset_fifo(fdctrl); fdctrl_reset_fifo(fdctrl);
/* Raise Interrupt */ /* Raise Interrupt */
@ -1711,9 +1714,9 @@ static void fdctrl_handle_relative_seek_in(FDCtrl *fdctrl, int direction)
SET_CUR_DRV(fdctrl, fdctrl->fifo[1] & FD_DOR_SELMASK); SET_CUR_DRV(fdctrl, fdctrl->fifo[1] & FD_DOR_SELMASK);
cur_drv = get_cur_drv(fdctrl); cur_drv = get_cur_drv(fdctrl);
if (fdctrl->fifo[2] > cur_drv->track) { if (fdctrl->fifo[2] > cur_drv->track) {
cur_drv->track = 0; fd_seek(cur_drv, cur_drv->head, 0, cur_drv->sect, 1);
} else { } else {
cur_drv->track -= fdctrl->fifo[2]; fd_seek(cur_drv, cur_drv->head, fdctrl->fifo[2], cur_drv->sect, 1);
} }
fdctrl_reset_fifo(fdctrl); fdctrl_reset_fifo(fdctrl);
/* Raise Interrupt */ /* Raise Interrupt */