Commit 2fee0088 authored by Pavel Hrdina's avatar Pavel Hrdina Committed by Kevin Wolf
Browse files

fdc: fix interrupt handling



If you call the SENSE INTERRUPT STATUS command while there is no interrupt
waiting you get as result unknown command.

Fixed status0 register handling for read/write/format commands.

Signed-off-by: default avatarPavel Hrdina <phrdina@redhat.com>
Signed-off-by: default avatarKevin Wolf <kwolf@redhat.com>
parent 6be01b1e
Loading
Loading
Loading
Loading
+21 −13
Original line number Diff line number Diff line
@@ -307,6 +307,9 @@ enum {
};

enum {
    FD_SR0_DS0      = 0x01,
    FD_SR0_DS1      = 0x02,
    FD_SR0_HEAD     = 0x04,
    FD_SR0_EQPMT    = 0x10,
    FD_SR0_SEEK     = 0x20,
    FD_SR0_ABNTERM  = 0x40,
@@ -972,14 +975,15 @@ static void fdctrl_reset_fifo(FDCtrl *fdctrl)
}

/* Set FIFO status for the host to read */
static void fdctrl_set_fifo(FDCtrl *fdctrl, int fifo_len, int do_irq)
static void fdctrl_set_fifo(FDCtrl *fdctrl, int fifo_len, uint8_t status0)
{
    fdctrl->data_dir = FD_DIR_READ;
    fdctrl->data_len = fifo_len;
    fdctrl->data_pos = 0;
    fdctrl->msr |= FD_MSR_CMDBUSY | FD_MSR_RQM | FD_MSR_DIO;
    if (do_irq)
        fdctrl_raise_irq(fdctrl, 0x00);
    if (status0) {
        fdctrl_raise_irq(fdctrl, status0);
    }
}

/* Set an error: unimplemented/unknown command */
@@ -1044,10 +1048,12 @@ static void fdctrl_stop_transfer(FDCtrl *fdctrl, uint8_t status0,
    FDrive *cur_drv;

    cur_drv = get_cur_drv(fdctrl);
    fdctrl->status0 = status0 | FD_SR0_SEEK | (cur_drv->head << 2) |
                      GET_CUR_DRV(fdctrl);

    FLOPPY_DPRINTF("transfer status: %02x %02x %02x (%02x)\n",
                   status0, status1, status2,
                   status0 | (cur_drv->head << 2) | GET_CUR_DRV(fdctrl));
    fdctrl->fifo[0] = status0 | (cur_drv->head << 2) | GET_CUR_DRV(fdctrl);
                   status0, status1, status2, fdctrl->status0);
    fdctrl->fifo[0] = fdctrl->status0;
    fdctrl->fifo[1] = status1;
    fdctrl->fifo[2] = status2;
    fdctrl->fifo[3] = cur_drv->track;
@@ -1060,7 +1066,7 @@ static void fdctrl_stop_transfer(FDCtrl *fdctrl, uint8_t status0,
    }
    fdctrl->msr |= FD_MSR_RQM | FD_MSR_DIO;
    fdctrl->msr &= ~FD_MSR_NONDMA;
    fdctrl_set_fifo(fdctrl, 7, 1);
    fdctrl_set_fifo(fdctrl, 7, fdctrl->status0);
}

/* Prepare a data transfer (either DMA or FIFO) */
@@ -1175,7 +1181,7 @@ static void fdctrl_start_transfer(FDCtrl *fdctrl, int direction)
    if (direction != FD_DIR_WRITE)
        fdctrl->msr |= FD_MSR_DIO;
    /* IO based transfer: calculate len */
    fdctrl_raise_irq(fdctrl, 0x00);
    fdctrl_raise_irq(fdctrl, FD_SR0_SEEK);

    return;
}
@@ -1608,12 +1614,14 @@ static void fdctrl_handle_sense_interrupt_status(FDCtrl *fdctrl, int direction)
        fdctrl->fifo[0] =
            FD_SR0_RDYCHG + FD_RESET_SENSEI_COUNT - fdctrl->reset_sensei;
        fdctrl->reset_sensei--;
    } else if (!(fdctrl->sra & FD_SRA_INTPEND)) {
        fdctrl->fifo[0] = FD_SR0_INVCMD;
        fdctrl_set_fifo(fdctrl, 1, 0);
        return;
    } else {
        /* XXX: status0 handling is broken for read/write
           commands, so we do this hack. It should be suppressed
           ASAP */
        fdctrl->fifo[0] =
            FD_SR0_SEEK | (cur_drv->head << 2) | GET_CUR_DRV(fdctrl);
                (fdctrl->status0 & ~(FD_SR0_HEAD | FD_SR0_DS1 | FD_SR0_DS0))
                | GET_CUR_DRV(fdctrl);
    }

    fdctrl->fifo[1] = cur_drv->track;