mirror of https://gitlab.com/qemu-project/qemu
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:
parent
4ddc07cac2
commit
6be01b1e0b
79
hw/fdc.c
79
hw/fdc.c
|
@ -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",
|
||||||
|
new_head, new_track, new_sect, fd_sector(cur_drv));
|
||||||
}
|
}
|
||||||
FLOPPY_DPRINTF("seek to next track (%d %02x %02x => %d)\n",
|
|
||||||
cur_drv->head, cur_drv->track,
|
|
||||||
cur_drv->sect, fd_sector(cur_drv));
|
|
||||||
} else {
|
} else {
|
||||||
cur_drv->sect++;
|
new_sect++;
|
||||||
}
|
}
|
||||||
return 1;
|
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 */
|
||||||
|
|
Loading…
Reference in New Issue